;-----------------------------------------------------------
;
; MXCC.ASM - Fast clip line function
; Copyright (c) 1994 by Alessandro Scotti
;
;-----------------------------------------------------------
WARN    PRO
NOWARN  RES
INCLUDE MODEX.DEF

PUBLIC  xsubClipLine

MX_TEXT SEGMENT USE16 PARA PUBLIC 'CODE'
        ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING

EXTRN   mx_BytesPerLine : WORD
EXTRN   mx_VideoSegment : WORD

EXTRN   mx_ClipX1       : WORD
EXTRN   mx_ClipY1       : WORD
EXTRN   mx_ClipX2       : WORD
EXTRN   mx_ClipY2       : WORD

tblGroups       LABEL WORD
        DW      10,     tbl00
        DW      10,     tbl10
        DW      9,      tbl20
        DW      -1,     0
        DW      10,     tbl40
        DW      10,     tbl50
        DW      9,      tbl60
        DW      -1,     0
        DW      6,      tbl80
        DW      6,      tbl90
        DW      5,      tblA0
        DW      -1,     0
        DW      -1,     0
        DW      -1,     0
        DW      -1,     0
        DW      -1,     0
tbl00   DW cc00, cc01, cc02, ccFF, cc04, cc05, cc06, ccFF, cc08, cc09, cc0A
tbl10   DW cc10, ccFF, cc12, ccFF, cc14, ccFF, cc16, ccFF, cc18, ccFF, cc1A
tbl20   DW cc20, cc21, ccFF, ccFF, cc24, cc25, ccFF, ccFF, cc28, cc29
tbl40   DW cc40, cc41, cc42, ccFF, ccFF, ccFF, ccFF, ccFF, cc48, cc49, cc4A
tbl50   DW cc50, ccFF, cc52, ccFF, ccFF, ccFF, ccFF, ccFF, cc58, ccFF, cc5A
tbl60   DW cc60, cc61, ccFF, ccFF, ccFF, ccFF, ccFF, ccFF, cc68, cc69
tbl80   DW cc80, cc81, cc82, ccFF, cc84, cc85, cc86
tbl90   DW cc90, ccFF, cc92, ccFF, cc94, ccFF, cc96
tblA0   DW ccA0, ccA1, ccFF, ccFF, ccA4, ccA5

ccTT:   clc
        ret
ccFF:   stc
        ret

; Group 00 -------------------------------------------------
;
cc00:
        clc
        ret
cc01:
        jmp     ClipQLeft
cc02:
        jmp     ClipQRight
cc04:
        jmp     ClipQTop
cc05:
        call    ClipQLeft
        cmp     si, [mx_ClipY1]
        jge     ccTT
        jmp     ClipQTop
cc06:
        call    ClipQRight
        cmp     si, [mx_ClipY1]
        jge     ccTT
        jmp     ClipQTop
cc08:
        jmp     ClipQBottom
cc09:
        call    ClipQLeft
        cmp     si, [mx_ClipY2]
        jle     ccTT
        jmp     ClipQBottom
cc0A:
        call    ClipQRight
        cmp     si, [mx_ClipY2]
        jle     ccTT
        jmp     ClipQBottom

; Group 10 -------------------------------------------------
;
cc10FF:
        stc
        ret
cc10TT:
        clc
        ret
cc10:
        jmp     ClipPLeft
cc12:
        call    ClipPLeft
        jmp     ClipQRight
cc14:
        call    ClipPLeft
        cmp     bx, [mx_ClipY1]
        jl      cc10FF
        jmp     ClipQTop
cc16:
        call    ClipPLeft
        cmp     bx, [mx_ClipY1]
        jl      cc10FF
        call    ClipQTop
        cmp     cx, [mx_ClipX2]
        jle     cc10TT
        jmp     ClipQRight
cc18:
        call    ClipPLeft
        cmp     bx, [mx_ClipY2]
        jg      cc10FF
        jmp     ClipQBottom
cc1A:
        call    ClipPLeft
        cmp     bx, [mx_ClipY2]
        jg      cc10FF
        call    ClipQBottom
        cmp     cx, [mx_ClipX2]
        jle     cc10TT
        jmp     ClipQRight

; Group 20 -------------------------------------------------
;
cc20TT:
        clc
        ret
cc20FF:
        stc
        ret
cc20:
        jmp     ClipPRight
cc21:
        call    ClipPRight
        jmp     ClipQLeft
cc24:
        call    ClipPRight
        cmp     bx, [mx_ClipY1]
        jl      cc20FF
        jmp     ClipQTop
cc25:
        call    ClipPRight
        cmp     bx, [mx_ClipY1]
        jl      cc20FF
        call    ClipQTop
        cmp     cx, [mx_ClipX1]
        jge     cc20TT
        jmp     ClipQLeft
cc28:
        call    ClipPRight
        cmp     bx, [mx_ClipY2]
        jg      cc20FF
        jmp     ClipQBottom
cc29:
        call    ClipPRight
        cmp     bx, [mx_ClipY2]
        jg      cc20FF
        call    ClipQBottom
        cmp     cx, [mx_ClipX1]
        jge     cc20TT
        jmp     ClipQLeft

; Group 40 -------------------------------------------------
;
cc40TT:
        clc
        ret
cc40FF:
        stc
        ret
cc40:
        jmp     ClipPTop
cc41:
        call    ClipPTop
        cmp     di, [mx_ClipX1]
        jl      cc40FF
        call    ClipQLeft
        cmp     si, [mx_ClipY1]
        jge     cc40TT
        jmp     ClipQTop
cc42:
        call    ClipPTop
        cmp     di, [mx_ClipX2]
        jg      cc40FF
        jmp     ClipQRight
cc48:
        call    ClipPTop
        jmp     ClipQBottom
cc49:
        call    ClipPTop
        cmp     di, [mx_ClipX1]
        jl      cc40FF
        call    ClipQLeft
        cmp     si, [mx_ClipY2]
        jle     cc40TT
        jmp     ClipQBottom
cc4A:
        call    ClipPTop
        cmp     di, [mx_ClipX2]
        jg      cc40FF
        call    ClipQRight
        cmp     si, [mx_ClipY2]
        jle     cc40TT
        jmp     ClipQBottom


; Group 50 -------------------------------------------------
;
cc50TT:
        clc
        ret
cc50FF:
        stc
        ret
cc50:
        call    ClipPLeft
        cmp     bx, [mx_ClipY1]
        jge     cc50TT
        jmp     ClipPTop
cc52:
        call    ClipQRight
        cmp     si, [mx_ClipY1]
        jl      cc50FF
        call    ClipPTop
        cmp     di, [mx_ClipX1]
        jge     cc50TT
        jmp     ClipPLeft
cc58:
        call    ClipQBottom
        cmp     cx, [mx_ClipX1]
        jl      cc50FF
        call    ClipPTop
        cmp     di, [mx_ClipX1]
        jge     cc50TT
        jmp     ClipPLeft
cc5A:
        call    ClipPLeft
        cmp     bx, [mx_ClipY2]
        jg      cc50FF
        call    ClipQRight
        cmp     bx, [mx_ClipY1]
        jl      cc50FF
        cmp     si, [mx_ClipY2]
        jle     cc50TT
        jmp     ClipQBottom

; Group 60 -------------------------------------------------
;
cc60TT:
        clc
        ret
cc60FF:
        stc
        ret
cc60:
        call    ClipPRight
        cmp     bx, [mx_ClipY1]
        jge     cc60TT
        jmp     ClipPTop
cc61:
        call    ClipQLeft
        cmp     si, [mx_ClipY2]
        jl      cc60FF
        call    ClipPTop
        cmp     di, [mx_ClipX2]
        jle     cc60TT
        jmp     ClipPRight
cc68:
        call    ClipQBottom
        cmp     cx, [mx_ClipX2]
        jg      cc60FF
        call    ClipPRight
        cmp     bx, [mx_ClipY1]
        jge     cc60TT
        jmp     ClipPTop
cc69:
        call    ClipQLeft
        cmp     si, [mx_ClipY1]
        jl      cc60FF
        call    ClipPRight
        cmp     bx, [mx_ClipY2]
        jg      cc60FF
        cmp     si, [mx_ClipY2]
        jle     cc69_1
        call    ClipQBottom
cc69_1:
        cmp     bx, [mx_ClipY1]
        jge     cc60TT
        jmp     ClipPTop

; Group 80 -------------------------------------------------
;
cc80TT:
        clc
        ret
cc80FF:
        stc
        ret
cc80:
        jmp     ClipPBottom
cc81:
        call    ClipPBottom
        cmp     di, [mx_ClipX1]
        jl      cc80FF
        jmp     ClipQLeft
cc82:
        call    ClipPBottom
        cmp     di, [mx_ClipX2]
        jg      cc80FF
        jmp     ClipQRight
cc84:
        call    ClipPBottom
        jmp     ClipQTop
cc85:
        call    ClipPBottom
        cmp     di, [mx_ClipX1]
        jl      cc80FF
        call    ClipQLeft
        cmp     si, [mx_ClipY1]
        jge     cc80FF
        jmp     ClipQTop
cc86:
        call    ClipPBottom
        cmp     di, [mx_ClipX2]
        jg      cc80FF
        call    ClipQRight
        cmp     si, [mx_ClipY1]
        jge     cc80TT
        jmp     ClipQTop

; Group 90 -------------------------------------------------
;
cc90TT:
        clc
        ret
cc90FF:
        stc
        ret
cc90:
        call    ClipPLeft
        cmp     bx, [mx_ClipY2]
        jle     cc90TT
        jmp     ClipPBottom
cc92:
        call    ClipQRight
        cmp     si, [mx_ClipY2]
        jg      cc90FF
        call    ClipPBottom
        cmp     di, [mx_ClipX1]
        jge     cc90TT
        jmp     ClipPLeft
cc94:
        call    ClipQTop
        cmp     cx, [mx_ClipX1]
        jl      cc90FF
        call    ClipPLeft
        cmp     bx, [mx_ClipY2]
        jle     cc90TT
        jmp     ClipPBottom
cc96:
        call    ClipPLeft
        cmp     bx, [mx_ClipY1]
        jl      cc90FF
        call    ClipQRight
        cmp     si, [mx_ClipY2]
        jg      cc90FF
        cmp     bx, [mx_ClipY2]
        jle     cc96_1
        call    ClipPBottom
cc96_1:
        cmp     si, [mx_ClipY1]
        jge     cc90TT
        jmp     ClipQTop

; Group A0 -------------------------------------------------
;
ccA0TT:
        clc
        ret
ccA0FF:
        stc
        ret
ccA0:
        call    ClipPRight
        cmp     bx, [mx_ClipY2]
        jle     ccA0TT
        jmp     ClipPBottom
ccA1:
        call    ClipQLeft
        cmp     si, [mx_ClipY2]
        jg      ccA0FF
        call    ClipPBottom
        cmp     di, [mx_ClipX2]
        jle     ccA0TT
        jmp     ClipPRight
ccA4:
        call    ClipQTop
        cmp     cx, [mx_ClipX2]
        jg      ccA0FF
        call    ClipPRight
        cmp     bx, [mx_ClipY2]
        jle     ccA0TT
        jmp     ClipPBottom
ccA5:
        call    ClipQLeft
        cmp     si, [mx_ClipY2]
        jg      ccA0FF
        call    ClipPRight
        cmp     bx, [mx_ClipY1]
        jl      ccA0FF
        cmp     si, [mx_ClipY1]
        jge     ccA5_1
        call    ClipQTop
ccA5_1:
        cmp     bx, [mx_ClipY2]
        jle     ccA0TT
        jmp     ClipPBottom

; Y1 = (Y2-Y1)*(mx_ClipX1-X1)/(X2-X1)+Y1 = (SI-BX)*(mx_ClipX1-DI)/(CX-DI)+BX
; X1 = mx_ClipX1
ClipPLeft:
        mov     ax, si
        sub     ax, bx
        mov     dx, [mx_ClipX1]
        sub     dx, di
        imul    dx
        mov     bp, cx
        sub     bp, di
        idiv    bp
        add     bx, ax
        mov     di, [mx_ClipX1]
        clc
        ret

; Y1 = (Y2-Y1)*(mx_ClipX2-X1)/(X2-X1)+Y1 = (SI-BX)*(mx_ClipX2-DI)/(CX-DI)+BX
; X1 = mx_ClipX2
ClipPRight:
        mov     ax, si
        sub     ax, bx
        mov     dx, [mx_ClipX2]
        sub     dx, di
        imul    dx
        mov     bp, cx
        sub     bp, di
        idiv    bp
        add     bx, ax
        mov     di, [mx_ClipX2]
        clc
        ret

; X1 = (X2-X1)*(mx_ClipY2-Y1)/(Y2-Y1)+X1 = (CX-DI)*(mx_ClipY2-BX)/(SI-BX)+DI
; Y1 = mx_ClipY2
ClipPBottom:
        mov     ax, cx
        sub     ax, di
        mov     dx, [mx_ClipY2]
        sub     dx, bx
        imul    dx
        mov     bp, si
        sub     bp, bx
        idiv    bp
        add     di, ax
        mov     bx, [mx_ClipY2]
        clc
        ret

; X1 = (X2-X1)*(mx_ClipY1-Y1)/(Y2-Y1)+X1 = (CX-DI)*(mx_ClipY1-BX)/(SI-BX)+DI
; Y1 = mx_ClipY1
ClipPTop:
        mov     ax, cx
        sub     ax, di
        mov     dx, [mx_ClipY1]
        sub     dx, bx
        imul    dx
        mov     bp, si
        sub     bp, bx
        idiv    bp
        add     di, ax
        mov     bx, [mx_ClipY1]
        clc
        ret

; Y2 = (Y1-Y2)*(mx_ClipX1-X2)/(X1-X2)+Y2 = (BX-SI)*(mx_ClipX1-CX)/(DI-CX)+SI
; X2 = mx_ClipX1
ClipQLeft:
        mov     ax, bx
        sub     ax, si
        mov     dx, [mx_ClipX1]
        sub     dx, cx
        imul    dx
        mov     bp, di
        sub     bp, cx
        idiv    bp
        add     si, ax
        mov     cx, [mx_ClipX1]
        clc
        ret

; Y2 = (Y1-Y2)*(mx_ClipX2-X2)/(X1-X2)+Y2 = (BX-SI)*(mx_ClipX2-CX)/(DI-CX)+SI
; X2 = mx_ClipX1
ClipQRight:
        mov     ax, bx
        sub     ax, si
        mov     dx, [mx_ClipX2]
        sub     dx, cx
        imul    dx
        mov     bp, di
        sub     bp, cx
        idiv    bp
        add     si, ax
        mov     cx, [mx_ClipX2]
        clc
        ret

; X2 = (X1-X2)*(mx_ClipY2-Y2)/(Y1-Y2)+X2 = (DI-CX)*(mx_ClipY2-SI)/(BX-SI)+CX
; Y2 = mx_ClipY1
ClipQBottom:
        mov     ax, di
        sub     ax, cx
        mov     dx, [mx_ClipY2]
        sub     dx, si
        imul    dx
        mov     bp, bx
        sub     bp, si
        idiv    bp
        add     cx, ax
        mov     si, [mx_ClipY2]
        clc
        ret

; X2 = (X1-X2)*(mx_ClipY1-Y2)/(Y1-Y2)+X2 = (DI-CX)*(mx_ClipY1-SI)/(BX-SI)+CX
; Y2 = mx_ClipY1
ClipQTop:
        mov     ax, di
        sub     ax, cx
        mov     dx, [mx_ClipY1]
        sub     dx, si
        imul    dx
        mov     bp, bx
        sub     bp, si
        idiv    bp
        add     cx, ax
        mov     si, [mx_ClipY1]
        clc
        ret

;-----------------------------------------------------------
;
; Checks the coordinates of a line against the active
; clip region.
; Uses the Sobkow-Pospisil-Yang (SPY) algorithm: this was
; supposed to be twice as fast as Cohen-Sutherland, but my
; tests show only a very small increase in speed and a noticeable
; increase of the program size! Maybe this is caused by the
; slow speed of VGA cards, so probably a better test should
; be performed with lines drawn in RAM.
;
; Input:
;       AX, BX  = X1, Y1
;       CX, DX  = X2, Y2
; Output:
;       CF      = set if line is full clipped
;       AX, BX  = clipped X1, Y1
;       CX, DX  = clipped X2, Y2
; Note:
;       destroys SI, DI
;
xsubClipLine     PROC    NEAR
        push    bp
        xor     si, si                  ; SPY code

        cmp     dx, [mx_ClipY2]
        jle     @@1
        or      si, 08h
        jmp     @@2
@@1:
        cmp     dx, [mx_ClipY1]
        jge     @@2
        or      si, 04h
@@2:

        cmp     cx, [mx_ClipX2]
        jle     @@3
        or      si, 02h
        jmp     @@4
@@3:
        cmp     cx, [mx_ClipX1]
        jge     @@4
        or      si, 01h
@@4:

        cmp     bx, [mx_ClipY2]
        jle     @@5
        or      si, 80h
        jmp     @@6
@@5:
        cmp     bx, [mx_ClipY1]
        jge     @@6
        or      si, 40h
@@6:

        cmp     ax, [mx_ClipX2]
        jle     @@7
        or      si, 20h
        jmp     @@8
@@7:
        cmp     ax, [mx_ClipX1]
        jge     @@8
        or      si, 10h
@@8:

        mov     di, si
        and     di, 000Fh               ; Index of procedure
        and     si, 00F0h
        .shr    si, 2                   ; Index of group (times 4)
        cmp     di, cs:tblGroups[si]    ; Is index within range?
        jg      @@Exit                  ; No, line is full clipped
        mov     si, cs:tblGroups[si+2]  ; Get offset of group table
        shl     di, 1                   ; We must index word elements
        add     si, di                  ; Make full offset
        mov     di, ax                  ; Move X1 to DI and free AX
        mov     si, cs:[si]             ; Get subroutine address
        xchg    dx, si                  ; Move Y2 to SI and free DX
        call    dx                      ; Call the proper subroutine
        mov     ax, di                  ; Restore AX to X1
        mov     dx, si                  ; Restore DX to Y2
        pop     bp
        ret

@@Exit:
        pop     bp
        stc
        ret
xsubClipLine     ENDP

MX_TEXT         ENDS
END
