QuickDraw/DrawLine.a

746 lines
34 KiB
Plaintext
Executable File

.INCLUDE GRAFTYPES.TEXT
;-----------------------------------------------------------------
;
; --> DRAWLINE.TEXT
;
.PROC DrawLine
.REF RgnBlt,RSect,ShieldCursor,ShowCursor,TrimRect
.REF InitRgn,SeekRgn,PatExpand,ColorMap
.REF XorSlab,DrawSlab,SlabMode,FastSlabMode,MaskTab
;----------------------------------------------------------------
;
; PROCEDURE DRAWLINE(P1,P2: POINT);
;
; DRAWS A LINE CLIPPED TO CURRENT PORT'S CLIPRGN AND VISRGN
;
; P1 AND P2 ARE GIVEN IN LOCAL COORDINATES OF THEPORT.
;
;------------------------------------------------
;
; A6 OFFSETS OF PARAMETERS AFTER LINK:
;
PARAMSIZE .EQU 8 ;SIZE OF PARAMETERS
P1 .EQU PARAMSIZE+8-4 ;POINT
P2 .EQU P1-4 ;POINT
;-------------------------------------------------
;
; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK:
;
EXPAT .EQU -64 ;16 LONGS
LINERECT .EQU EXPAT-8 ;RECT
MINRECT .EQU LINERECT-8 ;RECT
STATEA .EQU MINRECT-RGNREC ;RGN STATE RECORD
STATEB .EQU STATEA-RGNREC ;RGN STATE RECORD
STATEC .EQU STATEB-RGNREC ;RGN STATE RECORD
SAVESTK .EQU STATEC-4 ;LONG
RECTFLAG .EQU SAVESTK-2 ;WORD
MASKBUF .EQU RECTFLAG-4 ;LONG
BUFLEFT .EQU MASKBUF-2 ;WORD
BUFSIZE .EQU BUFLEFT-2 ;WORD
VERT .EQU BUFSIZE-2 ;WORD
MODECASE .EQU VERT-4 ;LONG
PAT .EQU MODECASE-4 ;LONG, ADDR OF PAT
LEFTEDGE .EQU PAT-4 ;LONG, FIXED POINT
RIGHTEDGE .EQU LEFTEDGE-4 ;LONG, FIXED POINT
SLOPE .EQU RIGHTEDGE-4 ;LONG, FIXED POINT
DSTLEFT .EQU SLOPE-4 ;LONG
SAVEA5 .EQU DSTLEFT-4 ;LONG
PORT .EQU SAVEA5-4 ;LONG
MODE .EQU PORT-2 ;WORD
FASTFLAG .EQU MODE-2 ;BYTE
BIGRGN .EQU FASTFLAG-4 ;LONG, RgnHandle
VARSIZE .EQU BIGRGN ;SIZE OF LOCAL VARIABLES
LINK A6,#VARSIZE ;ALLOCATE LOCAL VARS
MOVEM.L D0-D7/A1-A5,-(SP) ;SAVE REGS
MOVE.L SP,SAVESTK(A6) ;REMEMBER STACK FOR LATER
MOVE.L A5,SAVEA5(A6) ;REMEMBER GLOBAL PTR
MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS
MOVE.L WIDEOPEN(A0),BIGRGN(A6) ;STASH WIDEOPEN IN BIGRGN
MOVE.L THEPORT(A0),A3 ;POINT TO CURRENT GRAFPORT
TST PNVIS(A3) ;IS PNVIS NEGATIVE ?
BLT GOHOME ;YES, QUIT
MOVE.L A3,PORT(A6) ;SAVE PORT FOR LATER
;-------------------------------------------------------
;
; QUIT IF PEN MODE NOT IN 8..15
;
MOVEQ #-8,D0
AND PNMODE(A3),D0 ;GET ALL BUT 3 BITS OF PEN MODE
CMP #8,D0 ;IS PEN MODE 8..15 ?
BNE GOHOME ;NO, QUIT
;-------------------------------------------------------
;
; Check for color filtering. Alter mode and pattern accordingly.
;
MOVE PNMODE(A3),-(SP) ;PUSH PEN MODE
PEA PNPAT(A3) ;PUSH ADDR OF PEN PATTERN
TST COLRBIT(A3) ;IS COLORBIT = 0 ?
BEQ.S NOCOLOR ;YES, DON'T MAP
JSR COLORMAP ;CHECK AGAINST THECOLOR, THEFILTER
NOCOLOR MOVE.L (SP)+,PAT(A6) ;GET (ALTERED) PATTERN
MOVE (SP)+,MODE(A6) ;AND (ALTERED) MODE
;---------------------------------------------------------
;
; GET CLIPRGN AND VISRGN HANDLES AND DE-REFERENCE THEM
;
MOVE.L A3,A5 ;PUT GRAFPTR IN A5
MOVE.L CLIPRGN(A5),A2 ;GET CLIPRGN HANDLE
MOVE.L (A2),A2 ;GET CLIPRGN POINTER
MOVE.L VISRGN(A5),A3 ;GET VISRGN HANDLE
MOVE.L (A3),A3 ;GET VISRGN POINTER
;-------------------------------------------------------------
;
; SET UP LINERECT, THE RECTANGLE BOUNDING THE LINE AND PEN
;
MOVEM.W P2(A6),D1/D2/D3/D4 ;GET D1=V1, D2=H1, D3=V2, D4=H2
CMP D3,D1 ;IS V1 > V2 ?
BLE.S VOK2 ;NO, CONTINUE
EXG D1,D3 ;YES, SWAP VERT
VOK2 CMP D4,D2 ;IS H1 > H2 ?
BLE.S HOK2 ;NO, CONTINUE
EXG D2,D4 ;NO SWAP HORIZ
HOK2 ADD PNSIZE+H(A5),D4 ;ADD PEN WIDTH TO RIGHT
ADD PNSIZE+V(A5),D3 ;ADD PEN HEIGHT TO BOTTOM
MOVEM.W D1/D2/D3/D4,LINERECT(A6) ;STORE TOP, LEFT, BOTTOM, RIGHT
;-----------------------------------------------------------------------
;
; CALC MINRECT, THE INTERSECTION OF LINERECT, BITMAP BOUNDS,
; CLIPRGN BBOX, AND VISRGN BBOX. QUIT IF NO INTERSECTION.
;
PEA LINERECT(A6) ;PUSH LINE RECT
PEA PORTBITS+BOUNDS(A5) ;PUSH BITMAP BOUNDS
PEA RGNBBOX(A2) ;PUSH CLIPRGN BBOX
PEA RGNBBOX(A3) ;PUSH VISRGN BBOX
MOVE #4,-(SP) ;PUSH NRECTS=4
PEA MINRECT(A6) ;PUSH DST ADDR
JSR RSECT ;CALC INTERSECTION
BEQ GOHOME ;QUIT IF NO INTERSECT
;
; HIDE CURSOR IF CURSOR INTERSECTS MINRECT.
;
PEA MINRECT(A6) ;PUSH SHIELDRECT PARAMETER
MOVE.L PORTBITS+BOUNDS+TOPLEFT(A5),-(SP) ;PUSH DELTA TO CONVERT TO GLOBAL
MOVE.L SAVEA5(A6),A5 ;GET GLOBAL PTR
JSR SHIELDCURSOR ;HIDE CURSOR IF IT INTERSECTS
MOVE.L PORT(A6),A5 ;GET BACK THEPORT
;
; CHECK FOR BOTH VISRGN AND CLIPRGN RECTANGULAR
;
CLR.B FASTFLAG(A6) ;FASTFLAG := FALSE
CMP #10,RGNSIZE(A2) ;IS CLIPRGN RECTANGULAR ?
BNE.S FLAGOK ;NO, CONTINUE
CMP #10,RGNSIZE(A3) ;IS VISRGN RECTANGULAR ?
BEQ.S CKPAT ;YES, CONTINUE
;
; If only visRgn is non-rectangular, then check if
; its intersection with minrect would be rectangular.
; IF TrimRect(visRgn,minRect) then treat as rectangular.
;
MOVE.L visRgn(A5),-(SP) ;push rgnHandle
PEA minRect(A6) ;push addr of minRect
JSR TrimRect ;call trimRect
BLT DONE ;quit if intersection empty
BGT.S FLAGOK ;continue if non-rectangular
;
; CHECK FOR BLACK OR WHITE PATTERN
;
CKPAT MOVE.L PAT(A6),A0 ;POINT TO PATTERN
MOVE.L (A0)+,D0 ;GET 1ST HALF OF PATTERN
CMP.L (A0)+,D0 ;IS IT SAME AS 2ND HALF ?
BNE.S FLAGOK ;NO, CONTINUE
NOT.L D0 ;IS PATTERN BLACK ?
BEQ.S YESFLAG ;YES, WE MADE IT
NOT.L D0 ;IS PATTERN WHITE ?
BNE.S FLAGOK ;NO, CONTINUE
EOR #4,MODE(A6) ;YES, ALTER MODE AS IF BLACK
YESFLAG ST FASTFLAG(A6) ;RECT CLIPPED AND BLACK
;
; fast case: map mode into black,xor,white, or do-nothing
;
MOVEQ #7,D0 ;GET 3 BIT MASK
AND MODE(A6),D0 ;GET 3 BITS OF MODE
MOVE.B MODEMAP(D0),D0 ;MAP TO BLACK,XOR,WHITE,NOP
BMI DONE ;QUIT IF DO-NOTHING MODE
MOVE D0,MODE(A6) ;UPDATE MODE
BRA.S FLAGOK ;AND CONTINUE
MODEMAP .BYTE 0,0,1,2,2,255,255,255
FLAGOK
;
; GET THE TWO LINE ENDPOINTS INTO REGISTERS
; AND CHECK FOR HORIZONTAL OR VERTICAL LINE
;
MOVEM.W P2(A6),D1/D2/D3/D4 ;GET D1=V2, D2=H2, D3=V1, D4=H1
CMP D2,D4 ;H1=H2 ?
BEQ.S HVLINE ;YES, DO VERTICAL LINE
CMP D1,D3 ;NO, IS V2 > V1 ?
BGT.S SLANTED ;YES, DRAW SLANTED LINE
BLT.S VSWAP ;SWAP POINTS AND DRAW SLANTED
;ELSE V1=V2, DO HORIZONTAL
;-----------------------------------------------------------
;
; LINE IS EITHER HORIZONTAL OR VERTICAL.
; CHECK FOR ONE DOT LINE, BLACK OR WHITE PATTERN, AND
; CLIPRGN AND VISRGN BOTH RECTANGULAR. IF SO, OPTIMIZE FAST LINES.
;
HVLINE TST.B FASTFLAG(A6) ;RECT CLIPPED AND BLACK ?
BEQ.S NOTFAST ;NO, CONTINUE
CMP.L #$00010001,PNSIZE(A5) ;IS PEN 1 BY 1 ?
BEQ FASTLINE ;YES, DO IT FAST !
;--------------------------------------------------------------------
;
; NOT FASTLINE. PUSH PARAMS AND CALL RGNBLT FOR HORIZ OR VERT LINE.
;
NOTFAST PEA PORTBITS(A5) ;PUSH SRCBITS = DSTBITS
MOVE.L (SP),-(SP) ;PUSH DSTBITS
PEA MINRECT(A6) ;PUSH SRCRECT = DSTRECT
MOVE.L (SP),-(SP) ;PUSH DSTRECT
MOVE PNMODE(A5),-(SP) ;PUSH MODE
PEA PNPAT(A5) ;PUSH PATTERN
MOVE.L CLIPRGN(A5),-(SP) ;PUSH CLIPRGN HANDLE
MOVE.L VISRGN(A5),-(SP) ;PUSH VISRGN HANDLE
MOVE.L BIGRGN(A6),-(SP) ;PUSH SAVED WIDEOPEN
MOVE.L SAVEA5(A6),A5 ;GET GLOBAL PTR
JSR RGNBLT ;DRAW THE HORIZ OR VERT LINE
BRA DONE ;RESTORE CURSOR AND QUIT
;-------------------------------------------------------------
;
; THE LINE IS SLANTED. SORT VERTICALLY
; AND DRAW TOP TO BOTTOM AS HORIZONTAL SLABS.
;
VSWAP EXG D1,D3 ;SORT POINTS BY VERTICAL
EXG D2,D4 ;SWAP HORIZ TO MATCH
SLANTED MOVE D3,D0 ;COPY LINE BOTTOM
ADD PNSIZE+V(A5),D0 ;ADD PEN HEIGHT
CMP RGNBBOX+TOP(A2),D0 ;IS RESULT <= CLIP TOP ?
BLE DONE ;YES, RESTORE CURSOR AND QUIT
CMP RGNBBOX+BOTTOM(A2),D1 ;IS TOP >= CLIP BOTTOM ?
BGE DONE ;YES, RESTORE CURSOR AND QUIT
;-------------------------------------------------------------
;
; SET UP INITIAL FIXED POINT LEFTEDGE AND RIGHTEDGE
; AND CHECK FOR ZERO PENSIZE.
;
MOVE.W D2,LEFTEDGE(A6) ;LEFTEDGE.INT := TOP HORIZ
MOVE.W #$8000,LEFTEDGE+2(A6) ;LEFTEDGE.FRACT := 1/2
MOVE.L LEFTEDGE(A6),RIGHTEDGE(A6) ;RIGHTEDGE:=LEFTEDGE
MOVE PNSIZE+H(A5),D0 ;GET PEN WIDTH
BLE DONE ;QUIT IF PENWIDTH <= 0
ADD.W D0,RIGHTEDGE(A6) ;ADD TO RIGHTEDGE.INT
MOVE PNSIZE+V(A5),D6 ;GET PEN HEIGHT
BLE DONE ;QUIT IF PEN HEIGHT <= 0
;----------------------------------------------------
;
; CALC FIXED POINT SLOPE = FixRatio(dh,dv);
;
CLR.L -(SP) ;MAKE ROOM FOR FCN RESULT
MOVE D4,-(SP) ;PUSH BOTTOM HORIZ
SUB D2,(SP) ;CALC DH
MOVE D3,-(SP) ;PUSH BOTTOM VERT
SUB D1,(SP) ;CALC DV
_FixRatio ;CALC FIXED POINT SLOPE DH/DV
MOVE.L (SP)+,D7 ;POP RESULT
MOVE.L D7,SLOPE(A6) ;SAVE FOR LATER
;
; CALC adjust := pen height * slope
;
CLR.L -(SP) ;PUSH ROOM FOR FCN RESULT
CLR.W -(SP) ;PUSH LOWORD = 0
MOVE.W D6,-(SP) ;PUSH HIWORD = PEN HEIGHT
MOVE.L D7,-(SP) ;PUSH SLOPE
_FixMul ;CALC FixMul(pnSize.v,slope)
MOVE.L (SP)+,D6 ;POP ANSWER INTO D6
;
; ADJUST LEFTEDGE AND RIGHTEDGE DEPENDING ON SIGN AND MAGNITUDE OF SLOPE
;
MOVE.L D7,D0 ;COPY SLOPE
ASR.L #1,D0 ;CALC SLOPE/2
ADD.L D0,LEFTEDGE(A6) ;ADD SLOPE/2 TO LEFT EDGE
ADD.L D0,RIGHTEDGE(A6) ;ADD SLOPE/2 TO RIGHT EDGE
TST.L D7 ;IS SLOPE NEGATIVE ?
BMI.S NEGSLOPE ;YES, CONTINUE
SUB.L D6,LEFTEDGE(A6) ;SUBTRACT ADJUST FROM LEFTEDGE
CMP.L #$00010000,D7 ;IS SLOPE < ONE ?
BGE.S LESSV1 ;NO, BRANCH
MOREV1 ADD.L D7,LEFTEDGE(A6) ;ADD SLOPE TO LEFTEDGE
BRA.S SLOPEOK ;CONTINUE
LESSV1 SUB.W #1,RIGHTEDGE(A6) ;RIGHTEDGE := RIGHTEDGE - 1
BRA.S SLOPEOK ;CONTINUE
;----------------------------------------------------
;
; SLOPE IS NEGATIVE
;
NEGSLOPE SUB.L D6,RIGHTEDGE(A6) ;SUBTRACT ADJUST FROM RIGHTEDGE
CMP.L #$FFFF0000,D7 ;IS SLOPE > -ONE ?
BLT.S LESSV2 ;NO, CONTINUE
MOREV2 ADD.L D7,RIGHTEDGE(A6) ;ADD SLOPE TO RIGHTEDGE
BRA.S SLOPEOK
LESSV2 ADD.W #1,LEFTEDGE(A6) ;LEFTEDGE := LEFTEDGE + 1
SLOPEOK MOVEM.W MINRECT(A6),D1/D2/D3/D4 ;GET MINRECT TOP,LEFT,BOTTOM,RIGHT
;
; ADJUST LEFTEDGE AND RIGHTEDGE IF LINE WAS CLIPPED VERTICALLY
;
CMP LINERECT+TOP(A6),D1 ;DID TOP GET CLIPPED ?
BEQ.S TOPOK ;NO, CONTINUE
MOVE D1,D0
SUB LINERECT+TOP(A6),D0 ;CALC DISCARD AMMOUNT
MOVE.L D7,D5 ;GET 32 BIT SLOPE
SWAP D5 ;GET HI WORD OF SLOPE
MULS D0,D5 ;MULT TIMES DISCARD
SWAP D5 ;PUT RESULT IN HI WORD
CLR.W D5 ;CLEAR LO WORD
MOVE.L D7,D6 ;GET NEW COPY OF SLOPE
MULU D0,D6 ;MULT LO WORD TIMES DISCARD
ADD.L D6,D5 ;CALC 32BIT SLOPE*DISCARD
ADD.L D5,LEFTEDGE(A6) ;BUMP LEFTEDGE TO NEW TOP
ADD.L D5,RIGHTEDGE(A6) ;BUMP RIGHTEDGE TO NEW TOP
TOPOK
;
; CALC BUFLEFT
;
MOVE MINRECT+LEFT(A6),D2 ;GET MINRECT LEFT
SUB PORTBITS+BOUNDS+LEFT(A5),D2 ;CONVERT TO GLOBAL COORDS
AND #$FFF0,D2 ;TRUNC TO MULT OF 16
ADD PORTBITS+BOUNDS+LEFT(A5),D2 ;CONVERT BACK TO GLOBAL
MOVE D2,BUFLEFT(A6) ;SAVE AS BUFLEFT
;
; IF FASTFLAG, THEN SKIP REGION SETUP
;
TST.B FASTFLAG(A6) ;RECT CLIPPED AND BLACK ?
BNE SKIPSETUP ;YES, DON'T WASTE TIME WITH SETUP
;
; CALC BUFSIZE
;
MOVE MINRECT+RIGHT(A6),D0 ;GET MINRECT RIGHT
SUB D2,D0 ;CALC MAXH-BUFLEFT
LSR #5,D0 ;DIV BY 32 FOR LONGS
MOVE D0,BUFSIZE(A6) ;BUFSIZE = # LONGS - 1
;
; ALLOCATE AND CLEAR A SCANLINE BUFFER FOR THE COMPOSITE MASK
;
CLRMASK CLR.L -(SP) ;ALLOCATE AND CLEAR ONE LONG
DBRA D0,CLRMASK ;LOOP TILL DONE
MOVE.L SP,MASKBUF(A6) ;REMEMBER WHERE MASKBUF IS
;-------------------------------------------------------------------------
;
; INIT STATE RECORDS AND ALLOCATE BUFFERS FOR EACH NON-RECTANGULAR REGION
;
CLR D5 ;INIT BOTH ARE RECT
MOVE #-32767,STATEA+THISV(A6) ;INIT HARMLESS STATE
MOVE #32767,STATEA+NEXTV(A6) ;IN CASE RECTANGULAR
CMP #10,RGNSIZE(A2) ;IS CLIPRGN RECTANGULAR ?
BEQ.S ARECT ;YES, CONTINUE
ADD #2,D5 ;NO, SET ITS FLAG
MOVE.L A2,A0 ;POINT TO CLIPRGN
LEA STATEA(A6),A1 ;POINT TO STATE RECORD A
BSR.S INITONE ;INIT STATE, ALLOC BUFFER
ARECT
MOVE #-32767,STATEB+THISV(A6) ;INIT HARMLESS STATE
MOVE #32767,STATEB+NEXTV(A6) ;IN CASE RECTANGULAR
CMP #10,RGNSIZE(A3) ;IS VISRGN RECTANGULAR ?
BEQ.S BRECT ;YES, CONTINUE
ADD #4,D5 ;NO, SET ITS FLAG
MOVE.L A3,A0 ;POINT TO VISRGN
LEA STATEB(A6),A1 ;POINT TO STATE RECORD B
PEA BRECT ;PUSH FAKE RETURN ADDR
INITONE MOVE MINRECT+LEFT(A6),D0 ;GET MINH
MOVE MINRECT+RIGHT(A6),D1 ;GET MAXH
MOVE BUFLEFT(A6),D2 ;GET BUFLEFT
JMP INITRGN ;INIT STATE, ALLOC BUFFER
BRECT
;--------------------------------------------------------------------
;
; IF BOTH REGIONS ARE RECTANGULAR, THEN DRAW MINRECT INTO MASK BUFFER
;
MOVE.W D5,RECTFLAG(A6) ;ARE BOTH RGNS RECT ?
BNE.S NOTRECT ;NO, CONTNUE
MOVE.L MASKBUF(A6),A0 ;YES, POINT TO MASK BUFFER
MOVE MINRECT+LEFT(A6),D3 ;SET UP LEFT
SUB BUFLEFT(A6),D3 ;MAKE IT BUFFER RELATIVE
MOVE MINRECT+RIGHT(A6),D4 ;SET UP RIGHT
SUB BUFLEFT(A6),D4 ;MAKE IT BUFFER RELATIVE
JSR XorSlab ;AND XOR BETWEEN THEM
NOTRECT
SKIPSETUP
;------------------------------------
;
; CALC STARTING DSTLEFT
;
MOVE MINRECT+TOP(A6),D1
SUB PORTBITS+BOUNDS+TOP(A5),D1 ;CONVERT MINV TO GLOBAL COORDS
MULU PORTBITS+ROWBYTES(A5),D1 ;MULT BY DST ROWBYTES
ADD.L PORTBITS+BASEADDR(A5),D1 ;ADD START OF BITMAP
SUB PORTBITS+BOUNDS+LEFT(A5),D2 ;CONVERT BUFLEFT TO GLOBAL
LSR #3,D2 ;CALC BUFLEFT DIV 8
EXT.L D2 ;CLR HI WORD
ADD.L D2,D1 ;ADD HORIZ BYTE OFFSET
MOVE.L D1,DSTLEFT(A6) ;SAVE AS DSTLEFT
;----------------------------------------------------
;
; MAKE LEFTEDGE,RIGHTEDGE,MINRECT RELATIVE TO BUFFER LEFT
;
MOVE BUFLEFT(A6),D1
SUB.W D1,LEFTEDGE(A6) ;ADJUST LEFTEDGE.INT
SUB.W D1,RIGHTEDGE(A6) ;ADJUST RIGHTEDGE.INT
SUB D1,MINRECT+LEFT(A6)
SUB D1,MINRECT+RIGHT(A6)
;------------------------------------------------------------
;
; TAKE FAST OR SLOW OUTER CONTROL LOOP FOR SLANTED LINES:
;
TST.B fastFlag(A6) ;ARE WE RECT CLIPPED BLACK ?
BEQ.S GOSLOW ;NO, CONTINUE
MOVE MODE(A6),D2 ;GET (ALTERED) PEN MODE
JSR FastSlabMode ;Get fast case jump in A4
LEA MaskTab,A0 ;point to mask table
LEA MINRECT(A6),A3 ;POINT TO MINRECT
MOVE.L SLOPE(A6),D7 ;GET FIXED POINT SLOPE
MOVE PORTBITS+ROWBYTES(A5),D6 ;GET DST ROWBYTES
MOVE.L DSTLEFT(A6),A5 ;GET DSTLEFT
MOVE MINRECT+BOTTOM(A6),D5 ;GET MINRECT BOTTOM
SUB MINRECT+TOP(A6),D5 ;CALC HEIGHT
SUB #1,D5 ;MINUS 1 FOR DBRA COUNT
NXTFAST MOVE.W LEFTEDGE(A6),D1 ;GET LEFTEDGE.INT
MOVE.W RIGHTEDGE(A6),D2 ;GET RIGHTEDGE.INT
MOVE.L A5,A1 ;INIT DSTPTR TO LEFT
JSR DrawSlab ;DRAW ONE SLAB IN PENMODE
ADD D6,A5 ;BUMP DST TO NEXT ROW
ADD.L D7,LEFTEDGE(A6) ;ADD SLOPE TO LEFT EDGE
ADD.L D7,RIGHTEDGE(A6) ;ADD SLOPE TO RIGHT EDGE
DBRA D5,NXTFAST ;LOOP FOR ALL SCANLINES
BRA DONE ;AND QUIT
GOSLOW MOVE MODE(A6),D2 ;GET (ALTERED) PEN MODE
JSR SlabMode ;GET DrawSlab CASE JUMP IN A4
;------------------------------------------------------------------
;
; EXPAND 8 BYTE PATTERN TO 16 LONGS AND INIT PATTERN SELECTOR
;
CLR.L D7 ;SAY NOT INVERTED
MOVE MODE(A6),D2 ;GET (ALTERED) PEN MODE
BCLR #2,D2 ;TEST AND CLR INVERT BIT
BEQ.S NOTINV ;SKIP IF NOT INVERTED
NOT.L D7 ;INVERTED; D7 GETS ALL 1'S
NOTINV MOVE PORTBITS+BOUNDS+LEFT(A5),D2 ;GET GLOBAL-LOCAL OFFSET
MOVE.L PAT(A6),A0 ;POINT TO BYTE WIDE PATTERN
LEA EXPAT(A6),A1 ;POINT TO EXPANDED PATTERN
MOVE.L SAVEA5(A6),A5 ;GET GLOBAL PTR
JSR PATEXPAND ;EXPAND 8 BYTES TO 16 LONGS
MOVE.L PORT(A6),A5 ;RESTORE GRAFPTR IN A5
MOVEQ #$F,D7 ;TREAT COORD MOD 16
AND MINRECT+TOP(A6),D7 ;GET TOP VERT LOCAL COORD
LSL #2,D7 ;QUAD FOR LONG INDEX
;
; FOR EACH SLAB, MAKE MASK BUFFER CURRENT AND DRAW SLAB
;
LEA MINRECT(A6),A3 ;POINT TO MINRECT
MOVE PORTBITS+ROWBYTES(A5),D5 ;GET DST ROWBYTES
MOVE.L DSTLEFT(A6),A5 ;GET DSTLEFT
MOVE.L SLOPE(A6),D4 ;GET FIXED POINT SLOPE
MOVE MINRECT+TOP(A6),VERT(A6) ;INIT CURRENT VERT:=MINV
NXTMASK BSR.S SEEKMASK ;MAKE MASK BUFFER CURRENT
MOVE.L EXPAT(A6,D7),D6 ;GET PATTERN DATA
MOVE.W LEFTEDGE(A6),D1 ;GET LEFTEDGE.INT
MOVE.W RIGHTEDGE(A6),D2 ;GET RIGHTEDGE.INT
LEA MaskTab,A0 ;point to mask table
MOVE.L A5,A1 ;INIT DSTPTR TO LEFT
MOVE.L MASKBUF(A6),A2 ;INIT MASKPTR TO LEFT
JSR DrawSlab ;DRAW ONE SLAB IN PENMODE
ADD #4,D7 ;BUMP PATTERN SELECTOR
AND #$3F,D7 ;MOD 64 FOR 16 LONG REPEAT
ADD D5,A5 ;BUMP DST TO NEXT ROW
ADD.L D4,LEFTEDGE(A6) ;ADD SLOPE TO LEFT EDGE
ADD.L D4,RIGHTEDGE(A6) ;ADD SLOPE TO RIGHT EDGE
ADD #1,VERT(A6) ;BUMP CURRENT VERT
MOVE VERT(A6),D0 ;GET CURRENT VERT
CMP MINRECT+BOTTOM(A6),D0 ;ARE WE AT BOTTOM YET ?
BLT NXTMASK ;NO, LOOP ALL SCAN LINES
DONE MOVE.L SAVEA5(A6),A5 ;GET GLOBAL PTR
JSR SHOWCURSOR ;RESTORE CURSOR
GOHOME MOVE.L SAVESTK(A6),SP ;STRIP BUFFER
MOVEM.L (SP)+,D0-D7/A1-A5 ;RESTORE REGISTERS
UNLINK PARAMSIZE,'DRAWLINE'
;-----------------------------------------------------------------------------
;
; LOCAL ROUTINE TO UPDATE THE MASK BUFFER
; BASED ON WHICH REGIONS ARE RECTANGULAR
;
SEEKMASK MOVE VERT(A6),D0 ;GET CURRENT VERT COORD
MOVE RECTFLAG(A6),D1 ;GET RECTFLAG = 0,2,4
MOVE RECTJMP(D1),D1 ;GET OFFSET FROM TABLE
JMP RECTJMP(D1) ;TAKE CASE JUMP
RECTJMP .WORD IGNORE-RECTJMP ;DO NOTHING IF BOTH RECT
.WORD A-RECTJMP
.WORD B-RECTJMP
.WORD AB-RECTJMP
;--------------------------------------------------------------------
;
; ONLY REGION A IS NON RECTANGULAR. UPDATE IT AND USE IT AS THE MASK
;
A LEA STATEA(A6),A1
JSRSEEK JSR SEEKRGN
MOVE.L SCANBUF(A1),MASKBUF(A6)
IGNORE RTS
;--------------------------------------------------------------------
;
; ONLY REGION B IS NON RECTANGULAR. UPDATE IT AND USE IT AS THE MASK
;
B LEA STATEB(A6),A1
BRA.S JSRSEEK
;-------------------------------------------------------------------
;
; REGIONS A AND B ARE NON-RECTANGULAR. UPDATE EACH,
; THEN FORM INTERSECTION IN THE MASK BUFFER.
;
AB LEA STATEA(A6),A1
JSR SEEKRGN
LEA STATEB(A6),A1
JSR SEEKRGN
MOVE.L STATEA+SCANBUF(A6),A0
MOVE.L STATEB+SCANBUF(A6),A1
MOVE.L MASKBUF(A6),A2
MOVE BUFSIZE(A6),D1
ABLOOP MOVE.L (A0)+,D0
AND.L (A1)+,D0
MOVE.L D0,(A2)+
DBRA D1,ABLOOP
RTS
;-------------------------------------------------------
;
; SET UP AND DRAW A FAST HORIZONTAL OR VERTICAL LINE.
;
FASTLINE CMP D1,D3 ;IS LINE HORIZONTAL ?
BNE VLINE ;NO, MUST BE VERTICAL
BSR HVSETUP ;GET DSTPTR,ROWBYTES,HGLOBAL
MOVE 32(A0,D0),D6 ;GET LEFTMASK IN D6
MOVE MINRECT+RIGHT(A6),D2 ;GET MINRECT RIGHT
SUB PORTBITS+BOUNDS+LEFT(A5),D2 ;CONVERT TO GLOBAL
MOVE D2,D0 ;MAKE A COPY OF RIGHT
AND #$F,D0 ;TREAT RIGHT MOD 16
ADD D0,D0 ;DOUBLE FOR TABLE
MOVE 0(A0,D0),D3 ;GET RIGHTMASK IN D3
LSR #4,D2 ;CONVERT DOTS TO WORDS
CMP #1,MODE(A6) ;WHICH MODIFIED MODE ?
BLT.S HSET ;BR IF BLACK
BEQ.S HTOGL ;BR IF XOR
;ELSE WHITE
;------------------------------------------------------
;
; DRAW A WHITE HORIZONTAL LINE
;
NOT D6 ;MAKE NOT LEFTMASK
NOT D3 ;MAKE NOT RIGHTMASK
SUB D1,D2 ;CALC WORDCOUNT
BEQ.S ENDCLR ;BR IF ALL IN ONE WORD
AND D6,(A4)+ ;DO LEFT WORD WITH MASK
CLR.L D6 ;FLUSH LEFTMASK FOR END
SUB #1,D2 ;DEC WORD COUNT
BEQ.S ENDCLR ;BR IF NO UNMASKED WORDS
LSR #1,D2 ;HALVE WORDCOUNT FOR LONGCOUNT
BCC.S CLRONE ;BR IF EVEN # WORDS LEFT
MOVE D6,(A4)+ ;ELSE MAKE EVEN BY DOING A WORD
SUB #1,D2 ;ADJUST LONGCOUNT
BRA.S CLRMORE ;SEE IF ANY LONGS LEFT TO DO
CLRTWO MOVE.L D6,(A4)+ ;FILL A LONG WITH BLACK
CLRONE MOVE.L D6,(A4)+ ;FILL ANOTHER LONG
SUB #2,D2 ;ANY UNMASKED LONGS LEFT ?
CLRMORE BGT CLRTWO ;YES, AT LEAST TWO LONGS
BEQ CLRONE ;YES, FINISH UP LAST LONG
ENDCLR OR D3,D6 ;COMBINE LEFT AND RIGHT MASK
AND D6,(A4) ;DRAW LINE
BRA.S DONE ;RESTORE CURSOR AND QUIT
;--------------------------------------------------
;
; DRAW AN XOR HORIZONTAL LINE
;
HTOGL SUB D1,D2 ;CALC WORDCOUNT
BEQ.S ENDTOGL ;BR IF ALL IN ONE WORD
EOR D6,(A4)+ ;DO LEFT WORD WITH MASK
MOVEQ #-1,D6 ;FLUSH LEFTMASK FOR END
SUB #1,D2 ;DEC WORD COUNT
BEQ.S ENDTOGL ;BR IF NO UNMASKED WORDS
LSR #1,D2 ;HALVE WORDCOUNT FOR LONGCOUNT
BCC.S TOGLONE ;BR IF EVEN # WORDS LEFT
EOR D6,(A4)+ ;ELSE MAKE EVEN BY DOING A WORD
SUB #1,D2 ;ADJUST LONGCOUNT
BRA.S TOGLMORE ;SEE IF ANY LONGS LEFT TO DO
TOGLTWO NOT.L (A4)+ ;INVERT A LONG
TOGLONE NOT.L (A4)+ ;INVERT ANOTHER LONG
SUB #2,D2 ;ANY UNMASKED LONGS LEFT ?
TOGLMORE BGT TOGLTWO ;YES, AT LEAST TWO LONGS
BEQ TOGLONE ;YES, FINISH UP LAST LONG
ENDTOGL AND D3,D6 ;COMBINE LEFT AND RIGHT MASK
EOR D6,(A4) ;DRAW LINE
BRA.S DONE ;RESTORE CURSOR AND QUIT
;--------------------------------------------
;
; DRAW A BLACK HORIZONTAL LINE
;
HSET SUB D1,D2 ;CALC WORDCOUNT
BEQ.S ENDSET ;BR IF ALL IN ONE WORD
OR D6,(A4)+ ;DO LEFT WORD WITH MASK
MOVEQ #-1,D6 ;FLUSH LEFTMASK FOR END
SUB #1,D2 ;DEC WORD COUNT
BEQ.S ENDSET ;BR IF NO UNMASKED WORDS
LSR #1,D2 ;HALVE WORDCOUNT FOR LONGCOUNT
BCC.S SETONE ;BR IF EVEN # WORDS LEFT
MOVE D6,(A4)+ ;ELSE MAKE EVEN BY DOING A WORD
SUB #1,D2 ;ADJUST LONGCOUNT
BRA.S SETMORE ;SEE IF ANY LONGS LEFT TO DO
SETTWO MOVE.L D6,(A4)+ ;FILL A LONG WITH BLACK
SETONE MOVE.L D6,(A4)+ ;FILL ANOTHER LONG
SUB #2,D2 ;ANY UNMASKED LONGS LEFT ?
SETMORE BGT SETTWO ;YES, AT LEAST TWO LONGS
BEQ SETONE ;YES, FINISH UP LAST LONG
ENDSET AND D3,D6 ;COMBINE LEFT AND RIGHT MASK
OR D6,(A4) ;DRAW LINE
BRA.S DONE ;RESTORE CURSOR AND QUIT
;-------------------------------------------------------
;
; DRAW A VERTICAL LINE.
;
VLINE BSR.S HVSETUP ;GET DSTPTR,ROWBYTES,HGLOBAL
MOVE 64(A0,D0),D0 ;GET BITMASK IN D0
MOVE MINRECT+BOTTOM(A6),D1 ;GET BOTTOM
SUB MINRECT+TOP(A6),D1 ;CALC HEIGHT
SUB #1,D1 ;INIT HEIGHT COUNT
CMP #1,MODE(A6) ;WHICH MODIFIED MODE ?
BLT.S VSET ;BR IF BLACK
BEQ.S VTOGL ;BR IF XOR
;ELSE WHITE
NOT D0 ;MAKE NOTMASK
VCLR AND D0,(A4) ;CLEAR ONE DOT
ADD D7,A4 ;BUMP TO NEXT ROW
DBRA D1,VCLR ;LOOP ALL DOTS
BRA.S DONE ;RESTORE CURSOR AND QUIT
VTOGL EOR D0,(A4) ;TOGGLE ONE DOT
ADD D7,A4 ;BUMP TO NEXT ROW
DBRA D1,VTOGL ;LOOP ALL DOTS
BRA.S DONE ;RESTORE CURSOR AND QUIT
VSET OR D0,(A4) ;SET ONE DOT
ADD D7,A4 ;BUMP TO NEXT ROW
DBRA D1,VSET ;LOOP ALL DOTS
BRA.S DONE ;RESTORE CURSOR AND QUIT
;------------------------------------------------------------------------
;
; LOCAL ROUTINE TO SET UP POINTER TO FIRST WORD, BIT INDEX, AND ROWBYTES
;
; INPUTS: MINRECT
; A5: thePort
;
; OUTPUTS: D0: STARTING HORIZ GLOBAL COORDS
; D1: STARTING HORIZ GLOBAL DIV 16
; D7: ROWBYTES
; A0: MaskTab
; A4: POINTER TO FIRST WORD
;
; CLOBBERS: D0,D1,D7,A0,A4
;
HVSETUP MOVE.L PORTBITS+BASEADDR(A5),A4 ;GET BITMAP START
MOVE MINRECT+TOP(A6),D0 ;GET STARTING VERT
SUB PORTBITS+BOUNDS+TOP(A5),D0 ;CONVERT TO GLOBAL
MOVE PORTBITS+ROWBYTES(A5),D7 ;GET ROWBYTES
MULU D7,D0 ;MULT TOP BY ROWBYTES
ADD.L D0,A4 ;ADD TO BASEADDR
MOVE MINRECT+LEFT(A6),D0 ;GET STARTING HORIZ
SUB PORTBITS+BOUNDS+LEFT(A5),D0 ;CONVERT TO GLOBAL
MOVE D0,D1 ;MAKE A COPY
LSR #4,D1 ;CONVERT BITS TO WORDS
ADD D1,A4 ;ADD TO RUNNING TOTAL
ADD D1,A4 ;TWICE FOR BYTES
LEA MaskTab,A0 ;return with masktab in A0
AND #$F,D0 ;TREAT LEFT MOD 16
ADD D0,D0 ;DOUBLE FOR TABLE
RTS
.END