;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 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 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