M EQU Byte Ptr 0[BX] DGROUP GROUP DATA TITLE 'drawline - Draw segment SUPPORTING LINESTYLES' ;**************************************************************************** ;* * ;* SCAN-CONVERT LINE USING THE BASIC INCREMENTAL ALGORITHM * ;* * ;**************************************************************************** ; * ; Revision : June 08, 1983 File "drawline.a86" Version 1.0 * ; * ; * ;**** MODE NOTES : ********************************************************* ; * ; 1) Rotate LINE STYLE pattern mask : LSTYLE * ; 2) Special Line Style Support : * ; .Drawit Stores Line Start Point X0, Y0 for Swapping * ; .Clipit Returns ABOVE flag : 0=inside, 1=Y2 above, 2=Y1 above * ; .Drawxy rotates line pattern mask to x1, y1 for specil linestyles * ; Filters Y0 to TOPY and Sets Y0 inside flag for ADDRXY * ; and SETBIT Rontines to start Setting Bit in BITMAP * ; * ; 3) Change Ydir Flag : -1,0,1 to 0,1,2 Indicating the Line direction * ; June 07, 1983 rhk * ; replace swapy from change line direction to rotate pattern mask * ; May 04, 1983 rhk * ; Add Writing Mode Support * ;**** MODE NOTES : ********************************************************* ; * ; drawxy (x1,x2,y1,y2,cindex) * ; * ; Function : Convert line defined by endpoints x1,y1,x2,y2 into pixel * ; values and store into BITMAP for scan output later * ; * ; Calls & Processes : * ; Do until (x=x2 and y=y2) * ; INITXY (x1,y1,x2,y2) * ; initialze DX1, dy, xdir, ydir,... etc. * ; ADDRXY (x1, y1, cindex, nbyt, nbit) * ; get starting bitmap address pointer for pixel x1,y1 * ; SWAPY (x1, y1, xdir, ydir, doxy) * ; Rotate the line pattern mask to x1, y1 for special line types * ; LINETY (SPECIL) * ; Check line style, color and set logical op flag for SETBIT * ; SETBIT (nbyt, nbit) * ; "set" pixel at corresponding bitmap location * ; "set" = OR, XOR, or AND depending on the writing mode, * ; line style pattern, and the line color * ; * ; PIXEL STEPS X,Y * ; if ( abs(DX1) > abs(dy) ) ;jump x, maybe jump y * ; (xdir Indicates Line Direction in X-axis) * ; JUMPX ;x=x +xdir, f=f+(dy*xdir), update nbit * ; if ( abs(f) >= abs(DX1/2) ) then JUMPY * ; else ;jump y, maybe jump x * ; (ydir Indicates Line Direction in Y-axis) * ; JUMPY ;y=y+ydir, f=f+(DX1*ydir), update nbyt * ; if ( abs(f) >= abs(dy/2) ) then JUMPX * ; endif * ; * ; Input : X1, Y1, X2, Y2 - Endpoint coordinates * ; * ; Output : None * ; * ; Line Style Support Variables : * ; * ; X0, Y0, XN, YN - Unclipped Line Endpoints * ; ABOVE - Which Line EndPoint ABOVE Strip Flag * ; INSIDE- Line EndPoints INSIDE Strip Flag * ; * ; Raster Variables : * ; X0 - Line start point coord. * ; XN - Line end point coord. * ; * ; ROUTINES CALLED : * ; * ; ADDRXY : DETERMINE THE BITMAP ADDRESS FOR PIXEL X,Y * ; * ; SETBIT : 'SET' THE BIT AT THE BITMAP BUFFER ADDRESS NBYT,NBIT * ; * ;**************************************************************************** PUBLIC DRAWXY EXTRN GETADR:near, ADDRXY:near, SETBIT:near EXTRN SWAPY:NEAR, MIDH:NEAR, DIDH:NEAR, IMOD:near EXTRN ABSHL:NEAR, NEGHL:NEAR, CMPDH:NEAR, CMPS:NEAR, SUBDH:near dseg public doxy ;;;;; EXTRN BITMAP:word Extrn NBIT:byte, NBYT:word, MPTY:word EXTRN XMAX:word, YMAX:word EXTRN XW:word, TOPY:word, BOTY:word, BOTTY:word EXTRN LSTYLE:word, NDLNTY:byte, specil:word extrn nopflg:byte, bitmask:byte, ritflg:byte, ndlnco:byte EXTRN X:word, X1:word, Y:word, Y1:word, X2:word, Y2:word EXTRN DX1:word, DY:word, XDIR:word, YDIR:word EXTRN X0:word, Y0:word, XN:word, YN:word, ABOVE:byte, INSIDE:byte ;----------------------------------------------------------------------------+ ; LINE DRAWING (RASTERIZE VECTOR TO PIXEL) VARIABLES + ;----------------------------------------------------------------------------+ ABSDX1 RS 02 ABSDY RS 02 ABSD2 RS 02 ;if DX1>dy then absd2 = absDX1 div 2 ; else absd2 = absdy div 2 DOXY RS 01 ;if DX1>dy then doxy = 1 else doxy = 0 DF RS 02 ;Error term maintained for raster algorithm cseg ;----------------------------------------------------------------------------+ ; CALL DRAWXY + ; X0, Y0, XN, YN, X1, X2, Y1, Y2 stored in memory + ; RET + ; All registers used + ;----------------------------------------------------------------------------+ DRAWXY: ; Initialize raster parameters for the line (x1,y1,x2,y2) ;initialize DX1, dy, xdir, ydir,... etc. CALL INITXY ;Initialize line generation variables ; COMPUTE the PIXEL ADDRESS (nbyt, nbit) FOR FIRST POINT x1, y1 MOV DX,Word Ptr Y1 MOV BX,Word Ptr X1 CALL GETADR ;Returns = nbyt ; = nbit ;nbyt, nbit are stored by GETADR ; Check is Linestyle SOLID ? CMP Byte Ptr NDLNTY,0 ;0 = SOLID JNE DRWJ02 ;1 = special line type ; SOLID LINE, set up line pattern mask (specil) = 1111111111111111b mov word ptr specil, 0ffffH JMPS repit1 ;Alway SETBIT ; rotate the Line pattern mask to x1, y1 DRWJ02: CALL SWAPY ; Do until (x=x2 and y=y2) REPIT1: ; rotate the linestyle Pattern Mask, check the color and the writing mode ; and set the logical operation flag accordingly call linety jnc DRWJ08 ;----------------------------------------------------------------------------+ ; Set this bit + ;----------------------------------------------------------------------------+ DRWJ07: MOV BX,Word Ptr NBYT MOV CH,Byte Ptr NBIT CALL SETBIT ; = Byte position ; = bit position in Nbyt to be set DRWJ08: CMP Byte Ptr DOXY,0 XCHG BX,DX ;Put nbyt in JE DRWJ01 ;----------------------------------------------------------------------------+ ; doxy = 1, (ie. abs(DX1) > abs(dy)) + ; Always jump x, may be jump y + ;----------------------------------------------------------------------------+ MOV BX,Word Ptr X ; = x CALL JUMPX ;Returns = abs(df), = nbyt, ; = nbit, new x, df stored ; Test may be jump y PUSH DX ;Save nbyt MOV DX,Word Ptr ABSD2 ; = abs(DX1/2) CMP BX,DX ;abs(df) >= abs(DX1/2) ? POP DX ;Returns carry set if abs(DX1/2) < df JBE DRWL01 ;Don't Move Y MOV BX,Word Ptr Y ;Move Y coordinate by +- 1 CALL JUMPY ;Returns = abs(df), = nbyt, ; = nbit, new y, df stored JMPS DRWL01 ;----------------------------------------------------------------------------+ ;doxy = 0, always 'jump y', may be jump x (ie. abs(DX1) <= abs(dy) ) + ;----------------------------------------------------------------------------+ DRWJ01: MOV BX,Word Ptr Y ; = y CALL JUMPY ;Returns = abs(df), = nbyt ; new y, df stored ; Test and may be jump x, if abs(df) >= abs(dy/2) PUSH DX ;Save nbyt MOV DX,Word Ptr ABSD2 ; = abs(dy/2) CMP BX,DX ;abs(df) >= abs(dy/2) ? POP DX JBE DRWL01 MOV BX,Word Ptr X ;Move x CALL JUMPX ;Returns = abs(df), = nbyt, ; = nbit, new x,df stored DRWL01: PUSH DX ;Save nbyt ;----------------------------------------------------------------------------+ ; Test end of do until loop + ; x = x2 ? + ;----------------------------------------------------------------------------+ MOV DX,Word Ptr X MOV BX,Word Ptr X2 ; = x2 CMP BX,DX JNE UNTIL1 ;Not zero : x <> x2 ;----------------------------------------------------------------------------+ ; and y = y2 ? + ;----------------------------------------------------------------------------+ MOV DX,Word Ptr Y MOV BX,Word Ptr Y2 ; = y2 CMP BX,DX JNE UNTIL1 ;Not zero : Y <> y2 ;----------------------------------------------------------------------------+ ; end of line condition + ;----------------------------------------------------------------------------+ POP BX ; Check Linestyle, Writing Mode and Line Color ; rotate the linestyle Pattern Mask, check the color and the writing mode ; and set the logical operation flag accordingly call linety jnc dexit DRWRET: CALL SETBIT dexit: RET ;----------------------------------------------------------------------------+ ; UNTIL LOOP + ;----------------------------------------------------------------------------+ UNTIL1: POP BX ;Get nbyt into MOV Word Ptr NBYT,BX MOV Byte Ptr NBIT,CH JMP REPIT1 ;loop until x=x2 and y=y2 ;***************************************************************************** ; * ; LINETY : Rotate the linestyle pattern mask * ; Check Writing Mode Flag, nopflg, nopflg = 0 for replace mode * ; for replace mode, if Set Bit then rflag = 0, and bit mask = 00000001 * ; if Clear Bit then rflag = 1, and bit mask = 11111110 * ; if rflag = 0, then new data bit = old data or bitmask * ; 1, then new data bit = old data and bitmask * ; if nopflg = 0 then the writing mode is set/xor/clear * ; the ritflg and the bit mask is set up already * ; * ;***************************************************************************** linety: cmp nopflg, 0 ; check writing mode jne lij09 ; nopflg = 0, replace mode rol specil, 1 ; linestyle set or clear ? jnc lij00 ; clear bit cmp ndlnco, 0 ; line color, 0 or 1 ? je lij00 ; color = 0, clear bit ; color = 1, Set bit regaraless mov ritflg, 0 ; set logical op to OR mov bitmask, 1 ; set bit mask to 1 lij01: stc ret lij00: ; color = 0, Clear bit regardless mov ritflg, 1 ; set logical op to AND mov bitmask, 11111110b ; set bitmask to 0 jmp lij01 lij09: ; Set/Xor/Clear Mode, logical op flag and bit mask already set ; rotate the linestyle pattern and go do it rol specil, 1 lij99: ret EJECT ;*************************************************************************** ;* * ;* INITXY : INITIALIZE VALUES USED BY THE INCREMENTAL ALGORITHM * ;* * ;*************************************************************************** ; * ; Initxy : x1, x2, y1, y2 * ; * ; Function : Initialize parameters for the line generation algorithm * ; * ; Input : X1, X2, Y1, Y2 * ; * ; Output : DX1, DY, XDIR, YDIR, ABSDX1, ABSDY, ABSD2, DOXY * ; * ; Calls : DELTA - Compute Delta, Abs(delta) values and set the Dir flag* ; CMPDH - Double precision compare (DE >= HL ?) * ; CMPS - Double Precision compare (signed values DE >= HL ?) * ; SUBDH - Double precision subtract (HL = DE - HL) * ; NEGHL - Double precision negate (HL = 2's complement HL) * ; * ;--------------------------------------------------------------------------* ; ; CALL INITXY ; X1, Y1, X2, Y2 stored in memory ; RET ; INITXY: MOV DX,Word Ptr X2 MOV BX,Word Ptr x1 ;BX=x1¬ DX=x2 CALL delta MOV Byte Ptr XDIR,AL ;A=xdir MOV Word Ptr DX1,BX ;BX=DX1 CALL ABSHL ;Get abs(DX1) MOV Word Ptr ABSDX1,BX MOV DX,Word Ptr Y2 MOV BX,Word Ptr Y1 ;HL=y1, DE=y2 CALL DELTA ;Get dy, ydir MOV Byte Ptr YDIR,AL ;A=ydir MOV Word Ptr DY,BX ;HL=dy CALL ABSHL ;Get abs(dy) MOV Word Ptr ABSDY,BX MOV DX,Word Ptr ABSDX1 ;HL=absDX1, DE=absdy CMP DX,BX ;absDX1 > absdy ? JLE INIJ01 ;Set Jump Flag : Always Jump Y, Maybe Jump X ; Line drawing algorithm uses abs(DX1/2) if abs(DX1) > abs(dy) MOV BX,DX ;Put abs(DX) in BX MOV AL,01 ;Set abs(DX1) > abs(dy) flag JMPS INIJ02 ;DOXY = 1, Always Jump X, DX > DY ; Line Drawing Algorithm uses abs(DY/2) if abs(DY) >= abs(DX) inij01: ;abs(DY) in BX XOR AL,AL ;DOXY = 0, Always Jump Y, DX <= DY inij02: MOV Byte Ptr doxy,AL XOR AL,AL MOV AL,BH RCR AL,1 ;absd2 = abs(DX/2) If DX > DY MOV BH,AL ; = abs(DY/2) If DY >= dx MOV AL,BL RCR AL,1 MOV BL,AL MOV Word Ptr absd2,BX RET ;----------------------------------------------------------------------------+ ; + ; delta (x1, x2) + ; + ; Function : Compute DX1=x2-x1, set xdir = 0:x2x1 + ; + ; CALL DELTA + ; = X2 + ; = X1 + ; RET + ; = XDIR + ; = DX1 + ; + ;----------------------------------------------------------------------------+ DELTA: ;DX1=x2-x1 CMP DX,BX ;x2 > x1 ? JA DELJ02 ;xdir > 0 (x2>=x1) JE DELJ01 MOV AL,0 ;xdir = 0 (x2x1) DELJ99: SUB DX,BX ;DX1 = X2-X1 MOV BX,DX RET EJECT ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; ; ; JUMPX : INCREMENT X AND UPDATE THE DECISION VARIABLE DF, AND UPDATE ; ; ; THE BITMAP ADDRESS POINTER (INCREMENT NBIT) ; ; ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Jumpx (x,xdir,df,dy,nbyt,nbit) ; ; ; ; Function : Move x coordinate pixel by +-1 ; ; new x = x + xdir (xdir indicates Line Direction) ; ; update pixel address : nbyt, nbit ; ; df = df - (dy * xdir) ; ; ; ; Input : X - Current x coordinate ; ; NBYT - Pixel address pointer (byte position = y coord) ; ; NBIT - Pixel address pointer (bit position = x coord) ; ; DY - Change in DF due to a move in x ; ; XDIR - Direction of move (-1, 0 +1), Actual Value = 0,1,2 ; ; DF - Error term maintained for generating next pixel ; ; ; ; Output : X - New X ; ; NBYT - New NBYT ; ; NBIT - New NBIT ; ; DF - New DF ; ; ; ; Calls : NEGHL - Complement HL register pair ; ; ABSHL - Absolute HL ; ; ; ;----------------------------------------------------------------------------; ; ; CALL JUMPX ; = NBYT ; = X ; = NBIT ; RET ; = NBYT ; = ABS(DF) ; = NBIT ; NEW X, NEW DF Stored in memory ; ;----------------------------------------------------------------------------+ JUMPX: ; First check XDIR the move direction flag CMP Byte Ptr XDIR,1 JE JPXJ01 ;Xdir = 1, JUMPX = NOP (x2=x1) JB JPXJ02 ;Xdir = 0, Decrement X (x2 = 0 Indicates xdir = 0 DEC CH ;Nbit = nbit - 1 JNS JPXJ04 ;nbit < 0 ? MOV CH,07H ;Yes, Reset nbit = 7 DEC DX ;Decrement nbyt when NBIT = -1 JMPS JPXJ04 JPXJ03: MOV AL,1 ; = 1 indicates xdir = 2 JPXJ04: MOV Word Ptr X,BX ;Store new x PUSH CX ;Save nbit ;----------------------------------------------------------------------------+ ; Update df to reflect the move in x coordinate + ;----------------------------------------------------------------------------+ MOV BX,Word Ptr DY ;Get dy OR AL,AL ;Check xdir = 2 ? JZ L@2 NEG BX ;Yes, Negate dy : df = df - dy L@2: MOV CX,BX ;Move dy to MOV BX,Word Ptr DF ;Get df in ;df = df +- dy ADD BX,CX MOV Word Ptr DF,BX ;Store new df CALL ABSHL ; = abs(df) POP CX ; = nbit JPXJ01: RET ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; ; ; JUMPY : INCREMENT Y, UPDATE THE DECISION VARIABLE DF, AND UPDATE THE ; ; ; BITMAP ADDRESS POINTER NBYT ; ; ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Jumpy (y,ydir,df,DX1,nbyt) ; ; ; ; Function : Move y coordinate pixel by +-1 ; ; new y = y + ydir ; ; update pixel address : nbyt = nbyt + xw ; ; df = df + (DX1 * ydir) ; ; ; ; Input : Y - Current Y coordinate ; ; NBYT - Pixel address pointer (byte position : y coordinate) ; ; DX1 - Change in DF due to a move in Y ; ; YDIR - Direction of move (-1, 0 +1) , Actual Value = 0,1,2 ; ; DF - Error term maintained for generating next pixel ; ; ; ; Output : Y - New Y ; ; NBYT - New address pointer ; ; DF - New DF ; ; ; ; Calls : NEGHL - Complement HL register pair ; ; ABSHL - Absolute HL ; ; ; ;----------------------------------------------------------------------------; ; ; CALL JUMPY ; = Y ; = NBYT ; RET ; = ABS(DF) ; = NBYT ; NEW Y, NEW DF Stored ; * Uses ; Unchanged JUMPY: ; First check YDIR : the move direction flag CMP Byte Ptr YDIR,1 JE JPYJ01 ;Ydir = 1, JUMPY = NOP (y2=y1) JB JPYJ02 ;Ydir = 0, Decrement Y (y2 = 1 indicates Ydir = 2 JMPS JPYJ03 ;----------------------------------------------------------------------------+ ; else Ydir = 0, do Y = Y - 1, nbyt = nbyt + xw, df = df - DX1 + ;----------------------------------------------------------------------------+ JPYJ02: DEC BX ;Y = Y - 1 XOR AL,AL ; = 0 indicates Ydir = 0 JPYJ03: MOV Word Ptr Y,BX ;Store new Y PUSH AX ; Update bitmap address pointer for new Y : nbyt = nbyt + (xw*ydir) MOV BX,Word Ptr XW ;Load xw OR AL,AL ;Check ydir = 0 ? JNZ L@3 NEG BX ;No, Complement XW L@3: ADD BX,DX ;nbyt = nbyt +- xw ;----------------------------------------------------------------------------+ ; Update DF to reflect the move in Y coordinate + ;----------------------------------------------------------------------------+ POP AX ;Restore Ydir flag PUSH BX ;Save nbyt MOV BX,Word Ptr DX1 ;Get DX1 OR AL,AL ;Check ydir = 0 ? JNZ L@4 NEG BX ;Yes, Negate DX1 : df = df + (DX1*ydir) L@4: MOV DX,Word Ptr DF ;Get df in ;df = df +- DX1 ADD BX,DX MOV Word Ptr DF,BX ;Store df CALL ABSHL ; = abs(df) POP DX ;Restore nbyt JPYJ01: RET END