.INCLUDE GRAFTYPES.TEXT ;-------------------------------------------------------------- ; ; --> DRAWTEXT.TEXT ; ; QuickDraw Character Generator ; ; Completely reworked 29 Apr 85 by Bill Atkinson to get 50% speed up. ; Takes advantage of optional height table at end of font. ; .PROC DrText,4 .REF RightMask,MaskTab,RSect,ShieldCursor,ShowCursor .REF StdTxMeas,RectInRgn,MapRect,StretchBits,TrimRect ;------------------------------------------------------------ ; ; PROCEDURE DrText(count: INTEGER; textAddr: Ptr; numer,denom: Point); ; ; DRAWS CHARACTERS INTO THE CURRENT PORT'S BITMAP. ; THE FONT AND ATTRIBUTES ARE GIVEN IN THE CURRENT PORT'S CHARSTYLE. ; ;------------------------------------------- ; ; KERNED STRIKE FONT FORMAT OFFSETS: ; FORMAT .EQU 0 ;WORD MINCHAR .EQU 2 ;WORD MAXCHAR .EQU 4 ;WORD MAXWD .EQU 6 ;WORD FBBOX .EQU 8 ;WORD FBBOY .EQU 10 ;WORD FBBDX .EQU 12 ;WORD FBBDY .EQU 14 ;WORD LENGTH .EQU 16 ;WORD ASCENT .EQU 18 ;WORD DESCENT .EQU 20 ;WORD XOFFSET .EQU 22 ;WORD RASTER .EQU 24 ;WORD ;------------------------------------------------------ ; ; A6 OFFSETS OF PARAMETERS AFTER LINK: ; PARAMSIZE .EQU 14 ;SIZE OF PARAMETERS COUNT .EQU PARAMSIZE+8-2 ;WORD TEXTADDR .EQU COUNT-4 ;LONG NUMER .EQU TEXTADDR-4 ;LONG, POINT DENOM .EQU NUMER-4 ;LONG, POINT ;----------------------------------------------------------- ; ; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK: ; SAVESTK .EQU -4 ;LONG TEXTRECT .EQU SAVESTK-8 ;RECT TEXTR2 .EQU TEXTRECT-8 ;RECT MINRECT .EQU TEXTR2-8 ;RECT BUFEND .EQU MINRECT-4 ;LONG BUFSTART .EQU BUFEND-4 ;LONG BUFSIZE .EQU BUFSTART-2 ;WORD BUFROW .EQU BUFSIZE-2 ;WORD BUFLEFT .EQU BUFROW-2 ;WORD BUF2START .EQU BUFLEFT-4 ;LONG BUF2END .EQU BUF2START-4 ;LONG HEIGHT .EQU BUF2END-2 ;WORD SRCBITS .EQU HEIGHT-14 ;BITMAP DSTBITS .EQU SRCBITS-14 ;BITMAP FAKERGN .EQU DSTBITS-10 ;RECTANGULAR REGION FAKEPTR .EQU FAKERGN-4 ;LONG, FAKE MASTER POINTER SRCADDR .EQU FAKEPTR-4 ;LONG SRCROW .EQU SRCADDR-2 ;WORD FASTFLAG .EQU SRCROW-2 ;BYTE PENLOC .EQU FASTFLAG-4 ;POINT SRCPTR .EQU PENLOC-4 ;LONG DSTPTR .EQU SRCPTR-4 ;LONG STRETCH .EQU DSTPTR-2 ;BOOLEAN FROMRECT .EQU STRETCH-8 ;RECT TORECT .EQU FROMRECT-8 ;RECT SRCRECT .EQU TORECT-8 ;RECT DSTRECT .EQU SRCRECT-8 ;RECT SPWIDTH .EQU DSTRECT-4 ;FIXED POINT CHARLOC .EQU SPWIDTH-4 ;FIXED POINT INFO .EQU CHARLOC-8 ;4 WORDS HEIGHTAB .EQU INFO-4 ;LONG WIDTAB .EQU HEIGHTAB-4 ;LONG LOCTAB .EQU WIDTAB-4 ;LONG TOPHT .EQU LOCTAB-2 ;word HEIGHTFLAG .EQU TOPHT-2 ;byte MAXMIN .EQU HEIGHTFLAG-2 ;word MINCH .EQU MAXMIN-2 ;word SAVEA5 .EQU MINCH-4 ;LONG NUMER2 .EQU SAVEA5-4 ;Point DENOM2 .EQU NUMER2-4 ;Point VARSIZE .EQU DENOM2 ;SIZE OF VARIABLES LINK A6,#VARSIZE ;ALLOCATE TEMP VARS MOVEM.L D0-D7/A1-A4,-(SP) ;SAVE REGS MOVE.L SP,SAVESTK(A6) ;REMEMBER WHERE STACK WAS MOVE.L A5,SAVEA5(A6) ;REMEMBER GLOBAL PTR MOVE.L GRAFGLOBALS(A5),A4 ;POINT TO QUICKDRAW GLOBALS MOVE.L THEPORT(A4),A3 ;GET CURRENT GRAFPORT MOVE.L NUMER(A6),NUMER2(A6) ;SAVE ORIGINAL NUMER MOVE.L DENOM(A6),DENOM2(A6) ;SAVE ORIGINAL DENOM ; ; Call StdTxMeas to swap font and measure width. ; CLR -(SP) ;ROOM FOR FCN RESULT MOVE COUNT(A6),-(SP) ;PUSH COUNT BLE GOHOME ;QUIT IF COUNT <= 0 ;STACK CLEANED UP BY SAVESTK MOVE.L TEXTADDR(A6),-(SP) ;PUSH TEXTADDR PEA NUMER(A6) ;PUSH VAR NUMER PEA DENOM(A6) ;PUSH VAR DENOM PEA INFO(A6) ;PUSH VAR INFO JSR StdTxMeas ;MEASURE TEXT MOVE (SP)+,D1 ;POP UNSCALED WIDTH RESULT ; ; StdTxMeas also stashes FMOutPtr in QD global FONTPTR, ; and unscaled fixed point text width inn FixTxWid. ; MOVE.L FONTPTR(A4),A4 ;POINT TO FMOUTPUT MOVE.L 2(A4),A2 ;GET FONT HANDLE MOVE.L (A2),A2 ;DE-REFERENCE IT MOVE FBBDY(A2),TOPHT(A6) ;INIT TOPHT IN CASE OLD FONT BTST #0,1(A2) ;DOES FONT HAVE HEIGHT TABLE ? SNE HEIGHTFLAG(A6) ;REMEMBER FOR LATER ; ; Setup textRect, the rectangle bounding the entire string. ; MOVE.L PNLOC(A3),D2 ;GET PEN LOCATION MOVE.L D2,PENLOC(A6) ;SAVE FOR LATER MOVE.W D2,TEXTRECT+LEFT(A6) ;TEXTRECT.LEFT := PNLOC.H ADD.W D1,D2 ;right := left + width MOVEQ #7,D0 ;get mode mask AND TXMODE(A3),D0 ;is txMode = srcCopy ? BEQ.S NOSLOP ;yes, don't add slop CMP #3,D0 ;is textMode > srcBic ? BGT.S NOSLOP ;yes, don't add slop ADD.W #32,D2 ;SLOP FOR ITALIC,BOLD,OVERSTRIKE NOSLOP MOVE.W D2,TEXTRECT+RIGHT(A6) ;STORE IN TEXTRECT.RIGHT SWAP D2 ;GET PNLOC.V SUB ASCENT(A2),D2 ;SUBTRACT ASCENT MOVE D2,TEXTRECT+TOP(A6) ;TEXTRECT.TOP := PNLOC.V - ASCENT ADD FBBDY(A2),D2 ;ADD HEIGHT MOVE D2,TEXTRECT+BOTTOM(A6) ;TEXTRECT.BOTTOM := TOP + HEIGHT MOVE.L TEXTRECT(A6),TEXTR2(A6) ;MAKE AN EXTRA COPY MOVE.L TEXTRECT+4(A6),TEXTR2+4(A6) ;OF TEXTRECT IN TEXTR2 ; ; Check for stretching ; MOVE.L NUMER(A6),D0 ;GET NUMERATOR CMP.L DENOM(A6),D0 ;ARE WE STRETCHING ? SNE STRETCH(A6) ;REMEMBER THE ANSWER BEQ.S NOSTRCH ;CONTINUE IF NOT STRETCHING ; ; We will be stretching. Setup fromRect and toRect and map textR2. ; MULU D0,D1 ;MULT WIDTH BY NUMER.H DIVU DENOM+H(A6),D1 ;DIV BY DENOM.H MOVE.L PENLOC(A6),D0 ;GET PENLOC MOVE.L D0,TORECT+TOPLEFT(A6) ;SET UP TORECT TOPLEFT ADD.W NUMER+H(A6),D0 ;CALC PENLOC.H + NUMER.H MOVE D0,TORECT+RIGHT(A6) ;SET UP TORECT RIGHT SWAP D0 ;GET PENLOC.V ADD NUMER+V(A6),D0 ;CALC PENLOC.V + NUMER.V MOVE D0,TORECT+BOTTOM(A6) ;SET UP TORECT BOTTOM MOVE.L PENLOC(A6),D0 ;GET PENLOC MOVE.L D0,FROMRECT+TOPLEFT(A6) ;SET UP FROMRECT TOPLEFT ADD.W DENOM+H(A6),D0 ;CALC PENLOC.H + DENOM.H MOVE D0,FROMRECT+RIGHT(A6) ;SET UP FROMRECT RIGHT SWAP D0 ;GET PENLOC.V ADD DENOM+V(A6),D0 ;CALC PENLOC.V + DENOM.V MOVE D0,FROMRECT+BOTTOM(A6) ;SET UP FROMRECT BOTTOM PEA TEXTR2(A6) ;PUSH TEXTR2 PEA FROMRECT(A6) ;PUSH FROMRECT PEA TORECT(A6) ;PUSH TORECT JSR MAPRECT ;MAP TEXTR2 (PRESERVES ALL REGS) NOSTRCH ADD D1,PNLOC+H(A3) ;BUMP PEN BY (SCALED) TEXT WIDTH ; ; Quit if the pen is hidden ; TST PNVIS(A3) ;IS PNVIS < 0 ? BLT GOHOME ;YES, QUIT ; ; Calc minRect: the intersection of textRect, bitMap bounds, ; clipRgn and visRgn bounding boxes. Quit if no intersection. ; PEA TEXTR2(A6) ;PUSH (MAPPED) TEXTRECT PEA PORTBOUNDS(A3) ;PUSH BITMAP BOUNDS MOVE.L CLIPRGN(A3),A0 ;GET CLIPRGN HANDLE MOVE.L (A0),A0 ;DE-REFERENCE IT PEA RGNBBOX(A0) ;PUSH CLIPRGN BBOX MOVE.L VISRGN(A3),A0 ;GET VISRGN HANDLE MOVE.L (A0),A0 ;DE-REFERENCE IT PEA RGNBBOX(A0) ;PUSH VISRGN BBOX MOVE #4,-(SP) ;PUSH NRECTS=4 PEA MINRECT(A6) ;PUSH DST ADDR JSR RSECT ;CALC INTERSECTION BEQ GOHOME ;QUIT IF NO INTERSECTION ; ; Set up srcAddr, srcRow, and height ; LEA 26(A2),A0 ;GET START OF FONT BITMAP MOVE.L A0,SRCADDR(A6) ;SAVE FOR LATER MOVE RASTER(A2),D1 ;GET WORDS PER ROW IN FONT ADD D1,D1 ;DOUBLE FOR BYTES PER ROW MOVE D1,SRCROW(A6) ;REMEMBER FOR LATER MOVE FBBDY(A2),HEIGHT(A6) ;SETUP HEIGHT FOR LATER ; ; Test for fast case: ; not stretched, no color mapping, txMode = srcOr, ; not bold, italic, underlined, outlined or shadowed, ; visRgn and clipRgn both rectangular. ; TST.W 6(A4) ;TEST BOLD AND ITALIC BNE NOTFAST ;NOT FAST UNLESS BOTH ZERO CMP #1,TXMODE(A3) ;IS TEXT MODE SRCOR ? BNE NOTFAST ;NO, NOT FAST TST.W 10(A4) ;TEST ULTHICK AND SHADOW BNE NOTFAST ;NOT FAST UNLESS BOTH ZERO TST.B STRETCH(A6) ;IS TEXT STRETCHED ? BNE NOTFAST ;YES, NOT FAST MOVE COLRBIT(A3),D1 ;ARE WE COLOR MAPPING ? BEQ.S NOCOLOR ;NO, CONTINUE MOVE.L BKCOLOR(A3),D0 ;YES GET BACKGROUND COLOR NOT.L D0 ;INVERT IT AND.L FGCOLOR(A3),D0 ;AND WITH FOREGROUND COLOR BTST D1,D0 ;IS THAT PLANE NORMAL ? BEQ NOTFAST ;NO, NOT FAST NOCOLOR MOVE.L CLIPRGN(A3),A0 ;GET CLIPRGN HANDLE MOVE.L (A0),A0 ;DE-REFERENCE IT MOVEQ #10,D0 CMP RGNSIZE(A0),D0 ;IS CLIPRGN RECTANGULAR ? BNE.S NOTFAST ;NO, NOT FAST MOVE.L VISRGN(A3),A1 ;GET VISRGN HANDLE MOVE.L (A1),A0 ;DE-REFERENCE IT CMP RGNSIZE(A0),D0 ;IS VISRGN RECTANGULAR ? BEQ.S FAST ;YES, TAKE FAST OPTIMIZATION ; ; All systems go except for VisRgn not rectangular. ; Check if visRgn sect minRect is rectangular. ; IF TrimRect(visRgn,minRect) THEN take the fast way. ; MOVE.L A1,-(SP) ;PUSH VISRGN PEA MINRECT(A6) ;PUSH MINRECT JSR TRIMRECT ;CALL TRIMRECT BLT GOHOME ;quit if intersection empty BGT.S NOTFAST ;continue if non-rectangular ; ; Fast case, go directly to screen. ; If text is clipped vertically, then clear heightflag and update TOPHT ; FAST ST FASTFLAG(A6) ;REMEMBER WE'RE GOING FAST MOVE MINRECT+TOP(A6),D0 ;GET MINRECT.TOP MOVE MINRECT+BOTTOM(A6),D1 ;GET MINRECT.BOTTOM SUB TEXTRECT+TOP(A6),D0 ;was top clipped ? BNE.S VCLIP ;yes, handle clip CMP TEXTRECT+BOTTOM(A6),D1 ;was bottom clipped ? BEQ.S VCLIPOK ;no, continue VCLIP CLR.B HEIGHTFLAG(A6) ;can't use height table MOVE.B D0,TOPHT(A6) ;use adjusted top SUB MINRECT+TOP(A6),D1 ;calc clipped height MOVE.B D1,TOPHT+1(A6) ;replace TOPHT VCLIPOK MOVE TEXTRECT+TOP(A6),D0 ;GET DST TOP SUB PORTBOUNDS+TOP(A3),D0 ;CONVERT TO GLOBAL COORDINATES MULU PORTBITS+ROWBYTES(A3),D0 ;MULT BY ROWBYTES ADD.L PORTBITS+BASEADDR(A3),D0 ;ADD START OF DST BITMAP MOVE.L D0,BUFSTART(A6) ;SET UP BUFSTART FOR LATER MOVE PORTBITS+ROWBYTES(A3),BUFROW(A6) ;SET UP BUFROW FOR LATER MOVE PORTBOUNDS+LEFT(A3),BUFLEFT(A6) ;REMEMBER BUFLEFT PEA MINRECT(A6) ;PUSH SHIELD RECT MOVE.L PORTBOUNDS+TOPLEFT(A3),-(SP) ;PUSH DELTA TO CONVERT TO GLOBAL JSR SHIELDCURSOR ;HIDE CURSOR IF IT INTERSECTS BRA GETPTRS ; ; Slow case: Setup for an off-screen buffer. ; ; Calc bufLeft: (word-align to avoid shift) ; NOTFAST CLR.B FASTFLAG(A6) ;NOT GOING DIRECTLY TO SCREEN MOVE TEXTRECT+LEFT(A6),D0 ;GET TEXTRECT LEFT SUB PORTBOUNDS+LEFT(A3),D0 ;CONVERT TO GLOBAL AND #$FFF0,D0 ;TRUNC TO WORD BOUND SUB #32,D0 ;32 DOT SLOP FOR SLANT & SHADOW ADD PORTBOUNDS+LEFT(A3),D0 ;RETURN TO LOCAL COORDS MOVE D0,BUFLEFT(A6) ;REMEMBER FOR LATER ; ; Calculate buffer size ; MOVE TEXTRECT+RIGHT(A6),D1 ;BUFRIGHT := TEXTRECT RIGHT SUB D0,D1 ;WIDTH:=BUFRIGHT-BUFLEFT LSR #5,D1 ;CONVERT DOTS TO LONGS ADD #2,D1 ;ROUND UP PLUS EXTRA LONG MOVE HEIGHT(A6),D3 ;GET HEIGHT MULU D1,D3 ;BUFSIZE:=HEIGHT*BUFROW LONGS MOVE D3,BUFSIZE(A6) ;SAVE FOR LATER LSL #2,D1 ;QUAD BUFROW FOR BYTES MOVE D1,BUFROW(A6) ;SAVE FOR LATER ; ; Calculate total stack requirements for off-screen buffers. ; MOVE.L D3,D2 ;GET BUFSIZE LONGS TST.B 11(A4) ;ARE WE SHADOWING ? BEQ @1 ;NO, CONTINUE ADD.L D2,D2 ;YES, CALC 2*BUFSIZE EXT.L D1 ;SIGN EXTEND BUFROW ADD.L D1,D2 ;CALC TOTAL LONGS @1 LSL.L #2,D2 ;CALC TOTAL STACK BYTES NEEDED ADD.L #1024,D2 ;ADD 1 KBYTE SLOP ; ; If stack is too small to allocate buffer(s), then recursively call ; DrText with the left half and the right half of the text string. ; _StackAvail ;Get StackAvail IN D0 CMP.L D0,D2 ;IS stackNeeded > stackAvail ? BLE.S STACKOK ;NO, CONTINUE MOVE.L PENLOC+H(A6),PNLOC+H(A3) ;RESTORE PNLOC TO ORIGINAL MOVE COUNT(A6),D7 ;GET CHARACTER COUNT LSR #1,D7 ;DIVIDE IN HALF BEQ GOHOME ;GIVE UP IF COUNT WAS ONLY ONE MOVE D7,-(SP) ;PUSH NEW COUNT MOVE.L TEXTADDR(A6),-(SP) ;PUSH TEXTADDR MOVE.L NUMER2(A6),-(SP) ;PUSH ORIGINAL NUMER MOVE.L DENOM2(A6),-(SP) ;PUSH ORIGINAL DENOM JSR DrText ;DRAW THE FIRST HALF MOVE COUNT(A6),D0 ;GET ORIGINAL CHARACTER COUNT SUB D7,D0 ;SUBTRACT CHARS ALREADY DONE MOVE D0,-(SP) ;PUSH NEW COUNT MOVE.L TEXTADDR(A6),A0 ;GET ORIGINAL TEXTADDR ADD D7,A0 ;BUMP PAST CHARS ALREADY DONE MOVE.L A0,-(SP) ;PUSH NEW TEXTADDR MOVE.L NUMER2(A6),-(SP) ;PUSH ORIGINAL NUMER MOVE.L DENOM2(A6),-(SP) ;PUSH ORIGINAL DENOM JSR DrText ;DRAW THE SECOND HALF BRA GOHOME ;AND QUIT ! ; ; Allocate and clear an off-screen buffer ; STACKOK SUB #1,D3 ;INIT DBRA LOOP COUNT CLR.L -(SP) ;PAD BUFFER WITH AN EXTRA ZERO MOVE.L SP,BUFEND(A6) ;REMEMBER WHERE BUFFER ENDS CLRLOOP CLR.L -(SP) DBRA D3,CLRLOOP ;ALLOCATE AND CLEAR BUFFER MOVE.L SP,BUFSTART(A6) ;REMEMBER START OF BUFFER CLR.L -(SP) ;PAD BUFFER WITH AN EXTRA ZERO ; ; Get pointers to location table, width table, and height table in font ; GETPTRS LEA 26(A2),A0 ;GET START OF FONT BITMAP MOVE FBBDY(A2),D0 ;GET HEIGHT OF FONT BITMAP MULU SRCROW(A6),D0 ;CALC TOTAL SIZE OF STRIKE ADD.L D0,A0 ;A1 := START OF LOC TABLE MOVE.L A0,LOCTAB(A6) ;SAVE FOR LATER CLR.L D0 ;get ready for unsigned word MOVE LENGTH(A2),D0 ;HOW MANY WORDS IN STRIKE BODY ADD.L D0,D0 ;DOUBLE FOR BYTECOUNT LEA 16(A2,D0.L),A1 ;GET START OF WIDTH TABLE MOVE.L A1,WIDTAB(A6) ;SAVE FOR LATER MOVE MAXCHAR(A2),D0 ;GET MAXCHAR MOVE MINCHAR(A2),D1 ;GET MINCHAR MOVE D1,MINCH(A6) ;STASH MINCHAR FOR LATER SUB D1,D0 ;CALC MAXCHAR-MINCHAR MOVE D0,MAXMIN(A6) ;SAVE FOR LATER ADD #3,D0 ;CALC MAXMIN+3 ADD D0,D0 ;CALC 2*(MAX-MIN+3) BTST #1,1(A2) ;DOES FONT HAVE WIDTH TABLE ? BEQ.S NOWID ;NO, CONTINUE ADD D0,D0 ;YES, SKIP OVER WIDTH TABLE NOWID LEA 0(A1,D0),A0 ;POINT TO HEIGHT TABLE MOVE.L A0,HEIGHTAB(A6) ;SAVE FOR LATER ; ; Set up space width ; MOVE.L widthPtr,A0 ;point to width table MOVE.L 128(A0),SPWIDTH(A6) ;get width of the space char ; ; Setup misc stuff in registers for speed ; MOVE BUFLEFT(A6),D1 ;GET BUFLEFT MOVE PENLOC+H(A6),D0 ;GET PEN LOCATION ADD FBBOX(A2),D0 ;ADJUST FOR KERNING SUB D1,D0 ;MAKE CHARLOC RELATIVE TO BUFLEFT MOVE.W D0,CHARLOC(A6) ;INIT INT PART OF CHARLOC MOVE #$8000,CHARLOC+2(A6) ;SET FRACT PART TO ONE HALF SUB D1,MINRECT+LEFT(A6) ;MAKE MINRECT.LEFT AND SUB D1,MINRECT+RIGHT(A6) ;MINRECT.RIGHT BUFFER RELATIVE MOVE.L TEXTADDR(A6),A1 ;GET TEXTPTR BRA.S NEXTCH ;GO TO LOOP START ;--------------------------------------------------- ; ; Here's the main character drawing loop: ; SPACECH MOVE.L SPWIDTH(A6),D1 ;GET SPACE WIDTH ADD.L D1,CHARLOC(A6) ;BUMP CHARLOC SKIPCH SUB #1,COUNT(A6) ;DECREMENT CHAR COUNT BLE STRDONE ;QUIT IF CHARCOUNT <= 0 NEXTCH CLR D0 ;get ready for byte MOVE.B (A1)+,D0 ;GET NEXT CHAR CMP.B #32,D0 ;IS IT A SPACE ? BEQ SPACECH ;YES, HANDLE IT MOVE.L WidthPtr,A0 ;POINT TO WIDTH TABLE MOVE D0,D4 ;COPY CHARACTER LSL #2,D4 ;QUAD FOR TABLE OFFSET MOVE.L 0(A0,D4),D4 ;GET FIXED POINT WIDTH SUB MINCH(A6),D0 ;SUBTRACT SAVED MINCHAR CMP MAXMIN(A6),D0 ;IS CH BETWEEN MINCHAR AND MAXCHAR ? BLS.S OKCHAR ;YES, CONTINUE MISSING MOVE MAXMIN(A6),D0 ;NO, USE MISSING SYMBOL ADD #1,D0 ;WHICH IS ONE PAST MAXCHAR ADD D0,D0 ;INDEX := 2*(MISSING-MINCHAR) MOVE.L WIDTAB(A6),A0 ;POINT TO WIDTH TABLE MOVE 0(A0,D0),D3 ;GET OFFSET AND WIDTH BYTES BPL.S NOTMISS ;IS MISSING CHAR MISSING ? BRA NEXTCH ;YES, SKIP THIS CHAR OKCHAR ADD D0,D0 ;INDEX := 2*(ASCII-MINCHAR) MOVE.L WIDTAB(A6),A0 ;POINT TO WIDTH TABLE MOVE 0(A0,D0),D3 ;GET OFFSET AND WIDTH BYTES BMI MISSING ;OFFSET NEG = MISSING CHAR NOTMISS LSR #8,D3 ;GET OFFSET BYTE ADD.W CHARLOC(A6),D3 ;DSTLEFT := CHARLOC.INT + OFFSET ADD.L D4,CHARLOC(A6) ;ADD FIXED POINT WIDTH TO CHARLOC MOVE.L LOCTAB(A6),A0 ;POINT TO LOCATION TABLE MOVE 0(A0,D0),D1 ;GET SRCLEFT MOVE 2(A0,D0),D2 ;GET SRCRIGHT SUB D1,D2 ;CALC WIDTH OF BITS BLE SKIPCH ;SKIP CHARBLT IF WIDTH <= 0 ADD D3,D2 ;DSTRIGHT := DSTLEFT + WIDTH TST.B HEIGHTFLAG(A6) ;does font have height table ? BEQ.S NOHEIGHT ;no, continue MOVE.L HEIGHTAB(A6),A0 ;get height table MOVE 0(A0,D0),TOPHT(A6) ;get this char's top and height NOHEIGHT ;----------------------------------------------------------------------- ; ; Horizontal clip only if FastFlag: (else stretch,outline,shadow,italic die) ; ; skip if hidden on left, string done if hidden on right. ; ; at this point: D1: srcLeft ; D2: dstRight ; D3: dstLeft ; TST.B FastFlag(A6) ;ARE WE GOING FAST ? BEQ.S HORIZOK ;NO, DON'T CLIP CMP MINRECT+LEFT(A6),D3 ;IS DSTLEFT < MINRECT.LEFT ? BGE.S LEFTOK ;NO, CONTINUE CMP MINRECT+LEFT(A6),D2 ;IS DSTRIGHT <= MINRECT.LEFT ? BLE SKIPCH ;YES, SKIP THIS CHAR TRIMLFT MOVE MINRECT+LEFT(A6),D0 ;NO, GET MINRECT.LEFT SUB D3,D0 ;DISCARD:=MINRECT.LEFT-DSTLEFT ADD D0,D1 ;SRCLEFT:=SRCLEFT+DISCARD ADD D0,D3 ;DSTLEFT:=DSTLEFT+DISCARD CMP MINRECT+RIGHT(A6),D2 ;IS DSTRIGHT > MINRECT.RIGHT ? BLE.S HORIZOK ;NO, CONTINUE BRA.S TRIMRT ;YES, TRIM RIGHT LEFTOK CMP MINRECT+RIGHT(A6),D2 ;IS DSTRIGHT <= MINRECT.RIGHT ? BLE.S HORIZOK ;YES, CONTINUE CMP MINRECT+RIGHT(A6),D3 ;IS DSTLEFT >= MINRECT.RIGHT ? BGE STRDONE ;YES, IGNORE REST OF STRING TRIMRT MOVE MINRECT+RIGHT(A6),D2 ;NO, TRIM DSTRIGHT HORIZOK ;-------------------------------------------------------------- ; ; Inputs to local block CharBlt: ; ; srcAddr(A6) ; srcRow(A6) ; bufStart(A6) = dstAddr ; bufRow(A6) = dstRow ; D1 = srcLeft ; D2 = dstRight relative to buffer, > dstLeft ; D3 = dstLeft relative to buffer ; TOPHT(A6) top and height ; ; CLOBBERS: D0,D1,D2,D3,D4,D5,D6,D7,A0,A2,A3,A4,A5 ; PRESERVES: A1,A6,A7 ; ; ; Setup shift count in D5 (relative shift between src and dst) ; MOVE D3,D5 ;COPY DSTLEFT SUB D1,D5 ;SUB SRC LEFT MOVEQ #$F,D0 ;get a 4 bit mask AND D0,D5 ;SHIFTCNT:=DELTA HORIZ MOD 16 ; ; Setup srcAddr in A4, address of leftmost word ; MOVE.L SRCADDR(A6),A4 ;GET START OF SRC BITMAP ADD D5,D1 ;CALC SRCLEFT+SHIFTCNT ASR #4,D1 ;CONVERT FROM DOTS TO WORDS ADD D1,D1 ;DOUBLE FOR BYTES SUB #2,D1 ;BACK UP 1 WORD SINCE PICKING UP LONG ADD D1,A4 ;LEAVE SRCPTR IN A4 ; ; Setup dstPtr in A5, address of leftmost dst word ; MOVE.L BUFSTART(A6),A5 ;GET START OF DST BITMAP MOVE D3,D1 ;GET A COPY OF DSTLEFT ASR #4,D1 ;CONVERT FROM DOTS TO WORDS ADD D1,A5 ;ADD TO DSTPTR ADD D1,A5 ;TWICE FOR BYTES ; ; Setup leftMask in D3 and rightMask in D4 ; LEA MaskTab,A0 ;point to mask table AND D0,D3 ;get bottom 4 bits of dstLeft ADD D3,D3 ;double for table index MOVE 0(A0,D3),D3 ;get mask word from table NOT D3 ;invert it for leftMask MOVE D2,D6 ;copy dstRight AND D0,D2 ;get bottom 4 bits of dstRight ADD D2,D2 ;double for table index MOVE 0(A0,D2),D4 ;get rightMask from table ; ; Get srcRow, dstRow, and char height into regs ; MOVE SRCROW(A6),A2 MOVE BUFROW(A6),A3 MOVE.W #255,D7 ;GET -1 BYTE, CLEAR HI BYTE ADD.B TOPHT+1(A6),D7 ;CALC HEIGHT-1 FOR DBRA LOOP BMI SKIPCH ;OOPS HEIGHT WAS ZERO ! ; ; Adjust srcPtr and dstPtr for charTop ; CLR.W D0 ;get ready for byte MOVE.B TOPHT(A6),D0 ;get char top MOVE A2,D2 ;get srcRow in D-reg MULU D0,D2 ;calc charTop * srcRow ADD.L D2,A4 ;add to srcPtr MOVE A3,D2 ;get dstRow in D-reg MULU D0,D2 ;calc charTop * dstRow ADD.L D2,A5 ;add to dstPtr ; ; Branch based on total number of dst words ; ASR #4,D6 ;CALC (DSTRIGHT) DIV 16 SUB D1,D6 ;CALC TOTAL NUMBER OF WORDS-1 BEQ.S WORD1 ;BR IF DST ALL IN ONE WORD SUB #1,D6 BEQ.S LONG1 ;BR IF DST ALL IN ONE LONG ADD #1,D7 ;COMPENSATE FOR EXTRA DBRA BRA.S WIDE1 ;DST WIDER THAN ONE LONG ; ; Slow loop only taken in wierd cases where dst wider than a long. ; MAIN1 MOVE.L (A4),D0 ;GET SRC FROM BITMAP ADD #2,A4 ;BUMP SRCPTR RIGHT LSR.L D5,D0 ;ALIGN TO DST AND D1,D0 ;MASK EXTRA TO ZEROS OR D0,(A5)+ ;OR SRC INTO DST MOVEQ #-1,D1 ;FLUSH MASK DBRA D2,MAIN1 ;LOOP TILL LAST WORD MOVE.L (A4),D0 ;GET SRC FROM BITMAP LSR.L D5,D0 ;ALIGN TO DST AND D4,D0 ;MASK WITH RIGHTMASK OR D0,(A5) ;OR SRC INTO DST MOVE.L SRCPTR(A6),A4 ;RESTORE SRCPTR TO LEFT ADD A2,A4 ;BUMP TO NEXT ROW MOVE.L DSTPTR(A6),A5 ;RESTORE DSTPTR TO LEFT ADD A3,A5 ;BUMP DST TO NEXT ROW WIDE1 MOVE.L A4,SRCPTR(A6) ;REMEMBER SRCPTR AT LEFT MOVE.L A5,DSTPTR(A6) ;REMEMBER DSTPTR AT LEFT MOVE D3,D1 ;MASK:=LEFTMASK MOVE D6,D2 ;GET WORDCOUNT DBRA D7,MAIN1 ;LOOP ALL ROWS SUB #1,COUNT(A6) ;DECREMENT CHAR COUNT BGT NEXTCH ;LOOP IF MORE CHARS LEFT BRA STRDONE ;QUIT IF CHARCOUNT <= 0 ; ; Optimize if dst fits in one long. (30% of normal characters do) ; LONG1 SUB #2,A3 ;ADJUST DSTEND FOR WORD BUMP LONG1A MOVE.L (A4),D0 ;GET SRC DATA LSR.L D5,D0 ;ALIGN TO DST AND D3,D0 ;MASK EXTRA WITH LEFTMASK OR D0,(A5)+ ;OR RESULT INTO DST MOVE.L 2(A4),D0 ;GET SECOND WORD OF SRC LSR.L D5,D0 ;ALIGN IT AND D4,D0 ;MASK EXTRA WITH RIGHTMASK OR D0,(A5) ;OR RESULT INTO DST ADD A2,A4 ;BUMP SRCPTR TO NEXT ROW ADD A3,A5 ;BUMP DSTPTR TO NEXT ROW DBRA D7,LONG1A ;LOOP ALL ROWS SUB #1,COUNT(A6) ;DECREMENT CHAR COUNT BGT NEXTCH ;LOOP IF MORE CHARS LEFT BRA STRDONE ;QUIT IF CHARCOUNT <= 0 ; ; Optimize if dst fits in one word. (70% of normal characters do) ; WORD1 AND D4,D3 ;COMBINE LEFT AND RIGHT MASKS WORD1B MOVE.L (A4),D0 ;GET SRC DATA LSR.L D5,D0 ;ALIGN TO DST AND D3,D0 ;MASK EXTRA TO ZEROS OR D0,(A5) ;OR RESULT INTO DST ADD A2,A4 ;BUMP SRCPTR TO NEXT ROW ADD A3,A5 ;BUMP DSTPTR TO NEXT ROW DBRA D7,WORD1B ;LOOP ALL ROWS SUB #1,COUNT(A6) ;DECREMENT CHAR COUNT BGT NEXTCH ;LOOP IF MORE CHARS LEFT STRDONE MOVE.L SAVEA5(A6),A5 ;RESTORE GLOBAL PTR TST.B FASTFLAG(A6) ;WERE WE GOING DIRECT TO SCREEN ? BEQ.S @1 ;NO, CONTINUE JSR SHOWCURSOR ;YES, RESTORE CURSOR BRA GOHOME ;AND QUIT @1 MOVE.L GRAFGLOBALS(A5),A0 ;POINT TO QUICKDRAW GLOBALS MOVE.L THEPORT(A0),A3 ;GET CURRENT GRAFPORT MOVE.L FONTPTR(A0),A4 ;POINT TO FMOUTPUT MOVE.L 2(A4),A2 ;GET FONT HANDLE MOVE.L (A2),A2 ;DE-REFERENCE IT MOVE CHARLOC(A6),D7 ;GET FINAL CHARLOC INT PART SUB FBBOX(A2),D7 ;UN-ADJUST FROM KERNING ; ; Make buffer bold if necessary: ; CKBOLD CLR D2 ;GET READY FOR BYTE MOVE.B 6(A4),D2 ;GET NUMBER OF OVERSTRIKES BRA.S NXTBOLD ;BOLD BUFFER IF ANY BOLDIT MOVE.L BUFSTART(A6),A0 ;POINT TO START OF BUFFER MOVE BUFSIZE(A6),D1 ;HOW MANY LONGS IN BUF SUB D0,D0 ;CLEAR X-BIT BOLDLP MOVE.L (A0),D0 ;GET ONE LONG ROXR.L #1,D0 ;ROTATE RIGHT WITH EXTEND OR.L D0,(A0)+ ;OR BACK INTO BUFFER DBRA D1,BOLDLP ;LOOP ENTIRE BUFFER NXTBOLD DBRA D2,BOLDIT ;LOOP FOR EACH OVERSTRIKE ; ; Slant the buffer if necessary: ; Work from bottom of buffer up, shifting each row right. ; Work right to left to avoid clobbering src. ; CLR D2 ;GET READY FOR BYTE MOVE.B 7(A4),D2 ;DO WE NEED ITALIC ? BEQ.S CHECKUL ;NO, CONTINUE MOVE.L BUFEND(A6),A1 ;DSTPTR:=END OF BUFFER MOVE BUFROW(A6),D3 ;GET BUFFER ROWBYTES SUB D3,A1 ;BACK UP DSTPTR TO END OF 2ND ROW LSR #1,D3 ;WORDCNT:=ROWBYTES DIV 2 SUB #1,D3 ;WORDCOUNT-1 FOR DBRA LOOP MOVE HEIGHT(A6),D6 ;INIT ROW COUNTER CLR D4 ;INIT OFFSET BRA.S DOSLANT ;GO TO LOOP START NXTROW ADD D2,D4 ;OFFSET:=OFFSET+ITALIC MOVE D4,D0 ;COPY OFFSET LSR #4,D0 ;DELTA := OFFSET SCALED BY 16 MOVEQ #$F,D5 AND D0,D5 ;SHIFTCNT:=DELTA MOD 16 LSR #4,D0 ;DELWORD:=DELTA DIV 16 MOVE.L A1,A0 ;SRCPTR:=DSTPTR SUB #4,A0 ;BACK UP ONE LONG SUB D0,A0 ;SUBTRACT DELWORD SUB D0,A0 ;TWICE BECAUSE WORDS MOVE D3,D1 ;INIT LOOP TO WORDCNT NXTWORD MOVE.L (A0),D0 ;GET A LONG OF SRC SUB #2,A0 ;BUMP SRCPTR LEFT ONE WORD LSR.L D5,D0 ;SHIFT SRC TO ALIGN WITH DST MOVE D0,-(A1) ;STORE IN DST AND BUMP DSTPTR DBRA D1,NXTWORD ;LOOP ALL WORDS THIS ROW DOSLANT DBRA D6,NXTROW ;LOOP FOR ALL ROWS IN BUFFER ; ; Underline characters in buffer if necessary. ; ; Use characters in buffer to hide parts of the underline. ; CHECKUL TST.B 10(A4) ;IS ULTHICK ZERO ? BEQ NOTUL ;YES, CONTINUE MOVE.L BUFSTART(A6),A0 ;POINT TO BUFFER START MOVE BUFROW(A6),D1 ;GET BYTES PER ROW OF BUFFER MOVE ASCENT(A2),D0 ;GET ASCENT MOVE DESCENT(A2),D2 ;GET DESCENT MULU D1,D0 ADD.L D0,A0 ;POINT TO BASELINE ROW MOVE.L A0,A1 MOVE.L A0,A2 ADD D1,A1 ;POINT TO BASELINE+1 CMP #2,D2 ;IS DESCENT AT LEAST 2 ? BLT.S NOTUL ;NO, SKIP UNDERLINE BEQ.S ONLY2 ;ONLY USE 2 IF DESCENT=2 ADD D1,A2 ADD D1,A2 ;POINT TO BASELINE+2 ONLY2 SUB D1,SP ;ALLOCATE TEMP SCANBUF MOVE.L A3,-(SP) ;SAVE GRAFPORT LEA 4(SP),A3 ;POINT TO START OF TEMP LSR #2,D1 ;CONVERT BYTES TO LONGS SUB #1,D1 ;INIT DBRA LOOP COUNT MOVE D1,D2 ;COPY LOOP COUNT SUB D0,D0 ;CLEAR X-BIT UL1 MOVE.L (A0)+,D0 ;GET FROM BASELINE OR.L (A1)+,D0 ;OR WITH BASELINE+1 OR.L (A2)+,D0 ;OR WITH BASELINE+2 MOVE.L D0,(A3) ;PUT RESULT TO TEMP ROXR.L #1,D0 ;SHIFT WITH CARRY OR.L D0,(A3)+ ;OR INTO TEMP DBRA D1,UL1 ;LOOP ALL LONGS IN ROW MOVE.L A1,A0 ;COPY END PTR SUB D0,D0 ;CLEAR X-BIT UL2 MOVE.L -(A3),D0 ;GET FROM TEMP ROXL.L #1,D0 ;SHIFT LEFT WITH CARRY OR.L (A3),D0 ;OR WITH TEMP NOT.L D0 ;INVERT OR.L D0,-(A1) ;DRAW SOME UNDERLINE DBRA D2,UL2 ;LOOP ALL LONGS IN ROW MOVE.L (SP)+,A3 ;RESTORE GRAFPORT ; ; Trim right edge of underline. (left edge trimmed by StretchBits) ; MOVE BUFROW(A6),D0 ;GET BYTES PER ROW OF BUFFER LSL #3,D0 ;TIMES 8 FOR DOTS WIDE SUB D7,D0 ;OVERSHOOT:=BUFRIGHT-LASTRIGHT SUB #1,D0 ;BACK UP 1 SO MASK COMES OUT RIGHT LSR #4,D0 ;CONVERT DOTS TO WORDCOUNT BRA.S UL3 ;GO TO LOOP START ULTRIM CLR -(A0) ;ERASE SOME UNDERLINE UL3 DBRA D0,ULTRIM ;LOOP ALL FULL WORDS ADD BUFLEFT(A6),D7 ;UNDO BUFFER RELATIVE MOVE D7,D0 ;GET LAST RIGHT COORD SUB PORTBOUNDS+LEFT(A3),D0 ;CONVERT TO GLOBAL COORDS JSR RIGHTMASK ;COMPUTE A MASK AND D0,-(A0) ;ERASE LAST PARTIAL WORD ; ; Setup fakeRgn, a dummy rectangular region ; NOTUL MOVE #10,FAKERGN+RGNSIZE(A6) ;SIZE=10 BYTES FOR RECT RGN MOVE.L PORTBOUNDS(A3),FAKERGN+RGNBBOX(A6) MOVE.L PORTBOUNDS+4(A3),FAKERGN+RGNBBOX+4(A6) LEA FAKERGN(A6),A0 ;GET ADDR OF FAKERGN MOVE.L A0,FAKEPTR(A6) ;POINT FAKE MASTERPTR TO IT ; ; Setup bitMaps to transfer from buffer to screen. ; ; srcBits := buffer ; LEA SRCBITS(A6),A0 ;POINT TO SRCBITS MOVE.L BUFSTART(A6),(A0)+ ;SET UP BASEADDR MOVE BUFROW(A6),(A0)+ ;SET UP ROWBYTES MOVE TEXTRECT+TOP(A6),(A0)+ ;SET UP BOUNDS TOP MOVE BUFLEFT(A6),(A0)+ ;SET UP BOUNDS LEFT MOVE.L TEXTRECT+BOTRIGHT(A6),(A0)+ ;SET UP BOTTOM RIGHT ; ; dstBits := portBits ; LEA PORTBITS(A3),A2 ;POINT TO PORTBITS LEA DSTBITS(A6),A0 ;POINT TO DSTBITS MOVE.L (A2)+,(A0)+ ;COPY BASEADDR MOVE (A2)+,(A0)+ ;COPY ROWBYTES MOVE.L (A2)+,(A0)+ ;COPY BOUNDS.TOPLEFT MOVE.L (A2)+,(A0)+ ;COPY BOUNDS.BOTRIGHT ; ; check if any shadowing: ; CLR D3 ;GET READY FOR BYTE MOVE.B 11(A4),D3 ;GET SHADOW COUNT BEQ NOSHAD ;SKIP IF NO SHADOWING ; ; Shadowing will be used. Allocate buf2, 4 scans taller than BUF1. ; Clear out new 4 scanlines, and copy BUF1 into the rest. ; MOVE BUFROW(A6),D0 ;GET 4 * NUMBER OF LONGS PER ROW SUB #1,D0 ;INIT LOOP COUNTER CLR.L -(SP) ;ALLOW ONE LONG OF SLOP MOVE.L SP,BUF2END(A6) ;REMEMBER END OF BUF2 CLR2 CLR.L -(SP) ;ALLOCATE AND CLEAR A LONG DBRA D0,CLR2 ;CLEAR 4 SCANLINES WORTH MOVE BUFSIZE(A6),D0 ;GET NUMBER OF LONGS IN BUF1 SUB #1,D0 ;INIT DBRA COUNTER MOVE.L BUFEND(A6),A0 ;POINT TO END OF BUF1 COPYLP MOVE.L -(A0),-(SP) ;COPY FROM BUF1 TO NEW BUF2 DBRA D0,COPYLP ;COPY ALL OF BUF1 MOVE.L SP,BUF2START(A6) ;REMEMBER START OF BUF2 CLR.L -(SP) ;ALLOW ONE LONG OF SLOP ; ; Bold buf2 across to the right enough for shadow. ; AND #3,D3 ;RESTRICT SHADOW COUNT TO 1..3 MOVE D3,D2 ;INIT BOLD COUNTER ACROSS1 MOVE.L BUF2START(A6),A0 ;POINT TO START OF BUFFER2 MOVE BUFSIZE(A6),D1 ;INIT COUNT OF LONGS SUB D0,D0 ;CLEAR X-BIT ACROSS2 MOVE.L (A0),D0 ;GET A LONG FROM BUF2 ROXR.L #1,D0 ;SHIFT IT RIGHT EXTENDED OR.L D0,(A0)+ ;OR IT BACK INTO BUFFER DBRA D1,ACROSS2 ;LOOP FOR ALL LONGS DBRA D2,ACROSS1 ;BOLD RIGHT 2,3, OR 4 TIMES ; ; Bold BUF2 down enough for shadow. ; MOVE.L BUF2START(A6),A2 ;GET LIMIT POINTER DOWN1 MOVE.L BUF2END(A6),A1 ;DSTPTR:=END OF BUF2 MOVE.L A1,A0 SUB SRCBITS+ROWBYTES(A6),A0 ;SRCPTR:=END - 1 SCANLINE DOWN2 MOVE.L -(A0),D0 ;GET A LONG FROM LINE ABOVE OR.L D0,-(A1) ;OR INTO THIS LINE CMP.L A2,A0 ;IS SRCPTR <= BUF2START ? BGT DOWN2 ;NO, LOOP ALL LONGS DBRA D3,DOWN1 ;BOLD DOWN 2,3, OR 4 TIMES ; ; Alter srcBits to use BUF2 ; MOVE.L A2,SRCBITS+BASEADDR(A6) ;SRC BASEADDR:=BUF2START ADD #4,SRCBITS+BOUNDS+BOTTOM(A6) ;4 SCANS TALLER ; ; Push params and call StretchBits to transfer shadow to screen ; MOVE.L TEXTRECT(A6),SRCRECT(A6) ;SRCRECT := TEXTRECT MOVE.L TEXTRECT+4(A6),SRCRECT+4(A6) ADD #4,SRCRECT+BOTTOM(A6) ;PLUS 4 SCANS TALLER MOVE.L SRCRECT(A6),DSTRECT(A6) ;DSTRECT := SRCRECT MOVE.L SRCRECT+4(A6),DSTRECT+4(A6) LEA DSTRECT+TOP(A6),A0 ;OFFSET BY (-1,-1) SUB #1,(A0)+ ;TOP SUB #1,(A0)+ ;LEFT SUB #1,(A0)+ ;BOTTOM SUB #1,(A0)+ ;RIGHT TST.B STRETCH(A6) BEQ.S @1 PEA DSTRECT(A6) PEA FROMRECT(A6) PEA TORECT(A6) JSR MAPRECT ;THEN MAPPED FOR SCALING @1 PEA SRCBITS(A6) ;PUSH SRCBITS PEA DSTBITS(A6) ;PUSH DSTBITS PEA SRCRECT(A6) ;PUSH SRCRECT PEA DSTRECT(A6) ;PUSH DSTRECT MOVEQ #7,D0 ;GET A 3-BIT MASK AND TXMODE(A3),D0 ;GET TEXTMODE MOD 7 MOVE D0,-(SP) ;PUSH SHADOW MODE MOVE.L CLIPRGN(A3),-(SP) ;PUSH CLIPRGN HANDLE MOVE.L VISRGN(A3),-(SP) ;PUSH VISRGN HANDLE PEA FAKEPTR(A6) ;PUSH FAKE HANDLE JSR StretchBits ;TRANSFER BUFFER TO SCREEN ; ; restore altered srcBits ; MOVE.L BUFSTART(A6),SRCBITS+BASEADDR(A6) SUB #4,SRCBITS+BOUNDS+BOTTOM(A6) ; ; Push params and call StretchBits to transfer buffer to screen ; NOSHAD PEA SRCBITS(A6) ;PUSH SRCBITS PEA DSTBITS(A6) ;PUSH DSTBITS PEA TEXTRECT(A6) ;PUSH SRCRECT = TEXTRECT PEA TEXTR2(A6) ;PUSH DSTRECT = TEXTR2 MOVE TXMODE(A3),-(SP) ;PUSH TEXTMODE TST.B 11(A4) ;ARE WE USING SHADOW ? BEQ.S MODEOK ;NO, CONTINUE MOVE #2,(SP) ;YES, USE XOR MODE MODEOK AND #7,(SP) ;TREAT MODE MOD 8 MOVE.L CLIPRGN(A3),-(SP) ;PUSH CLIPRGN HANDLE MOVE.L VISRGN(A3),-(SP) ;PUSH VISRGN HANDLE PEA FAKEPTR(A6) ;PUSH FAKE HANDLE JSR StretchBits ;TRANSFER BUFFER TO SCREEN GOHOME MOVE.L SAVESTK(A6),SP ;STRIP BUFFER MOVEM.L (SP)+,D0-D7/A1-A4 ;RESTORE REGS UNLINK PARAMSIZE,'DRTEXT ' .END