File:  [WindowsNT SDKs] / ntddk / src / video / displays / s3 / i386 / lines.asm
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:31:12 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntddk-nov-1993, HEAD
Microsoft Windows NT Build 511 (DDK SDK) 11-01-1993

;---------------------------Module-Header------------------------------;
; Module Name: lines.asm
;
; ASM version of the line DDA calculator.
;
; Copyright (c) 1992 Microsoft Corporation
;-----------------------------------------------------------------------;

        .386

        .model  small,c

        assume cs:FLAT,ds:FLAT,es:FLAT,ss:FLAT
        assume fs:nothing,gs:nothing

        .xlist
        include stdcall.inc             ;calling convention cmacros
        include i386\strucs.inc
        include i386\lines.inc
        .list

        .data

        public gaflRoundTable
gaflRoundTable       label  dword
        dd      FL_H_ROUND_DOWN + FL_V_ROUND_DOWN       ; no flips
        dd      FL_H_ROUND_DOWN + FL_V_ROUND_DOWN       ; D flip
        dd      FL_H_ROUND_DOWN                         ; V flip
        dd      FL_V_ROUND_DOWN                         ; D & V flip
        dd      FL_V_ROUND_DOWN                         ; slope one
        dd      0baadf00dh
        dd      FL_H_ROUND_DOWN                         ; slope one & V flip
        dd      0baadf00dh

        .code

;--------------------------------Macro----------------------------------;
; testb ebx, <mask>
;
; Substitutes a byte compare if the mask is entirely in the lo-byte or
; hi-byte (thus saving 3 bytes of code space).
;
;-----------------------------------------------------------------------;

TESTB   macro   targ,mask,thirdarg
        local   mask2,delta

ifnb <thirdarg>
        .err    TESTB mask must be enclosed in brackets!
endif

        delta = 0
        mask2 = mask

        if mask2 AND 0ffff0000h
            test targ,mask                      ; If bit set in hi-word,
            exitm                               ; test entire dword
        endif

        if mask2 AND 0ff00h
            if mask2 AND 0ffh                   ; If bit set in lo-byte and
                test targ,mask                  ; hi-byte, test entire dword
                exitm
            endif

            mask2 = mask2 SHR 8
            delta = 1
        endif

ifidni <targ>,<EBX>
        if delta
            test bh,mask2
        else
            test bl,mask2
        endif
        exitm
endif

        .err    Too bad TESTB doesn't support targets other than ebx!
endm

;---------------------------Public-Routine------------------------------;
; bLines(ppdev, pptfxFirst, pptfxBuf, prun, cptfx, pls,
;        prclClip, apfn[], flStart)
;
; Handles lines with trivial or simple clipping.
;
;-----------------------------------------------------------------------;

cProc   bLines,36,< \
    uses esi edi ebx,  \
    ppdev:      ptr,   \
    pptfxFirst: ptr,   \
    pptfxBuf:   ptr,   \
    prun:       ptr,   \
    cptfx:      dword, \
    pls:        ptr,   \
    prclClip:   ptr,   \
    apfn:       ptr,   \
    flStart:    dword  >

        local pptfxBufEnd:           ptr   ; Last point in pptfxBuf
        local M0:                    dword ; Normalized x0 in device coords
        local dM:                    dword ; Delta-x in device coords
        local N0:                    dword ; Normalized y0 in device coords
        local dN:                    dword ; Delta-y in device coords
        local fl:                    dword ; Flags for current line
        local x:                     dword ; Normalized start pixel x-coord
        local y:                     dword ; Normalized start pixel y-coord
        local eqGamma_lo:            dword ; Upper 32 bits of Gamma
        local eqGamma_hi:            dword ; Lower 32 bits of Gamma
        local x0:                    dword ; Start pixel x-offset
        local y0:                    dword ; Start pixel y-offset
        local ulSlopeOneAdjustment:  dword ; Special offset if line of slope 1
        local cStylePels:            dword ; # of pixels in line (before clip)
        local xStart:                dword ; Start pixel x-offset before clip
        local pfn:                   ptr   ; Pointer to strip drawing function
        local cPels:                 dword ; # pixels to be drawn (after clip)
        local i:                     dword ; # pixels in strip
        local r:                     dword ; Remainder (or "error") term
        local d_I:                   dword ; Delta-I
        local d_R:                   dword ; Delta-R
        local plStripEnd:            ptr   ; Last strip in buffer
        local ptlStart[size POINTL]: byte  ; Unnormalized start coord
        local dN_Original:           dword ; dN before half-flip
        local xClipLeft:             dword ; Left side of clip rectangle
        local xClipRight:            dword ; Right side of clip rectangle
        local strip[size STRIPS]:    byte  ; Our strip buffer

        mov     ecx, cptfx
        mov     edx, pptfxBuf
        lea     eax, [edx + ecx * (size POINTL) - (size POINTL)]
        mov     pptfxBufEnd, eax        ; pptfxBufEnd is inclusive of end point

        mov     eax, [edx].ptl_x        ; Load up end point (M1, N1)
        mov     edi, [edx].ptl_y

        mov     edx, pptfxFirst         ; Load up start point (M0, N0)
        mov     esi, [edx].ptl_x
        mov     ecx, [edx].ptl_y

        mov     ebx, flStart

;-----------------------------------------------------------------------;
; Flip to the first octant.                                             ;
;-----------------------------------------------------------------------;

; Register state:       esi = M0
;                       ecx = N0
;                       eax = dM (M1)
;                       edi = dN (N1)
;                       ebx = fl

; Make sure we go left to right:

the_main_loop:
        cmp     esi, eax
        jle     short is_left_to_right  ; skip if M0 <= M1
        xchg    esi, eax                ; swap M0, M1
        xchg    ecx, edi                ; swap N0, N1
        or      ebx, FL_FLIP_H

is_left_to_right:

; Compute the deltas, remembering that the DDI says we should get
; deltas less than 2^31.  If we get more, we ensure we don't crash
; later on by simply skipping the line:

        sub     eax, esi                ; eax = dM
        jo      next_line               ; dM must be less than 2^31
        sub     edi, ecx                ; edi = dN
        jo      next_line               ; dN must be less than 2^31

        jge     short is_top_to_bottom  ; skip if dN >= 0
        neg     ecx                     ; N0 = -N0
        neg     edi                     ; N1 = -N1
        or      ebx, FL_FLIP_V

is_top_to_bottom:
        cmp     edi, eax
        jb      short done_flips        ; skip if dN < dM
        jne     short slope_more_than_one

; We must special case slopes of one:

        or      ebx, FL_FLIP_SLOPE_ONE
        jmp     short done_flips

slope_more_than_one:
        xchg    eax, edi                ; swap dM, dN
        xchg    esi, ecx                ; swap M0, N0
        or      ebx, FL_FLIP_D

done_flips:

        mov     edx, ebx
        and     edx, FL_ROUND_MASK
        .errnz  FL_ROUND_SHIFT - 2
        or      ebx, [gaflRoundTable + edx]  ; get our rounding flags

        mov     dM, eax                 ; save some info
        mov     dN, edi
        mov     fl, ebx

        mov     edx, esi                ; x = LFLOOR(M0)
        sar     edx, FLOG2
        mov     x, edx

        mov     edx, ecx                ; y = LFLOOR(N0)
        sar     edx, FLOG2
        mov     y, edx

;-----------------------------------------------------------------------;
; Compute the fractional remainder term                                 ;
;-----------------------------------------------------------------------;

        public  compute_fractional
compute_fractional:
        and     esi, F - 1              ; M0 = FXFRAC(M0)
        and     ecx, F - 1              ; N0 = FXFRAC(N0)

        mov     M0, esi                 ; save M0, N0 for later
        mov     N0, ecx

        lea     edx, [ecx + F/2]
        mul     edx                     ; [edx:eax] = dM * (N0 + F/2)
        xchg    eax, edi
        mov     ecx, edx                ; [ecx:edi] = dM * (N0 + F/2)
                                        ; (we just nuked N0)

        mul     esi                     ; [edx:eax] = dN * M0

; Now gamma = dM * (N0 + F/2) - dN * M0 - bRoundDown

        .errnz  FL_V_ROUND_DOWN - 8000h
        ror     bh, 8
        sbb     edi, eax
        sbb     ecx, edx

        shrd    edi, ecx, FLOG2
        sar     ecx, FLOG2              ; gamma = [ecx:edi] >>= 4

        mov     eqGamma_hi, ecx
        mov     eqGamma_lo, edi

        mov     eax, N0

; Register state:
;                       eax = N0
;                       ebx = fl
;                       ecx = eqGamma_hi
;                       edx = garbage
;                       esi = M0
;                       edi = eqGamma_lo

        testb   ebx, FL_FLIP_H
        jnz     line_runs_right_to_left

;-----------------------------------------------------------------------;
; Figure out which pixels are at the ends of a left-to-right line.      ;
;                               -------->                               ;
;-----------------------------------------------------------------------;

        public line_runs_left_to_right
line_runs_left_to_right:
        or      esi, esi
        jz      short LtoR_check_slope_one
                                        ; skip ahead if M0 == 0
                                        ;   (in that case, x0 = 0 which is to be
                                        ;   kept in esi, and is already
                                        ;   conventiently zero)

        or      eax, eax
        jnz     short LtoR_N0_not_zero

        .errnz  FL_H_ROUND_DOWN - 80h
        ror     bl, 8
        sbb     esi, -F/2
        shr     esi, FLOG2
        jmp     short LtoR_check_slope_one
                                        ; esi = x0 = rounded M0

LtoR_N0_not_zero:
        sub     eax, F/2
        sbb     edx, edx
        xor     eax, edx
        sub     eax, edx
        cmp     esi, eax
        sbb     esi, esi
        inc     esi                     ; esi = x0 = (abs(N0 - F/2) <= M0)

        public  LtoR_check_slope_one
LtoR_check_slope_one:
        mov     ulSlopeOneAdjustment, 0
        mov     eax, ebx
        and     eax, FL_FLIP_SLOPE_ONE + FL_H_ROUND_DOWN
        cmp     eax, FL_FLIP_SLOPE_ONE + FL_H_ROUND_DOWN
        jne     short LtoR_compute_y0_from_x0

; We have to special case lines that are exactly of slope 1 or -1:

        mov     eax, N0
        add     eax, dN
        and     eax, F - 1              ; eax = N1
        jz      short LtoR_slope_one_check_start_point

        mov     edx, M0
        add     edx, dM
        and     edx, F - 1              ; edx = M1

        add     eax, F/2
        cmp     edx, eax                ; cmp M1, N1 + F/2
        jne     short LtoR_slope_one_check_start_point
        mov     ulSlopeOneAdjustment, -1

LtoR_slope_one_check_start_point:
        mov     eax, M0
        or      eax, eax
        jz      short LtoR_compute_y0_from_x0

        add     eax, F/2
        cmp     eax, N0                 ; cmp M0 + 8, N0
        jne     short LtoR_compute_y0_from_x0

        xor     esi, esi                ; x0 = 0

LtoR_compute_y0_from_x0:

; ecx = eqGamma_hi
; esi = x0
; edi = eqGamma_lo

        mov     eax, dN
        mov     edx, dM

        mov     x0, esi
        mov     y0, 0
        cmp     ecx, 0
        jl      short LtoR_compute_x1

        neg     esi
        and     esi, eax
        sub     edx, esi
        cmp     edi, edx
        mov     edx, dM
        jl      short LtoR_compute_x1
        mov     y0, 1                   ; y0 = floor((dN * x0 + eqGamma) / dM)

LtoR_compute_x1:

; Register state:
;                       eax = dN
;                       ebx = fl
;                       ecx = garbage
;                       edx = dM
;                       esi = garbage
;                       edi = garbage

        mov     esi, M0
        add     esi, edx
        mov     ecx, esi
        shr     esi, FLOG2
        dec     esi                     ; x1 = ((M0 + dM) >> 4) - 1
        add     esi, ulSlopeOneAdjustment
        and     ecx, F-1                ; M1 = (M0 + dM) & 15
        jz      done_first_pel_last_pel

        add     eax, N0
        and     eax, F-1                ; N1 = (N0 + dN) & 15
        jnz     short LtoR_N1_not_zero

        .errnz  FL_H_ROUND_DOWN - 80h
        ror     bl, 8
        sbb     ecx, -F/2
        shr     ecx, FLOG2              ; ecx = LROUND(M1, fl & FL_ROUND_DOWN)
        add     esi, ecx
        jmp     done_first_pel_last_pel

LtoR_N1_not_zero:
        sub     eax, F/2
        sbb     edx, edx
        xor     eax, edx
        sub     eax, edx
        cmp     eax, ecx
        jg      done_first_pel_last_pel
        inc     esi
        jmp     done_first_pel_last_pel

;-----------------------------------------------------------------------;
; Figure out which pixels are at the ends of a right-to-left line.      ;
;                               <--------                               ;
;-----------------------------------------------------------------------;

; Compute x0:

        public  line_runs_right_to_left
line_runs_right_to_left:
        mov     x0, 1                   ; x0 = 1
        or      eax, eax
        jnz     short RtoL_N0_not_zero

        xor     edx, edx                ; ulDelta = 0
        .errnz  FL_H_ROUND_DOWN - 80h
        ror     bl, 8
        sbb     esi, -F/2
        shr     esi, FLOG2              ; esi = LROUND(M0, fl & FL_H_ROUND_DOWN)
        jz      short RtoL_check_slope_one

        mov     x0, 2
        mov     edx, dN
        jmp     short RtoL_check_slope_one

RtoL_N0_not_zero:
        sub     eax, F/2
        sbb     edx, edx
        xor     eax, edx
        sub     eax, edx
        add     eax, esi                ; eax = ABS(N0 - F/2) + M0
        xor     edx, edx                ; ulDelta = 0
        cmp     eax, F
        jle     short RtoL_check_slope_one

        mov     x0, 2                   ; x0 = 2
        mov     edx, dN                 ; ulDelta = dN

        public  RtoL_check_slope_one
RtoL_check_slope_one:
        mov     ulSlopeOneAdjustment, 0
        mov     eax, ebx
        and     eax, FL_FLIP_SLOPE_ONE + FL_H_ROUND_DOWN
        cmp     eax, FL_FLIP_SLOPE_ONE
        jne     short RtoL_compute_y0_from_x0

; We have to special case lines that are exactly of slope 1 or -1:

        mov     eax, N0
        add     eax, dN
        and     eax, F - 1              ; eax = N1
        jz      short RtoL_slope_one_check_start_point

        mov     esi, M0
        add     esi, dM
        and     esi, F - 1              ; esi = M1

        add     eax, F/2
        cmp     esi, eax                ; cmp M1, N1 + F/2
        jne     short RtoL_slope_one_check_start_point
        mov     ulSlopeOneAdjustment, 1

RtoL_slope_one_check_start_point:
        mov     eax, M0
        or      eax, eax
        jz      short RtoL_compute_y0_from_x0

        add     eax, F/2
        cmp     eax, N0                 ; cmp M0 + 8, N0
        jne     short RtoL_compute_y0_from_x0

        mov     x0, 2                   ; x0 = 2
        mov     edx, dN                 ; ulDelta = dN

RtoL_compute_y0_from_x0:

; eax = garbage
; ebx = fl
; ecx = eqGamma_hi
; edx = ulDelta
; esi = garbage
; edi = eqGamma_lo

        mov     eax, dN                 ; eax = dN
        mov     y0, 0                   ; y0 = 0

        add     edi, edx
        adc     ecx, 0                  ; eqGamma += ulDelta
                                        ; NOTE: Setting flags here!
        mov     edx, dM                 ; edx = dM
        jl      short RtoL_compute_x1   ; NOTE: Looking at the flags here!
        jg      short RtoL_y0_is_2

        lea     ecx, [edx + edx]
        sub     ecx, eax                ; ecx = 2 * dM - dN
        cmp     edi, ecx
        jge     short RtoL_y0_is_2

        sub     ecx, edx                ; ecx = dM - dN
        cmp     edi, ecx
        jl      short RtoL_compute_x1

        mov     y0, 1
        jmp     short RtoL_compute_x1

RtoL_y0_is_2:
        mov     y0, 2

RtoL_compute_x1:

; Register state:
;                       eax = dN
;                       ebx = fl
;                       ecx = garbage
;                       edx = dM
;                       esi = garbage
;                       edi = garbage

        mov     esi, M0
        add     esi, edx
        mov     ecx, esi
        shr     esi, FLOG2              ; x1 = (M0 + dM) >> 4
        add     esi, ulSlopeOneAdjustment
        and     ecx, F-1                ; M1 = (M0 + dM) & 15

        add     eax, N0
        and     eax, F-1                ; N1 = (N0 + dN) & 15
        jnz     short RtoL_N1_not_zero

        .errnz  FL_H_ROUND_DOWN - 80h
        ror     bl, 8
        sbb     ecx, -F/2
        shr     ecx, FLOG2              ; ecx = LROUND(M1, fl & FL_ROUND_DOWN)
        add     esi, ecx
        jmp     done_first_pel_last_pel

RtoL_N1_not_zero:
        sub     eax, F/2
        sbb     edx, edx
        xor     eax, edx
        sub     eax, edx
        add     eax, ecx                ; eax = ABS(N1 - F/2) + M1
        cmp     eax, F+1
        sbb     esi, -1

done_first_pel_last_pel:

; Register state:
;                       eax = garbage
;                       ebx = fl
;                       ecx = garbage
;                       edx = garbage
;                       esi = x1
;                       edi = garbage

        mov     ecx, x0
        lea     edx, [esi + 1]
        sub     edx, ecx                ; edx = x1 - x0 + 1

        jle     next_line
        mov     cStylePels, edx
        mov     xStart, ecx

;-----------------------------------------------------------------------;
; See if clipping or styling needs to be done.                          ;
;-----------------------------------------------------------------------;

        testb   ebx, FL_CLIP
        jnz     do_some_clipping

; Register state:
;                       eax = garbage
;                       ebx = fl
;                       ecx = x0
;                       edx = garbage
;                       esi = x1
;                       edi = garbage

done_clipping:
        mov     eax, y0

        sub     esi, ecx
        inc     esi                     ; esi = cPels = x1 - x0 + 1
        mov     cPels, esi

        add     ecx, x                  ; ecx = ptlStart.ptl_x
        add     eax, y                  ; eax = ptlStart.ptl_y

        testb   ebx, FL_FLIP_D
        jz      short do_v_unflip
        xchg    ecx, eax

do_v_unflip:
        testb   ebx, FL_FLIP_V
        jz      short done_unflips
        neg     eax

done_unflips:
        testb   ebx, FL_STYLED
        jnz     do_some_styling

done_styling:
        lea     edx, [strip.ST_alStrips + (STRIP_MAX * 4)]
        mov     plStripEnd, edx

;-----------------------------------------------------------------------;
; Setup to do DDA.                                                      ;
;-----------------------------------------------------------------------;

; Register state:
;                       eax = ptlStart.ptl_y
;                       ebx = fl
;                       ecx = ptlStart.ptl_x
;                       edx = garbage
;                       esi = garbage
;                       edi = garbage

        mov     strip.ST_ptlStart.ptl_x, ecx
        mov     strip.ST_ptlStart.ptl_y, eax

        mov     eax, dM
        mov     ecx, dN
        mov     esi, eqGamma_lo
        mov     edi, eqGamma_hi


; Register state:
;                       eax = dM
;                       ebx = fl
;                       ecx = dN
;                       edx = garbage
;                       esi = eqGamma_lo
;                       edi = eqGamma_hi

        lea     edx, [ecx + ecx]        ; if (2 * dN > dM)
        cmp     edx, eax
        mov     edx, y0                 ; Load y0 again
        jbe     short after_half_flip

        test    ebx, (FL_STYLED + FL_DONT_DO_HALF_FLIP)
        jnz     short after_half_flip

        or      ebx, FL_FLIP_HALF
        mov     fl, ebx

; Do a half flip!

        not     esi
        not     edi
        add     esi, eax
        adc     edi, 0                  ; eqGamma = -eqGamma - 1 + dM

        neg     ecx
        add     ecx, eax                ; dN = dM - dN

        neg     edx
        add     edx, x0                 ; y0 = x0 - y0

after_half_flip:
        mov     strip.ST_flFlips, ebx
        mov     eax, dM

; Register state:
;                       eax = dM
;                       ebx = fl
;                       ecx = dN
;                       edx = y0
;                       esi = eqGamma_lo
;                       edi = eqGamma_hi

        or      ecx, ecx
        jz      short zero_slope

compute_dda_stuff:
        inc     edx
        mul     edx
        stc                             ; set the carry to accomplish -1
        sbb     eax, esi
        sbb     edx, edi                ; (y0 + 1) * dM - eqGamma - 1
        div     ecx

        mov     esi, eax                ; esi = i
        mov     edi, edx                ; edi = r

        xor     edx, edx
        mov     eax, dM
        div     ecx                     ; edx = d_R, eax = d_I
        mov     d_I, eax

        sub     esi, x0
        inc     esi

done_dda_stuff:

; Register state:
;                       eax = d_I
;                       ebx = fl
;                       ecx = dN
;                       edx = d_R
;                       esi = i
;                       edi = r

; We're going to decide if we can call the short-vector routines.  They
; can only take strips that have a maximum length of 15 pixels each.
; We happen to know that the longest strip in our line could be is d_I + 1.

        and     ebx, FL_STRIP_MASK
        mov     eax, apfn

        .errnz  FL_STRIP_SHIFT
        lea     eax, [eax + ebx * 4]

        cmp     d_I, MAX_SHORT_STROKE_LENGTH
        sbb     ebx, ebx                ; ffffffffh when < 15, 0 when >= 15
        and     ebx, NUM_STRIP_DRAW_DIRECTIONS * 4
                                        ; Look four entries further into table

        mov     eax, [eax + ebx]
        mov     pfn, eax

        lea     eax, [strip.ST_alStrips]
        mov     ebx, cPels

;-----------------------------------------------------------------------;
; Do our main DDA loop.                                                 ;
;-----------------------------------------------------------------------;

; Register state:
;                       eax = plStrip
;                       ebx = cPels
;                       ecx = dN
;                       edx = d_R
;                       esi = i
;                       edi = r

dda_loop:
        sub     ebx, esi
        jle     final_strip

        mov     [eax], esi
        add     eax, 4
        cmp     plStripEnd, eax
        jbe     short output_strips

done_output_strips:
        mov     esi, d_I
        add     edi, edx
        cmp     edi, ecx
        jb      short dda_loop

        sub     edi, ecx
        inc     esi
        jmp     short dda_loop

zero_slope:
        mov     esi, 7fffffffh          ; Make run maximum length (cPels
                                        ;   actually decideds how long the line
                                        ;   is)
        mov     d_I, 7fffffffh          ; Make delta maximum length so that
                                        ; we don't try to do short vectors
        mov     eax, cPels              ; We need this when we decide if to do
        dec     eax                     ;   short strip routines.
        jmp     short done_dda_stuff

;-----------------------------------------------------------------------;
; Empty strips buffer.                                                  ;
;-----------------------------------------------------------------------;

output_strips:
        mov     d_R, edx
        mov     cPels, ebx
        mov     i, esi
        mov     r, edi
        mov     dN, ecx

        lea     edx, [strip.ST_alStrips]
        sub     eax, edx
        shr     eax, 2
        mov     strip.ST_cStrips, eax

        mov     eax, ppdev
        lea     edx, [strip]
        mov     ecx, pls

        ptrCall <dword ptr pfn>, \
                <eax, edx, ecx>

        mov     esi, i
        mov     edi, r
        mov     ebx, cPels
        mov     edx, d_R
        mov     ecx, dN
        lea     eax, [strip.ST_alStrips]
        jmp     done_output_strips

;-----------------------------------------------------------------------;
; Empty strips buffer and go on to next line.                           ;
;-----------------------------------------------------------------------;

final_strip:
        add     ebx, esi
        mov     [eax], ebx
        add     eax, 4

very_final_strip:
        lea     edx, [strip.ST_alStrips]
        sub     eax, edx
        shr     eax, 2
        mov     strip.ST_cStrips, eax

        mov     eax, ppdev
        lea     edx, [strip]
        mov     ecx, pls

        ptrCall   <dword ptr pfn>, \
                <eax, edx, ecx>

next_line:
        mov     ebx, flStart
        testb   ebx, FL_COMPLEX_CLIP
        jnz     short see_if_done_complex_clipping

        mov     edx, pptfxBuf
        cmp     edx, pptfxBufEnd
        je      short all_done

        mov     esi, [edx].ptl_x
        mov     ecx, [edx].ptl_y
        add     edx, size POINTL
        mov     pptfxBuf, edx
        mov     eax, [edx].ptl_x
        mov     edi, [edx].ptl_y
        jmp     the_main_loop

all_done:
        mov     eax, 1

        cRet    bLines

see_if_done_complex_clipping:
        mov     ebx, fl
        dec     cptfx
        jz      short all_done
        jmp     continue_complex_clipping

;---------------------------Private-Routine-----------------------------;
; do_some_styling
;
; Inputs:
;       eax = ptlStart.ptl_y
;       ebx = fl
;       ecx = ptlStart.ptl_x
; Preserves:
;       eax, ebx, ecx
; Output:
;       Exits to done_styling.
;
;-----------------------------------------------------------------------;

do_some_styling:
        mov     ptlStart.ptl_x, ecx

        mov     esi, pls
        mov     edi, [esi].LS_spNext    ; spThis
        mov     edx, edi
        add     edx, cStylePels         ; spNext

; For styles, we don't bother to keep the style position normalized.
; (we do ensure that it's positive, though).  If a figure is over 2
; billion pels long, we'll be a pel off in our style state (oops!).

        and     edx, 7fffffffh
        mov     [esi].LS_spNext, edx
        mov     ptlStart.ptl_y, eax

; Do arbitrary styles:

do_arbitrary_style:
        testb   ebx, FL_FLIP_H
        jz      short arbitrary_left_to_right

        sub     edx, x0
        add     edx, xStart
        mov     eax, edx
        xor     edx, edx
        div     [esi].LS_spTotal

        neg     edx
        jge     short continue_right_to_left
        add     edx, [esi].LS_spTotal
        not     eax

continue_right_to_left:
        mov     edi, dword ptr [esi].LS_jStartMask
        not     edi
        mov     ecx, [esi].LS_aspRtoL
        jmp     short compute_arbitrary_stuff

arbitrary_left_to_right:
        add     edi, x0
        sub     edi, xStart
        mov     eax, edi
        xor     edx, edx
        div     [esi].LS_spTotal
        mov     edi, dword ptr [esi].LS_jStartMask
        mov     ecx, [esi].LS_aspLtoR

compute_arbitrary_stuff:
;       eax = sp / spTotal
;       ebx = fl
;       ecx = pspStart
;       edx = sp % spTotal
;       esi = pla
;       edi = jStyleMask

        and     eax, [esi].LS_cStyle        ; if odd length style and second run
        and     al, 1                       ; through style array, flip the
        jz      short odd_style_array_done  ; meaning of the elements
        not     edi

odd_style_array_done:
        mov     [esi].LS_pspStart, ecx
        mov     eax, [esi].LS_cStyle
        lea     eax, [ecx + eax * 4 - 4]
        mov     [esi].LS_pspEnd, eax

find_psp:
        sub     edx, [ecx]
        jl      short found_psp
        add     ecx, 4
        jmp     short find_psp

found_psp:
        mov     [esi].LS_psp, ecx
        neg     edx
        mov     [esi].LS_spRemaining, edx

        sub     ecx, [esi].LS_pspStart
        test    ecx, 4                  ; size STYLEPOS
        jz      short done_arbitrary
        not     edi

done_arbitrary:
        mov     dword ptr [esi].LS_jStyleMask, edi
        mov     eax, ptlStart.ptl_y
        mov     ecx, ptlStart.ptl_x
        jmp     done_styling


;---------------------------Private-Routine-----------------------------;
; do_some_clipping
;
; Inputs:
;       eax = garbage
;       ebx = fl
;       ecx = x0
;       edx = garbage
;       esi = x1
;       edi = garbage
;
; Decides whether to do simple or complex clipping.
;
;-----------------------------------------------------------------------;

        align 4

        public  do_some_clipping
do_some_clipping:
        testb   ebx, FL_COMPLEX_CLIP
        jnz     initialize_complex_clipping

;-----------------------------------------------------------------------;
; simple_clipping
;
; Inputs:
;       ebx = fl
;       ecx = x0
;       esi = x1
; Output:
;       ebx = fl
;       ecx = new x0 (stack variable updated too)
;       esi = new x1
;       y0 stack variable updated
; Uses:
;       All registers
; Exits:
;       to done_clipping
;
; This routine handles clipping the line to the clip rectangle (it's
; faster to handle this case in the driver than to call the engine to
; clip for us).
;
; Fractional end-point lines complicate our lives a bit when doing
; clipping:
;
; 1) For styling, we must know the unclipped line's length in pels, so
;    that we can correctly update the styling state when the line is
;    clipped.  For this reason, I do clipping after doing the hard work
;    of figuring out which pixels are at the ends of the line (this is
;    wasted work if the line is not styled and is completely clipped,
;    but I think it's simpler this way).  Another reason is that we'll
;    have calculated eqGamma already, which we use for the intercept
;    calculations.
;
;    With the assumption that most lines will not be completely clipped
;    away, this strategy isn't too painful.
;
; 2) x0, y0 are not necessarily zero, where (x0, y0) is the start pel of
;    the line.
;
; 3) We know x0, y0 and x1, but not y1.  We haven't needed to calculate
;    y1 until now.  We'll need the actual value, and not an upper bound
;    like y1 = LFLOOR(dM) + 2 because we have to be careful when
;    calculating x(y) that y0 <= y <= y1, otherwise we can cause an
;    overflow on the divide (which, needless to say, is bad).
;
;-----------------------------------------------------------------------;

        public  simple_clipping
simple_clipping:
        mov     edi, prclClip           ; get pointer to normalized clip rect
        and     ebx, FL_RECTLCLIP_MASK  ;   (it's lower-right exclusive)

        .errnz  (FL_RECTLCLIP_SHIFT - 2); ((ebx AND FL_RECTLCLIP_MASK) shr
        .errnz  (size RECTL) - 16       ;   FL_RECTLCLIP_SHIFT) is our index
        lea     edi, [edi + ebx*4]      ;   into the array of rectangles

        mov     edx, [edi].xRight       ; load the rect coordinates
        mov     eax, [edi].xLeft
        mov     ebx, [edi].yBottom
        mov     edi, [edi].yTop

; Translate to our origin and so some quick completely clipped tests:

        sub     edx, x
        cmp     ecx, edx
        jge     totally_clipped         ; totally clipped if x0 >= xRight

        sub     eax, x
        cmp     esi, eax
        jl      totally_clipped         ; totally clipped if x1 < xLeft

        sub     ebx, y
        cmp     y0, ebx
        jge     totally_clipped         ; totally clipped if y0 >= yBottom

        sub     edi, y

; Save some state:

        mov     xClipRight, edx
        mov     xClipLeft, eax

        cmp     esi, edx                ; if (x1 >= xRight) x1 = xRight - 1
        jl      short calculate_y1
        lea     esi, [edx - 1]

calculate_y1:
        mov     eax, esi                ; y1 = (x1 * dN + eqGamma) / dM
        mul     dN
        add     eax, eqGamma_lo
        adc     edx, eqGamma_hi
        div     dM

        cmp     edi, eax                ; if (yTop > y1) clipped
        jg      short totally_clipped

        cmp     ebx, eax                ; if (yBottom > y1) know x1
        jg      short x1_computed

        mov     eax, ebx                ; x1 = (yBottom * dM + eqBeta) / dN
        mul     dM
        stc
        sbb     eax, eqGamma_lo
        sbb     edx, eqGamma_hi
        div     dN
        mov     esi, eax

; At this point, we've taken care of calculating the intercepts with the
; right and bottom edges.  Now we work on the left and top edges:

x1_computed:
        mov     edx, y0

        mov     eax, xClipLeft          ; don't have to compute y intercept
        cmp     eax, ecx                ;   at left edge if line starts to
        jle     short top_intercept     ;   right of left edge

        mov     ecx, eax                ; x0 = xLeft
        mul     dN                      ; y0 = (xLeft * dN + eqGamma) / dM
        add     eax, eqGamma_lo
        adc     edx, eqGamma_hi
        div     dM

        cmp     ebx, eax                ; if (yBottom <= y0) clipped
        jle     short totally_clipped

        mov     edx, eax
        mov     y0, eax

top_intercept:
        mov     ebx, fl                 ; get ready to leave
        mov     x0, ecx

        cmp     edi, edx                ; if (yTop <= y0) done clipping
        jle     done_clipping

        mov     eax, edi                ; x0 = (yTop * dM + eqBeta) / dN + 1
        mul     dM
        stc
        sbb     eax, eqGamma_lo
        sbb     edx, eqGamma_hi
        div     dN
        lea     ecx, [eax + 1]

        cmp     xClipRight, ecx         ; if (xRight <= x0) clipped
        jle     short totally_clipped

        mov     y0, edi                 ; y0 = yTop
        mov     x0, ecx
        jmp     done_clipping           ; all done!

totally_clipped:

; The line is completely clipped.  See if we have to update our style state:

        mov     ebx, fl
        testb   ebx, FL_STYLED
        jz      next_line

; Adjust our style state:

        mov     esi, pls
        mov     eax, [esi].LS_spNext
        add     eax, cStylePels
        mov     [esi].LS_spNext, eax

        cmp     eax, [esi].LS_spTotal2
        jb      next_line

; Have to normalize first:

        xor     edx, edx
        div     [esi].LS_spTotal2
        mov     [esi].LS_spNext, edx

        jmp     next_line

;-----------------------------------------------------------------------;

initialize_complex_clipping:
        mov     eax, dN                 ; save a copy of original dN
        mov     dN_Original, eax

;---------------------------Private-Routine-----------------------------;
; continue_complex_clipping
;
; Inputs:
;       ebx = fl
; Output:
;       ebx = fl
;       ecx = x0
;       esi = x1
; Uses:
;       All registers.
; Exits:
;       to done_clipping
;
; This routine handles the necessary initialization for the next
; run in the CLIPLINE structure.
;
; NOTE: This routine is jumped to from two places!
;-----------------------------------------------------------------------;

        public  continue_complex_clipping
continue_complex_clipping:
        mov     edi, prun
        mov     ecx, xStart
        testb   ebx, FL_FLIP_H
        jz      short complex_left_to_right

complex_right_to_left:

; Figure out x0 and x1 for right-to-left lines:

        add     ecx, cStylePels
        dec     ecx
        mov     esi, ecx                ; esi = ecx = xStart + cStylePels - 1
        sub     ecx, [edi].RUN_iStop    ; New x0
        sub     esi, [edi].RUN_iStart   ; New x1
        jmp     short complex_reset_variables

complex_left_to_right:

; Figure out x0 and x1 for left-to-right lines:

        mov     esi, ecx                ; esi = ecx = xStart
        add     ecx, [edi].RUN_iStart   ; New x0
        add     esi, [edi].RUN_iStop    ; New x1

complex_reset_variables:
        mov     x0, ecx

; The half flip mucks with some of our variables, and we have to reset
; them every pass.  We would have to reset eqGamma too, but it never
; got saved to memory in its modified form.

        add     edi, size RUN
        mov     prun, edi               ; Increment run pointer for next time

        mov     edi, pls
        mov     eax, [edi].LS_spComplex
        mov     [edi].LS_spNext, eax    ; pls->spNext = pls->spComplex

        mov     eax, dN_Original        ; dN = dN_Original
        mov     dN, eax

        mul     ecx
        add     eax, eqGamma_lo
        adc     edx, eqGamma_hi         ; [edx:eax] = dN*x0 + eqGamma

        div     dM
        mov     y0, eax
        jmp     done_clipping

endProc bLines
        end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.