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.
1331 lines
43 KiB
1331 lines
43 KiB
;---------------------------Module-Header------------------------------;
|
|
; Module Name: fastline.asm
|
|
;
|
|
; This module draws solid lines using the line hardware of the S3.
|
|
; It handles entirely unclipped lines, or lines clipped to a single
|
|
; rectangle by using the S3's hardware clipping.
|
|
;
|
|
; All lines that have integer end-points are drawn directly using the
|
|
; line hardware, and any lines having fractional end-points and are
|
|
; less than 256 pels long are also drawn directly by the line hardware.
|
|
; (Fractional end-point lines require 4 more bits of precision from the
|
|
; DDA hardware than do integer end-point lines, and the S3 has but 13
|
|
; bits to use. Lines longer than 255 pels are punted to the general
|
|
; purpose strip routines, which won't overflow the hardware).
|
|
;
|
|
; There are a number of ways unclipped lines can be sped up on the S3:
|
|
;
|
|
; 1) Optimize NT's GDI. This isn't an option for everybody.
|
|
;
|
|
; 2) Use memory-mapped I/O.
|
|
;
|
|
; 3) If you can't use memory-mapped I/O, you can at least minimize
|
|
; outs and ins because they are so painfully expensive. One
|
|
; way to do this is to amortize the cost of the in used for checking
|
|
; the FIFO: do one in to make sure a large number of entries on
|
|
; the FIFO are free (perhaps 6), then do the next 6 outs without
|
|
; having to check the FIFO.
|
|
;
|
|
; This will be a win on figures not requiring many outs (such as when
|
|
; radial lines are drawn as with a rectangle), assuming the hardware
|
|
; isn't always being overdriven.
|
|
;
|
|
; 4) In conjunction with 3) above, since short integer lines occur so
|
|
; frequently with CAD programs, it would be beneficial to use short-
|
|
; stroke vectors to do those lines, as they could reduce the number
|
|
; of outs required. Perhaps any line 10 pels or shorter could be
|
|
; output by using an array lookup to determine the short stroke vectors
|
|
; needed to represent that line.
|
|
;
|
|
; 5) Numerous other things I haven't thought of.
|
|
;
|
|
; Other improvements that should be done to make lines faster in general:
|
|
;
|
|
; 1) Simple clipping should be improved. Currently, we simply set the
|
|
; clip rectangle and let the hardware do everything. We should at least
|
|
; perform a trivial clip test to see if there's no chance the line
|
|
; intersects the clip rectangle.
|
|
;
|
|
; Also, for single lines it's expensive to do the 4 outs required to
|
|
; set the S3's clip rectangle, draw the line, then do 4 outs to reset
|
|
; the clip rectangle again. In those cases, it would be faster to do the
|
|
; clipping entirely in software.
|
|
;
|
|
; 2) This code can be enhanced to also handle styled lines, and to do
|
|
; complex clipping more efficiently than the strips routines.
|
|
;
|
|
; 3) It is possible to derive the mathematical algorithm for drawing any
|
|
; GIQ line in NT's 32 bit space using the limited bit precision of the
|
|
; S3's hardware. What this means is that absolutely any GIQ line can
|
|
; be drawn precisely with at most two drawing commands to the line
|
|
; hardware (and so the strips line drawing routine could be eliminated
|
|
; entirely). Just be careful of your math...
|
|
;
|
|
; 4) Numerous other things I haven't thought of.
|
|
;
|
|
; 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\hw.inc
|
|
include i386\lines.inc
|
|
.list
|
|
|
|
; Line coordinates are given in 28.4 fixed point format:
|
|
|
|
F equ 16
|
|
FLOG2 equ 4
|
|
|
|
; The S3's hardware can have 13 bits of significance for the error and
|
|
; step terms:
|
|
|
|
NUM_DDA_BITS equ 13
|
|
|
|
; GIQ lines have to dedicate 4 bits to the fractional term, so the largest
|
|
; delta we can handle for GIQ lines is calculated as follows (scaled by F
|
|
; so we can do the test in GIQ coordinates), and remembering that one bit
|
|
; has to be used as a sign bit:
|
|
|
|
MAX_GIQ_DELTA equ (((1 shl (NUM_DDA_BITS - 5)) - 1) * F)
|
|
|
|
; The following values must match those in winddi.h!
|
|
|
|
PD_BEGINSUBPATH equ 00000001h
|
|
PD_ENDSUBPATH equ 00000002h
|
|
PD_RESETSTYLE equ 00000004h
|
|
PD_CLOSEFIGURE equ 00000008h
|
|
PD_BEZIERS equ 00000010h
|
|
|
|
PATHDATA struc
|
|
|
|
pd_flags dd ?
|
|
pd_count dd ?
|
|
pd_pptfx dd ?
|
|
|
|
PATHDATA ends
|
|
|
|
;-------------------------------------------------------------------------;
|
|
; I felt a compelling need to use 'ebp' as a 7th general register, and we
|
|
; have no nifty macros for dereferencing frame variables off 'esp'. So
|
|
; with this structure I am rolling my own stack frame:
|
|
|
|
STATE_MEM_SIZE equ 4 ;4 dwords
|
|
PROC_MEM_SIZE equ 9 ;9 dwords
|
|
|
|
STACK_FRAME struc
|
|
|
|
; State variables (don't add/delete fields without modifying STATE_MEM_SIZE!)
|
|
|
|
sf_ulOurEbp dd ?
|
|
sf_ulOriginalEbx dd ?
|
|
sf_ulOriginalEdi dd ?
|
|
sf_ulOriginalEsi dd ?
|
|
|
|
; Frame variables (feel free to add/delete fields):
|
|
|
|
sf_y0 dd ? ;GIQ variables
|
|
sf_y1 dd ?
|
|
sf_x1 dd ?
|
|
sf_ptlOrg db (size POINTL) dup (?)
|
|
;our origin for normalizing the line
|
|
sf_ptfxLast db (size POINTL) dup (?)
|
|
;the most recent point
|
|
sf_ptfxStartFigure db (size POINTL) dup (?)
|
|
;the figure's 1st point
|
|
sf_bMore dd ? ;more path records to get?
|
|
sf_pptfxEnd dd ? ;points to last point in record
|
|
sf_pptfx dd ? ;points to current point
|
|
sf_pd db (size PATHDATA) dup (?)
|
|
;pathdata structure
|
|
sf_ptfxStart db (size POINTL) dup (?)
|
|
;temporary spot for saving start point
|
|
sf_ptfxEnd db (size POINTL) dup (?)
|
|
;temporary spot for saving end point
|
|
sf_ulCmd dd ? ;S3 draw command
|
|
sf_cPels dd ? ;length of line in pels
|
|
sf_bSetCP dd ? ;1 if first line in figure, 0 otherwise
|
|
sf_ulLastLength dd ? ;last value set as LINE_MAX
|
|
sf_ulErrorTerm dd ? ;error term for line
|
|
|
|
sf_xOffset dd ? ;stack copy of surface offset
|
|
sf_yOffset dd ?
|
|
sf_ioGp_stat_cmd dd ? ;local copy of gp_stat address
|
|
sf_pjMmBase dd ? ;local copy of the memory-mapped I/O
|
|
; base address
|
|
|
|
; Procedure variables (don't add/delete fields without modifying
|
|
; PROC_MEM_SIZE!)
|
|
|
|
sf_ulOriginalEbp dd ?
|
|
sf_ulOriginalReturn dd ?
|
|
sf_ppdev dd ?
|
|
sf_ppo dd ?
|
|
sf_prclClip dd ?
|
|
sf_apfn dd ?
|
|
sf_flags dd ?
|
|
sf_color dd ?
|
|
sf_ulHwMix dd ?
|
|
|
|
STACK_FRAME ends
|
|
|
|
.code
|
|
|
|
EXTRNP PATHOBJ_bEnum,8
|
|
EXTRNP bLines,36
|
|
|
|
ROUND_X_DOWN equ 01h
|
|
ROUND_Y_DOWN equ 02h
|
|
ROUND_SLOPE_ONE equ 04h
|
|
ROUND_X_AND_Y_DOWN equ (ROUND_X_DOWN + ROUND_Y_DOWN)
|
|
ROUND_X_DOWN_SLOPE_ONE equ (ROUND_X_DOWN + ROUND_SLOPE_ONE)
|
|
ROUND_Y_DOWN_SLOPE_ONE equ (ROUND_Y_DOWN + ROUND_SLOPE_ONE)
|
|
|
|
;--------------------------------Macro----------------------------------;
|
|
; GIQ flags
|
|
;
|
|
; This macros computes the start pixel, the number of pixels to
|
|
; be lit, and the initial error term given a GIQ line. The line must
|
|
; have already been normalized such that dM >= dN, dN >= 0.
|
|
;
|
|
; Input: ebx - M0
|
|
; ecx - N0
|
|
; esi - dM
|
|
; edi - dN
|
|
; Trashes:
|
|
; eax, edx
|
|
; [esp].sf_ptlOrg.ptl_x, [esp].sf_ptlOrg.ptl_y
|
|
; Output:
|
|
; [esp].sf_x1 - x-coordinate of last pixel (exclusive)
|
|
; ebx - x-coordinate of first pixel
|
|
; ecx - error term
|
|
; esi - dM
|
|
; edi - dN
|
|
; ebp - y-coordinate of first pixel
|
|
;-----------------------------------------------------------------------;
|
|
|
|
GIQ macro flags
|
|
local compute_x1, compute_error_term
|
|
|
|
; We normalize our coordinate system so that if the start point is
|
|
; (M0/F, N0/F), the origin is at (floor(M0/F), (N0/F)):
|
|
|
|
mov eax,ebx
|
|
mov ebp,ecx
|
|
sar eax,FLOG2
|
|
sar ebp,FLOG2
|
|
mov [esp].sf_ptlOrg.ptl_x,eax
|
|
;ptlOrg.x = floor(M0 / F)
|
|
mov [esp].sf_ptlOrg.ptl_y,ebp
|
|
;ptlOrg.y = floor(N0 / F)
|
|
|
|
; Calculate the correct [esp].sf_x1:
|
|
|
|
lea ebp,[ecx + edi] ;ebp = N1
|
|
and ebp,F - 1
|
|
|
|
if (flags AND ROUND_X_DOWN)
|
|
|
|
if (flags AND ROUND_SLOPE_ONE)
|
|
cmp ebp,8
|
|
sbb ebp,-1
|
|
endif
|
|
|
|
cmp ebp,1
|
|
sbb ebp,8 ;N1 -= 8
|
|
else
|
|
sub ebp,8 ;N1 -= 8
|
|
endif
|
|
sbb eax,eax
|
|
xor ebp,eax
|
|
sub ebp,eax ;N1 = ABS(N1)
|
|
|
|
lea edx,[ebx + esi]
|
|
mov eax,edx
|
|
sar edx,FLOG2
|
|
and eax,F - 1
|
|
jz short @f ;special case for M1 == 0
|
|
cmp eax,ebp ;cmp M1, N1
|
|
sbb edx,-1 ;edx is now one pixel past the actual
|
|
@@: ; end coordinate (note that it hasn't
|
|
; been affected by the origin shift)
|
|
|
|
compute_error_term:
|
|
|
|
; ebx = M0
|
|
; ecx = N0
|
|
; edx = x1
|
|
; esi = dM
|
|
; edi = dN
|
|
|
|
and ecx,F - 1
|
|
mov [esp].sf_x1,edx ;save x1
|
|
|
|
; Calculate our error term for x = 0.
|
|
;
|
|
; NOTE: Since this routine is used only for lines that are unclipped, we
|
|
; are guaranteed by our screen size that the values will be far less
|
|
; than 32 bits in significance, and so we don't worry about overflow.
|
|
; If this is used for clipped lines, these multiplies will have to
|
|
; be converted to give 64 bit results, because we can have 36 bits of
|
|
; significance!
|
|
|
|
|
|
lea ebp,[ecx + 8] ;ebp = N0 + 8
|
|
mov eax,esi
|
|
imul eax,ebp ;eax = dM * (N0 + 8)
|
|
mov ebp,edi
|
|
|
|
; We have to special case when M0 is 0 -- we know x0 will be zero.
|
|
; So we jump ahead a bit to a place where 'ebx' is assumed to contain
|
|
; x0 -- and it just so happens 'ebx' is zero in this case:
|
|
|
|
and ebx,F - 1
|
|
jz short @f
|
|
imul ebp,ebx ;ebp = dN * M0
|
|
sub eax,ebp
|
|
|
|
; Calculate the x-coordinate of the first pixel:
|
|
|
|
if (flags AND ROUND_X_DOWN)
|
|
|
|
if (flags AND ROUND_SLOPE_ONE)
|
|
cmp ecx,8
|
|
sbb ecx,-1
|
|
endif
|
|
|
|
cmp ecx,1
|
|
sbb ecx,8 ;N0 -= 8
|
|
else
|
|
sub ecx,8 ;N0 -= 8
|
|
endif
|
|
sbb ebp,ebp
|
|
xor ecx,ebp
|
|
sub ecx,ebp ;N0 = ABS(N0)
|
|
cmp ebx,ecx
|
|
sbb ebx,ebx
|
|
not ebx ;ebx = -x0
|
|
|
|
; Now adjust the error term accordingly:
|
|
|
|
@@:
|
|
if (flags AND ROUND_Y_DOWN)
|
|
dec eax
|
|
endif
|
|
sar eax,FLOG2 ;eax = floor((N0 + 8) dM - M0 dN] / 16)
|
|
|
|
mov ecx,[esp].sf_ptlOrg.ptl_x
|
|
mov ebp,[esp].sf_ptlOrg.ptl_y
|
|
|
|
sub ecx,ebx ;ecx = ptlOrg.ptl_x + x0
|
|
|
|
and ebx,edi
|
|
add ebx,eax
|
|
sub ebx,esi ;ebx = dN * x0 + initial error - dM
|
|
jl short @f ;if the error term >= 0, we have to
|
|
sub ebx,esi ; add 1 to the y position and subtract
|
|
inc ebp ; dM off again
|
|
@@:
|
|
xchg ebx,ecx
|
|
|
|
endm
|
|
|
|
;--------------------------------Macro----------------------------------;
|
|
; GIQR flags
|
|
;
|
|
; Same as above, except it handles flips about the line x = y.
|
|
;
|
|
; Input: ebx - M0
|
|
; ecx - N0
|
|
; esi - dM
|
|
; edi - dN
|
|
; Trashes:
|
|
; eax, edx
|
|
; [esp].sf_ptlOrg.ptl_x, [esp].sf_ptlOrg.ptl_y
|
|
; Output:
|
|
; [esp].sf_y1 - y-coordinate of last pixel (exclusive)
|
|
; ebx - x-coordinate of first pixel
|
|
; ecx - error term
|
|
; esi - dM
|
|
; edi - dN
|
|
; ebp - y-coordinate of first pixel
|
|
;-----------------------------------------------------------------------;
|
|
|
|
GIQR macro flags
|
|
|
|
; We normalize our coordinate system so that if the start point is
|
|
; (M0/F, N0/F), the origin is at (floor(M0/F), (N0/F)):
|
|
|
|
mov eax,ebx
|
|
mov ebp,ecx
|
|
sar eax,FLOG2
|
|
sar ebp,FLOG2
|
|
mov [esp].sf_ptlOrg.ptl_x,eax
|
|
;ptlOrg.x = floor(M0 / F)
|
|
mov [esp].sf_ptlOrg.ptl_y,ebp
|
|
;ptlOrg.y = floor(N0 / F)
|
|
|
|
; Calculate the correct [esp].sf_y1:
|
|
|
|
lea ebp,[ebx + esi] ;ebp = M1
|
|
and ebp,F - 1
|
|
|
|
if (flags AND ROUND_Y_DOWN)
|
|
cmp ebp,1
|
|
sbb ebp,8 ;M1 -= 8
|
|
else
|
|
sub ebp,8 ;M1 -= 8
|
|
endif
|
|
sbb eax,eax
|
|
xor ebp,eax
|
|
sub ebp,eax ;M1 = ABS(M1)
|
|
|
|
lea edx,[ecx + edi]
|
|
mov eax,edx
|
|
sar edx,FLOG2
|
|
and eax,F - 1
|
|
jz short @f ;special case for N1 == 0
|
|
cmp eax,ebp ;cmp N1, M1
|
|
sbb edx,-1 ;edx is now one pixel past the actual
|
|
@@: ; end coordinate (note that it hasn't
|
|
; been affected by the origin shift)
|
|
and ebx,F - 1
|
|
mov [esp].sf_y1,edx
|
|
|
|
; Calculate our error term for y = 0.
|
|
;
|
|
; NOTE: Since this routine is used only for lines that are unclipped, we
|
|
; are guaranteed by our screen size that the values will be far less
|
|
; than 32 bits in significance, and so we don't worry about overflow.
|
|
; If this is used for clipped lines, these multiplies will have to
|
|
; be converted to give 64 bit results, because we can have 36 bits of
|
|
; significance!
|
|
|
|
lea ebp,[ebx + 8] ;ebp = M0 + 8
|
|
mov eax,edi
|
|
imul eax,ebp ;eax = dN * (M0 + 8)
|
|
mov ebp,esi
|
|
|
|
; We have to special case when N0 is 0 -- we know y0 will be zero.
|
|
; So we jump ahead a bit to a place where 'ecx' is assumed to contain
|
|
; y0 -- and it just so happens 'ecx' is zero in this case:
|
|
|
|
and ecx,F - 1
|
|
jz short @f
|
|
imul ebp,ecx ;ebp = dM * N0
|
|
sub eax,ebp
|
|
|
|
; Calculate the x-coordinate of the first pixel:
|
|
|
|
if (flags AND ROUND_Y_DOWN)
|
|
cmp ebx,1
|
|
sbb ebx,8 ;M0 -= 8
|
|
else
|
|
sub ebx,8 ;M0 -= 8
|
|
endif
|
|
sbb ebp,ebp
|
|
xor ebx,ebp
|
|
sub ebx,ebp ;M0 = ABS(M0)
|
|
cmp ecx,ebx
|
|
sbb ecx,ecx
|
|
not ecx ;ecx = -y0
|
|
|
|
; Now adjust the error term accordingly:
|
|
|
|
@@:
|
|
if (flags AND ROUND_X_DOWN)
|
|
dec eax
|
|
endif
|
|
sar eax,FLOG2 ;eax = floor((M0 + 8) dN - N0 dM] / 16)
|
|
|
|
mov ebx,[esp].sf_ptlOrg.ptl_x
|
|
mov ebp,[esp].sf_ptlOrg.ptl_y
|
|
|
|
sub ebp,ecx ;ebp = ptlOrg.ptl_y + y0
|
|
|
|
and ecx,esi
|
|
add ecx,eax
|
|
sub ecx,edi ;ecx = dM * x0 + initial error - dN
|
|
jl short @f ;if the error term >= 0, we have to
|
|
sub ecx,edi ; add 1 to the x position and subtract
|
|
inc ebx ; dN off again
|
|
@@:
|
|
|
|
endm
|
|
|
|
;---------------------------Public-Routine------------------------------;
|
|
; vIoFastLine(ppdev, ppo, prclClip, apfn, flags, color, ulHwMix)
|
|
;
|
|
; Draws fast lines. Or at least attempts to. Uses normal I/O.
|
|
;
|
|
; Input:
|
|
;
|
|
; ppdev - PDEV pointer
|
|
; ppo - path to be drawn
|
|
; prclClip - pointer to rectangle array for passing to 'bLines'
|
|
; apfn - pointer to strip routines for passing to 'bLines'
|
|
; flags - status flag for passing to 'bLines'
|
|
; color - color
|
|
; ulHwMix - mix
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
; NOTE: Don't go changing parameters without also changing STACK_FRAME!
|
|
|
|
cProc vIoFastLine,28,< \
|
|
uses esi edi ebx, \
|
|
ebp_ppdev: ptr, \
|
|
ebp_ppo: ptr, \
|
|
ebp_prclClip: ptr, \
|
|
ebp_apfn: ptr, \
|
|
ebp_flags: dword,\
|
|
ebp_color: dword,\
|
|
ebp_ulHwMix: dword>
|
|
|
|
; Leave room for our stack frame.
|
|
;
|
|
; NOTE: Don't add local variables here -- you can't reference them with
|
|
; ebp anyway! Add them to the STACK_FRAME structure.
|
|
|
|
local aj[(size STACK_FRAME) - 4 * (STATE_MEM_SIZE + PROC_MEM_SIZE)]: byte
|
|
|
|
; We save 'ebp' on the stack (note that STACK_FRAME accounts for this push):
|
|
|
|
push ebp
|
|
|
|
mov esi,[esp].sf_ppdev
|
|
|
|
mov [esp].sf_ulLastLength,-1;make sure first line in path resets
|
|
; LINE_MAX value
|
|
|
|
; Warm up the hardware:
|
|
|
|
mov edx,[esi].pdev_ioGp_stat_cmd
|
|
@@: in ax,dx
|
|
and eax,FIFO_3_EMPTY
|
|
jnz short @b ;IO_FIFO_WAIT(ppdev, 3)
|
|
|
|
mov edx,[esi].pdev_ioFrgd_color
|
|
mov eax,[esp].sf_color
|
|
out dx,ax ;IO_FRGD_COLOR(ppdev, color)
|
|
|
|
mov edx,[esi].pdev_ioFrgd_mix
|
|
mov eax,[esp].sf_ulHwMix
|
|
or eax,FOREGROUND_COLOR
|
|
out dx,ax ;IO_FRGD_MIX(ppdev, FOREGROUND_COLOR |
|
|
; ulHwMix)
|
|
|
|
mov edx,[esi].pdev_ioMulti_function
|
|
mov eax,DATA_EXTENSION
|
|
out dx,ax ;IO_PIX_CNTL(ppdev, ALL_ONES)
|
|
|
|
|
|
; Now get some path stuff:
|
|
|
|
io_next_record:
|
|
|
|
mov eax,[esp].sf_ppo
|
|
lea ebx,[esp].sf_pd
|
|
cCall PATHOBJ_bEnum,<eax,ebx>
|
|
mov [esp].sf_bMore,eax ;save away return code for later
|
|
|
|
mov ebx,[esp].sf_pd.pd_count;if 0 points in record, get outta here
|
|
or ebx,ebx
|
|
jz io_check_for_closefigure
|
|
|
|
lea ebp,[8 * ebx - 8]
|
|
add ebp,[esp].sf_pd.pd_pptfx
|
|
mov [esp].sf_pptfxEnd,ebp ;points to last point in record
|
|
|
|
mov ecx,[esp].sf_pd.pd_flags
|
|
test ecx,PD_BEGINSUBPATH
|
|
jz short io_continue_subpath
|
|
|
|
; Handle a new sub-path:
|
|
|
|
mov eax,[esp].sf_pd.pd_pptfx
|
|
add eax,8
|
|
mov [esp].sf_pptfx,eax
|
|
|
|
mov esi,[ebp].ptl_x ;remember last point in case we have
|
|
mov edi,[ebp].ptl_y ; to continue to another record
|
|
mov [esp].sf_ptfxLast.ptl_x,esi
|
|
mov [esp].sf_ptfxLast.ptl_y,edi
|
|
|
|
mov ebx,[eax - 8].ptl_x ;load up current start and end point
|
|
mov ecx,[eax - 8].ptl_y
|
|
mov esi,[eax].ptl_x
|
|
mov edi,[eax].ptl_y
|
|
mov [esp].sf_ptfxStartFigure.ptl_x,ebx
|
|
mov [esp].sf_ptfxStartFigure.ptl_y,ecx
|
|
|
|
mov [esp].sf_bSetCP,1 ;this line is first in figure
|
|
|
|
cmp eax,[esp].sf_pptfxEnd ;we have to be careful when the only
|
|
; point in the record is the start-
|
|
; figure point (pretty rare)
|
|
jbe io_new_line
|
|
jmp short io_next_record
|
|
|
|
io_continue_subpath:
|
|
|
|
; This record continues the path:
|
|
|
|
mov eax,[esp].sf_pd.pd_pptfx
|
|
mov ebx,[esp].sf_ptfxLast.ptl_x ;load up current start point
|
|
mov ecx,[esp].sf_ptfxLast.ptl_y
|
|
|
|
mov esi,[ebp].ptl_x ;remember last point in case we have
|
|
mov edi,[ebp].ptl_y ; to continue to another record
|
|
mov [esp].sf_ptfxLast.ptl_x,esi
|
|
mov [esp].sf_ptfxLast.ptl_y,edi
|
|
|
|
mov esi,[eax].ptl_x ;load up current end point
|
|
mov edi,[eax].ptl_y
|
|
mov [esp].sf_pptfx,eax
|
|
|
|
jmp io_new_line
|
|
|
|
;/////////////////////////////////////////////////////////////////////
|
|
;// Next Line Stuff
|
|
;/////////////////////////////////////////////////////////////////////
|
|
|
|
io_handle_closefigure:
|
|
mov [esp].sf_pd.pd_flags,0
|
|
mov ebx,[esp].sf_ptfxLast.ptl_x
|
|
mov ecx,[esp].sf_ptfxLast.ptl_y
|
|
mov esi,[esp].sf_ptfxStartFigure.ptl_x
|
|
mov edi,[esp].sf_ptfxStartFigure.ptl_y
|
|
|
|
jmp io_new_line
|
|
|
|
; Before getting the next path record, see if we have to do a closefigure:
|
|
|
|
io_check_for_closefigure:
|
|
test [esp].sf_pd.pd_flags,PD_CLOSEFIGURE
|
|
jnz io_handle_closefigure
|
|
mov esi,[esp].sf_bMore
|
|
or esi,esi
|
|
jnz io_next_record
|
|
|
|
io_all_done:
|
|
|
|
pop ebp
|
|
cRet vIoFastLine
|
|
|
|
;/////////////////////////////////////////////////////////////////////
|
|
;// Output Integer Line
|
|
;/////////////////////////////////////////////////////////////////////
|
|
|
|
; ebx = x
|
|
; ecx = y
|
|
; esi = dx
|
|
; edi = dy
|
|
; [esp].sf_ulErrorTerm = incomplete error term (actual value is 'dx - bias')
|
|
; [esp].sf_ulCmd = draw command
|
|
|
|
; NOTE: The port values retrieved from the PDEV are word values, and word
|
|
; moves have a one cycle penalty. For this reason, the values should
|
|
; actually be defined as dwords in the PDEV...
|
|
|
|
public io_int_output_line
|
|
io_int_output_line::
|
|
mov ebp,[esp].sf_ppdev ;ebp = ppdev
|
|
cmp [esp].sf_bSetCP,0
|
|
je short io_int_current_position_already_set
|
|
|
|
mov edx,[ebp].pdev_ioGp_stat_cmd
|
|
@@: in ax,dx
|
|
and eax,FIFO_7_EMPTY ;wait for 7 entries
|
|
jnz short @b
|
|
|
|
mov edx,[ebp].pdev_ioCur_x
|
|
mov eax,ebx
|
|
add eax,[ebp].pdev_xOffset
|
|
out dx,ax
|
|
|
|
mov edx,[ebp].pdev_ioCur_y
|
|
mov eax,ecx
|
|
add eax,[ebp].pdev_yOffset
|
|
out dx,ax
|
|
|
|
mov [esp].sf_bSetCP,0 ;the next integer line in this figure
|
|
; will have the CP set correctly
|
|
|
|
jmp short io_int_output_common
|
|
|
|
io_int_current_position_already_set:
|
|
mov edx,[ebp].pdev_ioGp_stat_cmd
|
|
@@: in ax,dx
|
|
and eax,FIFO_5_EMPTY ;wait for 5 entries
|
|
jnz short @b
|
|
|
|
public io_int_output_common
|
|
io_int_output_common::
|
|
cmp esi,[esp].sf_ulLastLength
|
|
je short @f
|
|
|
|
mov edx,[ebp].pdev_ioMaj_axis_pcnt
|
|
mov eax,esi
|
|
out dx,ax
|
|
mov [esp].sf_ulLastLength,eax
|
|
@@:
|
|
mov edx,[ebp].pdev_ioDesty_axstp
|
|
mov eax,edi
|
|
out dx,ax ;axial = dy
|
|
|
|
mov edx,[ebp].pdev_ioDestx_diastp
|
|
sub eax,esi
|
|
out dx,ax ;diag = dy - dx
|
|
|
|
mov edx,[esp].sf_ulErrorTerm
|
|
sar edx,1
|
|
add eax,edx
|
|
mov edx,[ebp].pdev_ioErr_term
|
|
out dx,ax ;err = dy - dx + floor((dx - bias) / 2)
|
|
|
|
mov edx,[ebp].pdev_ioGp_stat_cmd
|
|
mov eax,[esp].sf_ulCmd
|
|
out dx,ax ;draw that puppy
|
|
|
|
;/////////////////////////////////////////////////////////////////////
|
|
;// Main Loop
|
|
;/////////////////////////////////////////////////////////////////////
|
|
|
|
public io_next_line
|
|
io_next_line::
|
|
mov eax,[esp].sf_pptfx
|
|
cmp eax,[esp].sf_pptfxEnd
|
|
jae io_check_for_closefigure
|
|
|
|
mov ebx,[eax].ptl_x
|
|
mov ecx,[eax].ptl_y
|
|
mov esi,[eax+8].ptl_x
|
|
mov edi,[eax+8].ptl_y
|
|
add eax,8
|
|
mov [esp].sf_pptfx,eax
|
|
|
|
public io_new_line
|
|
io_new_line::
|
|
|
|
; Octants are numbered as follows:
|
|
;
|
|
; \ 5 | 6 /
|
|
; \ | /
|
|
; 4 \ | / 7
|
|
; \ /
|
|
; -----+-----
|
|
; /|\
|
|
; 3 / | \ 0
|
|
; / | \
|
|
; / 2 | 1 \
|
|
;
|
|
|
|
; ebx = M0
|
|
; ecx = N0
|
|
; esi = M1 (dM)
|
|
; edi = N1 (dN)
|
|
|
|
mov [esp].sf_ptfxStart.ptl_x,ebx
|
|
mov [esp].sf_ptfxStart.ptl_y,ecx
|
|
mov [esp].sf_ptfxEnd.ptl_x,esi
|
|
mov [esp].sf_ptfxEnd.ptl_y,edi
|
|
;save points in case we have to punt
|
|
mov eax,ebx
|
|
or eax,ecx
|
|
or eax,esi
|
|
or eax,edi
|
|
and eax,F-1
|
|
jnz io_non_integer
|
|
|
|
;/////////////////////////////////////////////////////////////////////
|
|
;// Integer Lines
|
|
;/////////////////////////////////////////////////////////////////////
|
|
|
|
sar ebx,FLOG2 ;x0
|
|
sar ecx,FLOG2 ;y0
|
|
sar esi,FLOG2 ;x1 (soon to be dx)
|
|
sar edi,FLOG2 ;y1 (soon to be dy)
|
|
|
|
sub esi,ebx
|
|
jl io_int_2_3_4_5
|
|
jz io_int_radial_90_270
|
|
sub edi,ecx
|
|
jl io_int_6_7
|
|
jz io_int_radial_0
|
|
cmp esi,edi
|
|
jl io_int_1
|
|
je io_int_radial_315
|
|
|
|
io_int_0:
|
|
lea ebp,[esi - 1]
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD + PLUS_Y + PLUS_X
|
|
mov [esp].sf_ulErrorTerm,ebp
|
|
|
|
jmp io_int_output_line
|
|
|
|
public io_int_1
|
|
io_int_1::
|
|
xchg esi,edi
|
|
lea ebp,[esi - 1]
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD + PLUS_Y + PLUS_X + MAJOR_Y
|
|
mov [esp].sf_ulErrorTerm,ebp
|
|
|
|
jmp io_int_output_line
|
|
|
|
public io_int_2_3_4_5
|
|
io_int_2_3_4_5::
|
|
neg esi
|
|
sub edi,ecx
|
|
jl io_int_4_5
|
|
jz io_int_radial_180
|
|
cmp esi,edi
|
|
jl io_int_2
|
|
je io_int_radial_225
|
|
|
|
public io_int_3
|
|
io_int_3::
|
|
lea ebp,[esi - 1]
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD + PLUS_Y
|
|
mov [esp].sf_ulErrorTerm,ebp
|
|
|
|
jmp io_int_output_line
|
|
|
|
public io_int_2
|
|
io_int_2::
|
|
xchg esi,edi
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD + PLUS_Y + MAJOR_Y
|
|
mov [esp].sf_ulErrorTerm,esi
|
|
|
|
jmp io_int_output_line
|
|
|
|
public io_int_4_5
|
|
io_int_4_5::
|
|
neg edi
|
|
cmp esi,edi
|
|
jl io_int_5
|
|
je io_int_radial_135
|
|
|
|
io_int_4:
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD
|
|
mov [esp].sf_ulErrorTerm,esi
|
|
|
|
jmp io_int_output_line
|
|
|
|
public io_int_5
|
|
io_int_5::
|
|
xchg esi,edi
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD + MAJOR_Y
|
|
mov [esp].sf_ulErrorTerm,esi
|
|
|
|
jmp io_int_output_line
|
|
|
|
public io_int_6_7
|
|
io_int_6_7::
|
|
neg edi
|
|
cmp esi,edi
|
|
jg io_int_7
|
|
je io_int_radial_45
|
|
|
|
io_int_6:
|
|
xchg esi,edi
|
|
lea ebp,[esi - 1]
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD + MAJOR_Y + PLUS_X
|
|
mov [esp].sf_ulErrorTerm,ebp
|
|
|
|
jmp io_int_output_line
|
|
|
|
public io_int_7
|
|
io_int_7::
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD + PLUS_X
|
|
mov [esp].sf_ulErrorTerm,esi
|
|
|
|
jmp io_int_output_line
|
|
|
|
;/////////////////////////////////////////////////////////////////////
|
|
;// Lines In The 8 Cardinal Directions
|
|
;/////////////////////////////////////////////////////////////////////
|
|
|
|
public io_int_radial_45
|
|
io_int_radial_45::
|
|
mov ebp,DRAW_LINE + DRAW + DIR_TYPE_RADIAL + WRITE + \
|
|
LAST_PIXEL_OFF + MULTIPLE_PIXELS + DRAWING_DIRECTION_45
|
|
jmp short io_int_output_radial
|
|
|
|
public io_int_radial_135
|
|
io_int_radial_135::
|
|
mov ebp,DRAW_LINE + DRAW + DIR_TYPE_RADIAL + WRITE + \
|
|
LAST_PIXEL_OFF + MULTIPLE_PIXELS + DRAWING_DIRECTION_135
|
|
jmp short io_int_output_radial
|
|
|
|
public io_int_radial_225
|
|
io_int_radial_225::
|
|
mov ebp,DRAW_LINE + DRAW + DIR_TYPE_RADIAL + WRITE + \
|
|
LAST_PIXEL_OFF + MULTIPLE_PIXELS + DRAWING_DIRECTION_225
|
|
jmp short io_int_output_radial
|
|
|
|
public io_int_radial_315
|
|
io_int_radial_315::
|
|
mov ebp,DRAW_LINE + DRAW + DIR_TYPE_RADIAL + WRITE + \
|
|
LAST_PIXEL_OFF + MULTIPLE_PIXELS + DRAWING_DIRECTION_315
|
|
jmp short io_int_output_radial
|
|
|
|
public io_int_radial_90_270
|
|
io_int_radial_90_270::
|
|
mov ebp,DRAW_LINE + DRAW + DIR_TYPE_RADIAL + WRITE + \
|
|
LAST_PIXEL_OFF + MULTIPLE_PIXELS + DRAWING_DIRECTION_270
|
|
mov esi,edi
|
|
sub esi,ecx
|
|
jg short io_int_output_radial ;if top-to-bottom vertical line
|
|
jz io_next_line ;if zero length line
|
|
|
|
neg esi
|
|
mov ebp,DRAW_LINE + DRAW + DIR_TYPE_RADIAL + WRITE + \
|
|
LAST_PIXEL_OFF + MULTIPLE_PIXELS + DRAWING_DIRECTION_90
|
|
jmp short io_int_output_radial
|
|
|
|
public io_int_radial_180
|
|
io_int_radial_180::
|
|
mov ebp,DRAW_LINE + DRAW + DIR_TYPE_RADIAL + WRITE + \
|
|
LAST_PIXEL_OFF + MULTIPLE_PIXELS + DRAWING_DIRECTION_180
|
|
jmp short io_int_output_radial
|
|
|
|
io_int_radial_0:
|
|
mov ebp,DRAW_LINE + DRAW + DIR_TYPE_RADIAL + WRITE + \
|
|
LAST_PIXEL_OFF + MULTIPLE_PIXELS + DRAWING_DIRECTION_0
|
|
|
|
; ebx = x
|
|
; ecx = y
|
|
; esi = dx (length of radial line since it's normalized)
|
|
; ebp = drawing command
|
|
|
|
public io_int_output_radial
|
|
io_int_output_radial::
|
|
mov edi,[esp].sf_ppdev
|
|
cmp [esp].sf_bSetCP,0
|
|
je short io_int_radial_continue_figure
|
|
|
|
mov edx,[edi].pdev_ioGp_stat_cmd
|
|
@@: in ax,dx
|
|
and eax,FIFO_4_EMPTY
|
|
jnz short @b
|
|
|
|
mov edx,[edi].pdev_ioCur_x
|
|
mov eax,ebx
|
|
add eax,[edi].pdev_xOffset
|
|
out dx,ax
|
|
|
|
mov edx,[edi].pdev_ioCur_y
|
|
mov eax,ecx
|
|
add eax,[edi].pdev_yOffset
|
|
out dx,ax
|
|
|
|
mov [esp].sf_bSetCP,0 ;the next integer line in this figure
|
|
; will have the CP set correctly
|
|
|
|
cmp esi,[esp].sf_ulLastLength
|
|
je short @f
|
|
|
|
mov edx,[edi].pdev_ioMaj_axis_pcnt
|
|
mov eax,esi
|
|
out dx,ax
|
|
mov [esp].sf_ulLastLength,eax
|
|
@@:
|
|
mov edx,[edi].pdev_ioGp_stat_cmd
|
|
mov eax,ebp
|
|
out dx,ax
|
|
jmp io_next_line
|
|
|
|
; Jump to here if we don't have to update the current position first:
|
|
|
|
public io_int_radial_continue_figure
|
|
io_int_radial_continue_figure::
|
|
cmp esi,[esp].sf_ulLastLength
|
|
je short io_int_radial_skip_length
|
|
|
|
mov edx,[edi].pdev_ioGp_stat_cmd
|
|
@@: in ax,dx
|
|
and eax,FIFO_2_EMPTY
|
|
jnz short @b
|
|
|
|
mov edx,[edi].pdev_ioMaj_axis_pcnt
|
|
mov eax,esi
|
|
out dx,ax
|
|
mov [esp].sf_ulLastLength,eax
|
|
|
|
mov edx,[edi].pdev_ioGp_stat_cmd
|
|
mov eax,ebp
|
|
out dx,ax
|
|
jmp io_next_line
|
|
|
|
; Jump to here if we don't have to update the current position or the
|
|
; line length variable:
|
|
|
|
public io_int_radial_skip_length
|
|
io_int_radial_skip_length::
|
|
mov edx,[edi].pdev_ioGp_stat_cmd
|
|
@@: in ax,dx
|
|
and eax,FIFO_1_EMPTY
|
|
jnz short @b
|
|
|
|
mov edx,[edi].pdev_ioGp_stat_cmd
|
|
mov eax,ebp
|
|
out dx,ax
|
|
jmp io_next_line
|
|
|
|
;/////////////////////////////////////////////////////////////////////
|
|
;// Non-Integer Lines
|
|
;/////////////////////////////////////////////////////////////////////
|
|
|
|
public io_non_integer
|
|
io_non_integer::
|
|
sub esi,ebx
|
|
jl io_not_int_2_3_4_5
|
|
sub edi,ecx
|
|
jl io_not_int_6_7
|
|
cmp esi,edi
|
|
jl io_not_int_1
|
|
je io_not_int_0_slope_one
|
|
|
|
io_not_int_0:
|
|
cmp esi,MAX_GIQ_DELTA
|
|
jg io_punt_line
|
|
|
|
GIQ ROUND_X_AND_Y_DOWN
|
|
|
|
io_not_int_0_common:
|
|
add ecx,edi ;err += dN
|
|
mov [esp].sf_ulErrorTerm,ecx
|
|
|
|
mov eax,[esp].sf_x1
|
|
sub eax,ebx
|
|
jle io_next_line
|
|
mov [esp].sf_cPels,eax
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD + PLUS_Y + PLUS_X
|
|
|
|
public io_not_int_x_major
|
|
io_not_int_x_major::
|
|
mov ecx,[esp].sf_ppdev
|
|
mov edx,[ecx].pdev_ioGp_stat_cmd
|
|
@@: in ax,dx
|
|
and eax,FIFO_7_EMPTY ;wait for 7 entries
|
|
jnz short @b
|
|
|
|
; Fractional end-point lines aren't usually going to have the current
|
|
; position already set correctly, so we explicitly set the CP each time:
|
|
|
|
mov edx,[ecx].pdev_ioCur_x
|
|
mov eax,ebx
|
|
add eax,[ecx].pdev_xOffset
|
|
out dx,ax ;x0
|
|
|
|
mov edx,[ecx].pdev_ioCur_y
|
|
mov eax,ebp
|
|
add eax,[ecx].pdev_yOffset
|
|
out dx,ax ;y0
|
|
|
|
mov [esp].sf_bSetCP,1 ;the next integer line in this figure
|
|
; will not necessarily have the CP set
|
|
; correctly
|
|
|
|
mov eax,[esp].sf_cPels
|
|
cmp eax,[esp].sf_ulLastLength
|
|
je short @f
|
|
|
|
mov edx,[ecx].pdev_ioMaj_axis_pcnt
|
|
out dx,ax ;length = cPels
|
|
mov [esp].sf_ulLastLength,eax
|
|
@@:
|
|
mov edx,[ecx].pdev_ioDesty_axstp
|
|
mov eax,edi
|
|
out dx,ax ;axial = dN
|
|
|
|
mov edx,[ecx].pdev_ioDestx_diastp
|
|
sub eax,esi
|
|
out dx,ax ;diag = dN - dM
|
|
|
|
mov edx,[ecx].pdev_ioErr_term
|
|
mov eax,[esp].sf_ulErrorTerm
|
|
out dx,ax ;error term
|
|
|
|
mov edx,[ecx].pdev_ioGp_stat_cmd
|
|
mov eax,[esp].sf_ulCmd
|
|
out dx,ax ;output it
|
|
|
|
jmp io_next_line
|
|
|
|
; Lines of slope one have a special rounding rule: when the line
|
|
; runs exactly half way between two pixels, the upper or right pel
|
|
; is illuminated. This translates into x=1/2 rounding up in value,
|
|
; and y=1/2 rounding down:
|
|
|
|
public io_not_int_0_slope_one
|
|
io_not_int_0_slope_one::
|
|
or esi,esi
|
|
jz io_next_line ;quick check for a zero length GIQ line
|
|
|
|
cmp esi,MAX_GIQ_DELTA
|
|
jg io_punt_line
|
|
|
|
GIQ ROUND_Y_DOWN_SLOPE_ONE
|
|
jmp io_not_int_0_common
|
|
|
|
public io_not_int_1
|
|
io_not_int_1::
|
|
cmp edi,MAX_GIQ_DELTA
|
|
jg io_punt_line
|
|
|
|
GIQR ROUND_X_AND_Y_DOWN
|
|
add ecx,esi ;err += dM
|
|
mov [esp].sf_ulErrorTerm,ecx
|
|
|
|
mov eax,[esp].sf_y1
|
|
sub eax,ebp
|
|
jle io_next_line
|
|
mov [esp].sf_cPels,eax
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD + PLUS_Y + PLUS_X + MAJOR_Y
|
|
|
|
public io_not_int_y_major
|
|
io_not_int_y_major::
|
|
mov ecx,[esp].sf_ppdev
|
|
mov edx,[ecx].pdev_ioGp_stat_cmd
|
|
@@: in ax,dx
|
|
and eax,FIFO_7_EMPTY ;wait for 7 entries
|
|
jnz short @b
|
|
|
|
; Fractional end-point lines aren't usually going to have the current
|
|
; position already set correctly, so we explicitly set the CP each time:
|
|
|
|
mov edx,[ecx].pdev_ioCur_x
|
|
mov eax,ebx
|
|
add eax,[ecx].pdev_xOffset
|
|
out dx,ax ;x0
|
|
|
|
mov edx,[ecx].pdev_ioCur_y
|
|
mov eax,ebp
|
|
add eax,[ecx].pdev_yOffset
|
|
out dx,ax ;y0
|
|
|
|
mov [esp].sf_bSetCP,1 ;the next integer line in this figure
|
|
; will not necessarily have the CP set
|
|
; correctly
|
|
|
|
mov eax,[esp].sf_cPels
|
|
cmp eax,[esp].sf_ulLastLength
|
|
je short @f
|
|
|
|
mov edx,[ecx].pdev_ioMaj_axis_pcnt
|
|
out dx,ax ;length = cPels
|
|
mov [esp].sf_ulLastLength,eax
|
|
@@:
|
|
mov edx,[ecx].pdev_ioDesty_axstp
|
|
mov eax,esi
|
|
out dx,ax ;axial = dM
|
|
|
|
mov edx,[ecx].pdev_ioDestx_diastp
|
|
sub eax,edi
|
|
out dx,ax ;diag = dM - dN
|
|
|
|
mov edx,[ecx].pdev_ioErr_term
|
|
mov eax,[esp].sf_ulErrorTerm
|
|
out dx,ax ;error term
|
|
|
|
mov edx,[ecx].pdev_ioGp_stat_cmd
|
|
mov eax,[esp].sf_ulCmd
|
|
out dx,ax ;output it
|
|
|
|
jmp io_next_line
|
|
|
|
public io_not_int_2_3_4_5
|
|
io_not_int_2_3_4_5::
|
|
neg esi ;dM = -dM (now positive)
|
|
neg ebx ;M0 = -M0
|
|
sub edi,ecx
|
|
jl io_not_int_4_5
|
|
cmp esi,edi
|
|
jl io_not_int_2
|
|
|
|
io_not_int_3:
|
|
cmp esi,MAX_GIQ_DELTA
|
|
jg io_punt_line
|
|
|
|
GIQ ROUND_Y_DOWN
|
|
add ecx,edi ;err += dN
|
|
mov [esp].sf_ulErrorTerm,ecx
|
|
|
|
neg ebx ;untransform x0
|
|
|
|
mov eax,[esp].sf_x1
|
|
add eax,ebx
|
|
jle io_next_line
|
|
mov [esp].sf_cPels,eax
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD + PLUS_Y
|
|
|
|
jmp io_not_int_x_major
|
|
|
|
public io_not_int_2
|
|
io_not_int_2::
|
|
cmp edi,MAX_GIQ_DELTA
|
|
jg io_punt_line
|
|
|
|
GIQR ROUND_Y_DOWN
|
|
add ecx,esi ;err += dM
|
|
mov [esp].sf_ulErrorTerm,ecx
|
|
|
|
neg ebx ;untransform x0
|
|
|
|
mov eax,[esp].sf_y1
|
|
sub eax,ebp
|
|
jle io_next_line
|
|
mov [esp].sf_cPels,eax
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD + PLUS_Y + MAJOR_Y
|
|
|
|
jmp io_not_int_y_major
|
|
|
|
public io_not_int_4_5
|
|
io_not_int_4_5::
|
|
neg edi ;dN = -dN (now positive)
|
|
neg ecx ;N0 = -N0
|
|
cmp esi,edi
|
|
jl io_not_int_5
|
|
je io_not_int_4_slope_one
|
|
|
|
public io_not_int_4
|
|
io_not_int_4::
|
|
cmp esi,MAX_GIQ_DELTA
|
|
jg io_punt_line
|
|
|
|
GIQ 0
|
|
|
|
io_not_int_4_common:
|
|
add ecx,edi ;err += dN
|
|
mov [esp].sf_ulErrorTerm,ecx
|
|
|
|
neg ebx ;untransform x0
|
|
neg ebp ;untransform y0
|
|
|
|
mov eax,[esp].sf_x1
|
|
add eax,ebx
|
|
jle io_next_line
|
|
mov [esp].sf_cPels,eax
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD
|
|
|
|
jmp io_not_int_x_major
|
|
|
|
; Lines of slope one have a special rounding rule.
|
|
|
|
public io_not_int_4_slope_one
|
|
io_not_int_4_slope_one::
|
|
cmp esi,MAX_GIQ_DELTA
|
|
jg io_punt_line
|
|
|
|
GIQ ROUND_X_DOWN_SLOPE_ONE
|
|
jmp io_not_int_4_common
|
|
|
|
public io_not_int_5
|
|
io_not_int_5::
|
|
cmp edi,MAX_GIQ_DELTA
|
|
jg io_punt_line
|
|
|
|
GIQR 0
|
|
add ecx,esi ;err += dM
|
|
mov [esp].sf_ulErrorTerm,ecx
|
|
|
|
neg ebx ;untransform x0
|
|
neg ebp ;untransform y0
|
|
|
|
mov eax,[esp].sf_y1
|
|
add eax,ebp
|
|
jle io_next_line
|
|
mov [esp].sf_cPels,eax
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD + MAJOR_Y
|
|
|
|
jmp io_not_int_y_major
|
|
|
|
public io_not_int_6_7
|
|
io_not_int_6_7::
|
|
neg edi ;dN = -dN (now positive)
|
|
neg ecx ;M0 = -M0
|
|
cmp esi,edi
|
|
je io_not_int_7_slope_one
|
|
jg io_not_int_7
|
|
|
|
public io_not_int_6
|
|
io_not_int_6::
|
|
cmp edi,MAX_GIQ_DELTA
|
|
jg io_punt_line
|
|
|
|
GIQR ROUND_X_DOWN
|
|
add ecx,esi ;err += dM
|
|
mov [esp].sf_ulErrorTerm,ecx
|
|
|
|
neg ebp ;untransform y0
|
|
|
|
mov eax,[esp].sf_y1
|
|
add eax,ebp
|
|
jle io_next_line
|
|
mov [esp].sf_cPels,eax
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD + MAJOR_Y + PLUS_X
|
|
|
|
jmp io_not_int_y_major
|
|
|
|
public io_not_int_7
|
|
io_not_int_7::
|
|
cmp esi,MAX_GIQ_DELTA
|
|
jg io_punt_line
|
|
|
|
GIQ ROUND_X_DOWN
|
|
|
|
io_not_int_7_common:
|
|
add ecx,edi ;err += dN
|
|
mov [esp].sf_ulErrorTerm,ecx
|
|
|
|
neg ebp ;untransform y0
|
|
|
|
mov eax,[esp].sf_x1
|
|
sub eax,ebx
|
|
jle io_next_line
|
|
mov [esp].sf_cPels,eax
|
|
mov [esp].sf_ulCmd,DEFAULT_DRAW_CMD + PLUS_X
|
|
|
|
jmp io_not_int_x_major
|
|
|
|
public io_not_int_7_slope_one
|
|
io_not_int_7_slope_one::
|
|
cmp esi,MAX_GIQ_DELTA
|
|
jg io_punt_line
|
|
|
|
GIQ ROUND_X_DOWN_SLOPE_ONE
|
|
jmp io_not_int_7_common
|
|
|
|
;/////////////////////////////////////////////////////////////////////
|
|
;// Punt Line
|
|
;/////////////////////////////////////////////////////////////////////
|
|
|
|
; If the line is too long, we punt to our strip drawing routine.
|
|
|
|
public io_punt_line
|
|
io_punt_line::
|
|
mov esi,esp
|
|
lea eax,[esp].sf_ptfxStart
|
|
lea ebx,[esp].sf_ptfxEnd
|
|
|
|
cCall bLines,<[esi].sf_ppdev, eax, ebx, 0, 1, 0, \
|
|
[esi].sf_prclClip, [esi].sf_apfn, [esi].sf_flags>
|
|
|
|
mov [esp].sf_bSetCP,1 ;Always reset CP after punting
|
|
mov [esp].sf_ulLastLength,-1;Always reset line length after punting
|
|
|
|
jmp io_next_line
|
|
|
|
endProc vIoFastLine
|
|
|
|
end
|