You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1235 lines
38 KiB
1235 lines
38 KiB
;---------------------------Module-Header------------------------------;
|
|
; Module Name: lines.asm
|
|
;
|
|
; ASM version of the line DDA calculator.
|
|
;
|
|
; Copyright (c) 1992-1994 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:
|
|
|
|
;
|
|
; if (M1 > 0) AMD (N1 == M1 + 8)
|
|
;
|
|
|
|
mov eax, N0
|
|
add eax, dN
|
|
and eax, F - 1 ; eax = N1
|
|
|
|
mov edx, M0
|
|
add edx, dM
|
|
and edx, F - 1 ; edx = M1
|
|
|
|
jz short LtoR_slope_one_check_start_point
|
|
|
|
add edx, F/2 ; M1 + 8
|
|
cmp edx, eax ; cmp N1, M1 + 8
|
|
jne short LtoR_slope_one_check_start_point
|
|
mov ulSlopeOneAdjustment, -1
|
|
|
|
LtoR_slope_one_check_start_point:
|
|
|
|
;
|
|
; if (M0 > 0) AMD (N0 == M0 + 8)
|
|
;
|
|
|
|
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
|
|
jb short LtoR_compute_x1 ; Bug fix: Must be unsigned!
|
|
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:
|
|
|
|
;
|
|
; if ((N1 > 0) && (M1 == N1 + 8))
|
|
;
|
|
|
|
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 ; N1 + 8
|
|
cmp esi, eax ; cmp M1, N1 + 8
|
|
jne short RtoL_slope_one_check_start_point
|
|
mov ulSlopeOneAdjustment, 1
|
|
|
|
RtoL_slope_one_check_start_point:
|
|
|
|
;
|
|
; if ((N0 > 0) && (M0 == N0 + 8))
|
|
;
|
|
|
|
mov eax,N0 ; eax = N0
|
|
or eax,eax ; check for N0 == 0
|
|
jz short RtoL_compute_y0_from_x0
|
|
|
|
mov esi, M0 ; esi = M0
|
|
|
|
add eax, F/2 ; N0 + 8
|
|
cmp eax, esi ; cmp M0 , N0 + 8
|
|
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
|
|
jae short RtoL_y0_is_2 ; Bug fix: Must be unsigned!
|
|
|
|
sub ecx, edx ; ecx = dM - dN
|
|
cmp edi, ecx
|
|
jb short RtoL_compute_x1 ; Bug fix: Must be unsigned!
|
|
|
|
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
|