mac-rom/QuickDraw/Classic/Polygons.m.a
Elliot Nunn 0ba83392d4 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-09-20 18:04:16 +08:00

1412 lines
48 KiB
Plaintext

;EASE$$$ READ ONLY COPY of file ÒPOLYGONS.m.aÓ
; 1.2 cv 03/23/1989 Adding code corresponding to patch PMA361. It incorporates
; the routines from QuickPolysClassicPatch.a and speeds up polygons.
; 1.1 CCH 11/11/1988 Fixed Header.
; 1.0 CCH 11/ 9/1988 Adding to EASE.
; OLD REVISIONS BELOW
; 1.2 CCH 10/12/1988 Changed Òm.GrafType.aÓ to ÒGrafType.m.aÓ.
; 1.1 MSH 5/18/88 Changed inclides to use m.GRAPHTYPES to work under EASE.
; 1.0 BBM 2/11/88 Adding file for the first time into EASEÉ
; END EASE MODIFICATION HISTORY
BLANKS ON
STRING ASIS
INCLUDE 'GRAFTYPES.m.a'
INCLUDE 'traps.a' ;<1.2/15mar89>
;--------------------------------------------------------------
;
;
; **** *** * * * *** *** * * ***
; * * * * * * * * * * * * * * *
; * * * * * * * * * ** * *
; **** * * * * * ** * * * * * ***
; * * * * * * * * * * ** *
; * * * * * * * * * * * * *
; * *** ***** * *** *** * * ***
;
;
; <1.2/15mar89> This is the revision history for the old polygons.m.a file prior to rolling
; in the new code from QuickPolysClassicPatch.a.
;_______________________________________________________________________________________
; This code replaces StdPoly with a version that has two important features. It does
; not use QuickDraw regions, and so does not blow up. In addition, for screen sized
; polygons it performs about 4 times faster than QuickDraw polygons.
;_______________________________________________________________________________________
;
; modification history
;
; <18Jan88> AWC MacPlus/SE rom patch installed this date
; <24Mar88> PMAB440 AWC Fixed sorting problem to make QuickPolys match Classic QuickDraw
; <26Mar88> PMAB444 AWC Fixed nil NewHandle bug in QuickPolys; refixed save A0 across _FixRatio
; <31Mar88> PMAB451 AWC Fixed a bug in PMAB440 above and saved registers across FixRatio
; <25Jul88> PMAB543 BAL/JDB Implemented fast case for rectangular filled polys.
;
;-------------------------------------------------------------
;
; Definition of the VectorRec structure
;
YVector Equ 0
XVector Equ 2
YDelta Equ 4
XDelta Equ 6
VectorSize Equ 8
;-------------------------------------------------------------
;
; Definition of the EdgeRec structure
;
NextEdge Equ 0 ; pointer to next edge
PrevEdge Equ NextEdge+4 ; pointer to previous edge
XValue Equ PrevEdge+4 ; current x position (Fixed)
XSlope Equ XValue+4 ; slope of the line (Fixed)
LastY Equ XSlope+4 ; end of the edge
Sign Equ LastY+2 ; sign of the vector (+1 or -1)
EdgeRecSize Equ Sign+2 ; size of the EdgeRec structure (20)
;-------------------------------------------------------------
; Flag to switch between the old polygons and new quickpolys rtns
;
QuickPolys EQU 1
;-------------------------------------------------------------
;
StdPoly PROC EXPORT
IMPORT CheckPic,PutPicVerb,DPutPicByte,PutPicRgn
IMPORT PushVerb,FrPoly,RSect,DrawPoly
;---------------------------------------------------------------
;
; PROCEDURE StdPoly(verb: GrafVerb; poly: PolyHandle);
;
; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK:
;
PARAMSIZE EQU 6
VERB EQU PARAMSIZE+8-2 ;GRAFVERB
POLY EQU VERB-4 ;LONG, PolyHandle
MINRECT EQU -8 ;RECT
VARSIZE EQU MINRECT ;TOTAL BYTES OF LOCALS
LINK A6,#VARSIZE ;ALLOCATE STACK FRAME
MOVEM.L D5-D7/A2-A4,-(SP) ;SAVE REGS
MOVE.B VERB(A6),D7 ;GET VERB
JSR CHECKPIC ;SET UP A4,A3 AND CHECK PICSAVE
BLE.S NOTPIC ;BRANCH IF NOT PICSAVE
MOVE.B D7,-(SP)
JSR PutPicVerb ;PUT ADDIONAL PARAMS TO THEPIC
MOVEQ #$70,D0 ;PUT POLYNOUN IN HI NIBBLE
ADD D7,D0 ;PUT VERB IN LO NIBBLE
JSR DPutPicByte ;PUT OPCODE TO THEPIC
MOVE.L POLY(A6),-(SP) ;PUSH POLYHANDLE
JSR PutPicRgn ;TREAT SAME AS A REGION
NOTPIC MOVE.L POLY(A6),A2 ;GET POLYHANDLE
TST.B D7 ;IS VERB FRAME ?
BNE.S NOTFR ;NO, CONTINUE
MOVE.L A2,-(SP) ;PUSH POLYHANDLE
JSR FrPoly ;FrPoly(poly);
BRA.S GOHOME ;AND QUIT
NOTFR MOVE.L (A2),A0 ;DE-REFERANCE POLYHANDLE
PEA POLYBBOX(A0) ;PUSH POLYBBOX
MOVE.L VISRGN(A3),A0 ;GET VISRGN HANDLE
MOVE.L (A0),A0 ;DE-REFERENCE HANDLE
PEA RGNBBOX(A0) ;PUSH VISRGN BBOX
MOVE.L CLIPRGN(A3),A0 ;GET CLIPRGN HANDLE
MOVE.L (A0),A0 ;DE-REFERENCE HANDLE
PEA RGNBBOX(A0) ;PUSH CLIPRGN BBOX
MOVE #3,-(SP) ;PUSH NRECTS = 3
PEA MINRECT(A6) ;PUT RESULT IN MINRECT
JSR RSECT ;CALC INTERSECTION
BEQ.S GOHOME ;QUIT IF NO INTERSECT
MOVE.L A2,-(SP) ;PUSH POLYHANDLE
JSR PushVerb ;PUSH MODE AND PATTERN
JSR DrawPoly ;DrawPoly(poly,mode,pat);
GOHOME MOVEM.L (SP)+,D5-D7/A2-A4 ;RESTORE REGS
UNLINK PARAMSIZE,'STDPOLY '
FramePoly PROC EXPORT
EXPORT CallPoly,PaintPoly,ErasePoly,InvertPoly,FillPoly
;-----------------------------------------------------
;
; PROCEDURE FramePoly(* poly: PolyHandle *);
;
MOVEQ #FRAME,D0 ;VERB = FRAME
BRA.S CallPoly ;SHARE COMMON CODE
;-----------------------------------------------------
;
; PROCEDURE PaintPoly(* poly: PolyHandle *);
;
PaintPoly
MOVEQ #PAINT,D0 ;VERB = PAINT
BRA.S CallPoly ;SHARE COMMON CODE
;--------------------------------------------------------
;
; PROCEDURE ErasePoly(* poly: PolyHandle *);
;
ErasePoly
MOVEQ #ERASE,D0 ;VERB = ERASE
BRA.S CallPoly ;SHARE COMMON CODE
;--------------------------------------------------------
;
; PROCEDURE InvertPoly(* poly: PolyHandle *);
;
InvertPoly
MOVEQ #INVERT,D0 ;VERB = INVERT
BRA.S CallPoly ;SHARE COMMON CODE
;--------------------------------------------------------
;
; PROCEDURE FillPoly(* poly: PolyHandle; pat: Pattern *);
;
FillPoly
MOVE.L (SP)+,A0 ;POP RETURN ADDR
MOVE.L (SP)+,A1 ;POP ADDR OF PATTERN
MOVE.L A0,-(SP) ;PUT RETURN ADDR BACK
MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS
MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT
LEA FILLPAT(A0),A0 ;POINT TO FILLPAT
MOVE.L (A1)+,(A0)+ ;COPY PAT INTO FILLPAT
MOVE.L (A1)+,(A0)+ ;ALL EIGHT BYTES
MOVEQ #FILL,D0 ;VERB = FILL
BRA.S CallPoly ;SHARE COMMON CODE
;---------------------------------------------------------------
;
; PROCEDURE CallPoly(poly: PolyHandle);
;
; code shared by FramePoly, PaintPoly, ErasePoly, InvertPoly, and FillPoly.
; enter with verb in D0.
;
CallPoly
MOVE.L (SP)+,A0 ;POP RETURN ADDR
MOVE.L (SP)+,A1 ;POP POLY
MOVE.B D0,-(SP) ;PUSH VERB
MOVE.L A1,-(SP) ;PUSH POLY
MOVE.L A0,-(SP) ;RESTORE RETURN ADDR
MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO LISAGRAF GLOBALS
MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT
MOVE.L GRAFPROCS(A0),D0 ;IS GRAFPROCS NIL ?
MOVE.L JStdPoly,A0 ;get piece of trap table
BEQ.S USESTD ;YES, USE STD PROC
MOVE.L D0,A0
MOVE.L POLYPROC(A0),A0 ;NO, GET PROC PTR
USESTD JMP (A0) ;GO TO IT
OpenPoly FUNC EXPORT
IMPORT HidePen,NewHandle
;---------------------------------------------------------------
;
; FUNCTION OpenPoly: PolyHandle;
;
STARTSIZE EQU 138 ;ENOUGH FOR 32 POINTS
JSR HidePen ;TURN OFF DRAWING
CLR.L -(SP) ;MAKE ROOM FOR FCN RESULT
MOVE #STARTSIZE,-(SP) ;PUSH BYTE COUNT = STARTSIZE
JSR NEWHANDLE ;ALLOCATE NEWHANDLE
MOVE.L (SP)+,A1 ;POP RESULTING HANDLE
MOVE.L A1,4(SP) ;PUT HANDLE IN FCN RESULT
MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS
MOVE.L A1,THEPOLY(A0) ;REMEMBER HANDLE IN THEPOLY
MOVE #STARTSIZE,POLYMAX(A0) ;POLYMAX := STARTSIZE;
MOVE.L THEPORT(A0),A0 ;GET CURRENT GRAFPORT
MOVEQ #1,D0
MOVE.L D0,POLYSAVE(A0) ;POLYSAVE := TRUE
MOVE.L (A1),A1 ;DE-REFERENCE HANDLE
MOVE #10,(A1)+ ;INSTALL POLYSIZE = 10
CLR.L (A1)+ ;ZERO OUT POLYBBOX
CLR.L (A1)+
RTS ;RETURN
ClosePoly PROC EXPORT
IMPORT SETHSIZE,ShowPen
;---------------------------------------------------------------
;
; PROCEDURE ClosePoly;
;
; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK:
;
MOVEM.L D3-D7/A4,-(SP) ;SAVE REGS
MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS
MOVE.L THEPORT(A4),A0 ;GET CURRENT GRAFPORT
CLR.L POLYSAVE(A0) ;POLYSAVE := FALSE
MOVE.L THEPOLY(A4),A4 ;GET THEPOLY HANDLE
MOVE.L (A4),A0 ;DE-REFERENCE THEPOLY
MOVE (A0)+,D7 ;GET POLYSIZE
CLR.L (A0)+ ;ZERO OUT POLYBBOX
CLR.L (A0)+
MOVE D7,D6
SUB #10,D6
LSR #2,D6 ;NPOINTS = (SIZE-10) DIV 4
BEQ.S EMPTY ;QUIT IF NO POINTS
;-----------------------------------------------------
;
; SCAN FOR BOUNDING BOX OF POLYGON
;
MOVE (A0)+,D1 ;TOP := FIRST POINT VERT
MOVE D1,D2 ;BOTTOM := FIRST POINT VERT
MOVE (A0)+,D3 ;LEFT := FIRST POINT HORIZ
MOVE D3,D4 ;RIGHT := FIRST POINT HORIZ
SUB #1,D6 ;DECREMENT POINT COUNT
BRA.S RIGHTOK ;GO TO LOOP START
NEXTPT MOVE (A0)+,D0 ;GET VERT COORD
CMP D1,D0 ;IS VERT < BBOX TOP ?
BGE.S TOPOK ;NO, CONTINUE
MOVE D0,D1 ;YES, UPDATE BBOX TOP
TOPOK CMP D2,D0 ;IS VERT > BBOX BOTTOM ?
BLE.S BOTOK ;NO, CONTINUE
MOVE D0,D2 ;YES, UPDATE BBOX BOTTOM
BOTOK MOVE (A0)+,D0 ;GET HORIZ COORD
CMP D3,D0 ;IS HORIZ < BBOX LEFT ?
BGE.S LEFTOK ;NO, CONTINUE
MOVE D0,D3 ;YES, UPDATE BBOX LEFT
LEFTOK CMP D4,D0 ;IS HORIZ > BBOX RIGHT ?
BLE.S RIGHTOK ;NO, CONTINUE
MOVE D0,D4 ;YES, UPDATE BBOX RIGHT
RIGHTOK DBRA D6,NEXTPT ;LOOP ALL POINTS
MOVE.L (A4),A0 ;DE-REFERENCE THEPOLY
LEA POLYBBOX(A0),A0 ;POINT TO POLYBBOX
MOVE D1,(A0)+ ;INSTALL BBOX TOP
MOVE D3,(A0)+ ;INSTALL BBOX LEFT
MOVE D2,(A0)+ ;INSTALL BBOX BOTTOM
MOVE D4,(A0)+ ;INSTALL BBOX RIGHT
;--------------------------------------------------------
;
; TRIM THEPOLY TO FINAL SIZE, SHOW PEN AND QUIT
;
EMPTY MOVE.L A4,-(SP) ;PUSH THEPOLY HANDLE
MOVE D7,-(SP) ;PUSH BYTECOUNT = POLYSIZE
JSR SETHSIZE ;TRIM TO MINIMUM SIZE
JSR SHOWPEN ;RESTORE PNVIS
MOVEM.L (SP)+,D3-D7/A4 ;RESTORE REGS
RTS ;AND RETURN
KillPoly PROC EXPORT
;---------------------------------------------------
;
; PROCEDURE KillPoly(poly: PolyHandle);
;
MOVE.L (SP)+,A1 ;pop return addr
MOVE.L (SP)+,A0 ;pop handle
_DisposHandle ;discard it
JMP (A1) ;and return
OffsetPoly PROC EXPORT
;---------------------------------------------------
;
; PROCEDURE OffsetPoly(poly: PolyHandle; dh,dv: INTEGER);
;
MOVE.L (SP)+,A0 ;POP RETURN ADDRESS
MOVE (SP)+,D0 ;POP DV
MOVE (SP)+,D1 ;POP DH
MOVE.L (SP)+,A1 ;POP POLYHANDLE
MOVE.L (A1),A1 ;DE-REFERENCE POLYHANDLE
MOVE (A1)+,D2 ;GET POLYSIZE
SUB #2,D2 ;CALC TOTAL # POINTS, INCL BBOX
LSR #2,D2 ; # POINTS = (SIZE-2) DIV 4
SUB #1,D2 ;INIT DBRA COUNT
NEXTPT ADD D0,(A1)+ ;OFFSET VERT COORD
ADD D1,(A1)+ ;OFFSET HORIZ COORD
DBRA D2,NEXTPT ;LOOP FOR ALL POINTS
JMP (A0) ;AND RETURN
MapPoly PROC EXPORT
IMPORT MapPt,MapRect
;-------------------------------------------------------------
;
; PROCEDURE MapPoly(poly: PolyHandle; fromRect,toRect: Rect);
;
; A6 OFFSETS OF PARAMETERS AND LOCALS AFTER LINK:
;
PARAMSIZE EQU 12
POLY EQU PARAMSIZE+8-4 ;LONG, RGNHANDLE
FROMRECT EQU POLY-4 ;LONG, ADDR OF RECT
TORECT EQU FROMRECT-4 ;LONG, ADDR OF RECT
LINK A6,#0 ;ALLOCATE STACK FRAME
MOVEM.L D7/A2-A4,-(SP) ;SAVE REGS
;
; QUIT FAST IF FROMRECT = TORECT
;
MOVE.L FROMRECT(A6),A2 ;POINT TO FROMRECT
MOVE.L TORECT(A6),A3 ;POINT TO TORECT
MOVE.L (A2),D0
CMP.L (A3),D0 ;IS TOPLEFT SAME ?
BNE.S NOTSAME ;NO, CONTINUE
MOVE.L 4(A2),D0
CMP.L 4(A3),D0 ;YES, IS BOTRIGHT SAME TOO ?
BEQ.S DONE ;IF SO, JUST QUIT
NOTSAME MOVE.L POLY(A6),A4 ;GET POLYHANDLE
MOVE.L (A4),A4 ;DE-REFERENCE POLYHANDLE
PEA POLYBBOX(A4) ;PUSH ADDR OF BBOX
MOVE.L A2,-(SP) ;PUSH FROMRECT
MOVE.L A3,-(SP) ;PUSH TORECT
JSR MAPRECT ;MAP POLYBBOX
MOVEQ #10,D0
MOVE POLYSIZE(A4),D7 ;GET POLYSIZE
SUB D0,D7
LSR #2,D7 ;NPOINTS = (POLYSIZE-10) DIV 4
ADD D0,A4 ;POINT TO FIRST POINT
BRA.S START ;GO TO LOOP START
NEXTPT MOVE.L A4,-(SP) ;PUSH ADDR OF POINT
MOVE.L A2,-(SP) ;PUSH FROMRECT
MOVE.L A3,-(SP) ;PUSH TORECT
JSR MAPPT ;MAP THIS POINT
ADD #4,A4 ;BUMP TO NEXT POINT
START DBRA D7,NEXTPT ;LOOP ALL POINTS IN POLY
DONE MOVEM.L (SP)+,D7/A2-A4 ;RESTORE REGS
UNLINK PARAMSIZE,'MAPPOLY '
FrPoly PROC EXPORT
IMPORT MoveTo,DoLine
;--------------------------------------------------------
;
; PROCEDURE FrPoly(poly: PolyHandle);
;
; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK:
;
PARAMSIZE EQU 4
POLY EQU PARAMSIZE+8-4 ;LONG, POLYHANDLE
LINK A6,#0 ;ALLOCATE STACK FRAME
MOVEM.L D6-D7/A4,-(SP) ;SAVE REGS
MOVE.L POLY(A6),A4 ;GET POLYHANDLE
MOVE.L (A4),A0 ;DE-REFERENCE IT
MOVE (A0),D7 ;GET POLYSIZE
SUB #10,D7
LSR #2,D7 ;NPOINTS = (SIZE-10) DIV 4
BEQ.S DONE ;QUIT IF EMPTY POLYGON
MOVE.L 10(A0),-(SP) ;PUSH FIRST POINT
JSR MOVETO ;MOVETO(FIRST POINT)
MOVE.L #14,D6 ;INIT BYTE OFFSET
SUB #1,D7 ;DECREMENT COUNT
BRA.S START ;GOT TO LOOP START
NEXTPT MOVE.L (A4),A0 ;DE-REFERENCE POLYHANDLE
MOVE.L 0(A0,D6),-(SP) ;PUSH NEXT POINT
ADD #4,D6 ;BUMP BYTE OFFSET
JSR DOLINE ;DOLINE(PT)
START DBRA D7,NEXTPT ;LOOP FOR ALL POINTS
DONE MOVEM.L (SP)+,D6-D7/A4 ;RESTORE REGS
UNLINK PARAMSIZE,'FRPOLY '
;-------------------------------------------------------------
; <1.2/15mar89> This flag is used so that the old code could be
; kept around in case we need to use it at at later
; date. Now we always use the new quickpolybw code.
; A new Drawpoly routine has been developed along
; with supporting code.
IF QuickPolys THEN
;-------------------------------------------------------------
;
; PROCEDURE SortVectors(Vectors: Ptr; VCount: integer);
;
; SortVectors performs a non-recursive QuickSort on an array of
; vectors (y,x,dy,dx). The vectors are sorted first on y and second
; on x. The differential values are not examined. This code is
; a modified version of SortPoints, found in the QuickDraw ROM.
; The vectors are placed in increasing Y.X order. See the source
; reference "Algorithms + Data Structures = Programs, p. 80"
SortVectors PROC EXPORT
ParamSize Equ 6
Vectors Equ ParamSize+8-4
VCount Equ Vectors-2
VarSize Equ 0
Link A6,#VarSize ; no local variables
MoveM.L D3-D4/A2-A4,-(SP) ; save registers
Move.L Vectors(A6),A3 ; LeftPtr := start of point array
Move A3,D3 ; set up low bits for sort
And #7,D3 ; AWC - #3 => #7
MoveQ #0,D0 ; clear high word
Move VCount(A6),D0 ; get VCount
Ble.S GoHome ; do nothing if no vectors
Lsl.L #3,D0 ; AWC - #2 => #3; LineCount * 8 for bytes
Move.L A3,A4
Add.L D0,A4 ; add to DstStart
SubQ.L #8,A4 ; AWC - #4 => #8; RightPtr := DstEnd - 8
Move.L SP,D4 ; remember stack marker
MoveM.L A3/A4,-(SP) ; push LeftPtr and RightPtr
RePartition MoveM.L (SP)+,A3/A4 ; pop LeftPtr and RightPtr
Split Move.L A3,A1 ; IPtr := LeftPtr
Move.L A4,A2 ; JPtr := RightPtr
; Calculate MidPtr and MidPt
Move.L A3,D0 ; D0 := LeftPtr + RightPtr
Add.L A4,D0
RoxR.L #1,D0 ; divide by 2 for MidPtr
And #$FFF8,D0 ; AWC - #$FFFC => #$FFF8; truncate to multiple of 8 bytes
Or D3,D0 ; OR in low bits for vector boundary
Move.L D0,A0 ; put MidPtr into A0
Move XVector(A0),D1 ; D1 := MidPt.X
Move YVector(A0),D2 ; D2 := MidPt.Y
Bra.S IScan
; while IPtr^ < MidPt do IPtr := IPtr + 8
NextIPtr AddQ.L #8,A1 ; AWC - #4 => #8; bump IPtr to "right"
IScan Cmp YVector(A1),D2 ; is MidPt.Y > IPtr^.Y?
Bgt.S NextIPtr ; yes => continue bumping
Blt.S JScan ; MidPt.Y < IPtr^.Y? yes => done with IPtr
Cmp XVector(A1),D1 ; sort on X - is MidPt.X > IPtr^.X?
Bgt.S NextIPtr ; yes => continue bumping
Bra.S JScan ; go to loop start
; while JPtr^ > MidPt do JPtr := JPtr - 8
NextJPtr SubQ.L #8,A2 ; AWC - #4 => #8; decrement JPtr
JScan Cmp YVector(A2),D2 ; is JPtr^.Y > MidPt.Y?
Blt.S NextJPtr ; yes => look at the next JPtr
Bgt.S EndScan ; is JPtr^.Y < MidPt.Y? yes => this partition is done
Cmp XVector(A2),D1 ; is JPtr^.X > MidPt.X?
Blt.S NextJPtr ; yes => look at the next JPtr
; if IPtr <= JPtr then swap IPtr^ and JPtr^, and bump both pointers
EndScan Cmp.L A2,A1 ; is IPtr > JPtr?
Bgt.S NoSwap ; yes => all done
Move.L (A1),D0 ; D0 := IPtr^
Move.L (A2),(A1) ; IPtr^ := JPtr^
Move.L D0,(A2) ; JPtr^ := D0
Move.L 4(A1),D0 ; D0 := IPtr^.dy
Move.L 4(A2),4(A1) ; IPtr^.dy := JPtr^.dy
Move.L D0,4(A2) ; JPtr^.dy := D0
AddQ.L #8,A1 ; IPtr := IPtr + 8
SubQ.L #8,A2 ; JPtr := JPtr - 8
; repeat until this partitioning is complete, IPtr > JPtr
NoSwap CmpA.L A2,A1 ; is IPtr > JPtr
Bls.S IScan ; no => loop again
; if IPtr < RightPtr then stack request to sort right partition
CmpA.L A4,A1 ; is IPtr < RightPtr?
Bhs.S RightOkay ; yes => continue
MoveM.L A1/A4,-(SP) ; no => PushPartition(IPtr,RightPtr)
RightOkay Move.L A2,A4 ; RightPtr := JPtr
CmpA.L A4,A3 ; is LeftPtr >= RightPtr?
Blo.S Split ; no => partition again
CmpA.L D4,SP ; is stack empty yet?
Bne.S RePartition ; no => loop for more
GoHome MoveM.L (SP)+,D3-D4/A2-A4 ; restore registers
UNLINK PARAMSIZE,'SORTVECT'
;---------------------------------------------------
;
; PROCEDURE PaintVector(Vector:VectorArray; VCount:integer; EoFill:boolean;
; VectRect:Rect; Mode:integer; Pat:Pattern);
;
PaintVector PROC EXPORT
IMPORT ShowCursor,ShieldCursor,MaskTab,PatExpand,ColorMap,XorSlab
IMPORT DrawSlab,SlabMode,FastSlabMode,RSect,TrimRect
IMPORT InitRgn,SeekRgn
ParamSize Equ 18
Vector Equ ParamSize+8-4
VCount Equ Vector-2
EoFill Equ VCount-2
VectRect Equ EoFill-4
Mode Equ VectRect-2
Pat Equ Mode-4
;-------------------------------------------------
;
; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK:
;
EXPAT EQU -64 ;16 LONGS
MINRECT EQU EXPAT-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
MODECASE EQU BUFSIZE-4 ;LONG
DSTLEFT EQU MODECASE-4 ;LONG
SAVEA5 EQU DSTLEFT-4 ;LONG
PORT EQU SAVEA5-4 ;LONG
FASTFLAG EQU PORT-2 ;BYTE
TEMPRECT EQU FASTFLAG-8 ;RECT
PATINDEX EQU TEMPRECT-2 ;WORD
; Stack frame variables used only in DrawPoly
FreeList Equ PatIndex-4
StackLimit Equ FreeList-4
ActiveList Equ StackLimit-4
VarSize Equ ActiveList
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 THEPORT(A0),A3 ;GET CURRENT GRAFPORT
TST PNVIS(A3) ;IS PNVIS NEG ?
BLT GOHOME ;YES, QUIT
MOVE.L A3,PORT(A6) ;SAVE CURRENT GRAFPORT
;-------------------------------------------------------
;
; QUIT IF MODE NOT IN 8..15
;
MOVEQ #-8,D0 ;MASK TO KILL BOTTOM 3 BITS
AND MODE(A6),D0 ;GET ALL BUT 3 BITS OF MODE
CMP #8,D0 ;IS PEN MODE 8..15 ?
BNE GOHOME ;NO, QUIT
;----------------------------------------------------------------
;
; ADJUST MODE AND PATTERN IF COLOR FILTERING.
;
TST COLRBIT(A3) ;IS COLORBIT NEG ?
BMI.S NOCOLOR ;YES, DON'T MAP
MOVE MODE(A6),-(SP) ;PUSH INPUT MODE
MOVE.L PAT(A6),-(SP) ;PUSH ADDR OF INPUT PATTERN
JSR COLORMAP ;ALTER BY THECOLOR, THEFILTER
MOVE.L (SP)+,PAT(A6) ;GET (ALTERED) PATTERN
MOVE (SP)+,MODE(A6) ;GET (ALTERED) MODE
NOCOLOR MOVE.L A3,A5 ;PUT GRAFPORT IN A5
;---------------------------------------------------------
;
; GET CLIPRGN AND VISRGN HANDLES AND DE-REFERENCE THEM
;
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
;-----------------------------------------------------------------------
;
; CALC MINRECT, THE INTERSECTION OF DSTRECT, BITMAP BOUNDS,
; CLIPRGN BBOX, AND VISRGN BBOX. QUIT IF NO INTERSECTION.
;
MOVE.L VectRect(A6),-(SP) ;PUSH DSTRECT
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
;
; 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 GOHOME ;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) ;REMEMBER 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 GOHOME ;QUIT IF DO-NOTHING MODE
MOVE D0,MODE(A6) ;UPDATE MODE
BRA.S FLAGOK ;AND CONTINUE
MODEMAP DC.B 0,0,1,2,2,255,255,255
FLAGOK
;----------------------------------------------------------------
;
; 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 ;RESTORE GRAFPORT IN A5
;------------------------------------
;
; 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 REGION STATEA
MOVE #32767,STATEA+NEXTV(A6) ;TO HARMLESS IN CASE RECT
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 REGION STATEB
MOVE #32767,STATEB+NEXTV(A6) ;TO HARMLESS IN CASE RECT
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 ALL 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 ;GET MINRECT TOP
SUB PORTBITS+BOUNDS+TOP(A5),D1 ;CONVERT 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 ALL HORIZONTAL COORDINATES RELATIVE TO BUFFER
;
MOVE BUFLEFT(A6),D1
SUB D1,MINRECT+LEFT(A6)
SUB D1,MINRECT+RIGHT(A6)
;---------------------------------------------------
;
; SET UP CASE JUMP BASED ON MODE AND FASTFLAG
;
MOVE MODE(A6),D2 ;GET (ALTERED) PEN MODE
TST.B FastFlag(A6) ;Rect clipoped and black ?
BEQ.S @1 ;no, use slow drawslab loop
JSR FastSlabMode ;yes, get fast modeCase in A4
MOVE.L A4,MODECASE(A6) ;SAVE FOR LATER
CLR PATINDEX(A6) ;MAKE UNUSED PATINDEX EVEN
BRA.S GOFORIT ;SKIP PATTERN STUFF
@1 JSR SlabMode ;get slow modeCase in A4
MOVE.L A4,MODECASE(A6) ;SAVE FOR LATER
;------------------------------------------------------------------
;
; EXPAND 8 BYTE PATTERN TO 16 LONGS AND INIT PATTERN SELECTOR
;
CLR.L D7 ;SAY NOT INVERTED
MOVE MODE(A6),D2 ;GET 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 BYTE PATTERN TO 16 LONGS
MOVE.L PORT(A6),A5 ;RESTORE GRAFPORT IN A5
MOVEQ #$F,D0 ;TREAT COORD MOD 16
AND MINRECT+TOP(A6),D0 ;GET TOP VERT LOCAL COORD
LSL #2,D0 ;QUAD FOR 4 BYTE PATTERNS
MOVE D0,PATINDEX(A6) ;SET UP PATTERN INDEX
;;;;; End of sicko code from DrawArc
GoForIt Clr.L FreeList(A6) ; FreeList := nil;
Clr.L ActiveList(A6) ; ActiveList := nil;
_StackSpace ; how much stack is available
Move.L SP,D1 ; grab current stack
Sub.L D0,D1 ; calculate the maximum stack limit
Add.L #$100,D1 ; give us some spare room
Move.L D1,StackLimit(A6) ; save it
Move.L Vector(A6),A3 ; get pointer to VectorArray
Move (A3),D7 ; get CurrentY
Move VCount(A6),D3 ; get number of edges
ActiveLoop MoveQ #Nil,A0 ; NewEdges := nil
MoveQ #Nil,A1 ; CurrentEdge := nil
; while (Vector < VCount) & (CurrentY = Vectors[Vector+1].YVector) do begin
Tst D3 ; any new edges left?
Beq NoNewEdges ; no => don't add any new
NewEdgeLoop Cmp (A3),D7 ; does CurrentY = NextY?
Bne NoNewEdges ; no => don't add any at the moment
Move.L FreeList(A6),A2 ; grab the FreeList
Move.L A2,D0 ; CmpA #Nil,A2; can we get an edge from the free list?
Bne.S FreeAndEasy ; yes => good enough
SubA.L #EdgeRecSize,SP ; make room for daddy
Move.L SP,A2 ; and create a new edge on the stack (gross)
CmpA.L StackLimit(A6),A2 ; have we bombed
Bge.S StackEdge ; no => keep trucking
Bra NoMorePoly ; yes => get out of here
FreeAndEasy Move.L (A2),FreeList(A6) ; FreeList := FreeList^.NextEdge
StackEdge MoveM.L A0-A1,-(SP) ; save registers across the FixRatio AWC.PMAB451
Clr.L -(SP) ; FixRatio result AWC.PMAB440
Move.L YDelta(A3),-(SP) ; push numerator and denominator for FixRatio
_FixRatio ; calculate it
; The following few lines are excerpted from the PutLine code of Quickdraw so we can match
; the old polygon code precisely in terms of pixels rendered.
Move.L (SP)+,D2 ; D2 := slope
MoveM.L (SP)+,A0-A1 ; restore registers AWC.PMAB451
Move XVector(A3),D1 ; HiWord(D1) := XVector
Sub BufLeft(A6),D1 ; adjust to global coordinates
Swap D1 ; put the coordinate in the high word
Move #$8000,D1 ; LoWord(XVector) := 1/2
Move.L D2,D0 ; D0 := slope
Asr.L #1,D0 ; D0 := slope/2
Add.L D0,D1 ; XValue := XValue + Slope/2
Move.L #$10000,D0 ; D0 := 1.0000 fixed
Tst.L D2 ; is slope negative?
Bmi.S NegSlope ; yes => continue
Cmp.L D0,D2 ; is slope < 1.0000?
Bge.S SlopeOkay ; no => continue
Add.L D2,D1 ; XValue := XValue + Slope
Bra.S SlopeOkay ; continue
NegSlope Cmp.L #$FFFF0000,D2 ; is slope > -1.0000?
Bge.S SlopeOkay ; yes => continue
Add.L D0,D1 ; XValue := XValue + 1.0000
SlopeOkay Move.L D1,XValue(A2) ; XValue := D1
Move.L D2,XSlope(A2) ; XSlope := FixRatio(XVector,YVector)
MoveQ #1,D1 ; Sign := 1
Move YDelta(A3),D0 ; D0 := abs(YDelta)
Bpl.S SignOkay ; don't negate it
Neg D0 ; abs(YDelta)
Neg D1 ; Sign := -1
SignOkay Add D7,D0 ; D0 := CurrentY + abs(YDelta)
Move D0,LastY(A2) ; Edge^.LastY := CurrentY + abs(YDelta)
Tst.B EoFill(A6) ; are we EoFill'ing?
Beq.S Winder ; no => leave sign alone
MoveQ #0,D1 ; Sign := 0
Winder Move D1,Sign(A2) ; save Sign
Move.L A0,D0 ; CmpA.L #Nil,A0; is NewEdges nil? AWC.PMAB440
Bne.S InsertMid ; no => insert this new edge in the list AWC.PMAB440
Move.L A2,A0 ; NewEdges := Edge AWC.PMAB440
Move.L A2,A1 ; CurrentEdge := Edge AWC.PMAB440
Clr.L NextEdge(A2) ; end of list AWC.PMAB440
Clr.L PrevEdge(A2) ; beginning of list, too AWC.PMAB440
Bra.S InsertDone ; continue AWC.PMAB440
InsertMid Move.L A1,A4 ; InsertPt := CurrentEdge AWC.PMAB440
Move.L XValue(A2),D0 ; grab our compare value AWC.PMAB440
InsertNext Cmp.L XValue(A4),D0 ; D0 - InsertPt^.XValue AWC.PMAB440
Bge.S InsertIt ; if greater or equal, insert it AWC.PMAB440
Move.L PrevEdge(A4),A4 ; InsertPt := InsertPt^.NextEdge AWC.PMAB440
Move.L A4,D1 ; is the next edge nil? AWC.PMAB440
Bne.S InsertNext ; no => keep looking AWC.PMAB440
Move.L A0,NextEdge(A2) ; Edge^.NextEdge := NewEdges AWC.PMAB440
Move.L A2,PrevEdge(A0) ; NewEdges^.PrevEdge := Edge AWC.PMAB440
Clr.L PrevEdge(A2) ; Edge^.PrevEdge := nil AWC.PMAB440
Move.L A2,A0 ; NewEdges := Edge AWC.PMAB440
Bra.S InsertDone ; continue AWC.PMAB440
InsertIt CmpA.L A1,A4 ; at the end of the list? AWC.PMAB440
Beq.S InsertEnd ; yes => insert this edge at the end of list AWC.PMAB440
Move.L A4,PrevEdge(A2) ; Edge^.PrevEdge := InsertPt AWC.PMAB440
Move.L NextEdge(A4),D0 ; save InsertPt^.NextEdge AWC.PMAB440
Move.L A2,NextEdge(A4) ; InsertPt^.NextEdge := Edge AWC.PMAB451
Move.L D0,NextEdge(A2) ; Edge^.NextEdge := InsertPt^.NextEdge AWC.PMAB440
Move.L D0,A4 ; InsertPt := InsertPt^.NextEdge AWC.PMAB440
Move.L A2,PrevEdge(A4) ; InsertPt^.NextEdge^.PrevEdge := Edge AWC.PMAB440
Bra.S InsertDone ; continue AWC.PMAB440
InsertEnd Move.L A2,NextEdge(A1) ; CurrentEdge^.NextEdge := Edge AWC.PMAB440
Move.L A1,PrevEdge(A2) ; Edge^.PrevEdge := CurrentEdge AWC.PMAB440
Clr.L NextEdge(A2) ; Edge^.NextEdge := nil AWC.PMAB440
Move.L A2,A1 ; CurrentEdge := Edge AWC.PMAB440
InsertDone AddA.L #VectorSize,A3 ; bump A3 to the next vector AWC.PMAB440
SubQ #1,D3 ; VCount := VCount - 1
Bgt NewEdgeLoop ; check for more edges
; Merge the NewEdges with the ActiveList
NoNewEdges Move.L #Nil,A1 ; CurrentEdge := nil
Move.L ActiveList(A6),A4 ; NextActive := ActiveList
MergeLoop Move.L A4,D0 ; CmpA.L #Nil,A4; is NextActive nil?
Bne.S NextOrMerge ; no => merge edges
Move.L A0,D0 ; CmpA.L #Nil,A0; is NewEdges nil?
Beq.S Merged ; yes => don't merge edges
; NextActive = nil; NewEdges <> nil
Move.L A1,PrevEdge(A0) ; NewEdges^.PrevEdge := CurrentEdge; is CurrentEdge nil?
Bne.S C1 ; no => fix up CurrentEdge^.NextEdge
Move.L A0,ActiveList(A6) ; ActiveList := NewEdges
Bra.S Merged ; continue
C1 Move.L A0,NextEdge(A1) ; CurrentEdge^.NextEdge := NewEdges
Bra.S Merged ; continue
; else if NewEdges = nil { and therefore NextActive <> nil } then begin
NextOrMerge Move.L A0,D0 ; CmpA.L #Nil,A0; is NewEdges nil?
Bne.S MergeEdges ; no => merge edges
Move.L A1,PrevEdge(A4) ; NextActive^.PrevEdge := CurrentEdge; is CurrentEdge nil?
Bne.S C2 ; no => append NextActive to the list
Move.L A4,ActiveList(A6) ; ActiveList := NextActive
Bra.S Merged ; continue
C2 Move.L A4,NextEdge(A1) ; CurrentEdge^.NextEdge := NextActive
Bra.S Merged ; continue
; else { both are still active so } begin
MergeEdges Move.L XValue(A4),D0 ; get NextActive^.XValue
Cmp.L XValue(A0),D0 ; is NextActive^.XValue > NewEdges^.XValue?
Ble.S C3 ; no => select NextActive
Move.L A0,A2 ; Edge := NewEdges
Move.L NextEdge(A2),A0 ; NewEdges := Edge^.NextEdge
Bra.S C4 ; continue
C3 Move.L A4,A2 ; Edge := NextActive
Move.L NextEdge(A2),A4 ; NextActive := Edge^.NextEdge
C4 Move.L A1,PrevEdge(A2) ; Edge^.PrevEdge := CurrentEdge; is CurrentEdge nil?
Bne.S C5 ; no => patch CurrentEdge
Move.L A2,ActiveList(A6) ; ActiveList := Edge
Bra.S C6 ; continue
C5 Move.L A2,NextEdge(A1) ; CurrentEdge^.NextEdge := Edge
C6 Clr.L NextEdge(A2) ; Edge^.NextEdge := nil
Move.L A2,A1 ; CurrentEdge := Edge
Bra.S MergeLoop ; continue
Merged
;;;;; More DrawArc craziness
CMP MINRECT+TOP(A6),D7 ;IS CURRENT VERT < MINV ?
BLT.S NoMask ;YES, DON'T DRAW
; SEEK MASK TO THE CURRENT VERTICAL
TST.B FASTFLAG(A6) ;RECT CLIPPED AND BLACK ?
BNE.S NOMASK ;YES, DON'T BOTHER WITH MASK
Jsr SeekMask ; make MaskBuf Current
NoMask Move.L ActiveList(A6),A4 ; NextActive := ActiveList
MoveQ #0,D5 ; LineFlag := false or WrapCount := 0
SlabLoop Move.L A4,A1 ; CurrentEdge := NextActive
Move.L NextEdge(A1),A4 ; NextActive := CurrentEdge^.NextEdge
Cmp LastY(A1),D7 ; is LastY <= CurrentY?
Bge RemoveEdge ; yes => go remove the edge
Move Sign(A1),D0 ; grab the sign
Beq.S DoToggle1 ; if zero then EoFill; toggle the flag
Tst D5 ; is current wrapcount 0?
Bne.S NoWrapMove ; no => don't establish WrapMove
Move XValue(A1),D6 ; save wrapmove
NoWrapMove Add D0,D5 ; WrapCount += Sign; is it 0?
Bne.S BumpX ; no => don't draw a line
NoLineMove Move XValue(A1),D0 ; grab current value
Cmp D6,D0 ; is line XValue.HiWord > move XValue.HiWord?
Bgt.S DrawLine ; yes => draw a line
Bra.S BumpX ; continue
DoToggle1 Eor #1,D5 ; toggle D5
Beq.S NoLineMove ; yes => go draw the line
Move XValue(A1),D6 ; save line mvoe
Bra.S BumpX ; continue
ONESLAB MOVEQ #$3F,D6 ;GET WRAP-AROUND MASK
AND PATINDEX(A6),D6 ;GET PATINDEX MOD 64
MOVE.L EXPAT(A6,D6),D6 ;GET THIS ROW'S PATTERN
LEA MaskTab,A0 ;POINT TO MASK TABLE
MOVE.L DSTLEFT(A6),A1 ;INIT DSTPTR TO LEFT
MOVE.L MASKBUF(A6),A2 ;INIT MASKPTR TO LEFT
LEA MINRECT(A6),A3 ;POINT TO MINRECT
MOVE.L MODECASE(A6),A4 ;GET MODE CASE JUMP
JMP DrawSlab
DrawLine CMP MINRECT+TOP(A6),D7 ;IS CURRENT VERT < MINV ?
Blt.S BumpX ;YES, DON'T DRAW
Move D6,D1 ; get start of slab
Move D0,D2 ; get end of slab
MoveM.L D3-D6/A1-A4,-(SP) ; save everything
Bsr.S OneSlab ; jump to ROM calling routine
MoveM.L (SP)+,D3-D6/A1-A4 ; restore everything
BumpX Move.L XValue(A1),D0 ; grab current XValue
Add.L XSlope(A1),D0 ; bump it to the next value
Move.L D0,XValue(A1) ; XValue := XValue + XSlope
Move.L PrevEdge(A1),A2 ; Edge := CurrentEdge^.PrevEdge
Move.L A2,D1 ; CmpA.L #Nil,A2; is Edge = nil?
Beq.S CheckEdge ; yes => sorting order is okay
Cmp.L XValue(A2),D0 ; is PrevEdge^.XValue <= CurrentEdge^.XValue?
Bge.S CheckEdge ; yes => sorting order is okay
Move.L NextEdge(A1),NextEdge(A2) ; PrevEdge^.NextEdge := CurrentEdge^.NextEdge; nil?
Beq.S NextIsNil ; yes => don't bother setting backlink
Move.L NextEdge(A1),A0 ; grab the next edge
Move.L A2,PrevEdge(A0) ; NextEdge^.PrevEdge := CurrentEdge^.PrevEdge
NextIsNil Move.L PrevEdge(A2),A2 ; Edge := Edge^.PrevEdge
Move.L A2,D1 ; CmpA.L #Nil,A2; is it nil?
Bne.S CheckCross ; no => check for crossing
Move.L ActiveList(A6),A2 ; get NextEdge
Move.L A2,NextEdge(A1) ; CurrentEdge^.NextEdge := ActiveList
Clr.L PrevEdge(A1) ; PrevEdge := nil
Move.L A1,PrevEdge(A2) ; NextEdge^.PrevEdge := CurrentEdge
Move.L A1,ActiveList(A6) ; ActiveList := CurrentEdge
Bra.S CheckEdge ; continue
CheckCross Cmp.L XValue(A2),D0 ; is Edge^.XValue <=CurrentEdge^.XValue?
Blt.S NextIsNil ; no => continue searching
Move.L NextEdge(A2),A0 ; grab NextEdge
Move.L A0,NextEdge(A1) ; CurrentEdge^.NextEdge := Edge^.NextEdge
Move.L A2,PrevEdge(A1) ; CurrentEdge^.PrevEdge := Edge
Move.L A1,PrevEdge(A0) ; CurrentEdge^.NextEdge^.PrevEdge := CurrentEdge
Move.L A1,NextEdge(A2) ; Edge^.NextEdge := CurrentEdge
Bra.S CheckEdge ; continue
RemoveEdge Move.L PrevEdge(A1),A0 ; grab PrevEdge
Move.L A0,D0 ; CmpA.L #Nil,A0; is PrevEdge nil?
Bne.S PrevNotNil ; no => remove from middle
Move.L NextEdge(A1),ActiveList(A6) ; ActiveList := CurrentEdge^.NextEdge
Bra.S PrevWasNil ; continue
PrevNotNil Move.L NextEdge(A1),NextEdge(A0) ; PrevEdge^.NextEdge := CurrentEdge^.NextEdge
PrevWasNil Beq.S NextWasNil ; if NextEdge is nil, don't patch back pointer
Move.L NextEdge(A1),A2 ; grab NextEdge
Move.L A0,PrevEdge(A2) ; NextEdge^.PrevEdge := CurrentEdge^.PrevEdge
NextWasNil Move.L FreeList(A6),NextEdge(A1) ; CurrentEdge^.NextEdge := FreeList
Move.L A1,FreeList(A6) ; FreeList := CurrentEdge
Move.L A0,A1 ; CurrentEdge := CurrentEdge^.PrevEdge
CheckEdge Move.L A4,D0 ; CmpA.L #Nil,A4; is NextActive nil?
Bne SlabLoop ; no => do another edge
CMP MINRECT+TOP(A6),D7 ;IS CURRENT VERT < MINV ?
Blt.S BumpY ;YES, DON'T DRAW
;-------------------------------------------------------------------
;
; BUMP DESTINATION VERTICALLY AND LOOP FOR ALL SCAN LINES
;
NEXTPAT ADD #4,PATINDEX(A6) ;BUMP PATTERN INDEX
MOVE PORTBITS+ROWBYTES(A5),D0 ;GET DST ROWBYTES
EXT.L D0 ;MAKE IT LONG
ADD.L D0,DSTLEFT(A6) ;BUMP DST TO NEXT ROW
BumpY AddQ #1,D7 ; CurrentY += 1
Cmp MinRect+Bottom(A6),D7 ; have we reached the bottom?
Bge.S NoMorePoly ; yes => shut down ahead of schedule
Tst.L ActiveList(A6) ; does the ActiveList contain edges?
Bne ActiveLoop ; yes => loop
Tst D3 ; any new edges left?
Bne ActiveLoop ; yes => loop
NoMorePoly _ShowCursor ; restore cursor
GoHome Move.L SaveStk(A6),SP ; clean up the free list and strip buffer
MoveM.L (SP)+,D0-D7/A1-A5 ; restore registers
UNLINK PARAMSIZE,'PAINTVEC'
;-----------------------------------------------------------------------------
; <1.2/15mar89> Seekmask code copied from DrawArc which is what QuickPolys used.
;-----------------------------------------------------------------------------
;
; LOCAL ROUTINE TO UPDATE THE MASK BUFFER
; BASED ON WHICH REGIONS ARE RECTANGULAR
;
SEEKMASK MOVE D7,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 DC.W IGNORE-RECTJMP ;DO NOTHING IF BOTH RECT
DC.W A-RECTJMP
DC.W B-RECTJMP
DC.W 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
;---------------------------------------------------
;
; PROCEDURE DrawPoly(poly: PolyHandle; mode: integer; VAR pat: Pattern);
;
DrawPoly PROC EXPORT
IMPORT DrawRect
ParamSize Equ 10
Poly Equ ParamSize+8-4
Mode Equ Poly-2
Pat Equ Mode-4
PolyRect Equ -8
VarSize Equ PolyRect
; <25Jul88> PMAB543 BAL/JDB Implemented fast case for rectangular filled polys.
Link A6,#VarSize ; no local variables
move.l Poly(a6),a0 ; pick up polyhdl <Begin PMAB543 BAL/JDB>
move.l (a0),a0 ; deref to polyptr
move (a0)+,d0 ; pick up byte count
cmp #4*5+10,d0 ; quadrilateral?
bne.s @chk4pt ; no, take general case
move.l 8+4*4(a0),d1 ; pick up last pnt
cmp.l 8(a0),d1 ; cmpare with first pnt
bne.s @notRect ;
bra.s @4Pnts
@chk4pt cmp #4*4+10,d0 ; quadrilateral?
bne.s @notRect ; no, take general case
@4Pnts moveq #2,d0 ; force to 4 points
addq #8,a0 ; bump past rect
lea 4(a0),a1 ; point to next point
@nxtPnt cmp (a0)+,(a1)+ ; cmp h's
seq d1 ; remember equality
cmp (a0)+,(a1)+ ; cmp v's
seq d2 ; remember equality
or.b d1,d2 ; compute h1=h2 | v1=v2
beq.s @notRect ; no, not rect
dbra d0,@nxtPnt
lea -12(a0),a1 ; point to first point
cmp (a0)+,(a1)+ ; cmp h's
seq d1 ; remember equality
cmp (a0)+,(a1)+ ; cmp v's
seq d2 ; remember equality
or.b d1,d2 ; compute h1=h2 | v1=v2
beq.s @notRect ; no, not rect
lea PolyRect(A6),a0 ; point to rect
move.l -12(a1),(a0)+ ; save top left
move.l -8(a1),(a0) ; save bot rght
pea PolyRect(A6) ; push ptr to rect
move Mode(A6),-(SP) ; push mode
move.l Pat(A6),-(SP) ; push pattern
jsr DrawRect ; go so incredibly blindingly fast <End PMAB543 BAL/JDB>
bra GoHome2 ; get out of here, undoing the link
@notRect
MoveM.L D3-D5/A2,-(SP) ; save registers
Move.L GrafGlobals(A5),A0 ; point to QuickDraw globals
Move.L ThePort(A0),A0 ; get current port
Tst PnVis(A0) ; is PnVis neg ?
Bmi GoHome ; yes, quit AWC.PMAB444
Move.L Poly(A6),A0 ; get the poly handle
Move.L A0,D0 ; CmpA.L #Nil,A0; is it real?
Beq GoHome ; no => punt AWC.PMAB444
_HLock ; lock it down
Move.L (A0),A0 ; dereference poly
Move.L 2(A0),PolyRect(A6) ; move Top.Left
Move.L 6(A0),PolyRect+4(A6) ; move Bottom.Right
Move (A0),D4 ; get the length of the data
Sub #10,D4 ; remove the length word and the bounding box rect
Lsr #2,D4 ; D4 is temporarily the point count
MoveQ #0,D0 ; clear the high word
Move D4,D0 ; copy the number of points
AddQ.L #1,D0 ; bump it for the closing edge, maybe
Asl.L #3,D0 ; multiply by 8 bytes per edge
_NewHandle ; get a new handle
Tst D0 ; was there an error? AWC.PMAB444
Bne TempError ; yes => cleanup and get out of here AWC.PMAB444
Move.L A0,A2 ; copy it
_HLock ; lock it down
MoveQ #0,D3 ; clear VCount
Move.L Poly(A6),A1 ; get the handle again
Move.L (A1),A1 ; redereference it
AddA.L #polyPoints,A1 ; bump A1 to the first point
Move.L (A1)+,D5 ; get h and v for "old" position
Move D4,D2 ; copy loop counter to D2
SubQ.L #1,D2 ; remove the first point
Move.L (A2),A0 ; dereference the sorted edge list
Bra.S PolyEnd ; jump into the loop
PolyLoop Move.L D5,D4 ; copy current to old
Move.L (A1)+,D5 ; get next point
Move.L D4,D0 ; get the old point
Move.L D5,D1 ; copy the new point
Sub D0,D1 ; calculate XDelta
Swap D0 ; y1 is in D0.Low
Swap D1 ; y2 is in D1.Low
Sub D0,D1 ; calculate YDelta; does dy = 0?
Beq.S PolyEnd ; yes => ignore horizontal vectors
Bmi.S Upwards ; negative => save the new point
Move.L D4,(A0)+ ; save the old point
Bra.S IncVCount ; and continue
Upwards Move.L D5,(A0)+ ; save the new point
IncVCount AddQ #1,D3 ; bump VCount (D3)
Swap D1 ; XDelta:YDelta => YDelta:XDelta
Move.L D1,(A0)+ ; save YDelta:XDelta
PolyEnd DBra D2,PolyLoop ; loop for another poly point
Move.L D5,D4 ; save the new point to old
Move.L Poly(A6),A1 ; get poly handle again
Move.L (A1),A1 ; dereference it again
Move.L polyPoints(A1),D5 ; grab the first point again
Cmp.L D4,D5 ; did we end where we began?
Beq.S PolyDone ; yes => don't close it
Move.L D4,D0 ; get the old point
Move.L D5,D1 ; copy the new point
Sub D0,D1 ; calculate XDelta
Swap D0 ; y1 is in D0.Low
Swap D1 ; y2 is in D1.Low
Sub D0,D1 ; calculate YDelta; does dy = 0?
Beq.S PolyDone ; yes => ignore horizontal vectors
Bmi.S Upwards2 ; positive => use the old point
Move.L D4,(A0)+ ; save the old point
Bra.S IncVCount2 ; and continue
Upwards2 Move.L D5,(A0)+ ; save the new point
IncVCount2 AddQ #1,D3 ; bump VCount (D4)
Swap D1 ; XDelta:YDelta => YDelta:XDelta
Move.L D1,(A0)+ ; save deltas
PolyDone Move.L Poly(A6),A0 ; grab poly handle
_HUnlock ; unlock it
Move.L (A2),-(SP) ; push vectors pointer
Move D3,-(SP) ; push VCount
Jsr SortVectors ; sort them vectors
Move.L (A2),-(SP) ; push vectors pointer
Move D3,-(SP) ; push VCount
; Tst.B WnFill(A6) ; are we winding-number filling?
; Seq -(SP) ; push (not WnFill)
St -(SP) ; push EoFill
Pea PolyRect(A6) ; push rect
Move Mode(A6),-(SP) ; repush mode
Move.L Pat(A6),-(SP) ; repush pat
Jsr PaintVector ; go paint it
Move.L A2,A0 ; grab vectors handle
_HUnlock ; unlock it
Move.L A2,A0 ; grab it again
_DisposHandle ; dump it
Bra.S GoHome ; continue AWC.PMAB444
TempError Move.L Poly(A6),A0 ; grab poly handle AWC.PMAB444
_HUnlock ; unlock it AWC.PMAB444
GoHome MoveM.L (SP)+,D3-D5/A2 ; restore registers AWC.PMAB444
GoHome2 UNLINK PARAMSIZE,'DRAWPOLY'
ELSE ; <1.2/15mar89> Use original DrawPoly rtn
;--------------------------------------------------------
; <1.2/15mar89> THIS IS THE ORIGINAL DrawPoly CODE
DrawPoly PROC EXPORT
IMPORT OpenRgn,FrPoly,DoLine,NewRgn,CloseRgn,DrawRgn
;--------------------------------------------------------
;
; PROCEDURE DrawPoly(poly: PolyHandle; mode: INTEGER; VAR pat: Pattern);
;
; A6 OFFSETS OF PARAMS AND LOCALS AFTER LINK:
;
PARAMSIZE EQU 10
POLY EQU PARAMSIZE+8-4 ;LONG, POLYHANDLE
MODE EQU POLY-2 ;WORD
PAT EQU MODE-4 ;LONG, ADDR OF PATTERN
LINK A6,#0 ;NO LOCAL VARS
MOVE.L A4,-(SP) ;SAVE REG
MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS
MOVE.L THEPORT(A0),A0 ;GET CURRENT PORT
TST PNVIS(A0) ;IS PNVIS NEG ?
BMI.S DONE ;YES, QUIT
JSR OPENRGN ;OpenRgn
MOVE.L POLY(A6),-(SP)
JSR FRPOLY ;FrPoly(poly);
MOVE.L POLY(A6),A0
MOVE.L (A0),A0
MOVE.L 10(A0),-(SP) ;PUSH FIRST POINT
JSR DOLINE ;MAKE SURE IT CLOSES
CLR.L -(SP) ;ROOM FOR FCN RESULT
JSR NEWRGN ;ALLOCATE TEMPRGN
MOVE.L (SP),A4 ;PUT TEMPRGN IN A4
JSR CLOSERGN ;CLOSERGN(TEMPRGN)
MOVE.L A4,-(SP)
MOVE MODE(A6),-(SP)
MOVE.L PAT(A6),-(SP)
JSR DRAWRGN ;DrawRgn(tempRgn,mode,pat);
MOVE.L A4,A0 ;get tempRgn
_DisposHandle ;DISCARD IT
DONE MOVEM.L (SP)+,A4 ;RESTORE REG
UNLINK PARAMSIZE,'DRAWPOLY'
ENDIF ;<1.2/15mar89> QuickPolys
END