; ; File: DrawText.a ; ; Contains: QuickDraw Character Generator ; ; Copyright: © 1983-1993 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; 9/12/93 SAM Changed all instances of _Translate24to32 to _rTranslate24to32 ; so they can conditionalized out of the build. ; 5/21/93 CSS Fix some things with hasDoubleByte. ; 8/28/92 CSS Update from Reality: ; <77> 8/21/92 csd Reentered fix <76> since the file got messed up with garbage ; data when it was checked in. ; <76> 8/21/92 DTY #1039679 : #1039679 : Underlining TrueType characters ; would overrun the width of the string due to some code added for ; double byte TrueType support. This new code adds some slop to ; the rectangle that QuickDraw draws text into. When QuickDraw ; goes to underline the text, it draws a line the width of this ; rectangle, which is wider than the width of the text, because of ; this extra slop. Added a check to not add this slop if we’re not ; drawing with a double byte TrueType font. This returns the code ; path to what it was under 7.0, while leaving the code path there ; for double byte TrueType fonts. ; 7/16/92 CSS Update from Reality: ; <75> 6/8/92 SAH #1031825: Changed way the multColor flag is passed to ; StretchBits. Bit 0 now means the source is black and white only. ; Bit 1 means the source contains colour (not used). ; <74> 4/24/92 DTY Case Obj still sucks. Put the spline font conditionals back in ; until I can get this stupid case sensitivity stuff worked out so ; the ROM keeps building. ; <73> 4/24/92 DTY Don’t INCLUDE anything except for SysPrivateEqu.a and ; LinkedPatchMacros.a for ROM builds, since this file is included ; into CQD.a. ; <72> 4/24/92 DTY Remove all Spline_Fonts conditionals. ; 4/16/92 PN Include the right files for ROM build, BigJSR. Eliminated ; has_color condition and 68000 condition (SuperMario will always ; run with colorQD and >68000) ; <71> 9/27/91 JSM Don’t define hasDoubleByte for ROM builds. ; <70> 9/25/91 jlf Rolled in Pacific TrueType modifications and removed ; DOUBLE_BYTE conditional code. New doublebyte code is ; bracketed with hasDoubleByte conditional. ; <69> 7/10/91 JSM Remove obsolete SysVers conditionals. ; <68> 6/12/91 LN added #include 'SysPrivateEqu.a' ; <67> 4/30/91 dba move GWorldFlag equate inside PROC to get rid of warning ; <66> 3/27/91 KON MRR,gbm, WRKSHT#TitleBugTriggered: Colorized OR text mode to ; 1-bit source with bass font goes through text blit loop which ; does not know how to colorize OR mode. The fix is to force the ; drawing through stretch if going to 1-bit and the foreground ; color is not black. ; <65> 2/28/91 CL (KON)(RB)#82681 related bug. Need to make cache non purgeable ; during the memory call for offscreen text and then restore the ; state. ; <64> 1/18/91 CL (RB)Making the getmasktable conditional consistent with the ; original. Setting to NOT HAS_COLOR instead of NOT NOT_68000. ; This will fix the Mac32 build. ; <63> 1/16/91 gbm (csd) Fix total screwup by Chaz and KON. Checking in files that ; will NOT assemble is a heinous crime. Do it again, and it’s off ; to Saudi Arabia... ; <62> 1/16/91 CL (KON)Moving call to getmasktable from the inner blit loop to the ; set up instead. Setting it up on the stack. ; <61> 1/15/91 CL (MR)Now safecount must be set to -2 if the pen loc needs to be ; added inside of stdtxmeas. ; <60> 1/14/91 SMB (jdt) Removing initialization of overflow count since added to ; StdTxMeas. ; <59> 1/9/91 RB (CEL/PKE/GM/DA) Fixing long string overflow bug by truncating ; the count. ; <58> 12/13/90 CL (RB) Left overhang calculation did not work correctly unless the ; glyph was cached. A soft error of no_bits occured and the left ; overhang was skipped. ; <57> 12/13/90 CL (RB)In the deepChar blit loops when a character has no bitmap the ; pin needed to be advanced. ; <56> 11/27/90 CL (SMC) GC card cached the offscreen gworld. Must get and use the ; gc card cache addr. ; <55> 11/8/90 KON Call stretchbits trap for B&W machines if 7.0. [CEL] ; <54> 10/22/90 CL (BKR)Adding minimum memory mode to band characters and support ; minimum cache sizes. (SMC)Added in optimization for blit ; expansion loops. ; <53> 10/10/90 CL Adding call to preflight routine when banding to make sure we ; can get enough memory for the banded character. ; <52> 10/8/90 CL When figuring out how much space was needed for the offscreen ; buffer an ext.l was used to a unsigned word which turned into a ; negative number. Bad news! Not enough memory would be allocated ; and the heap got corrupted. Now a moveq before is used to clear ; the long. ; <50> 10/1/90 CL Added check to make sure the cache got loaded by the FontMgr. ; <49> 9/21/90 CL (BAL) A bug was introduced in the charextra code that treated ; chExtra as a unsigned character. It did a asl.l on a negative ; value making the space tremendous. An ext.l fixes the problem. ; <48> 9/18/90 CL No longer calling sbSearchForCache everytime since the ; fontMgr should load the cache in everytime ; <47> 9/17/90 BG Removed <29>, <33> and <38>. 040s are now behaving more ; reliably. ; <46> 9/4/90 CL Memory model changed a little for the cachehandle. The cacheHandle ; could change when a sbretrieveglyph call is made since it may place ; the block in another heap. So after call is made, re-init the cachehand ; via the splinekey. sb_shrinkbitmap is no longer called for cached contours ; so the bytewidth must be retrieved from the stack after calling the ; sbretrieveglyph call. No longer using the tempbitmapHand so ; there is no need for the check to dispose. ; <45> 8/27/90 RB A branch to decCount caused a warning since decCount is right ; next store and it turns to a NOP. Got rid of branch. ; <44> 8/24/90 CL Added back in changes in <39> version with bug fix to make sure ; the dither flag go set up. Also made 16 and 32 bit fonts work by ; making sure a color table was really truely pointed to by the ; source pixmap. ; <43> 8/24/90 PKE (per JT) Use new Script Mgr line layout values in GrafGlobals ; instead of soon-to-be-obsolete values in Script Mgr globals. ; <42> 8/18/90 RB Temporarily revert to version 38 so fonts work at all sizes ; again. ; <41> 8/18/90 RB Many sizes don't render to the screen ; <40> 8/17/90 gbm fix a warning about branching to the next instruction ; <39> 8/16/90 CL Color Fonts just didn’t work! First of all the Font DA/Mover ; never moved 'fctb's. Voila, no color. DrText assumed a 1 bit ; font to create the mask but could get a 2, 4, or 8 bit font. ; This created a bad mask. When shrinking the bits from a greater ; pointsize, text looked really bad. So on depths greater than one ; and we are shrinking, we use the Dither mode which looks pretty ; darn good. ; <38> 8/15/90 BG Found another place for an EclipseNOP. ; <37> 7/31/90 PKE (really CL on PKE’s machine) Needed to scale D3 value of the ; char code when the glyph does not exist. This caused an address ; error. ; <36> 7/30/90 CL Somehow the descent kerning adjustment code got deleted… So I am ; adding it back in. ; <35> 7/27/90 CL Needed to add cmpSize to the color pixmap. ; <34> 7/26/90 gbm change noCache to noCaching to avoid assembly conflict, collapse ; two conditional blocks together ; <33> 7/20/90 BG Found another place that an EclipseNOP was needed. ; <32> 7/20/90 DTY Bass: The Linked Patch. Changed loads of junk to make Bass work ; as a linked patch. Added conditional black and white procedure ; names, since we’re effectively carrying around two copies of ; DrawText in Bass, and we need to keep the procedure names ; unique. Also added check for Bass_Init for code that gets ; compiled when hasSplineFonts is true, since hasSplineFonts is ; not true when building Gaudi for System 6.0.x. Changed jumps ; into ROM to use the jmpROM macro. ; <31> 7/17/90 CL Did not need to call swapmmumode while going offscreen. ; <30> 6/29/90 CL Always calling sb_searchforcache to insure correct font cache is ; loaded for blitting. ; <29> 6/26/90 BG Rolled in 040-related changes. ; <28> 6/25/90 CL fontPrivate should only be included in this file when it is a ; splinefont build. ; <27> 6/22/90 CL Fixed up include files to use new fontPrivate.a, toolEqu.a and ; qdhooks. ; <26> 6/20/90 KON Despite the intials on this comment, JT fixed a bug in the ; character extra calculations. I was using the wrong register to ; find the current GrafPort, so the chExtra value for new ports ; was incorrect. This led to interesting, but potentially ; disasterous layout of text. ; <25> 6/18/90 CL Fixed Outline Font Clipping bug on the 68000 class machines. ; <24> 6/13/90 CL Fixing Outline & Italic Horizontal clipping bug. ; <23> 6/12/90 JT Got loose with the kerning adjustment. We now keep both the ; kerning adjustment for the pen and a separate kerning bounds for ; the left edge of the off-screen bit image that is then copied to ; the screen. The kerning adjustment for the pen works as before ; (the full fKernMax is used) but the kerning bounds for the ; offscreen bit image only includes that part of the first ; character in the string that actually kerns. I add the offset of ; the first character to the fKernMax and pin the value at zero to ; calculate the kerning bounds. All this only applies to bitmap ; fonts. ; <22> 6/12/90 JT Added alternate code for keeping the width fraction when scaling ; a bitmap font. This code replaces the nasty fixed-point trap ; routines mentioned in the previous comment. ; <21> 6/9/90 JT Removed some active and some commented out debugging traps. Also ; removed all commented out references to the old 32-bit flags. ; Sorry Chazz, I just couldn't help myself. ; <20> 6/9/90 JT Late-night session yields all kinds of interesting changes. ; First, the CalcCharExtra routine has been moved here from Text.a ; since it is now used by both the classic and the color versions ; of QuickDraw. Second, the classic version of QuickDraw now uses ; the fixed-point result of a StdTxMeas call by looking at the ; fontAdj value in the QuickDraw globals. It used to use the ; integer value that was returned as the result of the StdTxMeas ; call. Third, there is a big hack in the bitMap stretching code ; where we scale the width of the text by the horizontal numerator ; and denominator. For 68020 machines we use the double-register ; multiply and divide routines to properly scale the fixed-point ; text width by the integer numerator and denominator. But for ; 68000 machines we just toss the fractional part of the width and ; use standard single-register multiply and divide routines to do ; the scaling. As a result, stretched drawing results in truncated ; pen motions. That is, the fractional part of the pen motion is ; lost if we are drawing on an old machine and we do not have a ; font strike for the requested size and scaling parameters. ; Anyway, I put in a hack to use the fixed-point trap routines to ; do the correct scaling, but I think this probably causes some ; (don't laugh) performace degradation. Some arithmetic god should ; look into this. ; <19> 6/9/90 JT Now scale the horizontal pen fraction by the point size ; specified in the grafPort. This is the same treatment that Color ; QuickDraw normally gives the chExtra value. Note that two values ; are added together before the scaling occurs. ; <18> 5/31/90 CL Fixing QDDone parameters so the good’ol GC card works properly. ; <17> 5/30/90 JT For old grafPorts use the pnLocFixed value from the QuickDraw ; globals to created a fixed-point pen location. Added the ; penLocFixed local to record the value and restore it across ; recursive drawing operations on long strings. ; <16> 5/29/90 CL Fixed stretch bug in bitmap text. ; <15> 4/18/90 CL Needs32bit only is tested for a byte so set a byte instead of a ; word. The TrueType init does not contain the new bitstopix so we ; must set up the needs32bit flag up for the init. CrsrFlag broke ; the 68000 machines. It was included in the 68000 machines but ; never was initialized. ; <14> 4/16/90 HJR Correct some conditionals. Change SPLINE_FONTS to ; hasSplineFonts. ; <13> 4/16/90 KON File got trashed at rev 11, could be network weirdness or old ; ethertalk card. ; <12> 4/16/90 KON Make it build (equate problems). ; <11> 4/13/90 HJR Fix some case sensitive problem in Mac32 build. ; <10> 4/11/90 CL Added conditional for ROM to leave out is32QD flag since it is ; not needed and the splinekey since it does not exist. ; <9> 4/10/90 CL Fixing outline Text clipping bug. Conditionalize for ROM. Adding ; Double byte international coding. ; <8> 4/9/90 KON Fixed conditionals for ROM build. Script Manager char ; extra addition. ; <8> 4/9/90 KON Fixed problems with drawing to 32-bit addressed pixmaps that are ; not the screen. With BAL. ; <7> 3/21/90 CL Fixed conditionals for ROM build. Script Manager char extra ; addition. ; <6> 3/20/90 CL International character extra is added into QD char extra for ; $700 or greater systems. Non-rectangular visrgn clip did not ; work correctly. Bug in SE - did not scale up the glyphid in ; error case for the retrieval of the width char. Stack was not ; calculate correctly. Added positive value instead of negative. ; <5> 2/28/90 CL Can not do bit depth expansion when going to local off screen ; buffer. Fixes algorithmic boldening and other not fast cases ; <4> 2/27/90 CL Finishing previous comment. 2, 4 & 8-bit only uses 1bit source ; (saves tons of memory). 8 bit - ≈120% faster. 2 and 4 - 110-120% ; faster. 16-bit - 200 to 300% faster. 32-bit - 400-500% faster. 1 ; bit on Portable and SE - ≈182% faster. ; <3> 2/27/90 CL Optimized clip spline blit loops (10% faster). Wrote new fast ; loops for splines in 1, 2, 4, 8, 16 and 32 bit depth levels. ; Optimized pathway setup. Timings for 12 pt. Text on the CI ; compared to 6.0.4 systems are as follows: 1 bit is - 200% ; faster ; <1> 1/3/90 BAL Added a notice for Chazz. ; <2.8> 11/28/89 CEL Characters can have zero widths. Took out check to skip ; character if it has a zero advance width. Especially caused ; problems for International. ; <2.7> 11/14/89 CEL Added Device left side bearing. ; <2.6> 10/27/89 BAL Only define hasSplineFonts if currently undefined. Also ; translate24to32 thePort. ; <2.5> 10/10/89 CEL Fixed the notsrccopy and mask transfer mode for bitmaps. ; <2.4> 9/25/89 CEL Took out left italic descent adjustment. This adjustment to the ; over hang could cause clipping of the string before it. ; <2.3> 9/15/89 CEL Took out tempAscent and tempDescent. Use the always blit flag ; instead. Added in some new blitting code that is not turned on ; yet. Cursor bug: when 32-bit QD was not around BitsToPix did not ; return d2 value for crsrflag. ; <2.2> 8/28/89 CEL Only used byte of spline flag. ; <2.1> 8/14/89 CEL Added support for temp memory for spline bitmaps. Now works ; better in finder mode. Added in ability to set line height for ; splines. Usage from the SetLineHeight function. ; <2.0> 8/1/89 CEL Somehow SUBQ turned into SUBA while checking in… ; <1.9> 8/1/89 CEL Only effects spline font builds: Re-organized spline define ; structures. Cleaned up stack and took out conditionals. Fixed ; mask mode for splines. Fixed kerning adjusting values. Added in ; more comments. Added banding to styles. Merged B&W code to take ; advantage of the Color QD iteration, Banding code in low memory ; and Multi-Finder memory usage. Now DrText works for over 10,000 ; point for styles. Have tried 13,000 point in Shadow and works ; fine. Works at 32,767 point for plain. Used assembly record ; structures for easier mods. Added some code review changes. ; <1.8> 6/10/89 CEL Moved Private.a QuickDraw Equates into proper QuickDraw private ; file (colorequ.a), got rid of QuickDraw nFiles dependencies and ; fixed up necessary files… ; <•1.7> 5/29/89 BAL Blasting in 32-Bit QuickDraw version 1.0 Final ; <•1.6> 5/3/89 CEL Bass rolled into ROM. NOTE:Spline Fonts are conditionalized out. ; Blasting in correct file ; <•1.4> 5/1/89 cel Rolled in Bass… ; <•1.2> 2/14/89 CCH Rolling in 32-Bit color quickdraw sources from Bruce Leak and ; Dave Fung. ; 9/19/88 BAL Altered to get CRSRFLAG value from _BitsToPix; ; 7/4/88 BAL Fixed offscreen drawing to compute bkcol with long result of ; color2index ; 5/8/88 BAL Altered to use 32 bit addressing mode and allow 32 bit deep ; pixels ; 1/21/88 BAL changed pnLocHFrac(a3) to PenLocHFrac(A6) so fractional position ; is restored ; 11/6/87 CRC changed to take fast branch case correctly (branch to GetPtrs, ; not NotScreen) ; 6/4/87 CRC reordered shadow draw to draw outline and then center in old ; port cases ; 1/12/87 CRC rewrote recursive part to avoid reallocating stack frame each ; time through ; 1/6/87 CRC only change the source pixmap’s color table if the source is not ; 1 deep ; 1/3/87 CRC pass color param to stretch, estimate stack usage better, new ; outline/shadow allow initial left kerning, better right hand ; trim for outline ; 12/12/86 CRC Added support for arithmetic modes, character extra ; 12/8/86 CRC Faster case for characters contained in source longs ; 11/23/86 EHB Merged in multiple device changes ; 10/13/86 EHB Added MaskPix and MaskRect to stretchbits call ; 10/7/86 CRC Better measure of italic widths; italic character forces left ; kerning allow for larger strikes w/ long calcs. ; 9/29/86 CRC Changed WidthPtr to WidthTabHandle, added multibit font support ; 6/22/86 EHB Use BIC mode to clear out inner part of outline fonts. (XOR ; looked cool but was wrong). ; 6/18/86 EHB Added pattern to stretchbits calls ; 6/18/86 EHB Removed 68020 enhancements from charblt ; 6/17/86 EHB Added DSTPIX so we could access fields in cGrafPorts ; 6/15/86 EHB Make sure stack is longword aligned (for fast buffers) ; 6/10/86 EHB Modified to use longs and 68020 instructions ; 6/5/86 EHB Cleared flag bits in references to rowBytes ; ;———————————————————————————————————————————————————————————————————————————————————————————————— IF (&TYPE('hasSplineFonts') = 'UNDEFINED') THEN hasSplineFonts EQU 0 ENDIF IF (&TYPE('HAS_COLOR') = 'UNDEFINED') THEN HAS_COLOR EQU hasCQD ENDIF IF (&TYPE('has32bitQD') = 'UNDEFINED') THEN has32bitQD EQU 0 ;Once bits to pix is fixed we can turn this on and do ENDIF ;some conditionals in compiling IF (&TYPE('TIME_SPEED') = 'UNDEFINED') THEN TIME_SPEED EQU 0 ENDIF IF (&TYPE('INITVERSION') = 'UNDEFINED') THEN Gaudi EQU 0 ELSE Gaudi EQU 1 ENDIF IF (&TYPE('hasDoubleByte') = 'UNDEFINED') THEN IF forROM THEN hasDoubleByte EQU 0 ELSE hasDoubleByte EQU 1 ENDIF ENDIF IF (&TYPE('SCRIPT_CHAR_EXTRA') = 'UNDEFINED') THEN IF forROM THEN SCRIPT_CHAR_EXTRA EQU 0 ELSE SCRIPT_CHAR_EXTRA EQU 1 ENDIF ENDIF IF (&TYPE('hasPenFraction') = 'UNDEFINED') THEN IF forROM THEN hasPenFraction EQU 0 ELSE hasPenFraction EQU 1 ENDIF ENDIF IF (&TYPE('hasFullKerning') = 'UNDEFINED') THEN IF forROM THEN hasFullKerning EQU 0 ELSE hasFullKerning EQU 1 ENDIF ENDIF MACHINE MC68020 ; IF (NOT forROM) THEN ; <31> DTY CSS CASE OBJ ENDIF IF (NOT forROM) THEN ;<1.6-11april89-CEL> & <31> DTY ;————————————————————————————————————————————————————— ; Include files… ;————————————————————————————————————————————————————— INCLUDE 'sysequ.a' ;for SplineKey low mem INCLUDE 'Traps.a' INCLUDE 'Quickequ.a' INCLUDE 'ColorEqu.a' INCLUDE 'ToolEqu.a' INCLUDE 'QDHooks.a' INCLUDE 'SplineDefines.a' INCLUDE 'fontPrivate.a' INCLUDE 'SysPrivateEqu.a' ;————————————————————————————————————————————————————— ENDIF ;<1.6-11april89-CEL> INCLUDE 'LinkedPatchMacros.a' ; <31> DTY INCLUDE 'InternalOnlyEqu.a' ; if (hasDoubleByte) then include 'Script.a' endif ;———————————————————————————————————————————————————————————————————————————————————————————————— ; ; 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. ; ; DrText will handle both bitmap ‘FONT’s, ‘NFNT’s and new spline font ; ‘sfnt’s. ; ;———————————————————————————————————————————————————————————————————————————————————————————————— DrText PROC EXPORT ; If the portVersion/rowBytes of any port has the following bits set, it is a GWorld GWorldFlag equ $C001 ; isPixMap+isCPort+isGWorld IF TIME_SPEED THEN IMPORT INITTIMER, READTIMER, RESETTIMER ENDIF IMPORT ArithMode IMPORT GetStyleBufHand IMPORT CalcCharExtra ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Font structure for bitmaps ; ; 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 fKernMax FBBOY EQU 10 ;WORD save as nDescent; unused except as high owTLoc FBBDX EQU 12 ;WORD fRectWidth FBBDY EQU 14 ;WORD fRectHeight LENGTH EQU 16 ;WORD owTLoc locASCENT EQU 18 ;WORD Conflict with other Ascent and Descent defines locDESCENT EQU 20 ;WORD XOFFSET EQU 22 ;WORD leading RASTER EQU 24 ;WORD rowWords ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Input parameters ; ; 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 ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Stack Frame for locals ; ; A6 OFFSETS OF LOCAL VARIABLES AFTER LINK: ; SAVESTK EQU -4 ;long stack before allocating buffers TEXTRECT EQU SAVESTK-8 ;RECT original bounding rect TEXTR2 EQU TEXTRECT-8 ;RECT copy of textRext used by maprect SRCRECT EQU TEXTR2-8 ;RECT original shadow bounding rect DSTRECT EQU SRCRECT-8 ;RECT copy of srcRect used by maprect MINRECT EQU DSTRECT-8 ;RECT minimum rect for clipping BUFEND EQU MINRECT-4 ;LONG where the offscreen buffer ends BUFSIZE EQU BUFEND-4 ;LONG the size of the offscreen buffer BUFROW EQU BUFSIZE-2 ;WORD the rowBytes for the offscreen buffer BUF2START EQU BUFROW-4 ;LONG second buffer used for shadow BUF2END EQU BUF2START-4 ;LONG where shadow buffer ends BUFLEFT EQU BUF2END-2 ;WORD output left edge sHeight EQU BUFLEFT-2 ;WORD font fRectHeight copy SRCPTR EQU sHeight-4 ;LONG used only in wide character case as temp DSTPTR EQU SRCPTR-4 ;LONG used only in wide character case as temp maskStart EQU DSTPTR-4 ;LONG \ start of mask buffer maskAddr EQU maskStart-4 ;LONG >- these 3 grouped: address of mask bits mSrcRow EQU maskAddr-4 ;LONG / rowbytes of mask bits FROMRECT EQU mSrcRow-8 ;RECT mapRect parameter TORECT EQU FROMRECT-8 ;RECT mapRect parameter PENLOC EQU TORECT-4 ;POINT copy of original pnLoc SPWIDTH EQU PENLOC-4 ;FIXED POINT width of space CHARLOC EQU SPWIDTH-4 ;FIXED POINT fractional pen position HEIGHTAB EQU CHARLOC-4 ;LONG pointer to font height table WIDTAB EQU HEIGHTAB-4 ;LONG pointer to font offset/width table LOCTAB EQU WIDTAB-4 ;LONG pointer to font location table SAVEA5 EQU LOCTAB-4 ;LONG register saved so can be reused characterExtra EQU SAVEA5-4 ;LONG fixed point extra added to each character maskBitsPtr EQU characterExtra-4 ;LONG pointer to maskBits, sourcePix, or 0 bkCol EQU maskBitsPtr-4 ;LONG full of the background color leftBack EQU bkCol-4 ;LONG bkCol masked to the left part of the character rightBack EQU leftBack-4 ;LONG bkCol masked to the right part of the character realBounds EQU rightBack-4 ;LONG USED FOR SHIELDCURSOR leftOffset EQU realBounds-8 ;2 LONGs offset used by bit field instructions in charblt maskSize EQU leftOffset-2 ;WORD size of mask buffer mBufRow EQU maskSize-2 ;WORD \ these 2 mask buffer row size maskBlts EQU mBufRow-6 ;3 WORDS / grouped: saved state for mask blit FAKERGN EQU maskBlts-10 ;RECTANGULAR REGION FAKEPTR EQU FAKERGN-4 ;LONG, FAKE MASTER POINTER INFO EQU FAKEPTR-8 ;4 WORDS font info record returned by txMeasure (unused) numer2 EQU INFO-4 ;Point copy of numer for iterative case denom2 EQU numer2-4 ;Point copy of denom for iterative case charsRemain EQU denom2-2 ;word remaining characters to draw in iterative case srcBits EQU charsRemain-14 ;bitMap input to shadow stretchBits, bitsToPix srcPix EQU srcBits-(pmRec+ctRec+20) ;pixMap input to normal stretchbits maskBits EQU srcPix-14 ;bitMap input to bitsToPix for font mask DSTPIX EQU maskBits-(pmRec+ctRec+20) ;pixMap destination FASTFLAG EQU DSTPIX-1 ;BYTE flag set if source ORing to screen is OK maskFont EQU FASTFLAG-1 ;byte flag set if a maskFont is available + requested Stretch EQU maskFont-1 ;BOOLEAN flag set if numerator not equal denominator heightFlag EQU Stretch-1 ;byte flag set if font has a height table topHt EQU heightFlag-2 ;word character top & height from font or clip maxMin EQU topHt-2 ;word number of characters in font minCh EQU maxMin-2 ;word first character in font bitDepth EQU minCh-2 ;word \ These two bits per pixel in font bkCol1 EQU bitDepth-2 ;word / grouped. 1 pixel worth of background color kernAdjust EQU bkCol1-2 ;word pen adjustment to kerning and italic kernBounds EQU kernAdjust-2 ;word boundary adjustment due to kerning and italic penLocHFrac EQU kernBounds-2 ;word fractional pen position for recursive calls penLocFixed EQU penLocHFrac-2 ;word fractional pen position for recursive calls longCount EQU penLocFixed-2 ;word loop counter for doMove charWidth EQU longCount-2 ;word width in pixels of current character blt stackOffset EQU charWidth-2 ;word 2 if stack was word aligned before link countCopy EQU stackOffset-2 ;word copy of character count, decremented as drawn CRSRFLAG EQU countCopy-1 ;BYTE set if crsr is shielded (to screen) <1.6-11april89-CEL> MMUSave EQU CRSRFLAG-1 ;BYTE MMU mode on entry to drawText <1.6-11april89-CEL> locMode EQU MMUSave-2 ;word copy of text mode, adjusted if arith. + 1 bit <1.6-11april89-CEL> bitShift EQU locMode-2 ;word how far to shift to multiply by bitDepth orNotOK EQU bitShift-1 ;Boolean true if bit extract/insert must be used instead notMaskPass EQU orNotOK-1 ;Boolean true if blit is not creating font mask textCopyMode EQU notMaskPass-1 ;Boolean true if blit must use extract/insert orMode EQU textCopyMode-1 ;Boolean true if mode is srcOr & forecolor is black colorSource EQU orMode-1 ;Boolean true if font contains colors (nonblack/white) saveHilite EQU colorSource-1 ;byte saved hilite flag for iterative state unused1 EQU saveHilite-1 ;byte extra byte for somebody maybe Snapper-Head Joe is32QD EQU unused1-1 ;32 bit QD is around sAscent EQU is32QD-2 ;word for Ascent sDescent EQU sAscent-2 ;word for Descent rExtraHang EQU sDescent-2 ;word Right over hang max repeatBands EQU rExtraHang-2 ;word repeat banding for clipping regions off stack LItalicExtra EQU repeatBands-2 ;word Left italic extra RItalicExtra EQU LItalicExtra-2 ;word Right italic extra isSpline EQU RItalicExtra-1 ;byte for flag cacheState EQU isSpline-1 ;byte memory state for cache fontState EQU cacheState-2 ;word Save the state of the font clipStorage EQU fontState-4 ;long pointer to top of stack for clipping origCharCount EQU clipStorage-2 ;long pointer to top of stack for clipping saveMode EQU origCharCount-2 ;Transfer mode safe copy origTopClip EQU saveMode-2 ;WORD yMax Clipping origBotClip EQU origTopClip-2 ;WORD yMin Clipping bufHeight EQU origBotClip-2 ;Height of buffer needed currentEnd EQU bufHeight-4 ;Current end of style buffer for allocation bufferPtr EQU currentEnd-4 ;Pointer to style buffer stackHandle EQU bufferPtr-4 ;Handle to style buffer trimSrcRect EQU stackHandle-8 ;RECT trimmed source rect for init cacheHand EQU trimSrcRect-4 ;Handle to the cache cachePtr EQU cacheHand-4 ;Pointer to the cache glyphArray EQU cachePtr-4 ;Pointer to the glyph array topAdjust EQU glyphArray-2 ;(word)Top adjustment to calc destination widTabPtr EQU topAdjust-4 ;(long)Pointer to the fixed width table STARTTIME EQU widTabPtr-4 ;reserved for Chazz-man TIMINGS READADJ EQU STARTTIME-4 ;reserved for Chazz-man TIMINGS wordFunc EQU READADJ-4 ;pointer to word blit routine bigWordFunc EQU wordFunc-4 ;pointer to big word blit routine longFunc EQU bigWordFunc-4 ;pointer to long blit routine bigLongFunc EQU longFunc-4 ;pointer to big long blit routine overLongFunc EQU bigLongFunc-4 ;pointer to over long blit routine destShift EQU overLongFunc-2 ;word destination shift value textPtr EQU destShift-4 ;copy of text addr a4Check EQU textPtr-4 ;Temporary may rip out later - only checking for stack crash a6Check EQU a4Check-4 ;Temporary may rip out later - only checking for stack crash needs32Bit EQU a6Check-1 ;used by KON-mon, device deeds to be addressed in 32-bit mode notFastFlag EQU needs32Bit-1 ;do not go fast if set rOverHMax EQU notFastFlag-2 ;word right overhang maximum lowByte EQU rOverHMax-1 ;(boolean) is this a double-byte font? highByte EQU lowByte-1 ;(byte) low-byte of double-byte character. encodingTable EQU highByte-4 ;(pointer) encoding table address. FREEBYTE EQU encodingTable-1 ;(byte) doDither EQU FREEBYTE-1 ;(byte) Set if dither is needed synFont EQU doDither-1 ;(byte) Set if this is a synthetic font fluff EQU synFont-1 ;(byte) myPort EQU fluff-4 ;The current grafport maskTabPtr EQU myPort-4 ;ptr to mask table <62-CEL> resvLong1 EQU maskTabPtr-4 ;reserved for Chazz-man <62-CEL> resvLong2 EQU resvLong1-4 ;reserved for Bruce-dude resvLong3 EQU resvLong2-4 ;reserved for Kon-chap resvLong4 EQU resvLong3-4 ;reserved for Kindness resvLong5 EQU resvLong4-4 ;reserved for Joe-schmoe ;——————————————————————————————————————— ;sb_Retrieves input struct - Do not split this record up!!! ;###WARNING: If this changes, then change the same record in OutlineMetrics.a bufStart EQU resvLong5-4 ;(long) _ \ start of bits buffer srcAddr EQU bufStart-4 ;(long) | >- these 3 grouped: ptr to bits srcRow EQU srcAddr-4 ;(long) |/ rowbytes of font bits bitWidth EQU srcRow-2 ;(word) | for Width of char in bits entryOffset EQU bitWidth-4 ;(long) | entry offset of glyph fillBYTE EQU entryOffset-1 ;(Boolean) | nextBand EQU fillBYTE-1 ;(Boolean) | Another character band? nextTopBand EQU nextBand-2 ;(word) | next top character band nextBotBand EQU nextTopBand-2 ;(word) | next bot character band bandScan EQU nextBotBand-2 ;(word) | band size of char band scan EQU bandScan-2 ;(word) | number of scan lines devLSB EQU scan-2 ;(short) | Device for the LSB (short) lsb EQU devLSB-4 ;(long) | for the LSB (fixed) yMax EQU lsb-2 ;(word) | for the y min (short) yMin EQU yMax-2 ;(word) | for the y max (short) topClip EQU yMin-2 ;(word) | yMax Clipping botClip EQU topClip-2 ;(word) | yMin Clipping clipHorz EQU botClip-1 ;(Boolean) \ | Is it clipped horizontally clipVert EQU clipHorz-1 ;(Boolean) / | Is it clipped vertically destDepth EQU clipVert-2 ;(word) | depth of destination **CAN take out ptSize EQU destDepth-2 ;(word) | pixels per em **CAN take out glyphID EQU ptSize-2 ;(word) | glyph code fontID EQU glyphID-2 ;(word) _ font id code *** get rid of unwanted vars ;End of Structure ;——————————————————————————————————————— VARSIZE EQU ((fontID-3)/4)*4 ;SIZE OF VARIABLES long aligned <6> CEL ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Aligning the Stack ; ; MAKE SURE THE STACK IS ON A LONGWORD BOUNDARY (FOR FASTBUFFERS) ; ; Register Use: ; A3 = thePort ; A4 = QuickDraw Globals ; A6 = Stack frame ; A5 = Grafport handle ; ; Clobbers: ; D0 ; MOVE.L D0,A0 ;save D0 $$$ WHY MOVE.L SP,D0 ;GET THE STACK POINTER ASR #2,D0 ;WORD BOUNDARY? SCS D0 ;remember balance BCC.S STKOK ;=>NO, GOT LONG BOUNDARY SUBQ #2,SP ;ELSE MAKE STACK LONG ALIGNED STKOK LINK A6,#VARSIZE ;ALLOCATE TEMP VARS AND #2,D0 ;amount stack was adjusted by MOVE D0,stackOffset(A6) MOVE.L A0,D0 ;restore D0 $$$ WHY MOVEM.L D0-D7/A1-A4,-(SP) ;SAVE REGS MOVE.L SP,SAVESTK(A6) ;remember where the 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 IF (hasSplineFonts OR Gaudi) THEN MOVE.L expandMem,A0 ; get low memory expand pointer. <61-CEL/RWB> MOVE.L ExpandMemRec.emSplineKey(A0),A0 ; get handle to splineKey globals. <61-CEL/RWB> MOVE.L (A0), A0 ; get pointer to splineKey globals. <61-CEL/RWB> MOVE.W #-2, splineKeyRec.safeCount(A0) ;init to -1 for flagging <61-CEL/RWB> ENDIF MOVE.B splineKeyRec.is32bit(A0),is32QD(A6) ; get 32 bit CQD flag in CCR. MOVE.L TheGDevice,LastTxGDevice ;save the text device for next time ;———————————————————————————————————————————————————————————————————————————————————————————————— ; ; CONVERT DSTBITS (THE PORT) TO A PIXMAP ; (A5 must contain global ptr) ; LEA PORTBITS(A3),A1 ;GET PORTBITS POINTER LEA DSTPIX(A6),A2 ;GET DSTPIX POINTER _BitsToPix ;CONVERT BITMAP MOVE.L D1,REALBOUNDS(A6) ;SAVE REAL DST BOUNDS.TOPLEFT IF NOT Gaudi THEN MOVE.B D2,CRSRFLAG(A6) ;REMEMBER IF DST IS SCREEN swap d2 ; <9Apr90 KON> move.b d2,needs32Bit(a6) ;save whether device needs 32-bit addressing<7Apr90 KON> ELSE CLR.B needs32Bit(a6) ;Set if 32-bit TST.B is32QD(A6) ;check for 32 bit QD BEQ.S @no32QD ;no so do it the old way MOVE.B D2,CRSRFLAG(A6) ;REMEMBER IF DST IS SCREEN BNE.S @checkScreen ;yes -> check gdevice LEA DSTPIX(A6),A2 ;GET DSTPIX POINTER MOVE.W pmVersion(A2), D0 ;if flags are set check if 32-bit addressing BEQ.S @doneSetFlag ;not needing 32 bit addressing so branch BTST #2,D0 ;32-bit clean address? SNE needs32Bit(A6) ;Set if 32-bit BRA.S @doneSetFlag @checkScreen MOVE.L THEGDEVICE,A0 ;GET HANDLE TO THE GDEVICE MOVE.L (A0),A0 ;GET POINTER TO THE GDEVICE BTST #ext32Device,gdFlags(A0) ;does it need 32-bit addressing? SNE needs32Bit(a6) ;Set if 32-bit BRA.S @doneSetFlag @no32QD MOVE.L TheGDevice, A0 ;Get the gdevice MOVE.L (A0), A0 ;Point at it MOVE.L GDPMAP(A0), A0 ;Get its pixmap MOVE.L (A0),A0 ;Point at it MOVE.L BASEADDR(A0),D0 ;Get base of screen CMP.L DSTPIX+BASEADDR(A6),D0 ;Drawing to the screen SEQ CRSRFLAG(A6) ;If so, set it @doneSetFlag ENDIF ;Gaudi ;——————————————————————————————————————————————————— ; Load the matching Font and Measure the string ; ; MOVE stackOffset(A6),D0 ;either zero if stack was long aligned, or two if not CLR -(SP) ;ROOM FOR FCN RESULT MOVE.L numer(A6,D0),numer2(A6) MOVE.L denom(A6,D0),denom2(A6) ;save original numer, denom for iterative case MOVE COUNT(A6,D0),D1 ;get count MOVE D1,-(SP) ;PUSH COUNT MOVE D1,countCopy(A6) ;save copy of count IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY MOVE D1,origCharCount(A6) ;save copy of count ENDIF MOVE.L TEXTADDR(A6,D0), A0 MOVE.L A0, textPtr(A6) ;Keep a copy for later use MOVE.L A0, -(SP) ;PUSH TEXTADDR PEA NUMER(A6,D0) ;PUSH VAR NUMER PEA DENOM(A6,D0) ;PUSH VAR DENOM PEA INFO(A6) ;PUSH VAR INFO lea JStdTxMeas,A0 ;get piece of trap table <31> DTY Changed from move.l move.l (a0),a0 JSR (A0) ;MEASURE TEXT ;——————————————————————— ; Set up mask table ptr ;——————————————————————— ;—————————————————————— ; Fix for overflow of stdtxmeas ;—————————————————————— IF (hasSplineFonts OR Gaudi) THEN ; <31> DTY <59-CEL/RWB> MOVE.L expandMem,A0 ; get low memory expand pointer. <59-CEL/RWB> MOVE.L ExpandMemRec.emSplineKey(A0),A0 ; get handle to splineKey globals. <59-CEL/RWB> MOVE.L (A0), A0 ; get pointer to splineKey globals. <59-CEL/RWB> CMP.B #-1, splineKeyRec.safeCount(A0) ; check to see if count changed <59-CEL/RWB> BEQ.S @noOverFlow ; <59-CEL/RWB> MOVE.W splineKeyRec.safeCount(A0), D1 ;get safe count in reg for assigns <59-CEL/RWB> MOVE stackOffset(A6),D0 ;either zero if stack was long aligned, or two if not <59-CEL/RWB> MOVE D1, COUNT(A6,D0) ;new count <59-CEL/RWB> MOVE D1, countCopy(A6) ;save copy of count <59-CEL/RWB> MOVE D1, origCharCount(A6) ;save copy of count <59-CEL/RWB> @noOverFlow ; <59-CEL/RWB> ENDIF ;—————————————————————— ; Get the Width in D1 ;—————————————————————— ADDQ #2,SP ;POP (and ignore) UNSCALED WIDTH RESULT MOVE.L fontAdj(A4),D1 ;get fixed point width MOVE.L fontPtr(A4),A4 ;Point to FmOutput record move portVersion(a3),d0 ; get the port's portVersion/rowBytes and #GWorldFlag,d0 ; mask all other bits than the GWorldFlag cmp #GWorldFlag,d0 ; is it exactly equal to GWorldFlag? BNE.S @1 MOVEM.L A0-A1/D0-D2,-(SP) ;Save registers clr.l -(sp) ; leave room for Ptr result move.l portPixMap(a3),-(sp) ; push handle to pixmap _GetPixBaseAddr ; get address of offscreen buffer move.l (sp)+,d0 ; put it in d0 MOVE.L D0, DSTPIX+BASEADDR(A6) ; MOVEM.L (SP)+, A0-A1/D0-D2 ;Restore registers ST needs32Bit(A6) ; sending 32-bit data @1 MOVE.W dstPix+pixelSize(A6),destDepth(A6) ;Get the pixel depth IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY ;——————————————————————————————————————————————————— ; DO FORK ; ; Check if splines or bitmaps and make the fork!!! ; ; if (hasDoubleByte) then clr.l encodingTable(a6) ; assume no encoding table. endif MOVE.L WidthTabHandle, A1 ;Get the Width Table MOVE.L (A1), A1 ;Dereference the table TST.B WidthIsSpline(A1) ;Is it a spline font BEQ BitVarSetUp ;Not spline then branch ;———————————————————————————————————————————————————————————————————————————————————————————————— ; STARTING hasSplineFonts SETUP ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————————————— ; SPLINE Stack Variable SetUp ; ; Registers on Entry: ; A4 = Graf globals ; ; Registers used: ; A1 = WidthPtr ; A6 = Stack frame ; A4 = FmOutput record ptr ; ; Preserves: ; D1 = Width of string (We could save it on the stack to be safe!!! ; ; CLOBBERS: D0, D2, D3 ; ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————— ; Set flags ;———————————————————————————————————— ST isSpline(A6) ;Set is a spline font SF clipVert(A6) ;Init to no clip <6> CEL SF doDither(A6) ;No dither for 1-bit splines SF clipHorz(A6) ;Init to no clip <6> CEL SF nextBand(A6) ;init to no next char band CLR.L maskBitsPtr(A6) ;assume no mask CLR.L stackHandle(A6) ;clear stackHandle CLR.W repeatBands(A6) ;no banding at first CLR.W bitShift(A6) ;Incoming 1 deep CLR.W kernAdjust(A6) ;init kern value CLR.W rExtraHang(A6) ;init rExtraHang value CLR.B stretch(A6) ;set up bit insert/extract flag CLR.B colorSource(A6) ;if so, pass info to stretch later MOVE.W #1,bitDepth(A6) ;bits per pixel MOVE.B WidthNotFast(A1), notFastFlag(A6) ;Looks like fast if set ;———————————————————————————————————— ; get cache and Save metrics on stack ;———————————————————————————————————— WITH cache ; <47-CEL> MOVE.L expandMem, A2 ; get low mem expand <47-CEL> MOVE.L ExpandMemRec.emSplineKey(A2), A2 ; Handle to splineKey <47-CEL> MOVE.L (A2), A2 ; pointer to splinekey <47-CEL> MOVE.L splineKeyRec.cacheHand(A2), D2 ; Do we even have a cache??? BEQ GOHOME ; bail since we have no cache MOVE.L D2, A2 ;cacheHand in Addr reg MOVE.L A2, cacheHand(A6) ;get a copy of cache hand MOVE.L (A2), D2 ;cache pointer BEQ GOHOME ;is purged? <65-CEL> MOVE.L D2, A2 ;pointer to the cache in addr reg if (hasDoubleByte) then move.l fEncodingTablePointer(a2),encodingTable(a6) ; load encoding table pointer. endif MOVE.W yMax(A2), sAscent(A6) ;set stack Ascent MOVE.W yMin(A2), sDescent(A6) ;Place descent on stack MOVE.W height(A2), sHeight(A6) ;Place Height on stack ;————————————————— ; OverHang calcs ;————————————————— ;regs used: ; D2 = cachePtr ; A2 = glyphArrayPtr ; MOVEQ #0,D5 MOVEQ #0,D3 if (hasDoubleByte) then tst.l encodingTable(a6) ; CSS <76> Is this a double byte font? bz.s @getFirstAndLastCharacters ; CSS <76> If not, don’t add these overhang values move.w rOverHMax(a2),d0 ; get right overhang value add.w rightItalic(a2),d0 ; add in possible italic overhang move.w d0,rExtraHang(a6) ; initialize total right overhang endif ENDWITH @getFirstAndLastCharacters MOVE.L textPtr(A6),A0 ;pointer to the text MOVE countCopy(A6),D0 ;get count <6> CEL use d0 instead of d3 SUBQ.W #1, D0 ;count-1 is last char index MOVE.B (A0),D5 ;first character MOVE.B (A0,D0),D3 ;last character <6> CEL if (hasDoubleByte) then move.b d5,highByte(a6) ; save the high byte for later use. clr.b lowByte(a6) ; clear the low byte for now tst.l encodingTable(a6) ; is this a double byte font? beq.s @normalFont ; no, skip low byte loading move.l encodingTable(a6),a2 ; load the encoding table tst.b 0(a2,d5.w) ; is this a double byte character? beq.s @normalCharacter ; no, skip low byte loading move.w countCopy(a6),d0 ; get the text length cmpi.w #1,d0 ; is there a low byte character? bls @remapCharacterToNull ; no, remap the high byte adda.w #256,a2 ; offset to the lowByte encoding table. clr.w d0 ; clear high byte of low word move.b 1(a0),d0 ; grab the low byte. tst.b 0(a2,d0.w) ; is this a valid low byte? beq @remapCharacterToNull ; no, remap the high byte move.b d0,lowByte(a6) ; save the valid low byte for later use bra @normalCharacter ; continue normally. @remapCharacterToNull move.b #1,d5 ; remap the high byte character move.b d5,highByte(a6) ; save the remapped value in the stack for later use bra @doRSB ; skip the rest of this stuff @normalCharacter @normalFont endif MOVE.L D2, A0 ;cache pointer LEA cache.glyphArray(A0), A2 ;Get array of glyphs into A2 MOVE.L 0(A2,D5*4),D0 ;Get offset to glyph in D0 BGT.S @okayGlyph BTST.L #30, D0 ;Check if there is an error BNE.S @doRSB ;branch if error AND.L #$3FFFFFFF, D0 ;Clear contour entry bit flag BNE.S @okayGlyph ;Got the info BSR renderChar ;get the glyph and returns non-zero error BEQ.S @doRSB ;skip this glyph <58-CEL> BRA.S @checkLSB ;did not get the offset <58-CEL> @okayGlyph ADD.L D2, D0 ;glyphrec = cache + offset MOVE.L D0, A0 ;in address reg if (hasDoubleByte) then clr.l d0 ; clear a long for the character code move.b lowByte(a6),d0 ; double byte character? beq.s @checkLSB ; no, skip this move.l 0(a0,d0.w*4),d0 ; load glyph record offset bgt.s @haveGlyphOffset ; skip checks if positive btst.l #30,d0 ; error rendering glyph? bne.s @doRSB ; yes, skip this glyph and.l #$3fffffff,d0 ; clear contour and error flags bne.s @haveGlyphOffset ; skip rendering if positive bsr renderChar ; can render the glyph? beq.s @doRSB ; no, skip this glyph bra.s @checkLSB ; already have the offset @haveGlyphOffset add.l d2,d0 ; convert offset to pointer move.l d0,a0 ; load glyph record pointer endif @checkLSB MOVE.W glyph.devLSB(A0), D0 ;Get integralized left side bearing BGE.S @doRSB ADD.W D0, kernAdjust(A6) ;Save extra copy that can contain italic extra @doRSB if (hasDoubleByte) then tst.l encodingTable(a6) ; is this a double byte font? bne.s @doneOverHang ; yes, skip overhang calculations endif MOVE.W D3, D5 ;copy of D3 MOVE.L 0(A2,D3*4),D0 ;Get offset to glyph in D0 BGT.S @okayGlyph2 BTST.L #30, D0 ;Check if there is an error BNE.S @doneOverHang AND.L #$3FFFFFFF, D0 ;Clear contour entry bit flag BNE.S @okayGlyph2 ;Got the info MOVE.W D5, D0 ;D0 for renderchar BSR renderChar ;get the glyph and returns non-zero error BEQ.S @doneOverHang ;skip this glyph <58-CEL> BRA.S @calcROverHang ;got the glyph <58-CEL> @okayGlyph2 ADD.L D2, D0 ;add offset and point to glyph data MOVE.L D0, A0 ;Get in address reg @calcROverHang MOVE.W 0(A1,D3*4),D0 ;Get the width MOVE.W glyph.devLSB(A0), D3 ;Get integralized left side bearing ADD.W glyph.bitWidth(A0), D3 ;RoverHang = (lsb+bitwidth)-Width SUB.W D0, D3 ; BLE.S @doneOverHang MOVE.W D3, rExtraHang(A6) ;————————————————— ; End OverHang calcs ;————————————————— @doneOverHang MOVE.W sAscent(A6), topClip(A6) ;Assign Ascent as top clip initially MOVE.W sDescent(A6), botClip(A6) ;opened up bot clip MOVE.W botClip(A6), origBotClip(A6);Init for fakergn check MOVE.W topClip(A6), origTopClip(A6);Init for fakergn check MOVE txMode(A3),D0 AND #$FFF7,D0 ;clear pattern bit (let stretch reject invalid modes) MOVE D0,locMode(A6) ;initialize copy BTST #6,D0 ;bit 6 if set says use a mask SNE D3 ;remember it BEQ.S @notMask LEA srcPix(A6),A0 ;assume no mask font needed; just use source instead MOVE.L A0,maskBitsPtr(A6) ;pass mask to stretch bits @notMask MOVE.B D3,maskFont(A6) ;0 if mask bit clear, no mask font, or incoming 1 deep MOVE.B D3,textCopyMode(A6) ;set up bit insert/extract flag BTST #5,D0 ;arithmetic mode? BEQ.S @doneMode ;if not, don’t map if dest. is 1 bit deep CMP #1,dstPix+pixelSize(A6) ;1 bit deep destination? BNE.S @doneMode ;if not, arithmetic mode is OK LEA ArithMode,A0 ;get mode map AND #7,D0 ;look at each different arith mode MOVE.B 0(A0,D0),D0 ;map into 1 bit safe mode MOVE D0,locMode(A6) ;alter mode properly for 1 bit depth @doneMode ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Bounding Rect set up ; ; Setup textRect, the rectangle bounding the entire string. ; ; Registers on Entry: ; A2 = Font Ptr ; A3 = thePort ; A4 = FmOutput record ptr ; A6 = Stack frame ; ; D1 = Width of string ; ; Register Use: ; D2 = PenLocation (Set up as fixed) ; ; Clobbers: ; D0, D3 ; ;———————————————————————————————————————————————————————————————————————————————————————————————— 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 SWAP D2 IF hasPenFraction THEN move.l grafGlobals(a5),a0 ; load quickDraw globals. move.w pnLocFixed(a0),d2 ; append pen fraction. move.w d2,penLocFixed(a6) ; save pen fraction for recursive drawing. ELSE move.w #$8000,d2 ; append default fraction. ENDIF ;——————————————————————————————————————————————————————————————— ; set flag to note if mode is srcOr & foreColor is black ; set up characterExtra if new port or script manager around ; set up pnLocHFrac if new port ;——————————————————————————————————————————————————————————————— CMP #srcOr,locMode(A6) ;is the mode srcOr? SEQ orMode(A6) BCLR #6,locMode+1(A6) ;was mask set? BEQ.S @noMaskMode TST locMode(A6) ;is it srcCopy + mask? SEQ orMode(A6) ;that can go fast, too. @noMaskMode moveq #0, d0 ; clear the character extra. <49> tst.b portBits+rowBytes(a3) ; is this an old grafPort? bpl.s @oldGrafPort ; yes -> skip this. move.w chExtra(a3),d0 ; load the character extra. ext.l d0 ; for sign bits <49> asl.l #4,d0 ; convert to 16.16 format. @oldGrafPort IF SCRIPT_CHAR_EXTRA THEN move.l grafGlobals(a5),a0 ; load quickDraw globals. <43> add.l qdChExtra(a0),d0 ; add in the character extra. <43> ENDIF tst.l d0 ; have zero character extra? beq.s @zeroCharExtra ; yes -> skip call to scale. bsr CalcCharExtra ; scale by point size, etc. @zeroCharExtra move.l d0,characterExtra(a6) ; store scaled character extra. TST PORTBITS+ROWBYTES(A3) ; is it a new port? BPL.S @useOld1 ; no -> don’t set up fraction MOVE pnLocHFrac(A3),D2 ; set up with proper fraction MOVE D2,penLocHFrac(A6) ; save for later as well for recursive drawing ;——————————————————————————————————————————————————————————————————————————————————————— ; ForeGround - BackGround check ; ; This next part is a little tricky: ; If the source does not contain any colors (that is, regardless of whether the source is ; one bit per pixel or more, the pixels are either black or white) then we can go fast if ; the forecolor is black, regardless of the background color. If the font does contain colors, ; then we can go fast if the background is white, regardless of the foreground colors. ; ; But, if the foreground and background pixels are equal (but the font is a 1 bit font), then go ; slow. ColorMap will be called later to sort out whether the foreground color needs to be ; remapped or not. ;——————————————————————————————————————————————————————————————————————————————————————— ;——————————————————————————————————— ; This is the real code ;——————————————————————————————————— MOVE.L fgColor(A3),D0 MOVE dstPix+pixelSize(A6),D3 ;bits per pixel CMP.W #1, D3 ;1 bit depth??? BNE.S @multiDepth CMP.L bkColor(A3),D0 ;same as background? <66> beq.s @goSlow ; <66> tst.l d0 ;forecolor white? <66> BNE.S @doneCheck ;We are okay BRA.S @goSlow ;forecolor white, use stretch <66> @multiDepth CMP.W #16, D3 ;16 or 32 bit??? BLT.S @not16or32 TST.L D0 ;If zero then black BEQ.S @doneCheck ;Do not change mode if black CLR.B orMode(A6) ;Do not do fast case BRA.S @doneCheck ;done so continue @not16or32 CMP.L bkColor(A3),D0 ;same as background? BEQ.S @goSlow ;if so, go slow ADDQ.L #1,D0 ;now equal to number of colors, if black LSR.L D3,D0 ;1 if black, 0 if other color @goSlow SNE D0 ;remember if black (or if fg/bk pixels are not equal) BRA.S @oldCommon @useOld1 BTST #5,fgColor+3(A3) ;is the foreground color black? SNE D0 ;set to zero if not @oldCommon AND.B D0,orMode(A6) ;true if or mode and black monochrome or white multi. @doneCheck ADD.L D1,D2 ;right := left + width SWAP D2 ;just look at high word TST.B fmOutCurStyle(A4) BEQ @noSlop ;if no style, certainly no slop MOVEQ #0,D0 ;clear out high word ADD.B fmOutBold(A4),D0 ;add boldness EXT D0 ;make it a word MOVEQ #4,D3 ;restrict shadow in the range of 0 .. 3 (+1 if shadow) CMP.B fmOutShadow(A4),D3 ;is it less or same? BLE.S @pinShadow ;if so, pin at limit MOVE.B fmOutShadow(A4),D3 ;otherwise, pass actual value BEQ.S @pinShadow ADDQ #1,D3 ;plus 1 for character insides shifted to right @pinShadow ADD D3,D0 ;combine shadow with italic slop count ADD D0,D2 ;SLOP FOR ITALIC,BOLD,OVERSTRIKE @noSlop MOVE.W kernAdjust(A6), D0 ;reg for add ADD.W D0,textRect+left(A6) ;include kerning in text rectangle ADD.W rExtraHang(A6), D2 ;Add in extra for right over hang max MOVE.W D2,TEXTRECT+RIGHT(A6) ;STORE IN TEXTRECT.RIGHT MOVE PENLOC(A6),D2 ;GET PNLOC.V SUB sAscent(A6),D2 ;Use the stack Ascent MOVE D2,TEXTRECT+TOP(A6) ;TEXTRECT.TOP := PNLOC.V - ASCENT ADD sHeight(A6),D2 ;Height metric off stack 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 ANDI #$0F,CCR ; need to clear 'x' flag IF hasPenFraction THEN move.l grafGlobals(a5),a0 ; load quickDraw globals. add.w d1,pnLocFixed(a0) ; add width fraction to location fraction. ENDIF TST PORTBITS+ROWBYTES(A3) ; is it a new port? BPL.S @useOld ; no, don’t bother with fraction ADD D1,pnLocHFrac(A3) @useOld ;————————————————————————————— ; Move pen by the scaled text width ;————————————————————————————— SWAP D1 ;Make integer MOVE PNLOC+H(A3),D0 ;Get the current pen location ADDX D1,D0 ;New Pen Loc = OldPenLoc + TextWidth MOVE D0,PNLOC+H(A3) ;Save new pen location ;———————————————————————————— ; Quit if the pen is hidden ;———————————————————————————— TST PNVIS(A3) ;IS PNVIS < 0 ? BLT GOHOME ;YES, QUIT ;———————————————————————————————————————————————————————————————————————————————————————————————— ; END Bounding Rect set up ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Calculate the MinRect ; ; Calc minRect: the intersection of textRect, bitMap bounds, ; clipRgn and visRgn bounding boxes. Quit if no intersection. ; The right bounds of the destination rect is set to the max to allow right kerning ; (Right kerning only works (without trailing spaces) in OR mode. ; ; Registers on Entry: ; A2 = Font Ptr ; A3 = thePort ; A4 = FmOutput record ptr ; A6 = Stack frame ; ; Clobbers: ; A0, A1 ; D0, D1, D2, D3 ; ;———————————————————————————————————————————————————————————————————————————————————————————————— MOVE textR2+right(A6),-(SP) ;preserve existing right MOVE #32000,textR2+right(A6) ;get right from other rects PEA TEXTR2(A6) ;PUSH (MAPPED) TEXTRECT PEA DSTPIX+BOUNDS(A6) ;PUSH PIXMAP 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 _RSECT ;CALC INTERSECTION BEQ GOHOME ;QUIT IF NO INTERSECTION MOVE (SP)+,textR2+right(A6) ;restore text right ;——————————————————————————————— MOVE.L VISRGN(A3),A1 ;GET VISRGN HANDLE <6> CEL MOVE.L (A1),A0 ;DE-REFERENCE IT CMP #10,RGNSIZE(A0) ;IS VISRGN RECTANGULAR ? BEQ.S @rectRgn ;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 MOVE.W #-1, -(SP) ;trim = true for BRUCE @no32bit _TRIMRECT ;CALL TRIMRECT BEQ.S @rectRgn BLT GOHOME ;quit if intersection empty ST clipHorz(A6) ;It was clipped so mark it BRA NOTFAST ;continue if non-rectangular @rectRgn ;GET VISRGN HANDLE <6> CEL ;——————————————————————————————— ;——————————————————————————— ; Spline Clip Value Set up ;——————————————————————————— MOVE.W MINRECT+TOP(A6),D0 ;GET MINRECT.TOP SUB.W TEXTRECT+TOP(A6),D0 ;Get Text Top BLE.S @checkBottom ST clipVert(A6) ;It was clipped so mark it SUB.W D0, topClip(A6) ;Adjust the top clipping value @checkBottom MOVE.W TEXTRECT+BOTTOM(A6),D0 ;GET MINRECT.BOTTOM SUB.W MINRECT+BOTTOM(A6),D0 ;Is there clipping BLE.S @checkHorz ;check horz clip ST clipVert(A6) ;It was clipped so mark it ADD.W D0, botClip(A6) ;Adjust the bottom clip @checkHorz MOVE.W botClip(A6), origBotClip(A6) ;Init for fakergn check MOVE.W topClip(A6), origTopClip(A6) ;Init for fakergn check MOVE.W TEXTRECT+LEFT(A6), D0 ;Get the left CMP.W MINRECT+LEFT(A6), D0 ;clipped on left??? BGE.S @checkRight ; ST clipHorz(A6) ;clipping on left @checkRight MOVE.W TEXTRECT+RIGHT(A6), D0 ;Get the right CMP.W MINRECT+RIGHT(A6), D0 ;clipped on right??? BLE.S @doneRight ST clipHorz(A6) ;clipping on left @doneRight TST.B notFastFlag(A6) ;combines the style and stretch checks BNE NotFast ;NOT FAST TST.B orMode(A6) ;IS TEXT MODE SRCOR ? (or srcCopy + mask, see above) BEQ NotFast ;NO, NOT FAST MOVE.L CLIPRGN(A3),A0 ; Get clip region MOVE.L (A0),A0 ; Dereference handle MOVEQ #10,D0 CMP RGNSIZE(A0),D0 ;IS CLIPRGN RECTANGULAR ? BNE NotFast ;NO, NOT FAST CMP #1, destDepth(A6) ;****1-bit we can go fast BEQ.S @depthFast TST.W clipVert(A6) ;Vertically or horizontally clipped then go do norm loops BNE NotFast ;check to see if one bit only @depthFast ;———————————————————————————————————————————————————————————————————————————————————————————————— ; END Calculate the MinRect ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————————————— ; FAST case Setup ; ; Fast case, go directly to screen. ; If text is clipped vertically, then clear heightflag and update TOPHT ; ; Registers on Entry: ; A2 = Font Ptr ; A3 = thePort ; A4 = FmOutput record ptr ; A6 = Stack frame ; ; Saves & Restores: ; A2 ; ; Clobbers: ; ; D0, D1 ; ;———————————————————————————————————————————————————————————————————————————————————————————————— sFAST MOVEM.L A0-A1/D0-D2,-(SP) ;Save registers @tryAgain CLR.B -(SP) ;result MOVE.L A3, -(SP) ;needs the current grafport _QDDone ;Is accelerator really done and ready for us to blit??? TST.B (SP)+ ;Check result BEQ.S @tryAgain ;Check until ready! MOVEM.L (SP)+, A0-A1/D0-D2 ;Restore registers ST FASTFLAG(A6) ;REMEMBER WE'RE GOING FAST MOVE sAscent(A6), topAdjust(A6) ;Get ascent into D0 MOVE TEXTRECT+TOP(A6),D0 ;GET DST TOP SUB DSTPIX+BOUNDS+TOP(A6),D0 ;CONVERT TO GLOBAL COORDINATES MOVE DSTPIX+ROWBYTES(A6),D1 ;GET ROWBYTES AND #nuRBMask,D1 ;CLEAR OFF FLAG BITS MULS D1,D0 ;MULT BY ROWBYTES ADD.L DSTPIX+BASEADDR(A6),D0 ;ADD START OF DST BITMAP MOVE.L D0,BUFSTART(A6) ;SET UP BUFSTART FOR LATER MOVE D1,BUFROW(A6) ;SET UP BUFROW FOR LATER MOVE DSTPIX+BOUNDS+LEFT(A6),BUFLEFT(A6) ;REMEMBER BUFLEFT TST.B CRSRFLAG(A6) ;IS DST TO A SCREEN? BEQ @Check32Bit ;=>NO <9Apr90 KON> PEA MINRECT(A6) ;PUSH SHIELD RECT MOVE.L REALBOUNDS(A6),-(SP) ;PUSH DELTA FOR GLOBAL _SHIELDCURSOR ;HIDE CURSOR IF IT INTERSECTS @Check32Bit tst.b needs32bit(a6) ;<9Apr90 KON> beq.s @skip32bit ;<9Apr90 KON> move.l a3,d0 ;get thePort ptr _rTranslate24To32 ;mask off high byte BAL/MCF 03Dec88 move.l d0,a3 ;clean thePort ptr MOVE stackOffset(A6),D1 MOVE.L textPtr(A6),D0 ;GET TEXTPTR _rTranslate24To32 ;mask off high byte BAL/MCF 03Dec88 MOVE.L d0,textPtr(A6) ;SAVE FOR LATER moveq #true32b,d0 ;switch to 32 bit addressing _rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2) move.b d0,MMUsave(a6) ;save previous state for later @skip32bit ;———————————————————————————————————————————————————————————————————————————————————————————————— ; ; Get pointers to location table, width table, and height table in font ; ;———————————————————————————————————————————————————————————————————————————————————————————————— TST.W clipVert(A6) ;Can we try the fast blitting routine??? BNE sGetPtrs ;go to clipping blit loop fastBlit ;———————————————————————————————————————————————————————————————————————————————————————————————— ; NEW FAST blit loop ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Registers Use: ; D0 = scratch A0 = scratch ; D1 = scratch A1 = TextPtr.l ; D2 = shift.w A2 = bitsPtr.l ; D3 = scan.w & nextBand.w(high bit) A3 = glyphArray.l ; D4 = charLoc.l A4 = widTabPtr.l ; D5 = cachePtr.l A5 = DestPtr.l ; D6 = #chars.w A6 = stack frame.l ; D7 = destRowBytes.w A7 = stack pointer.l ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————- ; Figure out Charloc ;———————————————————————- MOVE bufLeft(A6),D1 ;get bufleft in register MOVE penLoc+H(A6),D4 ;Horz pen location SUB D1,D4 ;charloc relative to the buffer SWAP D4 ;turn into fixed TST PORTBITS+ROWBYTES(A3) ;is it a new port? BPL.S @useOld ;no, set fraction to 1/2 MOVE penLocHFrac(A6),D4 ;set up fractional part BRA.S @goOn @useOld MOVE #$8000,D4 ;Treat so it will round @goOn ;———————————————————————- ; Register setup ;———————————————————————- MOVEQ #0, D3 ;Init for nextBand to false MOVE.L cacheHand(A6), A0 ;Handle to the cache MOVE.L (A0), D0 ;pointer to the cache _StripAddress ;Make sure it is the right mode MOVE.L D0, D5 ;save it for later MOVE.L D0, A0 ;get in address register LEA cache.glyphArray(A0), A3 ;Get array of glyphs into A0 MOVE.L widthTabHandle,A0 ;point to width table MOVE.L (A0),A4 ;Save pointer to the width table MOVE.L textPtr(A6),A1 ;get textPtr MOVE.W countCopy(A6), D6 ;decrement partial draw character count SUBQ.W #1,D6 ;make it a DBRA count MOVE.L bufStart(A6), A5 ;BufStart (dst bitmap) MOVE.W bufRow(A6), D7 ;Copy of rowbytes IF HAS_COLOR | SCRIPT_CHAR_EXTRA THEN ;<7> CEL MOVE.L characterExtra(A6),D1 ;add in character extra, if any ENDIF CMP.W #1, destDepth(A6) ;is it 1 deep BEQ.S @depth1 ;Multi-depth blits TST.B FastFlag(A6) ;If not fast then do 1-bit to buffer <5>CEL BEQ.S @depth1 ;do 1-bit TST.B orMode(A6) ;If not src or then do 1 bit and buffer BNE deepChar ;It is deep char @depth1 MOVE.L A6,-(SP) ;REMEMBER Stack frame ptr BRA.S NextChar doNextBand ADDQ.W #1, D6 ;bump count since we are banding MOVE.L (SP), A6 ;restore stack frame MOVE.W glyphID(A6), D3 ;put glyphID into d3 for renderIt BSR renderIt ;Get the glyph MOVE.L A0, A6 ;restore glyphDataPtr in A6 BEQ gotGlyph ;go blit it BRA.S skipBand renderIt1 BTST.L #30, D0 ;Check if there is an error BNE.S skipChar ;Still an error so skip it MOVE.W #0, D3 MOVE.L (SP), A6 ;restore stack frame if (hasDoubleByte) then move.b highByte(a6),d3 ; load high byte of single byte character else move.b -1(a1),d3 ; load single byte character endif @render BSR renderIt ;Get the glyph MOVE.L A0, A6 ;glyphDataPtr in A6 BEQ gotGlyph ;go blit it skipBand skipChar ADD.L 0(A4,D3*4),D4 ;GET FIXED POINT WIDTH IF HAS_COLOR | SCRIPT_CHAR_EXTRA THEN ;<7> CEL ADD.L D1,D4 ;add in character extra, if any ENDIF BRA.S decCharCount ;continue to nextChar spaceChar ADD.L 128(A4), D4 ;Advance a space decCharCount SUBQ.W #1, D6 BLT doneStr ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Registers Use: ; D0 = scratch A0 = scratch ; D1 = characterExtra A1 = TextPtr.l ; D2 = shift.w A2 = bitsPtr.l ; D3 = scan.w & nextBand.w(high) A3 = glyphArray.l ; D4 = charLoc.l A4 = widTabPtr.l ; D5 = cachePtr.l A5 = DestPtr.l ; D6 = #chars.w A6 = glyphdataPtr.l ; D7 = destRowBytes.w (A7) = Save a6 ;———————————————————————————————————————————————————————————————————————————————————————————————— NextChar TST.L D3 ;another char band then call retrieve!!! BMI.S doNextBand ;do the next char band MOVEQ #0,D3 MOVE.B (A1)+,D3 ;get the next character if (hasDoubleByte) then move.l (sp),a6 ; reload the stack frame pointer move.b d3,highByte(a6) ; save the high byte for later use clr.b lowByte(a6) ; clear the low byte for now tst.l encodingTable(a6) ; is this a double byte font? beq.s @normalFont ; no, skip low byte loading move.l encodingTable(a6),a0 ; grab pointer to high byte mapping table tst.b 0(a0,d3.w) ; is this a double byte character? beq @normalCharacter ; no, skip low byte loading tst.w d6 ; more bytes left in text? ble @remapCharacterToNull ; no, remap the high byte subq.w #1,d6 ; decrement the character count clr.w d0 ; clear high byte of low word move.b (a1)+,d0 ; grab the low byte and bump the text pointer adda.w #256,a0 ; offset to the low byte encoding table tst.b 0(a0,d0.w) ; is this a valid low byte? beq @remapCharacterToNull ; no, remap the high byte character move.b d0,lowByte(a6) ; save the valid low byte for later use bra @normalCharacter ; continue normally @remapCharacterToNull move.b #1,d3 ; remap the high byte character to the missing glyph move.b d3,highByte(a6) ; save the remapped value in the stack @normalCharacter @normalFont endif CMP.B #32,D3 ;IS IT A SPACE ? BEQ.S spaceChar ;Skip the char extra MOVE.L 0(A3,D3*4),D0 ;Get offset to glyph in D3 BLE.S renderIt1 ;Must render it ADD.L D5, D0 ;Add in cacheptr address MOVE.L D0, A6 ;glyphrec = cache + offset if (hasDoubleByte) then clr.l d0 ; clear a long for the character code move.l (sp),a0 ; reload the stack frame pointer move.b lowByte(a0),d0 ; double byte character? beq.s @haveGlyphRecord ; no, skip this move.l 0(a6,d0.w*4),d0 ; load glyph record offset ble.s renderIt1 ; render if error or not cached add.l d5,d0 ; convert offset to pointer move.l d0,a6 ; load glyph record pointer @haveGlyphRecord endif LEA glyph.cacheData(A6), A2 ;Get address gotGlyph MOVE.L D4,D2 ;charloc in D2 SWAP D2 ;Just use integer portion ADD.W glyph.devLSB(A6), D2 ;Get integralized left side bearing ;••• spot for skipping advance if char banding!!! TST.L D3 ;do not advance since the is more of char BMI.S @skipAdvance ;another band of char ADD.L 0(A4,D3*4),D4 ;GET FIXED POINT WIDTH IF HAS_COLOR OR SCRIPT_CHAR_EXTRA THEN ;char extra used in 700 and/or color - not B&W < $700 ADD.L D1,D4 ;add in character extra, if any ENDIF @skipAdvance MOVE.L A5,A0 ;copy of destPtr MOVE.W glyph.adjustTop(A6), D0 ;Subtract the YMax MULS.W D7,D0 ;Vertical offset value ADD.L D0,A0 ;Add in the vert offset MOVE.W glyph.bitWidth(A6),D3 ;shift count plus width CMP.W #16,D3 ;bigger than 16? BGT.S overWord ;We are bigger than a word MOVE.W D2, D0 ;Use D0 to calc horz dest adjust LSR.W #4,D0 ;convert to words ADD.W D0,D0 ;convert to bytes (Horz. offset) ADD.W D0,A0 ;Add in the horz offset AND.W #15,D2 ;allow a shift of 0 to 15 ADD.W D2,D3 ;shift + bitwidth CMP.W #16,D3 ;bigger than 16? BGT.S bigWord ;——————————————————— ; blit loops ;——————————————————— ;———————————————————————— ; Word Blit ;Regs used: ; D0 = BlitSource.l ; D2 = ShiftAdjust.w ; D3 = Scan.w ; D6 = charNum.w ; D7 = destRow.w ; A0 = DestPtr.l ; A2 = SourcePtr.l word MOVE.W glyph.scan(A6), D3 ;Height of character SUBQ.W #1,D3 @mid MOVE.W (A2)+,D0 ;this particular example is or mode LSR D2,D0 ;shift into place OR.W D0,(A0) ;add the bits ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid skipIt DBRA D6,NextChar TST.L D3 ;another char band then call retrieve!!! BMI.S doNextBand ;do the next char band doneStr MOVE.L (SP)+,A6 ;Restore Stack frame ptr BRA strDone ;no more chars to do… ;———————————————————————— ; BigWord Blit ;Regs used: ; D0 = BlitSource.l ; D2 = ShiftAdjust.w ; D3 = Scan.w ; D6 = charNum.w ; D7 = destRow.w ; A0 = DestPtr.l ; A2 = SourcePtr.l ; here, the character spans a word boundary, so must be handled with a long loop on 68K machines bigWord MOVE.W glyph.scan(A6), D3 ;Height of character SUBQ.W #1,D3 @mid MOVE.L (A2),D0 ;this particular example is a or mode CLR D0 ;clear the low word LSR.L D2,D0 ;shift into place OR.L D0,(A0) ;add the bits ADD.W D7,A0 ;advance to the next dest row ADDQ #2, A2 ;advance to the next src row DBRA D3,@mid DBRA D6,NextChar TST.L D3 ;another char band then call retrieve!!! BMI.S doNextBand ;do the next char band MOVE.L (SP)+,A6 ;Restore Stack frame ptr BRA strDone ;no more chars to do… OverWord MOVE.W D2, D0 ;Use D0 to calc horz dest adjust LSR #5,D0 ;convert to longs ADD.W D0,D0 ;convert to words (Horz. offset) ADD.W D0,D0 ;convert to bytes (Horz. offset) ADD.W D0,A0 ;Add in the horz offset CMP.W #32,D3 ;bigger than 32? BGT.S overLong ;Got more than one long AND.W #31,D2 ;allow a shift of 0 to 31 ADD.W D2, D3 ;shift + bitwidth CMP.W #32,D3 ;bigger than 32? BGT.S bigLong ;Shift and width is greater than a long ;———————————————————————— ; long Blit ;Regs used: ; D0 = BlitSource.l ; D2 = ShiftAdjust.w ; D3 = Scan.w ; D6 = charNum.w ; D7 = destRow.w ; A0 = DestPtr.l ; A2 = SourcePtr.l ; We fit inside a long with the shift long MOVE.W glyph.scan(A6), D3 ;Height of character SUBQ #1,D3 @mid MOVE.L (A2)+,D0 ;this particular example is a or mode LSR.L D2,D0 ;shift into place OR.L D0,(A0) ;add the bits ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid DBRA D6,NextChar TST.L D3 ;another char band then call retrieve!!! BMI.S doNextBand ;do the next char band MOVE.L (SP)+,A6 ;Restore Stack frame ptr BRA strDone ;no more chars to do… ;———————————————————————— ; bigLong Blit ;Regs used: ; D0 = BlitSource.l ; D1 = Left Shift.w ; D2 = Right Shift.w ; D3 = Scan.w ; D6 = charNum.w ; D7 = destRow.w ; A0 = DestPtr.l ; A2 = SourcePtr.l bigLong MOVE.L D1, -(SP) ;save d1 MOVE.W glyph.scan(A6), D3 ;Height of character SUBQ.W #1,D3 MOVE.W #32, D1 ;get number of long bits SUB.W D2, D1 ;Get the shift next long shift SUBQ.W #4, D7 ;Advance one long less for dest @mid MOVE.L (A2),D0 ;this particular example is a or mode LSR.L D2,D0 ;shift into place OR.L D0,(A0)+ ;add the bits MOVE.L (A2)+,D0 ;get second piece of the long LSL.L D1,D0 ;shift into place OR.L D0,(A0) ;Next long ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid ADDQ.W #4, D7 ;restore true value of dest row bytes MOVE.L (SP)+, D1 ;restore d1 DBRA D6,NextChar TST.L D3 ;another char band then call retrieve!!! BMI.S doNextBand ;do the next char band MOVE.L (SP)+,A6 ;Restore Stack frame ptr BRA strDone ;no more chars to do… ;———————————————————————— ; bigLong Blit ;Regs used: ; D0 = BlitSource.l ; D1 = Left Shift.w ; D2 = Right Shift.w ; D3 = Scan.w ; D5 = longsInScan.w ; D6 = charNum.w & rowBytesAdjust.w ; D7 = destRow.w ; A0 = DestPtr.l ; A2 = SourcePtr.l ; A6 = copy of longsInScan.w overLong ;Many Longs to move MOVEM.L D1/D5, -(SP) ;save regs SWAP D6 ;less longs to advance dest MOVE.W glyph.scan(A6), D3 ;Height of character SUBQ.W #1,D3 MOVE.W glyph.byteWidth+2(A6),D6 ;src byte width in D5 SUB.W D6, D7 ;Advance one long less for dest MOVE.W D6, D5 ;# of src bytes LSR #2, D5 ;# of longs for inner loop SUBQ.W #1, D5 ;init for dbra MOVE.W D5, A6 ;Keep a copy for re-initialization AND.W #31,D2 ;allow a shift of 0 to 31 MOVE.W #32, D1 ;get number of long bits SUB.W D2, D1 ;Get the shift next long shift @mid MOVE.L (A2),D0 ;this particular example is a or mode LSR.L D2,D0 ;shift into place OR.L D0,(A0)+ ;add the bits MOVE.L (A2)+,D0 ;get second piece of the long LSL.L D1,D0 ;shift into place OR.L D0,(A0) ;Next long DBRA D5,@mid ;# of longs in a scan line MOVE.W A6, D5 ;# of src bytes ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid ADD.W D6, D7 ;restore true value of dest row bytes SWAP D6 ;Restore # of chars MOVEM.L (SP)+, D1/D5 ;restore regs DBRA D6,NextChar TST.L D3 ;another char band then call retrieve!!! BMI.S doNextBand ;do the next char band MOVE.L (SP)+,A6 ;Restore Stack frame ptr BRA strDone ;no more chars to do… ;———————————————————————————————————————————————————————————————————————————————————————————————— ; MULTI-bit blit routine CHOICE ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Registers Use: ; D0 = scratch A0 = scratch ; D1 = bitdepth A1 = TextPtr.l ; D2 = shift.w A2 = bitsPtr.l ; D3 = scan.w A3 = glyphArray.l ; D4 = charLoc.l A4 = widTabPtr.l ; D5 = char*4.w & longInScan A5 = DestPtr.l ; D6 = #chars.w A6 = stack frame.l ; D7 = destRowBytes.w A7 = stack pointer.l ;———————————————————————————————————————————————————————————————————————————————————————————————— IF 0 THEN blitJmpTable DC.W word-blitJmpTable ;0 1-bit blit functions DC.W bigWord-blitJmpTable ;2 DC.W long-blitJmpTable ;4 DC.W bigLong-blitJmpTable ;6 DC.W overLong-blitJmpTable ;8 DC.W word2-blitJmpTable ;0 2-bit blit functions DC.W bigWord2-blitJmpTable ;2 DC.W long2-blitJmpTable ;4 DC.W bigLong2-blitJmpTable ;6 DC.W overLong2-blitJmpTable ;8 DC.W word4-blitJmpTable ;0 4-bit blit functions DC.W bigWord4-blitJmpTable ;2 DC.W long4-blitJmpTable ;4 DC.W bigLong4-blitJmpTable ;6 DC.W overLong4-blitJmpTable ;8 DC.W word8-blitJmpTable ;0 8-bit blit functions DC.W bigWord8-blitJmpTable ;2 DC.W long8-blitJmpTable ;4 DC.W bigLong8-blitJmpTable ;6 DC.W overLong8-blitJmpTable ;8 DC.W word16-blitJmpTable ;0 16-bit blit functions DC.W bigWord16-blitJmpTable ;2 DC.W long16-blitJmpTable ;4 DC.W bigLong16-blitJmpTable ;6 DC.W overLong16-blitJmpTable ;8 DC.W word32-blitJmpTable ;0 32-bit blit functions DC.W bigWord32-blitJmpTable ;2 DC.W long32-blitJmpTable ;4 DC.W bigLong32-blitJmpTable ;6 DC.W overLong32-blitJmpTable ;8 ENDIF deepChar ;———————————————————————————————- ; Set up blit function pointers ;———————————————————————————————- MOVEQ #0, D7 ; MOVE.W destDepth(A6), D0 ;get depth in D0 CMP.W #8, D0 ;is it 8 deep BNE @chk2 ;eight deep will not use function ptrs MOVE.W #3, destShift(A6) ;Shift for multiply BRA @doneFuncPtrs @chk2 MOVEQ #-1, D7 ;negate is 1 bit flag for faster check CMP.W #2, D0 ;is it 2 deep BNE.S @chk4 MOVE.W #1, destShift(A6) ;Shift for multiply LEA word2, A0 ;pointer to the function MOVE.L A0, wordFunc(A6) ;save it away LEA bigWord2, A0 ;pointer to the function MOVE.L A0, bigWordFunc(A6) ;save it away LEA long2, A0 ;pointer to the function MOVE.L A0, longFunc(A6) ;save it away LEA bigLong2, A0 ;pointer to the function MOVE.L A0, bigLongFunc(A6) ;save it away LEA overLong2, A0 ;pointer to the function MOVE.L A0, overLongFunc(A6) ;save it away BRA @doneFuncPtrs @chk4 CMP.W #4, D0 ;is it 4 deep BNE.S @chk16 MOVE.W #2, destShift(A6) ;Shift for multiply LEA word4, A0 ;pointer to the function MOVE.L A0, wordFunc(A6) ;save it away LEA bigWord4, A0 ;pointer to the function MOVE.L A0, bigWordFunc(A6) ;save it away LEA long4, A0 ;pointer to the function MOVE.L A0, longFunc(A6) ;save it away LEA bigLong4, A0 ;pointer to the function MOVE.L A0, bigLongFunc(A6) ;save it away LEA overLong4, A0 ;pointer to the function MOVE.L A0, overLongFunc(A6) ;save it away BRA @doneFuncPtrs @chk16 CMP.W #16, D0 ;is it 16 deep BNE.S @chk32 MOVE.W #4, destShift(A6) ;Shift for multiply LEA word16, A0 ;pointer to the function MOVE.L A0, wordFunc(A6) ;save it away LEA bigWord16, A0 ;pointer to the function MOVE.L A0, bigWordFunc(A6) ;save it away LEA long16, A0 ;pointer to the function MOVE.L A0, longFunc(A6) ;save it away LEA bigLong16, A0 ;pointer to the function MOVE.L A0, bigLongFunc(A6) ;save it away LEA overLong16, A0 ;pointer to the function MOVE.L A0, overLongFunc(A6) ;save it away BRA.S @doneFuncPtrs @chk32 MOVE.W #5, destShift(A6) ;Shift for multiply LEA word32, A0 ;pointer to the function MOVE.L A0, wordFunc(A6) ;save it away LEA bigWord32, A0 ;pointer to the function MOVE.L A0, bigWordFunc(A6) ;save it away LEA long32, A0 ;pointer to the function MOVE.L A0, longFunc(A6) ;save it away LEA bigLong32, A0 ;pointer to the function MOVE.L A0, bigLongFunc(A6) ;save it away LEA overLong32, A0 ;pointer to the function MOVE.L A0, overLongFunc(A6) ;save it away @doneFuncPtrs MOVE.W bufRow(A6), D7 ;Copy of rowbytes BRA.S NextChar8 doNextBand8 ADDQ.W #1, D6 ;bump count since we are banding MOVE.W glyphID(A6), D3 ;put glyphID into d3 for renderIt BSR renderIt ;Get the glyph BEQ gotGlyph8 ;go blit it BRA skipIt8 renderIt8 BTST.L #30, D0 ;Check if there is an error BNE skipChar8 ;Still an error so skip it <57-CEL> BSR renderIt ;Get the glyph BEQ gotGlyph8 ;go blit it skipChar8 ADD.L 0(A4,D3*4),D4 ;Add fixed point width <57-CEL> ADD.L characterExtra(A6),D4 ;add in character extra, if any BRA.S decCharCount8 ;continue to nextChar spaceChar8 ADD.L 128(A4), D4 ;Advance a space decCharCount8 SUBQ.W #1, D6 BLT strDone NextChar8 MOVE.W #0,D3 MOVE.B (A1)+,D3 ;get the next character if (hasDoubleByte) then move.b d3,highByte(a6) ; save the high byte for later use clr.b lowByte(a6) ; clear the low byte for now tst.l encodingTable(a6) ; is this a double byte font? beq.s @normalFont ; no, skip low byte loading move.l encodingTable(a6),a0 ; load the encoding table tst.b 0(a0,d3.w) ; is this a double byte character? beq.s @normalCharacter ; no, skip low byte loading tst.w d6 ; more bytes left in text? ble.s @remapCharacterToNull ; no, remap the high byte subq.w #1,d6 ; decrement the character count clr.w d0 ; clear high byte of low word move.b (a1)+,d0 ; grab the low byte and bump the text pointer adda.w #256,a0 ; offset to the low byte encoding table tst.b 0(a0,d0.w) ; is this a valid low byte? beq @remapCharacterToNull ; no, remap the high byte character move.b d0,lowByte(a6) ; save the valid low byte for later use bra @normalCharacter ; continue normally @remapCharacterToNull move.b #1,d3 ; remap the high byte character to the missing glyph move.b d3,highByte(a6) ; save the remapped value in the stack @normalCharacter @normalFont endif CMP.B #32,D3 ;IS IT A SPACE ? BEQ spaceChar8 ;Skip the char extra MOVE.L 0(A3,D3*4),D0 ;Get offset to glyph in D0 BLE renderIt8 ;Must render it ADD.L D5, D0 ;Add in cacheptr address MOVE.L D0, A0 ;glyphrec = cache + offset if (hasDoubleByte) then clr.l d0 ; clear a long for the character code move.b lowByte(a6),d0 ; double byte character? beq.s @haveGlyphRecord ; no, skip this move.l 0(a0,d0.w*4),d0 ; load glyph record offset ble renderIt8 ; render if error or not cached add.l d5,d0 ; convert offset to pointer move.l d0,a0 ; load glyph record pointer @haveGlyphRecord endif LEA glyph.cacheData(A0), A2 ;Get address gotGlyph8 MOVE.L D4,D2 ;charloc in D2 SWAP D2 ;Just use integer portion ADD.W glyph.devLSB(A0), D2 ;Get integralized left side bearing ;••• spot for skipping advance if char banding!!! TST.L D3 ;do not advance since the is more of char BMI.S @skipAdvance ;another band of char ADD.L 0(A4,D3*4),D4 ;Add fixed point width ADD.L characterExtra(A6),D4 ;add in character extra, if any @skipAdvance MOVE.W glyph.scan(A0), D3 ;Height of character SUBQ.W #1,D3 MOVE.W glyph.adjustTop(A0), D0 ;Subtract the YMax MULS.W D7,D0 ;Vertical offset value MOVE.W glyph.bitWidth(A0),D1 ;shift count plus width TST.L D7 ;if negative then multi-bit BLT notEight ;Multi-depth blits CMP.W #16,D1 ;bigger than 16? BGT overWord8 ;We are bigger than a word MOVEM.L D4/D6, -(SP) ;Save regs MOVEQ #$F, D4 ;Low 4-bit mask MOVE.L A5,A0 ;get top screen destination copy ADD.L D0,A0 ;Add in the vert offset MOVEQ #0, D0 ;long ready MOVE.W D2, D0 ;Use D0 to calc horz dest adjust LSR.W #4,D0 ;convert to words ADD.W D0,D0 ;convert to bytes (Horz. offset) MOVE.W destShift(A6), D6 ;Get the destination shift value LSL.W D6, D0 ;Multiply by dest depth ADD.W D0,A0 ;Add in the horz offset AND.W #15,D2 ;allow a shift of 0 to 15 ADD.W D2,D1 ;shift + bitwidth CMP.W #16,D1 ;bigger than 16? BGT bigWord8 ;——————————————————— ;blitting loops ;——————————————————— word8 ADD.L #12, A0 ;Advance to last long of scan line @mid MOVE.W (A2)+,D0 ;this particular example is or mode LSR D2,D0 ;shift into place MOVE.W D0, D1 ;Get a copy AND.W D4, D1 ;Get lower four bits BEQ.S @1 ;nothing to blit MOVE.L bitTable8(D1*4), D1 ;Add the bits OR.L D1, (A0) ;Add the bits @1 LSR.W #4, D0 ;Next four bits MOVE.W D0, D1 ;Get a copy AND.W D4, D1 ;Get lower four bits BEQ.S @2 ;nothing to blit MOVE.L bitTable8(D1*4), D1 ;Add the bits OR.L D1, -4(A0) ;Add the bits @2 LSR.W #4, D0 ;Next four bits MOVE.B D0, D1 ;Get a copy AND.W D4, D1 ;Get lower four bits BEQ.S @3 ;nothing to blit MOVE.L bitTable8(D1*4), D1 ;Add the bits OR.L D1, -8(A0) ;Add the bits @3 LSR.W #4, D0 ;Next four bits BEQ.S @4 ;nothing to blit MOVE.L bitTable8(D0*4), D1 ;Add the bits OR.L D1, -12(A0) ;Add the bits @4 ADD D7,A0 ;advance to the next dest row DBRA D3,@mid MOVEM.L (SP)+, D4/D6 ;Save regs skipIt8 DBRA D6,NextChar8 TST.L D3 ;another char band then call retrieve!!! BMI.S doNextBand8 ;do the next char band BRA strDone ;no more chars to do… MACRO _blit8long MOVE.W D0, D1 ;Get a copy AND.W D4, D1 ;Get lower four bits BEQ.S @1 ;nothing to blit MOVE.L 0(A1, D1*4), D1 ;Add the bits OR.L D1, (A0) ;Add the bits @1 LSR.W #4, D0 ;Next four bits MOVE.W D0, D1 ;Get a copy AND.W D4, D1 ;Get lower four bits BEQ.S @2 ;nothing to blit MOVE.L 0(A1, D1*4), D1 ;Add the bits OR.L D1, -4(A0) ;Add the bits @2 LSR.W #4, D0 ;Next four bits MOVE.W D0, D1 ;Get a copy AND.W D4, D1 ;Get lower four bits BEQ.S @3 ;nothing to blit MOVE.L 0(A1, D1*4), D1 ;Add the bits OR.L D1, -8(A0) ;Add the bits @3 LSR.W #4, D0 ;Next four bits BEQ.S @4 ;nothing to blit MOVE.L 0(A1, D0*4), D1 ;Add the bits OR.L D1, -12(A0) ;Add the bits @4 SWAP D0 ;Next four bits MOVE.W D0, D1 ;Get a copy AND.W D4, D1 ;Get lower four bits BEQ.S @5 ;nothing to blit MOVE.L 0(A1, D1*4), D1 ;Add the bits OR.L D1, -16(A0) ;Add the bits @5 LSR.W #4, D0 ;Next four bits MOVE.W D0, D1 ;Get a copy AND.W D4, D1 ;Get lower four bits BEQ.S @6 ;nothing to blit MOVE.L 0(A1, D1*4), D1 ;Add the bits OR.L D1, -20(A0) ;Add the bits @6 LSR.W #4, D0 ;Next four bits MOVE.W D0, D1 ;Get a copy AND.W D4, D1 ;Get lower four bits BEQ.S @7 ;nothing to blit MOVE.L 0(A1, D1*4), D1 ;Add the bits OR.L D1, -24(A0) ;Add the bits @7 LSR.W #4, D0 ;Next four bits BEQ.S @8 ;nothing to blit MOVE.L 0(A1, D0*4), D1 ;Add the bits OR.L D1, -28(A0) ;Add the bits @8 ENDM align 4 ;Make long word aligned <54> bitTable8 DC.L $00000000, $000000FF, $0000FF00, $0000FFFF, $00FF0000, $00FF00FF, $00FFFF00, $00FFFFFF DC.L $FF000000, $FF0000FF, $FF00FF00, $FF00FFFF, $FFFF0000, $FFFF00FF, $FFFFFF00, $FFFFFFFF bigWord8 ; here, the character spans a word boundary, so must be handled with a long loop on 68K machines MOVE.L A1, -(SP) ;Save regs LEA bitTable8, A1 ;Table to the blit longs ADD.L #28, A0 ;Advance to last long @mid MOVE.L (A2),D0 ;this particular example is a copy mode CLR D0 ;clear the low word LSR.L D2,D0 ;shift into place _blit8long ;move src long ADD D7,A0 ;advance to the next dest row ADD #2,A2 ;advance to the next src row DBRA D3,@mid MOVE.L (SP)+, A1 ;Restore regs MOVEM.L (SP)+, D4/D6 ;Save regs DBRA D6,NextChar8 TST.L D3 ;another char band then call retrieve!!! BMI.S doNextBand8 ;do the next char band BRA strDone ;no more chars to do… overWord8 CMP.W #32,D1 ;bigger than 32? BGT overLong8 ;Got more than one long MOVEM.L D4/D6/D7/A1, -(SP) ;Save regs MOVEQ #$F, D4 ;Low 4-bit mask MOVE.L A5,A0 ;get top screen destination copy ADD.L D0,A0 ;Add in the vert offset MOVEQ #0, D0 ;long ready MOVE.W D2, D0 ;Use D0 to calc horz dest adjust LSR #5,D0 ;convert to longs ADD.W D0,D0 ;convert to bytes (Horz. offset) ADD.W D0,D0 ;convert to bytes (Horz. offset) MOVE.W destShift(A6), D6 ;Get the destination shift value LSL.W D6, D0 ;Multiply by dest depth ADD.W D0,A0 ;Add in the horz offset AND.W #31,D2 ;allow a shift of 0 to 31 ADD.W D2, D1 ;shift + bitwidth CMP.W #32,D1 ;bigger than 32? BGT bigLong8 ;Shift and width is greater than a long ; We fit inside a long with the shift long8 LEA bitTable8, A1 ;Table to the blit longs ADD.L #28, A0 ;Advance to last long of scan line @mid MOVE.L (A2)+,D0 ;this particular example is a or mode LSR.L D2,D0 ;shift into place _blit8long ;move src long ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid MOVEM.L (SP)+, D4/D6/D7/A1 ;Restore regs DBRA D6,NextChar8 TST.L D3 ;another char band then call retrieve!!! BMI.S doNextBand8 ;do the next char band BRA strDone ;no more chars to do… bigLong8 MOVE.W #32, D1 ;get number of long bits SUB.W D2, D1 ;Get the shift next long shift SWAP D1 ;rightShift in high-word MOVE D2, D1 ;leftShift in low-word MOVE.L D1, D2 ;Leave shift in D2 LEA bitTable8, A1 ;Table to the blit longs ADD.L #28, A0 ;Advance to last long of scan line SUB.W #32, D7 ;Advance one long less for dest @mid MOVE.L (A2),D0 ;this particular example is a or mode LSR.L D2,D0 ;shift into place _blit8long ;move src long SWAP D2 ;get the rightShift MOVE.L (A2)+,D0 ;get second piece of the long LSL.L D2,D0 ;shift into place ADD.W #32, A0 ;next long _blit8long ;move src long SWAP D2 ;restore the leftShift ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid MOVEM.L (SP)+, D4/D6/D7/A1 ;Save regs DBRA D6,NextChar8 TST.L D3 ;another char band then call retrieve!!! BMI.S doNextBand8 ;do the next char band BRA strDone ;no more chars to do… overLong8 ;Many Longs to move MOVEM.L D4-D7/A1/A4, -(SP) ;Save regs MOVEQ #$F, D4 ;Low 4-bit mask SWAP D6 ;less longs to advance dest MOVE.W destShift(A6), D1 ;Get the destination shift value MOVE.W glyph.byteWidth+2(A0),D5 ;# of src bytes MOVEQ #4, D6 ;Calculate less long adjustment LSR #2, D5 ;# of longs for inner loop LSL D1, D6 ;Long less adjustment MULU D5, D6 ;multiply by number of longs SUB.W D6, D7 ;Advance one long less for dest SUBQ.W #1, D5 ;init for dbra MOVE.W D5, A4 ;Keep a copy for re-initialization MOVE.L A5,A0 ;get top screen destination copy ADD.L D0,A0 ;Add in the vert offset MOVEQ #0, D0 ;long ready MOVE.W D2, D0 ;Use D0 to calc horz dest adjust LSR #5,D0 ;convert to longs ADD.W D0,D0 ;convert to words (Horz. offset) ADD.W D0,D0 ;convert to bytes (Horz. offset) LSL.W D1, D0 ;Multiply by dest depth ADD.W D0,A0 ;Add in the horz offset AND.W #31,D2 ;allow a shift of 0 to 31 MOVE.W #32, D1 ;get number of long bits SUB.W D2, D1 ;Get the shift next long shift SWAP D1 ;rightShift in high-word MOVE D2, D1 ;leftShift in low-word MOVE.L D1, D2 ;Leave shift in D2 LEA bitTable8, A1 ;Table to the blit longs ADD.L #28, A0 ;Advance to last long of scan line @mid MOVE.L (A2),D0 ;this particular example is a or mode LSR.L D2,D0 ;shift into place _blit8long ;move src long SWAP D2 ;get the rightShift MOVE.L (A2)+,D0 ;get second piece of the long LSL.L D2,D0 ;shift into place ADD.W #32, A0 ;next long _blit8long ;move src long SWAP D2 ;restore the leftShift DBRA D5,@mid ;# of longs in a scan line MOVE.W A4, D5 ;# of src bytes ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid ADD.W D6, D7 ;Next row MOVEM.L (SP)+, D4-D7/A1/A4 ;Save regs DBRA D6,NextChar8 TST.L D3 ;another char band then call retrieve!!! BMI.S doNextBand8 ;do the next char band BRA strDone ;no more chars to do… ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Not eight bit but it is multi bit ;———————————————————————————————————————————————————————————————————————————————————————————————— notEight MOVEM.L D4-D7/A1/A4, -(SP) ;Save regs CMP.W #16,D1 ;bigger than 16? BGT.S @overWord ;We are bigger than a word MOVE.L A5,A0 ;get top screen destination copy ADD.L D0,A0 ;Add in the vert offset MOVEQ #0, D0 ;long ready MOVE.W D2, D0 ;Use D0 to calc horz dest adjust LSR.W #4,D0 ;convert to words ADD.W D0,D0 ;convert to bytes (Horz. offset) MOVE.W destShift(A6), D6 ;Get the destination shift value LSL.W D6, D0 ;Multiply by dest depth ADD.W D0,A0 ;Add in the horz offset AND.W #15,D2 ;allow a shift of 0 to 15 ADD.W D2,D1 ;shift + bitwidth CMP.W #16,D1 ;bigger than 16? BGT.S @bigWord MOVE.L wordFunc(A6), A1 ;point to blit function BRA @blitIt @bigWord MOVE.L bigWordFunc(A6), A1 ;point to blit function BRA @blitIt @overWord CMP.W #32,D1 ;bigger than 32? BGT.S @overLong ;Got more than one long MOVE.L A5,A0 ;get top screen destination copy ADD.L D0,A0 ;Add in the vert offset MOVEQ #0, D0 ;long ready MOVE.W D2, D0 ;Use D0 to calc horz dest adjust LSR #5,D0 ;convert to longs ADD.W D0,D0 ;convert to bytes (Horz. offset) ADD.W D0,D0 ;convert to bytes (Horz. offset) MOVE.W destShift(A6), D6 ;Get the destination shift value LSL.W D6, D0 ;Multiply by dest depth ADD.W D0,A0 ;Add in the horz offset AND.W #31,D2 ;allow a shift of 0 to 31 ADD.W D2, D1 ;shift + bitwidth CMP.W #32,D1 ;bigger than 32? BGT.S @bigLong ;Shift and width is greater than a long MOVE.L longFunc(A6), A1 ;point to blit function BRA.S @blitIt @bigLong MOVE.W #32, D1 ;get number of long bits SUB.W D2, D1 ;Get the shift next long shift SWAP D1 ;rightShift in high-word MOVE D2, D1 ;leftShift in low-word MOVE.L D1, D2 ;Leave shift in D2 MOVE.L bigLongFunc(A6), A1 ;point to blit function BRA.S @blitIt @overLong SWAP D6 ;less longs to advance dest MOVE.W destShift(A6), D1 ;Get the destination shift value MOVE.W glyph.byteWidth+2(A0),D5 ;# of src bytes MOVEQ #4, D6 ;Calculate less long adjustment LSR #2, D5 ;# of longs for inner loop LSL D1, D6 ;Long less adjustment MULU D5, D6 ;multiply by number of longs SUB.W D6, D7 ;Advance one long less for dest SUBQ.W #1, D5 ;init for dbra MOVE.W D5, A4 ;Keep a copy for re-initialization MOVE.L A5,A0 ;get top screen destination copy ADD.L D0,A0 ;Add in the vert offset MOVEQ #0, D0 ;long ready MOVE.W D2, D0 ;Use D0 to calc horz dest adjust LSR #5,D0 ;convert to longs ADD.W D0,D0 ;convert to words (Horz. offset) ADD.W D0,D0 ;convert to bytes (Horz. offset) LSL.W D1, D0 ;Multiply by dest depth ADD.W D0,A0 ;Add in the horz offset AND.W #31,D2 ;allow a shift of 0 to 31 MOVE.W #32, D1 ;get number of long bits SUB.W D2, D1 ;Get the shift next long shift SWAP D1 ;rightShift in high-word MOVE D2, D1 ;leftShift in low-word MOVE.L D1, D2 ;Leave shift in D2 MOVE.L overLongFunc(A6), A1 ;point to blit function @blitIt JSR (A1) ;go blit it MOVEM.L (SP)+, D4-D7/A1/A4 ;Save regs DBRA D6,NextChar8 TST.L D3 ;another char band then call retrieve!!! BMI.S doNextBand8 ;do the next char band BRA strDone ;no more chars to do… ;———————————————————————————————————————————————————————————————————————————————————————————————— ; 2-bit NEW FAST blit loop ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Registers Use: ; D0 = scratch A0 = scratch ; D1 = scratch A1 = TextPtr.l ; D2 = shift.w A2 = bitsPtr.l ; D3 = scan.w A3 = glyphArray.l ; D4 = charLoc.l A4 = widTabPtr.l ; D5 = char*4.w A5 = DestPtr.l ; D6 = #chars.w A6 = stack frame.l ; D7 = rowBytes.w A7 = stack pointer.l ;———————————————————————————————————————————————————————————————————————————————————————————————— align 4 ;Make long word aligned <54> Table2 DC $0000,$0003,$000c,$000f,$0030,$0033,$003c,$003f DC $00c0,$00c3,$00cc,$00cf,$00f0,$00f3,$00fc,$00ff DC $0300,$0303,$030c,$030f,$0330,$0333,$033c,$033f DC $03c0,$03c3,$03cc,$03cf,$03f0,$03f3,$03fc,$03ff DC $0c00,$0c03,$0c0c,$0c0f,$0c30,$0c33,$0c3c,$0c3f DC $0cc0,$0cc3,$0ccc,$0ccf,$0cf0,$0cf3,$0cfc,$0cff DC $0f00,$0f03,$0f0c,$0f0f,$0f30,$0f33,$0f3c,$0f3f DC $0fc0,$0fc3,$0fcc,$0fcf,$0ff0,$0ff3,$0ffc,$0fff DC $3000,$3003,$300c,$300f,$3030,$3033,$303c,$303f DC $30c0,$30c3,$30cc,$30cf,$30f0,$30f3,$30fc,$30ff DC $3300,$3303,$330c,$330f,$3330,$3333,$333c,$333f DC $33c0,$33c3,$33cc,$33cf,$33f0,$33f3,$33fc,$33ff DC $3c00,$3c03,$3c0c,$3c0f,$3c30,$3c33,$3c3c,$3c3f DC $3cc0,$3cc3,$3ccc,$3ccf,$3cf0,$3cf3,$3cfc,$3cff DC $3f00,$3f03,$3f0c,$3f0f,$3f30,$3f33,$3f3c,$3f3f DC $3fc0,$3fc3,$3fcc,$3fcf,$3ff0,$3ff3,$3ffc,$3fff DC $c000,$c003,$c00c,$c00f,$c030,$c033,$c03c,$c03f DC $c0c0,$c0c3,$c0cc,$c0cf,$c0f0,$c0f3,$c0fc,$c0ff DC $c300,$c303,$c30c,$c30f,$c330,$c333,$c33c,$c33f DC $c3c0,$c3c3,$c3cc,$c3cf,$c3f0,$c3f3,$c3fc,$c3ff DC $cc00,$cc03,$cc0c,$cc0f,$cc30,$cc33,$cc3c,$cc3f DC $ccc0,$ccc3,$cccc,$cccf,$ccf0,$ccf3,$ccfc,$ccff DC $cf00,$cf03,$cf0c,$cf0f,$cf30,$cf33,$cf3c,$cf3f DC $cfc0,$cfc3,$cfcc,$cfcf,$cff0,$cff3,$cffc,$cfff DC $f000,$f003,$f00c,$f00f,$f030,$f033,$f03c,$f03f DC $f0c0,$f0c3,$f0cc,$f0cf,$f0f0,$f0f3,$f0fc,$f0ff DC $f300,$f303,$f30c,$f30f,$f330,$f333,$f33c,$f33f DC $f3c0,$f3c3,$f3cc,$f3cf,$f3f0,$f3f3,$f3fc,$f3ff DC $fc00,$fc03,$fc0c,$fc0f,$fc30,$fc33,$fc3c,$fc3f DC $fcc0,$fcc3,$fccc,$fccf,$fcf0,$fcf3,$fcfc,$fcff DC $ff00,$ff03,$ff0c,$ff0f,$ff30,$ff33,$ff3c,$ff3f DC $ffc0,$ffc3,$ffcc,$ffcf,$fff0,$fff3,$fffc,$ffff ;——————————————————— ;blitting loops ;——————————————————— MACRO _blitWord2 MOVE.B D0,D4 ;Get a copy LSR.W #8,D0 ;Next four bits MOVE.L 0(A1,D0*2),D0 ;Add the bits MOVE.W 0(A1,D4*2),D0 ;Add the bits OR.L D0,(A0) ;Add the bits ENDM MACRO _blitLong2 MOVE.B D0,D4 LSR.W #8,D0 ;Next bytes worth MOVE.L 0(A1,D0*2),D1 ;get the bits MOVE.W 0(A1,D4*2),D1 ;get the next word OR.L D1,(A0) ;Add the bits SWAP D0 ;High Word MOVE.B D0,D4 LSR.W #8,D0 ;Next bytes worth MOVE.L 0(A1,D0*2),D1 ;get the bits MOVE.W 0(A1,D4*2),D1 ;get the next word OR.L D1,-4(A0) ;Add the bits ENDM word2 LEA table2, A1 ;Table to the blit longs MOVEQ #0, D4 ;ready for blitloop @mid MOVE.W (A2)+,D0 ;this particular example is or mode LSR D2,D0 ;shift into place _blitWord2 ADD D7,A0 ;advance to the next dest row DBRA D3,@mid RTS bigWord2 ; here, the character spans a word boundary, so must be handled with a long loop on 68K machines MOVEQ #0, D4 ;ready for blitloop LEA table2, A1 ;Table to the blit longs ADD.L #4, A0 ;Advance to last long of scan line @mid2 MOVE.L (A2),D0 ;this particular example is a copy mode CLR D0 ;clear the low word LSR.L D2,D0 ;shift into place _blitLong2 ;blit one source long to dest ADD D7,A0 ;advance to the next dest row ADD #2,A2 ;advance to the next src row DBRA D3,@mid2 RTS long2 ; We fit inside a long with the shift MOVEQ #0, D4 ;ready for blitloop LEA table2, A1 ;Table to the blit longs ADD.L #4, A0 ;Advance to last long of scan line @mid MOVE.L (A2)+,D0 ;this particular example is a or mode LSR.L D2,D0 ;shift into place _blitLong2 ;blit one source long to dest ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid RTS bigLong2 MOVEQ #0, D4 ;ready for blitloop LEA table2, A1 ;Table to the blit longs ADD.L #4, A0 ;Advance to last long of scan line SUBQ.W #8, D7 ;Advance one long less for dest @mid MOVE.L (A2),D0 ;this particular example is a or mode LSR.L D2,D0 ;shift into place _blitLong2 ;blit one source long to dest SWAP D2 ;get the rightShift MOVE.L (A2)+,D0 ;get second piece of the long LSL.L D2,D0 ;shift into place ADDQ.W #8, A0 ;next long _blitLong2 ;blit one source long to dest SWAP D2 ;restore the leftShift ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid RTS overLong2 ;Many Longs to move MOVEQ #0, D4 ;ready for blitloop LEA table2, A1 ;Table to the blit longs ADD.L #4, A0 ;Advance to last long of scan line @mid MOVE.L (A2),D0 ;this particular example is a or mode LSR.L D2,D0 ;shift into place _blitLong2 ;blit one source long to dest SWAP D2 ;get the rightShift ADDQ.W #8, A0 ;next long MOVE.L (A2)+,D0 ;get second piece of the long LSL.L D2,D0 ;shift into place _blitLong2 ;blit one source long to dest SWAP D2 ;restore the leftShift DBRA D5,@mid ;# of longs in a scan line MOVE.W A4, D5 ;# of src bytes ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid ADD.W D6,D7 ;re-adjust the rowbytes to it’s original value SWAP D6 ;Restore # of chars RTS ;———————————————————————————————————————————————————————————————————————————————————————————————— ; End 2-bit NEW FAST blit loop ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————————————— ; 4-bit NEW FAST blit loop ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Registers Use: ; D0 = scratch A0 = scratch ; D1 = scratch A1 = TextPtr.l ; D2 = shift.w A2 = bitsPtr.l ; D3 = scan.w A3 = glyphArray.l ; D4 = charLoc.l A4 = widTabPtr.l ; D5 = char*4.w A5 = DestPtr.l ; D6 = #chars.w A6 = stack frame.l ; D7 = rowBytes.w A7 = stack pointer.l ;———————————————————————————————————————————————————————————————————————————————————————————————— ;——————————————————— ;blitting loops ;——————————————————— align 4 ;Make long word aligned <54> TABLE4 DC.L $00000000,$0000000F,$000000F0,$000000FF ;QUADRUPLING TABLE DC.L $00000F00,$00000F0F,$00000FF0,$00000FFF DC.L $0000F000,$0000F00F,$0000F0F0,$0000F0FF DC.L $0000FF00,$0000FF0F,$0000FFF0,$0000FFFF DC.L $000F0000,$000F000F,$000F00F0,$000F00FF ;QUADRUPLING TABLE DC.L $000F0F00,$000F0F0F,$000F0FF0,$000F0FFF DC.L $000FF000,$000FF00F,$000FF0F0,$000FF0FF DC.L $000FFF00,$000FFF0F,$000FFFF0,$000FFFFF DC.L $00F00000,$00F0000F,$00F000F0,$00F000FF ;QUADRUPLING TABLE DC.L $00F00F00,$00F00F0F,$00F00FF0,$00F00FFF DC.L $00F0F000,$00F0F00F,$00F0F0F0,$00F0F0FF DC.L $00F0FF00,$00F0FF0F,$00F0FFF0,$00F0FFFF DC.L $00FF0000,$00FF000F,$00FF00F0,$00FF00FF ;QUADRUPLING TABLE DC.L $00FF0F00,$00FF0F0F,$00FF0FF0,$00FF0FFF DC.L $00FFF000,$00FFF00F,$00FFF0F0,$00FFF0FF DC.L $00FFFF00,$00FFFF0F,$00FFFFF0,$00FFFFFF DC.L $0F000000,$0F00000F,$0F0000F0,$0F0000FF ;QUADRUPLING TABLE DC.L $0F000F00,$0F000F0F,$0F000FF0,$0F000FFF DC.L $0F00F000,$0F00F00F,$0F00F0F0,$0F00F0FF DC.L $0F00FF00,$0F00FF0F,$0F00FFF0,$0F00FFFF DC.L $0F0F0000,$0F0F000F,$0F0F00F0,$0F0F00FF ;QUADRUPLING TABLE DC.L $0F0F0F00,$0F0F0F0F,$0F0F0FF0,$0F0F0FFF DC.L $0F0FF000,$0F0FF00F,$0F0FF0F0,$0F0FF0FF DC.L $0F0FFF00,$0F0FFF0F,$0F0FFFF0,$0F0FFFFF DC.L $0FF00000,$0FF0000F,$0FF000F0,$0FF000FF ;QUADRUPLING TABLE DC.L $0FF00F00,$0FF00F0F,$0FF00FF0,$0FF00FFF DC.L $0FF0F000,$0FF0F00F,$0FF0F0F0,$0FF0F0FF DC.L $0FF0FF00,$0FF0FF0F,$0FF0FFF0,$0FF0FFFF DC.L $0FFF0000,$0FFF000F,$0FFF00F0,$0FFF00FF ;QUADRUPLING TABLE DC.L $0FFF0F00,$0FFF0F0F,$0FFF0FF0,$0FFF0FFF DC.L $0FFFF000,$0FFFF00F,$0FFFF0F0,$0FFFF0FF DC.L $0FFFFF00,$0FFFFF0F,$0FFFFFF0,$0FFFFFFF DC.L $F0000000,$F000000F,$F00000F0,$F00000FF ;QUADRUPLING TABLE DC.L $F0000F00,$F0000F0F,$F0000FF0,$F0000FFF DC.L $F000F000,$F000F00F,$F000F0F0,$F000F0FF DC.L $F000FF00,$F000FF0F,$F000FFF0,$F000FFFF DC.L $F00F0000,$F00F000F,$F00F00F0,$F00F00FF ;QUADRUPLING TABLE DC.L $F00F0F00,$F00F0F0F,$F00F0FF0,$F00F0FFF DC.L $F00FF000,$F00FF00F,$F00FF0F0,$F00FF0FF DC.L $F00FFF00,$F00FFF0F,$F00FFFF0,$F00FFFFF DC.L $F0F00000,$F0F0000F,$F0F000F0,$F0F000FF ;QUADRUPLING TABLE DC.L $F0F00F00,$F0F00F0F,$F0F00FF0,$F0F00FFF DC.L $F0F0F000,$F0F0F00F,$F0F0F0F0,$F0F0F0FF DC.L $F0F0FF00,$F0F0FF0F,$F0F0FFF0,$F0F0FFFF DC.L $F0FF0000,$F0FF000F,$F0FF00F0,$F0FF00FF ;QUADRUPLING TABLE DC.L $F0FF0F00,$F0FF0F0F,$F0FF0FF0,$F0FF0FFF DC.L $F0FFF000,$F0FFF00F,$F0FFF0F0,$F0FFF0FF DC.L $F0FFFF00,$F0FFFF0F,$F0FFFFF0,$F0FFFFFF DC.L $FF000000,$FF00000F,$FF0000F0,$FF0000FF ;QUADRUPLING TABLE DC.L $FF000F00,$FF000F0F,$FF000FF0,$FF000FFF DC.L $FF00F000,$FF00F00F,$FF00F0F0,$FF00F0FF DC.L $FF00FF00,$FF00FF0F,$FF00FFF0,$FF00FFFF DC.L $FF0F0000,$FF0F000F,$FF0F00F0,$FF0F00FF ;QUADRUPLING TABLE DC.L $FF0F0F00,$FF0F0F0F,$FF0F0FF0,$FF0F0FFF DC.L $FF0FF000,$FF0FF00F,$FF0FF0F0,$FF0FF0FF DC.L $FF0FFF00,$FF0FFF0F,$FF0FFFF0,$FF0FFFFF DC.L $FFF00000,$FFF0000F,$FFF000F0,$FFF000FF ;QUADRUPLING TABLE DC.L $FFF00F00,$FFF00F0F,$FFF00FF0,$FFF00FFF DC.L $FFF0F000,$FFF0F00F,$FFF0F0F0,$FFF0F0FF DC.L $FFF0FF00,$FFF0FF0F,$FFF0FFF0,$FFF0FFFF DC.L $FFFF0000,$FFFF000F,$FFFF00F0,$FFFF00FF ;QUADRUPLING TABLE DC.L $FFFF0F00,$FFFF0F0F,$FFFF0FF0,$FFFF0FFF DC.L $FFFFF000,$FFFFF00F,$FFFFF0F0,$FFFFF0FF DC.L $FFFFFF00,$FFFFFF0F,$FFFFFFF0,$FFFFFFFF MACRO _Blit4word MOVE.B D0,D4 BEQ.S @1 MOVE.L 0(A1,D4*4),D1 OR.L D1,(A0) @1 LSR.W #8,D0 BEQ.S @2 MOVE.L 0(A1,D0*4),D1 OR.L D1,-4(A0) @2 ENDM MACRO _Blit4long ;move src long MOVE.B D0, D4 ;Get a copy BEQ.S @1 ;nothing to blit MOVE.L 0(A1,D4*4), D1 ;Add the bits OR.L D1, (A0) ;Add the bits @1 LSR.W #8, D0 ;Next four bits BEQ.S @2 ;nothing to blit MOVE.L 0(A1,D0*4), D1 ;Add the bits OR.L D1, -4(A0) ;Add the bits @2 SWAP D0 MOVE.B D0, D4 ;Get a copy BEQ.S @3 ;nothing to blit MOVE.L 0(A1,D4*4), D1 ;Add the bits OR.L D1, -8(A0) ;Add the bits @3 LSR.W #8, D0 ;Next four bits BEQ.S @4 ;nothing to blit MOVE.L 0(A1,D0*4), D1 ;Add the bits OR.L D1, -12(A0) ;Add the bits @4 ENDM word4 MOVEQ #0, D4 ;ready for blit macro LEA table4, A1 ;Table to the blit longs ADD.L #4 , A0 ;Advance to last long of scan line @mid MOVE.W (A2)+,D0 ;this particular example is or mode LSR.W D2,D0 ;shift into place _Blit4word ADD D7,A0 ;advance to the next dest row DBRA D3,@mid RTS bigWord4 ; here, the character spans a word boundary, so must be handled with a long loop on 68K machines MOVEQ #0, D4 ;ready for blit macro LEA table4, A1 ;Table to the blit longs ADD.L #12, A0 ;Advance to last long of scan line @mid2 MOVE.L (A2),D0 ;this particular example is a copy mode CLR D0 ;clear the low word LSR.L D2,D0 ;shift into place _Blit4long ;move src long ADD D7,A0 ;advance to the next dest row ADD #2,A2 ;advance to the next src row DBRA D3,@mid2 RTS long4 ; We fit inside a long with the shift MOVEQ #0, D4 ;ready for blit macro LEA table4, A1 ;Table to the blit longs ADD.L #12, A0 ;Advance to last long of scan line @mid MOVE.L (A2)+,D0 ;this particular example is a or mode LSR.L D2,D0 ;shift into place _Blit4long ;move src long ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid RTS bigLong4 MOVEQ #0, D4 ;ready for blit macro LEA table4, A1 ;Table to the blit longs ADD.L #12, A0 ;Advance to last long of scan line SUB.W #16, D7 ;Advance one long less for dest @mid MOVE.L (A2),D0 ;this particular example is a or mode LSR.L D2,D0 ;shift into place _Blit4long ;move src long SWAP D2 ;get the rightShift MOVE.L (A2)+,D0 ;get second piece of the long LSL.L D2,D0 ;shift into place ADD.W #16, A0 ;next long _Blit4long ;move src long SWAP D2 ;restore the leftShift ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid RTS overLong4 ;Many Longs to move MOVEQ #0, D4 ;ready for blit macro LEA table4, A1 ;Table to the blit longs ADD.L #12, A0 ;Advance to last long of scan line @mid MOVE.L (A2),D0 ;this particular example is a or mode LSR.L D2,D0 ;shift into place _Blit4long ;move src long SWAP D2 ;get the rightShift ADD.W #16, A0 ;next long MOVE.L (A2)+,D0 ;get second piece of the long LSL.L D2,D0 ;shift into place _Blit4long ;move src long SWAP D2 ;restore the leftShift DBRA D5,@mid ;# of longs in a scan line MOVE.W A4, D5 ;# of src bytes ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid ADD.W D6, D7 ;restore true value of dest row bytes SWAP D6 ;Restore # of chars RTS ;———————————————————————————————————————————————————————————————————————————————————————————————— ; End 4-bit NEW FAST blit loop ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————————————— ; 16-bit NEW FAST blit loop ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Registers Use: ; D0 = scratch A0 = scratch ; D1 = scratch A1 = TextPtr.l ; D2 = shift.w A2 = bitsPtr.l ; D3 = scan.w A3 = glyphArray.l ; D4 = charLoc.l A4 = widTabPtr.l ; D5 = char*4.w A5 = DestPtr.l ; D6 = #chars.w A6 = stack frame.l ; D7 = rowBytes.w A7 = stack pointer.l ;———————————————————————————————————————————————————————————————————————————————————————————————— ;——————————————————— ;blitting loops ;——————————————————— MACRO _blit16word MOVEQ #1, D4 ;for inner loop @inner ADDX.W D0,D0 ;if extended then blit BCC.S @1 MOVE.W D1, (A0) ;Make 16-bit black bit @1 ADDX.W D0,D0 ;if extended then blit BCC.S @2 MOVE.W D1, 2(A0) ;Make 16-bit black bit @2 ADDX.W D0,D0 ;if extended then blit BCC.S @3 MOVE.W D1, 4(A0) ;Make 16-bit black bit @3 ADDX.W D0,D0 ;if extended then blit BCC.S @4 MOVE.W D1, 6(A0) ;Make 16-bit black bit @4 ADDX.W D0,D0 ;if extended then blit BCC.S @5 MOVE.W D1, 8(A0) ;Make 16-bit black bit @5 ADDX.W D0,D0 ;if extended then blit BCC.S @6 MOVE.W D1, 10(A0) ;Make 16-bit black bit @6 ADDX.W D0,D0 ;if extended then blit BCC.S @7 MOVE.W D1, 12(A0) ;Make 16-bit black bit @7 ADDX.W D0,D0 ;if extended then blit BCC.S @8 MOVE.W D1, 14(A0) ;Make 16-bit black bit @8 ADD #16, A0 ;Bump to next set DBRA D4,@inner ENDM MACRO _blit16long MOVEQ #3, D4 ;for inner loop @inner ADDX.L D0,D0 ;if extended then blit BCC.S @1 MOVE.W D1, (A0) ;Make 16-bit black bit @1 ADDX.L D0,D0 ;if extended then blit BCC.S @2 MOVE.W D1, 2(A0) ;Make 16-bit black bit @2 ADDX.L D0,D0 ;if extended then blit BCC.S @3 MOVE.W D1, 4(A0) ;Make 16-bit black bit @3 ADDX.L D0,D0 ;if extended then blit BCC.S @4 MOVE.W D1, 6(A0) ;Make 16-bit black bit @4 ADDX.L D0,D0 ;if extended then blit BCC.S @5 MOVE.W D1, 8(A0) ;Make 16-bit black bit @5 ADDX.L D0,D0 ;if extended then blit BCC.S @6 MOVE.W D1, 10(A0) ;Make 16-bit black bit @6 ADDX.L D0,D0 ;if extended then blit BCC.S @7 MOVE.W D1, 12(A0) ;Make 16-bit black bit @7 ADDX.L D0,D0 ;if extended then blit BCC.S @8 MOVE.W D1, 14(A0) ;Make 16-bit black bit @8 ADD #16, A0 ;Bump to next set DBRA D4,@inner ENDM bigWord16 word16 SUB.W #32,D7 ;adjust the rowbytes for loop ADD.W D2,D2 ;NOT NEEDED AFTER SHIFT ADJUSTMENTS MADE ABOVE ADD.W D2,A0 ;NOT NEEDED AFTER SHIFT ADJUSTMENTS MADE ABOVE MOVEQ #0,D1 ;for dest black @mid MOVE.W (A2)+,D0 ;this particular example is or mode _blit16word ;Blit the bits ADD D7,A0 ;advance to the next dest row DBRA D3,@mid RTS bigLong16 long16 SUB.W #64,D7 ;adjust the rowbytes for loop ADD.W D2,D2 ;NOT NEEDED AFTER SHIFT ADJUSTMENTS MADE ABOVE ADD.W D2,A0 ;NOT NEEDED AFTER SHIFT ADJUSTMENTS MADE ABOVE MOVEQ #0,D1 ;for dest black @mid MOVE.L (A2)+,D0 ;this particular example is a or mode _blit16long ;Blit the bits ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid RTS overLong16 ADD.W D2,D2 ;NOT NEEDED AFTER SHIFT ADJUSTMENTS MADE ABOVE ADD.W D2,A0 ;NOT NEEDED AFTER SHIFT ADJUSTMENTS MADE ABOVE MOVEQ #0,D1 ;for dest black @mid MOVE.L (A2)+,D0 ;this particular example is a or mode BEQ.S @skip _blit16long ;Blit the bits DBRA D5,@mid ;# of longs in a scan line MOVE.W A4,D5 ;# of src bytes ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid RTS @skip ADD.W #64,A0 DBRA D5,@mid ;# of longs in a scan line MOVE.W A4,D5 ;# of src bytes ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid RTS ;———————————————————————————————————————————————————————————————————————————————————————————————— ; END 16-bit NEW FAST blit loop ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————————————— ; 32-bit NEW FAST blit loop ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Registers Use: ; D0 = scratch A0 = scratch ; D1 = scratch A1 = TextPtr.l ; D2 = shift.w A2 = bitsPtr.l ; D3 = scan.w A3 = glyphArray.l ; D4 = charLoc.l A4 = widTabPtr.l ; D5 = char*4.w A5 = DestPtr.l ; D6 = #chars.w A6 = stack frame.l ; D7 = rowBytes.w A7 = stack pointer.l ;———————————————————————————————————————————————————————————————————————————————————————————————— ;——————————————————— ;blitting loops ;——————————————————— MACRO _blit32word MOVEQ #1, D4 ;for inner loop @inner ADDX.W D0,D0 ;if extended then blit BCC.S @1 MOVE.L D1, (A0) ;Make 16-bit black bit @1 ADDX.W D0,D0 ;if extended then blit BCC.S @2 MOVE.L D1, 4(A0) ;Make 16-bit black bit @2 ADDX.W D0,D0 ;if extended then blit BCC.S @3 MOVE.L D1, 8(A0) ;Make 16-bit black bit @3 ADDX.W D0,D0 ;if extended then blit BCC.S @4 MOVE.L D1, 12(A0) ;Make 16-bit black bit @4 ADDX.W D0,D0 ;if extended then blit BCC.S @5 MOVE.L D1, 16(A0) ;Make 16-bit black bit @5 ADDX.W D0,D0 ;if extended then blit BCC.S @6 MOVE.L D1, 20(A0) ;Make 16-bit black bit @6 ADDX.W D0,D0 ;if extended then blit BCC.S @7 MOVE.L D1, 24(A0) ;Make 16-bit black bit @7 ADDX.W D0,D0 ;if extended then blit BCC.S @8 MOVE.L D1, 28(A0) ;Make 16-bit black bit @8 ADD #32, A0 ;Bump to next set DBRA D4,@inner ENDM MACRO _blit32long MOVEQ #3, D4 ;for inner loop @inner ADDX.L D0,D0 ;if extended then blit BCC.S @1 MOVE.L D1, (A0) ;Make 16-bit black bit @1 ADDX.L D0,D0 ;if extended then blit BCC.S @2 MOVE.L D1, 4(A0) ;Make 16-bit black bit @2 ADDX.L D0,D0 ;if extended then blit BCC.S @3 MOVE.L D1, 8(A0) ;Make 16-bit black bit @3 ADDX.L D0,D0 ;if extended then blit BCC.S @4 MOVE.L D1, 12(A0) ;Make 16-bit black bit @4 ADDX.L D0,D0 ;if extended then blit BCC.S @5 MOVE.L D1, 16(A0) ;Make 16-bit black bit @5 ADDX.L D0,D0 ;if extended then blit BCC.S @6 MOVE.L D1, 20(A0) ;Make 16-bit black bit @6 ADDX.L D0,D0 ;if extended then blit BCC.S @7 MOVE.L D1, 24(A0) ;Make 16-bit black bit @7 ADDX.L D0,D0 ;if extended then blit BCC.S @8 MOVE.L D1, 28(A0) ;Make 16-bit black bit @8 ADD #32, A0 ;Bump to next set DBRA D4,@inner ENDM bigWord32 word32 SUB.W #64,D7 ;adjust the rowbytes for loop LSL.W #2,D2 ;NOT NEEDED AFTER SHIFT ADJUSTMENTS MADE ABOVE ADD.W D2,A0 ;NOT NEEDED AFTER SHIFT ADJUSTMENTS MADE ABOVE MOVEQ #0, D1 ;for dest black @mid MOVE.W (A2)+,D0 ;this particular example is or mode _blit32word ;Blit the bits ADD D7,A0 ;advance to the next dest row DBRA D3,@mid RTS bigLong32 long32 SUB.W #128,D7 ;adjust the rowbytes for loop LSL.W #2,D2 ;NOT NEEDED AFTER SHIFT ADJUSTMENTS MADE ABOVE ADD.W D2,A0 ;NOT NEEDED AFTER SHIFT ADJUSTMENTS MADE ABOVE MOVEQ #0,D1 ;for dest black @mid MOVE.L (A2)+,D0 ;this particular example is a or mode _blit32long ;Blit the bits ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid RTS overLong32 LSL.W #2,D2 ;NOT NEEDED AFTER SHIFT ADJUSTMENTS MADE ABOVE ADD.W D2,A0 ;NOT NEEDED AFTER SHIFT ADJUSTMENTS MADE ABOVE MOVEQ #0,D1 ;for dest black @mid MOVE.L (A2)+,D0 ;this particular example is a or mode BEQ.S @skip _blit32long ;Blit the bits DBRA D5,@mid ;# of longs in a scan line MOVE.W A4,D5 ;# of src bytes ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid RTS @skip ADD.W #128,A0 DBRA D5,@mid ;# of longs in a scan line MOVE.W A4,D5 ;# of src bytes ADD.W D7,A0 ;advance to the next dest row DBRA D3,@mid RTS ;———————————————————————————————————————————————————————————————————————————————————————————————— ; END 32-bit NEW FAST blit loop ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————————————— ; CACHE RETRIEVAL ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Input: ; D3 = glyphID ; renderIt MOVEM.L A1/D0-D2,-(SP) ;Save off all registers before JSR SUBQ #4,SP ;make room for result MOVE.W D3, glyphID(A6) ;put glyphID into sp_Glyph if (hasDoubleByte) then tst.l encodingTable(a6) ; is this a double byte font? beq.s @singleByteFont ; no, skip loading low byte move.b highByte(a6),glyphID(a6) ; save the high byte move.b lowByte(a6),glyphID+1(a6) ; save the low byte @singleByteFont endif MOVE.L WidthTabHandle, -(SP) ;2) Push the Width Table Handle onto the stack PEA fontID(A6) ;1) Push the Glyph Rec Ptr TST.B FASTFLAG(A6) ;if slow no need for 32-bit stuff BEQ.S @skip32 ; TST.B needs32bit(A6) ;running 32 bit clean BEQ.S @skip32 ;NOPE, so skip it move.b MMUsave(a6),d0 ;get previous MMU state in d0 _rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2) _sbRetrieveGlyph ;Call the routine via SplineDispatch moveq #true32b,d0 ;switch to 32 bit addressing _rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2) MOVE.L srcAddr(A6), A2 ;Get the address MOVE.L A2, D0 ;get 24 bit base addr _rTranslate24To32 ;mask off high byte MOVE.L D0,A2 ;SAVE FOR LATER BRA.S @skip24 @skip32 _sbRetrieveGlyph ;Call the routine via SplineDispatch MOVE.L srcAddr(A6), A2 ;Get the address @skip24 ;—————————————————— ; Set up pointers ;—————————————————— TST.B nextBand(A6) ;another band? BEQ.S @noBands ;no so continue BSET.L #31, D3 ;set continue bit BRA.S @1 @noBands BCLR.L #31, D3 ;no new bands @1 MOVE.L WidthTabHandle,A0 ;Get the handle MOVE.L (A0),A4 ;restore the width table pointer ;The cacheHand may have change if we got ;Memory somewhere else MOVE.L expandMem,A0 ; get low memory expand pointer. MOVE.L ExpandMemRec.emSplineKey(A0),A0 ; get handle to splineKey globals. MOVE.L (A0), A0 ; get pointer to splineKey globals. MOVE.L splineKeyRec.cacheHand(A0),A0 ; Get the handle in case it changed. MOVE.L A0, cacheHand(A6) ;restore cacheHand MOVE.L (A0), D0 ;pointer to the cache _StripAddress ;Make sure it is the right mode MOVE.L D0, D5 ;restore cache pointer MOVE.L D0, A0 ; LEA cache.glyphArray(A0), A3 ;Get array of glyphs into A3 ;—————————————————— TST.L (SP)+ ;Any Errors MOVEM.L (SP)+, A1/D0-D2 ;Restore all registers on return BNE @skipGlyph MOVE.L entryOffset(A6), D0 ADD.L D0, A0 ;point to glyph record MOVEQ #0, D0 ;No error @skipGlyph RTS ;———————————————————————————————————————————————————————————————————————————————————————————————— ; END CACHE RETRIEVAL ;———————————————————————————————————————————————————————————————————————————————————————————————— renderChar MOVEM.L D0-D1,-(SP) ;Save off all registers before JSR MOVE.W D5, glyphID(A6) ;put glyphID into sp_Glyph if (hasDoubleByte) then tst.l encodingTable(a6) ; is this a double byte font? beq.s @singleByteFont ; no, skip loading low byte move.b highByte(a6),glyphID(a6) ; save the high byte move.b lowByte(a6),glyphID+1(a6) ; save the low byte @singleByteFont endif MOVE.W #0, topClip(A6) ;do not need the bits MOVE.W #0, botClip(A6) ;do not need the bits SUBQ #4,SP ;make room for result MOVE.L WidthTabHandle, -(SP) ;2) Push the Width Table Handle onto the stack PEA fontID(A6) ;1) Push the Glyph Rec Ptr _sbRetrieveGlyph ;Call the routine via SplineDispatch ;——————————————————— ; Re-establish ptrs ;——————————————————— ;The cacheHand may have change if we got ;Memory somewhere else MOVE.L expandMem,A0 ; get low memory expand pointer. MOVE.L ExpandMemRec.emSplineKey(A0),A0 ; get handle to splineKey globals. MOVE.L (A0), A0 ; get pointer to splineKey globals. MOVE.L splineKeyRec.cacheHand(A0),A0 ; Get the handle in case it changed. MOVE.L A0, cacheHand(A6) ;restore cacheHand MOVE.L (A0), A0 ;pointer to the cache MOVE.L A0, D2 ;pointer to the cache LEA cache.glyphArray(A0), A2 ;Get array of glyphs into A0 MOVE.L WidthTabHandle,A1 ;Get the handle MOVE.L (A1),A1 ;restore the width table pointer ;——————————————————— ADDQ #4, SP ;Ignore errors <58-CEL> MOVEM.L (SP)+, D0-D1 ;Restore all registers on return MOVE.L entryOffset(A6), D0 BEQ @errExit ;if zero then no info <58-CEL> ADD.L D2, D0 ;add offset and point to glyph data MOVE.L D0, A0 ;Get in address reg @errExit RTS ;———————————————————————————————————————————————————————————————————————————————————————————————— ; END NEW FAST BLIT loop ;———————————————————————————————————————————————————————————————————————————————————————————————— ENDIF ;hasSplineFonts ;———————————————————————————————————————————————————————————————————————————————————————————————— ; END hasSplineFonts… BEGIN BITMAPS ;———————————————————————————————————————————————————————————————————————————————————————————————— BitVarSetUp MOVE stackOffset(A6),D0 ;either zero if stack was long aligned, or two if not ; MOVE.L numer(A6,D0),numer2(A6) ; MOVE.L denom(A6,D0),denom2(A6) ;save original numer, denom for iterative case CLR charsRemain(A6) ;for iterative case BRA.S goBitSetUp ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Iterate ; ; Entry point when subdividing a string ; Iterate MOVE stackOffset(A6),D0 ;either zero if stack was long aligned, or two if not CLR -(SP) ;ROOM FOR FCN RESULT MOVE COUNT(A6,D0),D1 ;get count MOVE D1,-(SP) ;PUSH COUNT BLE GOHOME ;QUIT IF COUNT <= 0 ;STACK CLEANED UP BY SAVESTK MOVE D1,countCopy(A6) ;save copy of count IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY MOVE D1,origCharCount(A6) ;save copy of count ENDIF ; ;———————————————————————————————————————————————————————————————————————————————————————————————— ; CALL to StdTxMeas ; ; Routine will load font and return width. StdTxMeas stashes FMOutPtr in ; QD global FONTPTR. Unscaled fixed point text width is stored in FontAdj ; for CQD not B&W. ; MOVE.L textPtr(A6),-(SP) ;PUSH TEXTADDR PEA NUMER(A6,D0) ;PUSH VAR NUMER PEA DENOM(A6,D0) ;PUSH VAR DENOM PEA INFO(A6) ;PUSH VAR INFO lea JStdTxMeas,A0 ;get piece of trap table move.l (a0),a0 ; <31> DTY changed from move.l JSR (A0) ;MEASURE TEXT ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Stack Variable SetUp ; ; Registers on Entry: ; A4 = Graf globals ; ; Registers used: ; A1 = WidthPtr ; A2 = Font strike ptr ; A6 = Stack frame ; A4 = FmOutput record ptr ; ; Preserves: ; D1 = Width of string ; ; CLOBBERS: A0, D0, D2, D3 ; ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————— ; Get the text width in D1. ;———————————————————————————————————————————————————————————————————————————————————————— ADDQ #2,SP ;POP (and ignore) UNSCALED WIDTH RESULT MOVE.L fontAdj(A4),D1 ;get fixed point width MOVE.L fontPtr(A4),A4 ;Point to FmOutput record ;———————————————————————————————————————————————————————————————————————————————————————— ; Common entry point for iteration or first pass. Same register setup as above, with ; the FMOutput pointer already loaded into A4. Load the font strike pointer into A2. ;———————————————————————————————————————————————————————————————————————————————————————— goBitSetUp CLR.L maskBitsPtr(A6) ;assume no mask IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY CLR.L stackHandle(A6) ;clear stackHandle SF isSpline(A6) ;Set not spline font ENDIF MOVE.L fmOutFontH(A4),A2 ;Font Handle in register MOVE.L (A2),A2 ;Dereference for Font Ptr ;———————————————————————————————————————————————————————————————————————————————————————— ; Check font flag bits and set local flags. ;———————————————————————————————————————————————————————————————————————————————————————— CLR.B doDither(A6) ;init to no dither MOVE stackOffset(A6),D4 ;0 if no offset, 2 if word offset MOVE fFontType(A2),D0 ;font flags BTST #8,D0 ;synthetic font ? SNE synFont(A6) ;used for check if orig fctb is needed BTST #9,D0 ;contains colors? SNE colorSource(A6) ;if so, pass info to stretch later BEQ.S @noDither ;do not set the dither bit MOVE.W numer(A6,D4),D2 ;get the numer.v CMP.W denom(A6,D4), D2 ;Check if shrinking SLT doDither(A6) ;Do the dither if shrinking @noDither ; LSR #2,D0 ;toss bottom two bits AND #$7,D0 ;0 … 5 (bit depth of 1 … 32) SNE D2 ;note that the incoming font is not 1 deep MOVE D0,bitShift(A6) ;bits per pixel shift count MOVEQ #1,D3 LSL D0,D3 MOVE D3,bitDepth(A6) ;bits per pixel BTST #0,fFontType+1(A2) ;DOES FONT HAVE HEIGHT TABLE ? SNE HEIGHTFLAG(A6) ;REMEMBER FOR LATER MOVE.L numer(A6,D4),D0 ;Numer in reg CMP.L denom(A6,D4),D0 ;Is denom different SNE stretch(A6) ;Different then set the flag ;———————————————————————————————————————————————————————————————————————————————————————— ; Set up the kerning properties. If this font has kerning, we only want to adjust by ; the kerning amount plus the offset for the first character in the text. ;———————————————————————————————————————————————————————————————————————————————————————— clr.w kernBounds(a6) ; clear kerning boundary. move.w fKernMax(a2),kernAdjust(a6) ; have a kerning adjustment? IF hasFullKerning THEN bpl.s @noKerning ; no -> skip kerning stuff. move.l textPtr(a6),a0 ; load the text pointer. clr.l d0 ; clear a long. move.b (a0),d0 ; load the first character. move.w fNDescent(a2),d2 ; extended offset/width table location? bpl.s @0 ; yes -> use as the high word. clr.l d2 ; no -> clear the high word. @0 swap d2 ; move to the high word. move.w LENGTH(a2),d2 ; load the low word too. lea 16(a2,d2.l*2),a0 ; load pointer to offset/width table. move.w 0(a0,d0.w*2),d0 ; load character offset/width. cmp.w #-1,d0 ; missing character? bne.s @1 ; no -> skip this. move.w (a0),d0 ; load missing character offset/width. @1 lsr.w #8,d0 ; isolate the offset byte. add.w fKernMax(a2),d0 ; kerning adjustment > 0? bgt.s @noKerning ; yes -> use kerning adjustment. move.w d0,kernBounds(a6) ; save the kerning adjustment. @noKerning ENDIF MOVE.W fDescent(A2), D0 NEG D0 MOVE.W D0, sDescent(A6) ;Descent val on stack MOVE.W locASCENT(A2), sAscent(A6) ;Ascent val on stack MOVE.W FBBDY(A2), sHeight(A6) ;Height val on stack MOVE.W FBBDY(A2), TOPHT(A6) ;Top and Height vals on stack @noItalic MOVE txMode(A3),D0 AND #$FFF7,D0 ;clear pattern bit (let stretch reject invalid modes) TST.B colorSource(A6) ;does the source contain colors? BEQ.S @noColors CMP #srcOr,D0 ;is it srcOr? BNE.S @noColors MOVEQ #64,D0 ;set it to srcCopy + mask @noColors MOVE D0,locMode(A6) ;initialize copy BTST #6,D0 ;bit 6 if set says use a mask SNE D3 ;remember it BEQ.S @skipMask LEA srcPix(A6),A0 ;assume no mask font needed; just use source instead MOVE.L A0,maskBitsPtr(A6) ;pass mask to stretch bits @skipMask BTST #5,D0 ;arithmetic mode? BEQ.S @skipArith ;if not, don’t map if dest. is 1 bit deep CMP #1,dstPix+pixelSize(A6) ;1 bit deep destination? BNE.S @multideep ;if not, arithmetic mode is OK LEA ArithMode,A0 ;get mode map AND #7,D0 ;look at each different arith mode MOVE.B 0(A0,D0),D0 ;map into 1 bit safe mode MOVE D0,locMode(A6) ;alter mode properly for 1 bit depth @skipArith @multideep AND.B D2,D3 ;build mask characters if incoming is not 1 deep BEQ.S @noMask MOVE.L widTabFont(A1),A0 ;Add offset MOVE.L (A0),D0 ;Get pointer SNE D3 BEQ.S @noMask MOVE.L D0,A0 ;get address of font MOVEQ #0,D0 MOVE fRowWords(A0),D0 ;width of strike bit map in words ADD.L D0,D0 ;convert to bytes MOVE.L D0,mSrcRow(A6) ;save it LEA 26(A0),A0 MOVE.L A0,maskAddr(A6) ;address of mask bits LEA maskBits(A6),A0 ;pointer to mask bitmap MOVE.L A0,maskBitsPtr(A6) ;pass mask to stretch bits @noMask MOVE.B D3,maskFont(A6) ;0 if mask bit clear, no mask font, or incoming 1 deep OR.B colorSource(A6),D3 ;if color source or mask font, do bit insert/extract MOVE.B D3,textCopyMode(A6) ;set up bit insert/extract flag ;———————————————————————————————————————————————————————————————————————————————————————————————— ; END Stack Variable SetUp ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Bounding Rect set up ; ; Setup textRect, the rectangle bounding the entire string. ; ; Registers on Entry: ; A2 = Font Ptr ; A3 = thePort ; A4 = FmOutput record ptr ; A6 = Stack frame ; ; D1 = Width of string ; ; Register Use: ; D2 = PenLocation (Set up as fixed) ; ; Clobbers: ; D0, D3 ; ;———————————————————————————————————————————————————————————————————————————————————————————————— 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 SWAP D2 IF hasPenFraction THEN move.l grafGlobals(a5),a0 ; load quickDraw globals. move.w pnLocFixed(a0),d2 ; append pen fraction. move.w d2,penLocFixed(a6) ; save pen fraction for recursive drawing. ELSE move.w #$8000,d2 ; append default fraction. ENDIF ;——————————————————————————————————————————————————————————————— ; set flag to note if mode is srcOr & foreColor is black ; set up characterExtra if new port or script manager around ; set up pnLocHFrac if new port ;——————————————————————————————————————————————————————————————— CMP #srcOr,locMode(A6) ;is the mode srcOr? SEQ orMode(A6) BCLR #6,locMode+1(A6) ;was mask set? BEQ.S @noMaskMode TST locMode(A6) ;is it srcCopy + mask? SEQ orMode(A6) ;that can go fast, too. @noMaskMode moveq #0, d0 ; clear the character extra. <49> tst.b portBits+rowBytes(a3) ; is this an old grafPort? bpl.s @oldGrafPort ; yes -> skip this. move.w chExtra(a3),d0 ; load the character extra. ext.l d0 ; extend sign bits <49> asl.l #4,d0 ; convert to 16.16 format. @oldGrafPort IF SCRIPT_CHAR_EXTRA THEN move.l grafGlobals(a5),a0 ; load quickDraw globals. <43> add.l qdChExtra(a0),d0 ; add in the character extra. <43> ENDIF tst.l d0 ; have zero character extra? beq.s @zeroCharExtra ; yes -> skip call to scale. bsr CalcCharExtra ; scale by point size, etc. @zeroCharExtra move.l d0,characterExtra(a6) ; store scaled character extra. TST PORTBITS+ROWBYTES(A3) ; is it a new port? BPL.S @useOld ; no -> don’t set up fraction MOVE pnLocHFrac(A3),D2 ; set up with proper fraction MOVE D2,penLocHFrac(A6) ; save for later as well for recursive drawing ;——————————————————————————————————————————————————————————————————————————————————————— ; ForeGround - BackGround check ; ; This next part is a little tricky: ; If the source does not contain any colors (that is, regardless of whether the source is ; one bit per pixel or more, the pixels are either black or white) then we can go fast if ; the forecolor is black, regardless of the background color. If the font does contain colors, ; then we can go fast if the background is white, regardless of the foreground colors. ; ; But, if the foreground and background pixels are equal (but the font is a 1 bit font), then go ; slow. ColorMap will be called later to sort out whether the foreground color needs to be ; remapped or not. ;——————————————————————————————————————————————————————————————————————————————————————— ;——————————————————————————————————— ; This is the real code ;——————————————————————————————————— MOVE.L fgColor(A3),D0 CMP.L bkColor(A3),D0 ;same as background? BEQ.S @goSlow ;if so, go slow ADDQ.L #1,D0 ;now equal to number of colors, if black MOVE dstPix+pixelSize(A6),D3 ;bits per pixel LSR.L D3,D0 ;1 if black, 0 if other color @goSlow SNE D0 ;remember if black (or if fg/bk pixels are not equal) TST.B colorSource(A6) ;is the source multicolored? BEQ.S @oldCommon ;just worry about black TST.L bkColor(A3) ;if colored source, must worry about bk = white also BRA.S @oldBackCommon ;share with old mode @useOld BTST #5,fgColor+3(A3) ;is the foreground color black? SNE D0 ;set to zero if not TST.B colorSource(A6) ;is the source multicolored? BEQ.S @oldCommon BTST #0,bkColor+3(A3) ;is the background white? @oldBackCommon SEQ D0 ;true if white @oldCommon AND.B D0,orMode(A6) ;true if or mode and black monochrome or white multi. ADD.L D1,D2 ;right := left + width SWAP D2 ;just look at high word TST.B fmOutCurStyle(A4) BEQ noSlop ;if no style, certainly no slop MOVEQ #0,D0 ;clear out high word MOVE.B fmOutItalic(A4),D0 ;figure out italic EXT.W D0 ;Make it a word MOVE sAscent(A6),D3 ;Use the stack Ascent SUBQ #1,D3 ;the line above the baseline is not shifted MULU D3,D0 ;maximum italic = char ascent * FOutItalic ASR #4,D0 ;italic factor is divided by 16 (normally 8) @2 ADD.B fmOutBold(A4),D0 ;add boldness SUB.B fmOutExtra(A4),D0 ;less total extra added EXT D0 ;make it a word MOVEQ #4,D3 ;restrict shadow in the range of 0 .. 3 (+1 if shadow) CMP.B fmOutShadow(A4),D3 ;is it less or same? BLE.S @pinShadow ;if so, pin at limit MOVE.B fmOutShadow(A4),D3 ;otherwise, pass actual value BEQ.S @pinShadow ADDQ #1,D3 ;plus 1 for character insides shifted to right @pinShadow ADD D3,D0 ;combine shadow with italic slop count ADD D0,D2 ;SLOP FOR ITALIC,BOLD,OVERSTRIKE MOVEQ #0, D0 MOVE.B fmOutItalic(A4),D0 ;get the bit size below the baseline MULU fDescent(A2),D0 ;maximum italic = char descent * FOutItalic ASR #4,D0 ;which is based on 16 = 1 dot per line IF hasFullKerning THEN SUB D0, kernBounds(A6) ;include italic in calculating kerning ELSE SUB D0, kernAdjust(A6) ENDIF NOSLOP IF hasFullKerning THEN move.w kernBounds(a6),d0 ; load kerning boundary. ELSE move.w kernAdjust(a6),d0 ; load kerning adjustment. ENDIF ADD.W D0,textRect+left(A6) ;include kerning in text rectangle MOVE.W D2,TEXTRECT+RIGHT(A6) ;STORE IN TEXTRECT.RIGHT MOVE PENLOC(A6),D2 ;GET PNLOC.V SUB sAscent(A6),D2 ;Use the stack Ascent MOVE D2,TEXTRECT+TOP(A6) ;TEXTRECT.TOP := PNLOC.V - ASCENT ADD sHeight(A6),D2 ;Height metric off stack 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 ;——————————————————————— TST.B Stretch(A6) ;Are we stretching? BEQ NOSTRCH ;Skip stretching ;————————————————————————————————————————————————————————————————— ; Set up for stretching ; ; We will be stretching. Setup fromRect and toRect and map textR2. ; MOVE stackOffset(A6),D3 ;0 if no offset, 2 if word offset MOVE.L NUMER(A6,D3),D0 ;GET NUMERATOR SWAP D0 CLR D0 ;make it fixed point MULU.L D0,D0:D1 ;MULT WIDTH BY NUMER.H MOVEQ #0,D2 MOVE Denom+H(A6,D3),D2 SWAP D2 DIVU.L D2,D0: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,D3),D0 ;CALC PENLOC.H + NUMER.H MOVE D0,TORECT+RIGHT(A6) ;SET UP TORECT RIGHT SWAP D0 ;GET PENLOC.V ADD NUMER+V(A6,D3),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,D3),D0 ;CALC PENLOC.H + DENOM.H MOVE D0,FROMRECT+RIGHT(A6) ;SET UP FROMRECT RIGHT SWAP D0 ;GET PENLOC.V ADD DENOM+V(A6,D3),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 _MAPRECT ;MAP TEXTR2 (PRESERVES ALL REGS) NOSTRCH ANDI #$0F,CCR ; need to clear 'x' flag IF hasPenFraction THEN move.l grafGlobals(a5),a0 ; load quickDraw globals. add.w d1,pnLocFixed(a0) ; add width fraction to location fraction. ENDIF TST PORTBITS+ROWBYTES(A3) ; is it a new port? BPL.S @useOld ; no, don’t bother with fraction ADD D1,pnLocHFrac(A3) @useOld ;————————————————————————————— ; Move pen by the scaled text width ;————————————————————————————— SWAP D1 ;Make integer MOVE PNLOC+H(A3),D0 ;Get the current pen location ADDX D1,D0 ;New Pen Loc = OldPenLoc + TextWidth MOVE D0,PNLOC+H(A3) ;Save new pen location ;———————————————————————————— ; Quit if the pen is hidden ;———————————————————————————— TST PNVIS(A3) ;IS PNVIS < 0 ? BLT GOHOME ;YES, QUIT ;———————————————————————————————————————————————————————————————————————————————————————————————— ; END Bounding Rect set up ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Calculate the MinRect ; ; Calc minRect: the intersection of textRect, bitMap bounds, ; clipRgn and visRgn bounding boxes. Quit if no intersection. ; The right bounds of the destination rect is set to the max to allow right kerning ; (Right kerning only works (without trailing spaces) in OR mode. ; ; Registers on Entry: ; A2 = Font Ptr ; A3 = thePort ; A4 = FmOutput record ptr ; A6 = Stack frame ; ; Clobbers: ; A0, A1 ; D0, D1, D2, D3 ; ;———————————————————————————————————————————————————————————————————————————————————————————————— MOVE textR2+right(A6),-(SP) ;preserve existing right MOVE #32000,textR2+right(A6) ;get right from other rects PEA TEXTR2(A6) ;PUSH (MAPPED) TEXTRECT PEA DSTPIX+BOUNDS(A6) ;PUSH PIXMAP 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 _RSECT ;CALC INTERSECTION BEQ GOHOME ;QUIT IF NO INTERSECTION MOVE (SP)+,textR2+right(A6) ;restore text right ;————————————————————————————————————————————— ; Bitmap Font Ptrs SetUp ; ; Set up srcAddr, srcRow, and height ;————————————————————————————————————————————— LEA 26(A2),a0 ;GET START OF FONT BITMAP MOVE.L a0,SRCADDR(A6) ;SAVE FOR LATER MOVEQ #0,D1 ;zero high word MOVE RASTER(A2),D1 ;GET WORDS PER ROW IN FONT MOVE bitShift(A6),D0 LSL.L D0,D1 ;scale up font rowWords ADD.L D1,D1 ;DOUBLE FOR BYTES PER ROW MOVE.L D1,SRCROW(A6) ;REMEMBER FOR LATER ;————————————————————————————————————————————————————————————————————— ; FAST or NOTFAST check ; ; Test for fast case: ; not stretched, no color mapping, txMode = srcOr, same bits per pixel ; not bold, italic, underlined, outlined or shadowed, ; visRgn and clipRgn both rectangular. ;————————————————————————————————————————————————————————————————————— TST.B fmOutItalic(A4) ;TEST BOLD $$$ BNE NOTFAST ;NOT FAST UNLESS BOTH ZERO TST.B fmOutBold(A4) ;TEST BOLD BNE NOTFAST ;NOT FAST TST.W fmOutULThick(A4) ;Test ULTHICK and SHADOW (fmOutULThick,fmOutShadow) BNE NOTFAST ;NOT FAST UNLESS BOTH ZERO TST.B Stretch(A6) ;IS TEXT STRETCHED ? BNE NOTFAST ;YES, NOT FAST TST.B orMode(A6) ;IS TEXT MODE SRCOR ? (or srcCopy + mask, see above) BEQ NOTFAST ;NO, NOT FAST MOVE.L CLIPRGN(A3),A0 ; Get clip region MOVE.L (A0),A0 ; Dereference handle MOVEQ #10,D0 CMP RGNSIZE(A0),D0 ;IS CLIPRGN RECTANGULAR ? BNE NOTFAST ;NO, NOT FAST MOVEQ #1,D0 MOVE bitShift(A6),D1 ;get the depth of the source map LSL D1,D0 ;turn into 1 … 8 CMP DSTPIX+PIXELSIZE(A6),D0 ;same depth per pixel? BNE NOTFAST ;=>NOPE cmp #16,dstPix+pixelType(A6) ;is it a direct device? @@@@ BAL 16Jun88 bne.s modeok seq textCopyMode(a6) ;yes, can't go fast for now @@@@ BAL 16Jun88 clr locmode(a6) ;this essentially alters mode to srcCopy bra NotFast modeok MOVE.L VISRGN(A3),A1 ;GET VISRGN HANDLE MOVE.L (A1),A0 ;DE-REFERENCE IT CMP #10,RGNSIZE(A0) ;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 MOVE.W #-1, -(SP) ;trim = true for BRUCE _TRIMRECT ;CALL TRIMRECT BLT GOHOME ;quit if intersection empty BGT NOTFAST ;continue if non-rectangular ;———————————————————————————————————————————————————————————————————————————————————————————————— ; END Calculate the MinRect ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————————————— ; FAST case Setup ; ; Fast case, go directly to screen. ; If text is clipped vertically, then clear heightflag and update TOPHT ; ; Registers on Entry: ; A2 = Font Ptr ; A3 = thePort ; A4 = FmOutput record ptr ; A6 = Stack frame ; ; Saves & Restores: ; A2 ; ; Clobbers: ; ; D0, D1 ; ;———————————————————————————————————————————————————————————————————————————————————————————————— FAST IF has32bitQD THEN ;If 32-bit QD was around always we could do this MOVEM.L A0-A1/D0-D2,-(SP) ;Save registers @tryAgain CLR.B -(SP) ;result MOVE.L A3, -(SP) ;needs the current grafport _QDDone ;Is accelerator really done and ready for us to blit??? TST.B (SP)+ ;Check result BEQ.S @tryAgain ;Check until ready! MOVEM.L (SP)+, A0-A1/D0-D2 ;Restore registers ENDIF @not32bit ST FASTFLAG(A6) ;REMEMBER WE'RE GOING FAST ;————————————————————————————— ; Clipping set up ;————————————————————————————— CLR.B maskFont(A6) ;no need for second mask pass in fast case CLR.L bkCol(A6) ;zero out back color long 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 DSTPIX+BOUNDS+TOP(A6),D0 ;CONVERT TO GLOBAL COORDINATES MOVE DSTPIX+ROWBYTES(A6),D1 ;GET ROWBYTES AND #nuRBMask,D1 ;CLEAR OFF FLAG BITS MULS D1,D0 ;MULT BY ROWBYTES ADD.L DSTPIX+BASEADDR(A6),D0 ;ADD START OF DST BITMAP MOVE.L D0,BUFSTART(A6) ;SET UP BUFSTART FOR LATER MOVE D1,BUFROW(A6) ;SET UP BUFROW FOR LATER MOVE DSTPIX+BOUNDS+LEFT(A6),BUFLEFT(A6) ;REMEMBER BUFLEFT TST.B CRSRFLAG(A6) ;IS DST TO A SCREEN? BEQ @Check32Bit ;=>NO <9Apr90 KON> PEA MINRECT(A6) ;PUSH SHIELD RECT MOVE.L REALBOUNDS(A6),-(SP) ;PUSH DELTA FOR GLOBAL _SHIELDCURSOR ;HIDE CURSOR IF IT INTERSECTS @Check32Bit tst.b needs32bit(a6) ;<9Apr90 KON> beq.s @skip32bit ;<9Apr90 KON> ;——————————————————————————————————————— ; ; Clean pointers and then ; Switch to 32 bit addressing mode ;——————————————————————————————————————— MOVE.L SRCADDR(A6),d0 ;get 24 bit base addr _rTranslate24To32 ;mask off high byte BAL/MCF 03Dec88 MOVE.L d0,SRCADDR(A6) ;SAVE FOR LATER move.l a2,d0 ;get FontPtr _rTranslate24To32 ;mask off high byte BAL/MCF 03Dec88 move.l d0,a2 ;clean font ptr move.l a3,d0 ;get thePort ptr _rTranslate24To32 ;mask off high byte BAL/MCF 03Dec88 move.l d0,a3 ;clean thePort ptr MOVE.L textPtr(A6),D0 ;GET TEXTPTR _rTranslate24To32 ;mask off high byte BAL/MCF 03Dec88 MOVE.L d0,textPtr(A6) ;SAVE FOR LATER moveq #true32b,d0 ;switch to 32 bit addressing move.l a2,-(sp) ;save FontPtr _rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2) move.l (sp)+,a2 ;restore FontPtr move.b d0,MMUsave(a6) ;save previous state for later @skip32bit BRA GETPTRS ;———————————————————————————————————————————————————————————————————————————————————————————————— ; END FAST case Setup ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Slow case Set up ; ; Slow case: Setup for an off-screen buffer. ; ; Calc bufLeft: (LONG-align to avoid shift) ; ; Registers on Entry: ; A2 = Font Ptr ; A3 = thePort ; A4 = FmOutput record ptr ; A6 = Stack frame ; ; Clobbers: ; A0, A1 ; D0, D1, D2, D3, D4 ; ;———————————————————————————————————————————————————————————————————————————————————————————————— NOTFAST SF FASTFLAG(A6) ;NOT GOING DIRECTLY TO SCREEN IF (hasSplineFonts AND 0) OR (Gaudi AND 0) THEN ;————————————————————————————— ; Horizontal buffer use that is not yet used ;————————————————————————————— TST.B isSpline(A6) ;Is it a spline BEQ.S @skipNewTextRect ;Do not adjust the textrect MOVE MINRECT+LEFT(A6), D0 ;Min left in D0 MOVE MINRECT+RIGHT(A6), D1 ;Min Right in D1 TST.B fmOutShadow(A4) BEQ.S @noExtraOnEnds SUB #3, D0 ADD #3, D1 @noExtraOnEnds CMP TEXTRECT+LEFT(A6), D0 ;Is TextRect Left Greater BLT.S @noSubLeft MOVE D0, TEXTRECT+LEFT(A6) ;New TextRect Left used for buffer calc @noSubLeft CMP TEXTRECT+RIGHT(A6), D1 ;Is TextRect Left Greater BGT.S @skipNewTextRect MOVE D1, TEXTRECT+RIGHT(A6) ;New TextRect Right used for buffer calc @skipNewTextRect ENDIF MOVE TEXTRECT+LEFT(A6),D0 ;GET TEXTRECT LEFT SUB DSTPIX+BOUNDS+LEFT(A6),D0 ;CONVERT TO GLOBAL AND #$FFE0,D0 ;TRUNC TO LONG BOUND ADD DSTPIX+BOUNDS+LEFT(A6),D0 ;RETURN TO LOCAL COORDS MOVE D0,BUFLEFT(A6) ;REMEMBER FOR LATER ;———————————————————————— ; Calculate buffer size ;———————————————————————— CLR.L D1 ;clear high word MOVE TEXTRECT+RIGHT(A6),D1 ;BUFRIGHT := TEXTRECT RIGHT SUB D0,D1 ;WIDTH:=BUFRIGHT-BUFLEFT MOVE D1,D2 ;mask depth as well MOVE bitShift(A6),D4 ;convenient constant LSL.L D4,D1 ;scale up by pixel size + 1 for mask LSR.L #5,D1 ;CONVERT DOTS TO LONGS ADD #2,D1 ;ROUND UP PLUS EXTRA LONG IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY TST.B isSpline(A6) ;is it a spline BEQ.S @fullHeight ;skip bitmap clipping MOVE.W botClip(A6), origBotClip(A6) MOVE.W topClip(A6), origTopClip(A6) TST.B fmOutShadow(A4) BEQ.S @doneAdjustTop MOVE.W botClip(A6), D3 SUB.W #2, D3 CMP.W sDescent(A6), D3 BGE.S @doneAdjustBot ;Do not adjust bottom MOVE.W sDescent(A6), D3 @doneAdjustBot MOVE.W D3, botClip(A6) MOVE.W topClip(A6), D3 ADD.W #3, D3 CMP.W sAscent(A6), D3 BGE.S @setTopSame ;Do not adjust bottom MOVE.W D3, topClip(A6) BRA.S @doneAdjustTop @setTopSame MOVE.W sAscent(A6), topClip(A6) @doneAdjustTop MOVE.W topClip(A6), D3 ;Get the top clipping height MOVE.W D3, topAdjust(A6) ;Get top adjust for dest adjustment SUB.W botClip(A6), D3 ;Not missing but really clipped out BLE.W GOHOME ;Done if zero ADD.W #1, D3 ;height = topClip - botClip + 1 MOVE.W D3, bufHeight(A6) ;Save it away BRA.S @skipFullHeight ;Do not get full height for buffer ENDIF ;$$$NEW @fullHeight MOVE sHeight(A6),D3 ;GET HEIGHT @skipFullHeight MULU D1,D3 ;BUFSIZE:=HEIGHT*BUFROW LONGS IF 0 THEN IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY TST.B isSpline(A6) ;skip check if spline BNE.S @noCompare ;Do not compare ENDIF ;————————————————————————————————————————————————— ; if the intermediate result is too big, stop before going any further ; ; Why does this happen??? ;————————————————————————————————————————————————— CMP.L #$1C00,D3 ;is it bigger than 28K? (unit is longs) BGT DoSubDivide ;if so, draw fewer characters at a time @noCompare ENDIF MOVE.L D3,BUFSIZE(A6) ;Made a long SAVE FOR LATER EXT.L D1 ;Make it a long ADD.L D1,D3 ;add for stretch srcBuf LSL #2,D1 ;QUAD BUFROW FOR BYTES MOVE D1,BUFROW(A6) ;SAVE FOR LATER MOVE TEXTR2+RIGHT(A6),D5 SUB TEXTR2+LEFT(A6),D5 LSR #5,D5 ;convert to longs ADDQ #2,D5 ;account for slop MOVE D5,D0 EXT.L D0 ;Make it a long ADD.L D0,D3 ;in case clip is nonrectangular ADD.L D0,D3 ;in case vis is nonrectangular LSL D4,D0 ;scale up by source depth ADD.L D0,D3 ;add stretch destination buffer size MULU dstPix+pixelSize(A6),D5 ;size of composite mask EXT.L D5 ;$$$ Make it a long ADD.L D5,D3 ;include it ;————————————————————————————————————————————————— ;if srcDepth not equal to dstDepth, add stretch dest. buf. again ;————————————————————————————————————————————————— ADD.L D5,D3 ;include space for scale buffer ;————————————————————————————————————————————————— ;set up maskSize, maskRow ;————————————————————————————————————————————————— TST.B maskFont(A6) ;do we need a mask to pass to stretchBits? BEQ.S @noMask LSR #5,D2 ;CONVERT DOTS TO LONGS ADD #2,D2 ;ROUND UP PLUS EXTRA LONG ADD D2,D1 ;total number of longs IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY TST.B isSpline(A6) ;is it a spline BEQ.S @useNormalHeight ;use the normal height MOVE bufHeight(A6), D0 ;use bufHeight BRA.S @contCalc @useNormalHeight MOVE sHeight(A6),D0 ;GET HEIGHT @contCalc ELSE MOVE sHeight(A6),D0 ;GET HEIGHT ENDIF MULU D2,D0 ;BUFSIZE:=HEIGHT*BUFROW LONGS MOVE D0,maskSize(A6) ;SAVE FOR LATER LSL #2,D2 ;QUAD BUFROW FOR BYTES MOVE D2,mBufRow(A6) ;SAVE FOR LATER ADD.L D0,D3 ;add for stack check calculation EXT.L D2 ADD.L D2,D3 ;add for stretch srcMaskBuf MOVE TEXTR2+RIGHT(A6),D0 SUB TEXTR2+LEFT(A6),D0 LSR #5,D0 ;convert from dots to longs EXT.L D0 ;Make it a long ADD.L D0,D3 ;add stretch mask destination buffer size @noMask IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY TST.B isSpline(A6) ;Is it a spline BNE.S @doNewAlloc ;Then subdivide ENDIF ;————————————————————————————————————————————————— ; Calculate total stack requirements for off-screen buffers. ;————————————————————————————————————————————————— TST.B fmOutShadow(A4) ;ARE WE SHADOWING ? BEQ.S @1 ;NO, CONTINUE ADD.L bufSize(A6),D3 ;(long) YES, CALC 2*BUFSIZE EXT.L D1 ;make long for long add ADD.L D1,D3 ;add in 4 * source rows for shadow @1 LSL.L #2,D3 ;CALC TOTAL STACK BYTES NEEDED ;————————————————————————————————————————————————— ; how much slop? size of scale table (256 bytes maximum) ; size of stretch stack frame (750 bytes for parameters, local stack frame, saved regs), ; and about 1K for interrupts. ;————————————————————————————————————————————————— ADD.L #2048,D3 ;ADD 2 KBYTE SLOP ;————————————————————————————————————————————————— ; If stack is too small to allocate buffer(s), then draw half as many characters at a time. ;————————————————————————————————————————————————— _StackAvail ;Get StackAvail IN D0 CMP.L D0,D3 ;IS stackNeeded > stackAvail ? BLE StackAlmost ;NO, CONTINUE BRA DoSubDivide @doNewAlloc IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY ;————————————————————————————————————————————————— ; Calculate the buffer size ;————————————————————————————————————————————————— MOVE.L bufSize(A6),D0 ;Get size of buffer to initialize ADD.L #2, D0 ;Add 2 padding buffer on each end TST.B maskFont(A6) BEQ.S @skipMaskAlloc MOVEQ #0, D1 ;clear the long MOVE maskSize(A6),D1 ;Get maskSize ADD.L D1,D0 ;Adding in maskSize ADD.L #2, D0 ;Add 2 padding buffer on each end @skipMaskAlloc TST.B fmOutShadow(A4) ;Is there shadow BEQ.S @noShadBuf ;SKIP IF NO SHADOWING ADD.L bufSize(A6),D0 ;GET NUMBER OF LONGS IN BUF1 MOVE BUFROW(A6),D1 ;GET 4 * NUMBER OF LONGS PER ROW EXT.L D1 ADD.L D1,D0 ;GET 4 * NUMBER OF LONGS PER ROW ADD.L #2, D0 ;Add 2 padding buffer on each end @noShadBuf LSL.L #2, D0 ;longs to bytes MOVE.L D0, D3 ;Save value away CMP.L #$7000,D3 ;is it bigger than 28K? (unit is longs) BGT.S @otherAlloc ;Try to get memory from other places _StackAvail ;Get StackAvail IN D0 MOVE.L D3, D2 ;get needed space ADD.L #3346, D2 ;make sure there is an extra 2.5k bytes CMP.L D0,D2 ;IS stackNeeded > stackAvail ? BGT.S @otherAlloc ;NEW Changed to word branch - NO, CONTINUE SUB.L D3, SP ;Allocate the sucker MOVE.L SP, bufferPtr(A6) ;Save away the buffer pointer BRA @gotIt ;<65-CEL> @otherAlloc MOVE.L fmOutFontH(A4),A0 ;GET FONT HANDLE _HGetState ;get the purge state MOVE.B D0,fontState(A6) ;preserve it until the next change _HNoPurge ;Make it non-purgeable MOVE.L cacheHand(A6),A0 ;GET cache HANDLE <65-CEL> _HGetState ;get the purge state <65-CEL> MOVE.B D0,cacheState(A6) ;preserve it until the next change <65-CEL> _HNoPurge ;Make it non-purgeable <65-CEL> MOVE.L stackHandle(A6), D0 ;Check if exists BEQ.S @skipReSize MOVE.L D0, A0 ;Get handle in A0 _HUnlock MOVE.L D3, D0 ;restore size _SetHandleSize ;try a sethandlesize first BEQ.S @gotMem ;No problems we got it _DisposHandle ;Get rid of buffer - could be MF temp handle CLR.L stackHandle(A6) ;Zero out handle @skipReSize MOVE.L D3, D0 ;restore size MOVE.L A4,-(SP) ;save a4 BigJSR GetStyleBufHand,A4 ;Expecting size in D0 MOVE.L (SP)+,A4 ;restore a4 BEQ.S @subDivide ;go and band MOVE.L A0, stackHandle(A6) ;save away for later @gotMem MOVEM.L A0-A1/D0-D2,-(SP) ;Save off all registers before JSR SUBQ #4,SP ;make room for result MOVE.L widthTabHandle,A0 ;point to width table MOVE.L A0, -(SP) ;Push the WidthTable MOVE.L (A0),A0 ;Ptr to widthtable MOVE.L WidTabFont(A0), -(SP) ;font handle MOVE.W bufHeight(A6), -(SP) ;Scan lines MOVE.W WidthASize(A0), -(SP) ;ppem _sbPreFlightFontMem ;Call the routine via SplineDispatch TST.L (SP)+ ;Check the errors MOVEM.L (SP)+, A0-A1/D0-D2 ;Restore all registers on return BNE.S @subDivide ; _MoveHHi ;Move it high _HLock ;Lock it down for now MOVE.L (A0), D0 ;pointer to the cache _StripAddress ;Make sure it is the right mode MOVE.L D0, bufferPtr(A6) ;Save away the buffer pointer MOVE.L fmOutFontH(A4),A0 ;GET FONT HANDLE MOVE.B fontState(A6), D0 ;preserve it until the next change _HSetState ;restore purgability of original strike MOVE.L cacheHand(A6),A0 ;GET FONT HANDLE <65-CEL> MOVE.B cacheState(A6), D0 ;preserve it until the next change <65-CEL> _HSetState ;restore purgability of original strike <65-CEL> @gotIt BRA StackAlmost ; We are in business @subDivide MOVE.L fmOutFontH(A4),A0 ;GET FONT HANDLE MOVE.B fontState(A6), D0 ;preserve it until the next change _HSetState ;restore purgability of original strike ENDIF ;—————————————————————————————————————————————————————————————————————————————————————————————————— ; SUB-dividing routine ; ; Not enough memory - Divide area ; ; Currently there are two types of sub-dividing. ; 1) splitting the string in half ; 2) Banding vertically ; ; Banding vertically will render the characters correctly for all styles ; It seems as though splitting the string could have bad effects in italics ; in certain modes (e.g., srccopy). The sub-dividing of strings may go away ; In the case for splines, banding vertically will only take place. Splitting ; the string may also run out of memory and still need to be banded vertically. ; Banding vertically seems to be the best approach. Note: By banding vertically ; StdTxmeas will not need to be called again. The setup does not need to be re-done ; ; Registers on Entry: ; A2 = Font Ptr ; A3 = thePort ; A4 = FmOutput record ptr ; A6 = Stack frame ; ; Clobbers: ; A0, A1 ; D0, D3, D6, D7 ; ;—————————————————————————————————————————————————————————————————————————————————————————————————— DoSubDivide IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY TST.B isSpline(A6) ;is it a spline BEQ.S @contNormSplit ;skip bitmap clipping ST clipVert(A6) ;banding so set clip vertical flag <51> MOVE.W origTopClip(A6), D3 ;Get original value SUB.W origBotClip(A6), D3 ;Get original height to divide LSR.W #1, D3 ;Divide by 2 is new Height MOVE.W origBotClip(A6), -(SP) ;nextBotClip = botClip MOVE.W origTopClip(A6), D0 ;Get topclip SUB.W D3, D0 ;Get new botClip MOVE.W D0, -(SP) ;nextTopClip = newBotClip-1 MOVE.W D0, botClip(A6) ;newBotClip = (topClip - (oldHeight / 2)) + 1 @noNew MOVE.L SP, clipStorage(A6) ;Save Address on variable for later cleanup ADD.W #1, repeatBands(A6) ;Bump up by one MOVE.B HiliteMode,saveHilite(A6) ;save original in case stretch is called multiple times MOVE.L PENLOC(A6),PNLOC(A3) ;RESTORE PNLOC TO ORIGINAL IF hasPenFraction THEN move.l grafGlobals(a5),a0 ; load quickDraw globals. move.w penLocFixed(a6),pnLocFixed(a0) ; restore fractional pen location. ENDIF TST PORTBITS+ROWBYTES(A3) ; is it a new port? BPL.S @useOld2 ; no, no fraction to restore MOVE PenLocHFrac(A6),pnLocHFrac(A3) ;restore fraction if applicable @useOld2 BRA NOTFAST ;do new divide @contNormSplit ENDIF ;———————————————————————————————————————————————————— ; Here is the bitmap subdivide of the string ;———————————————————————————————————————————————————— MOVE stackOffset(A6),D6 ;2 if stack was not aligned, otherwise, 0 MOVE count(A6,D6),D0 ;how many characters to draw MOVE.W D0,D7 ;figure half LSR #1,D7 BNE.S @subDivide ;if more than 1 left, can subdivide problem SUBQ #1,charsRemain(A6) ;pretend the one character was drawn BRA GoHome ;if only 1 character, punt @subDivide ; *** look for space character? Could adjust D7 to coincide with a space if any, making ; *** drawing look better (for italics, kerns) TST charsRemain(A6) ;if zero, this is the first time through BNE.S @notFirst MOVE.B HiliteMode,saveHilite(A6) ;save original in case stretch is called multiple times MOVE D0,charsRemain(A6) ;initialize partial count drawing location @notFirst MOVE.L PENLOC(A6),PNLOC(A3) ;RESTORE PNLOC TO ORIGINAL IF hasPenFraction THEN move.l grafGlobals(a5),a0 ; load quickDraw globals. move.w penLocFixed(a6),pnLocFixed(a0) ; restore fractional pen location. ENDIF TST PORTBITS+ROWBYTES(A3) ; is it a new port? BPL.S @useOld ; no, no fraction to restore MOVE PenLocHFrac(A6),pnLocHFrac(A3) ;restore fraction if applicable @useOld MOVE D7,count(A6,D6) ;reset count to draw doIterate MOVE.L grafGlobals(A5),A4 ;set up grafGlobals pointer for getting real width MOVE.L numer2(A6),numer(A6,D6) ;restore numerator MOVE.L denom2(A6),denom(A6,D6) ;restore denominator MOVE.B saveHilite(A6),HiliteMode ;restore hilite bit JMP Iterate ;draw first half of string ; draw the second half of the string, but drawing no more characters than could be successfully ; drawn by the first half. secondHalf MOVEQ #0,D7 ;zero high word MOVE stackOffset(A6),D6 ;2 if stack was not aligned, otherwise, 0 MOVE count(A6,D6),D7 ;number of characters drawn last MOVE charsRemain(A6),D0 ;how many characters remain? CMP D0,D7 ;don’t try to draw more than worked last BLE.S @ok MOVE D0,count(A6,D6) ;draw what remains for the second half @ok ADD.L D7,textPtr(A6) ;bump source address by half already drawn BRA.S doIterate ; ———————————————————————————————————————————————————————————————————————————————————————————— ; END SUB-dividing routine ; ———————————————————————————————————————————————————————————————————————————————————————————— ; ———————————————————————————————————————————————————————————————————————————————————————————— ; Off-Screen Allocation ; ; Allocate and clear an off-screen buffer ; ; If the source font is only 1 bit deep, clear the screen to white. Also, if the transfer ; mode is xor, bic, or, clear the screen to white. If an arithmetic mode or copy and ; source is multibits deep, assume depth of source font is equal to destination depth. ; Also assume that background of buffer must be colored the same as the port background color. ; ; ; ———————————————————————————————————————————————————————————————————————————————————————————— StackAlmost MOVEQ #0,D0 ;get a long of white CMP.W #16, destDepth(A6) ;get destination bits per pixel BGE.S @whiteBackCol ;16 or 32 bit will not happen TST bitShift(A6) ;is source 1 bit? BEQ.S @whiteBackCol ; CMP #srcXor,locMode(A6) ;srcXor? BEQ.S @whiteBackCol ;even if font contains colors, leave background white TST.B colorSource(A6) ;font contains color? BNE.S @useBackCol ;if so, must color the buffer CMP #$32,locMode(A6) ;hilite? BEQ.S @whiteBackCol ;leave background white if so BTST #5,locMode+1(A6) ;arithmetic? BEQ.S @whiteBackCol ;if copy, or leave background white @useBackCol SUBQ #6,SP ;allocate VAR RGBColor MOVE.L SP,-(SP) ;point to VAR RGBColor _GetBackColor ;ask for the background color CLR.L -(SP) ;make room for function result PEA 4(SP) ;point to VAR RGBColor _Color2Index MOVEQ #0,D0 MOVEQ #32,D1 ; MOVE bitDepth(A6),D2 ;get destination bits per pixel @nxtPixel ASL.L D2,D0 OR.l (SP),D0 ;or in result of color2Index SUB D2,D1 BGT.S @nxtPixel ADD #10,SP ;strip RGBColor and long result @whiteBackCol MOVE.L D0,bkCol(A6) ;save for comparing with background, later STACKOK IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY TST.B isSpline(A6) BEQ.S oldAlloc ;Go to old way of allocating MOVE.L bufferPtr(A6), A0 ;Point to the buffer MOVE.L D0,(A0)+ ;PAD BUFFER WITH AN EXTRA ZERO MOVE.L A0, BUFSTART(A6) ;Save the start of the buffer MOVE.L bufSize(A6),D3 ;Get size of buffer to initialize SUBQ #1,D3 ;INIT DBRA LOOP COUNT CLRLP MOVE.L D0,(A0)+ SUB.L #1, D3 ;Decrement count TST.L D3 ;Is it done looping BGT.S CLRLP ;Done looping MOVE.L A0, bufEnd(A6) ;point to end of buffer MOVE.L D0,(A0)+ ;PAD BUFFER WITH AN EXTRA ZERO TST.B maskFont(A6) BEQ.S @noMask CLR.L (A0)+ MOVE.L A0, maskStart(A6) ;Set the maskStart pointer MOVE maskSize(A6),D3 ;Get the size of the mask SUB #1, D3 ;Init loop count @clrMask CLR.L (A0)+ DBRA D3,@clrMask @noMask MOVE.L A0, currentEnd(A6) ;current end of allocated buffer BRA.S doneNEW1 oldAlloc MOVE.L bufSize(A6),D3 SUBQ #1,D3 ;INIT DBRA LOOP COUNT MOVE.L D0,-(SP) ;PAD BUFFER WITH AN EXTRA ZERO MOVE.L SP,BUFEND(A6) ;REMEMBER WHERE BUFFER ENDS CLRLOOP MOVE.L D0,-(SP) DBRA D3,CLRLOOP ;ALLOCATE AND CLEAR BUFFER MOVE.L SP,BUFSTART(A6) ;REMEMBER START OF BUFFER MOVE.L D0,-(SP) ;PAD BUFFER WITH AN EXTRA ZERO TST.B maskFont(A6) BEQ.S @noMask MOVE maskSize(A6),D3 SUBQ #1,D3 CLR.L -(SP) @clrMask CLR.L -(SP) DBRA D3,@clrMask MOVE.L SP,maskStart(A6) @noMask CLR.L -(SP) doneNEW1 ELSE MOVE.L bufSize(A6),D3 SUBQ #1,D3 ;INIT DBRA LOOP COUNT MOVE.L D0,-(SP) ;PAD BUFFER WITH AN EXTRA ZERO MOVE.L SP,BUFEND(A6) ;REMEMBER WHERE BUFFER ENDS CLRLOOP MOVE.L D0,-(SP) DBRA D3,CLRLOOP ;ALLOCATE AND CLEAR BUFFER MOVE.L SP,BUFSTART(A6) ;REMEMBER START OF BUFFER MOVE.L D0,-(SP) ;PAD BUFFER WITH AN EXTRA ZERO TST.B maskFont(A6) BEQ.S @noMask MOVE maskSize(A6),D3 SUBQ #1,D3 CLR.L -(SP) @clrMask CLR.L -(SP) DBRA D3,@clrMask MOVE.L SP,maskStart(A6) @noMask CLR.L -(SP) ENDIF IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY TST.B isSpline(A6) ;Is it a spline BEQ.S @1 ;no so continue to bitmap getptrs TST.W clipVert(A6) ;Horz or Vert clipped BNE sGetPtrs ;take clipping loops BRA FastBlit ;go really fast @1 ENDIF ;———————————————————————————————————————————————————————————————————————————————————————————————— ; END Off-Screen Allocation ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————————————— ; END Slow case Set up ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————————————— ; ; Get pointers to location table, width table, and height table in font ; ;———————————————————————————————————————————————————————————————————————————————————————————————— GETPTRS LEA 26(A2),A0 ;GET START OF FONT BITMAP MOVEQ #0,D0 ;zero high word MOVE sHeight(A6),D0 ;GET HEIGHT OF FONT BITMAP MOVE.L SRCROW(A6), D1 ;Get Source in D1 to use as word, never a long MULU.W D1,D0 ;CALC TOTAL SIZE OF STRIKE ADD.L D0,A0 ;A1 := START OF LOC TABLE MOVE.L A0,LOCTAB(A6) ;SAVE FOR LATER MOVE.W fNDescent(A2),D0 ;possibly the high word of owTLoc SWAP D0 ;put it in the high word BPL.S @notNegative MOVEQ #0,D0 ;old fonts have negative of ascent here @notNegative MOVE LENGTH(A2),D0 ;HOW MANY WORDS IN STRIKE BODY LEA 16(A2,D0.L*2),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 BTST #1,1(A2) ;DOES FONT HAVE WIDTH TABLE ? BEQ.S NOWID ;NO, CONTINUE ADD D0,D0 ;SKIP WIDTH TABLE NOWID LEA 0(A1,D0*2),A0 ;POINT TO HEIGHT TABLE MOVE.L A0,HEIGHTAB(A6) ;SAVE FOR LATER skipBitTables ;Skipped the bitmap table setup ; ; Set up space width ; MOVE.L widthTabHandle,A0 ;point to width table MOVE.L (A0),A0 MOVE.L A0, widTabPtr(A6) ;Save pointer to the 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 kernAdjust(A6),D0 ;ADJUST FOR KERNING SUB D1,D0 ;MAKE CHARLOC RELATIVE TO BUFLEFT MOVE.W D0,CHARLOC(A6) ;LOAD INTEGER PART IF hasPenFraction THEN move.w penLocFixed(a6),charLoc+2(a6) ; use saved fraction. ELSE move.w #$8000,charLoc+2(a6) ; default fraction to 1/2. ENDIF TST PORTBITS+ROWBYTES(A3) ; is it a new port? BPL.S @useOld ; no -> skip this. MOVE penLocHFrac(A6),CHARLOC+2(A6) ; use saved fraction. @useOld SUB D1,MINRECT+LEFT(A6) ;MAKE MINRECT.LEFT AND SUB D1,MINRECT+RIGHT(A6) ;MINRECT.RIGHT BUFFER RELATIVE MOVE.L textPtr(A6),A1 ;GET TEXTPTR BRA.S NEXTCH ;GO TO LOOP START ;———————————————————————————————————————————————————————————————————————————————————————————————— ; ; Here's the main character drawing loop: ; ;———————————————————————————————————————————————————————————————————————————————————————————————— MISSING MOVE MAXMIN(A6),D5 ;NO, USE MISSING SYMBOL ADD #1,D5 ;WHICH IS ONE PAST MAXCHAR MOVE.L WIDTAB(A6),A0 ;POINT TO WIDTH TABLE MOVE 0(A0,D5*2),D3 ;GET OFFSET AND WIDTH BYTES CMP #-1,D3 ;missing? BNE NOTMISS ;IS MISSING CHAR MISSING ? BRA.S NEXTCH ;YES, SKIP THIS CHAR SPACECH MOVE.L SPWIDTH(A6),D1 ;GET SPACE WIDTH ADD.L D1,CHARLOC(A6) ;BUMP CHARLOC SKIPCH SUBQ.W #1,charsRemain(A6) ;decrement total character count SUBQ.W #1,countCopy(A6) ;decrement partial draw character count BLE STRDONE ;QUIT IF CHARCOUNT <= 0 NEXTCH MOVEQ #0, D5 ;get ready for byte MOVE.B (A1)+,D5 ;GET NEXT CHAR CMP.B #32,D5 ;IS IT A SPACE ? BEQ.S SPACECH ;YES, HANDLE IT MOVE.L widTabPtr(A6),A0 ;Point to the width table MOVE.L 0(A0,D5*4),D4 ;GET FIXED POINT WIDTH ADD.L characterExtra(A6),D4 ;add in character extra, if any SUB MINCH(A6),D5 ;SUBTRACT SAVED MINCHAR CMP MAXMIN(A6),D5 ;IS CH BETWEEN MINCHAR AND MAXCHAR ? BHI MISSING ;Missing so skip it OKCHAR MOVE.L WIDTAB(A6),A0 ;POINT TO WIDTH TABLE MOVE 0(A0,D5*2),D3 ;GET OFFSET AND WIDTH BYTES CMP #-1,D3 ;missing? BEQ 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 MOVEQ #0,D1 ; *** clear top word MOVE 0(A0,D5*2),D1 ;GET SRCLEFT MOVE 2(A0,D5*2),D2 ;GET SRCRIGHT SUB D1,D2 ;CALC WIDTH OF BITS BLE SKIPCH ;SKIP CHARBLT IF WIDTH <= 0 MOVE D2,charWidth(A6) ;save for later 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,D5*2),TOPHT(A6) ;get this char's top and height NOHEIGHT ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Horizontal Clipping ; ; 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 fixCharWidth ;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 fixCharWidth MOVE D2,D0 ;char width has been trimmed left, right, or both SUB D3,D0 ;so recalculate char width to draw MOVE D0,charWidth(A6) ;and save this tidbit of info. for later HORIZOK ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Blit loop for the 68020+ machines ; ; 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) ; ;———————————————————————————————————————————————————————————————————————————————————————————————— MOVEM D1-D3,maskBlts(A6) MOVE.B textCopyMode(A6),orNotOK(A6) ;if copy or if mask mode, do bit moves instead of OR ST notMaskPass(A6) ;use the bitDepth this pass MOVE BUFROW(A6),A3 MOVEM.L SRCROW(A6),A2/A4-A5 ;srcRow, srcAddr (src bitmap), bufStart (dst bitmap) <1.4-4april89-CEL> MOVE bitShift(A6),D0 ;get font scale factor LSL D0,D1 LSL D0,D2 LSL D0,D3 ;scale up all three maskBlt ; ; Get char height into D7 ; 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 ; MOVEQ #0,D0 ;get ready for byte MOVE.B TOPHT(A6),D0 ;get char top MOVE.L A2,D4 ;get srcRow in D-reg MULU.L D0,D4 ;calc charTop * srcRow ADD.L D4,A4 ;add to srcPtr MOVE A3,D4 ;get dstRow in D-reg MULU D0,D4 ;calc charTop * dstRow ADD.L D4,A5 ;add to dstPtr BRA pastBitMapPointers ;———————————————————————————————————————————————————————————————————————————————————————————————— ; ; SPLINE DRAWING LOOP ; ; Registers Use: ; D0 = xxxxxxx A0 = xxxxxxx ; D1 = xxxxxxx A1 = TextPtr ; D2 = xxxxxxx A2 = xxxxxxx ; D3 = xxxxxxx A3 = xxxxxxx ; D4 = Advance Width A4 = xxxxxxx ; D5 = Char Code A5 = xxxxxxx ; D6 = xxxxxxx A6 = stack frame ; D7 = xxxxxxx A7 = xxxxxxx ; ; ;———————————————————————————————————————————————————————————————————————————————————————————————— IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY sGETPTRS MOVE stackOffset(A6),D0 MOVE.L textPtr(A6),A1 ;GET TEXTPTR MOVE.L cacheHand(A6), A0 ;Handle to the cache MOVE.L (A0), D0 ;pointer to the cache _StripAddress ;Make sure it is the right mode MOVE.L D0, cachePtr(A6) ;save it for later MOVE.L D0, A0 LEA cache.glyphArray(A0), A0 ;Get array of glyphs into A0 MOVE.L A0, glyphArray(A6) ;Save the glyph array pointer ; ; Set up space width ; MOVE.L widthTabHandle,A0 ;point to width table MOVE.L (A0),A0 MOVE.L A0, widTabPtr(A6) ;Save pointer to the 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 SUB D1,D0 ;MAKE CHARLOC RELATIVE TO BUFLEFT MOVE.W D0,CHARLOC(A6) ;INIT INT PART OF CHARLOC TST PORTBITS+ROWBYTES(A3) ;is it a new port? BPL.S @useOld ;no, set fraction to 1/2 MOVE penLocHFrac(A6),CHARLOC+2(A6) ;set up fractional part BAL BRA.S @goOn @useOld MOVE #$8000,CHARLOC+2(A6) @goOn SUB D1,MINRECT+LEFT(A6) ;MAKE MINRECT.LEFT AND SUB D1,MINRECT+RIGHT(A6) ;MINRECT.RIGHT BUFFER RELATIVE BRA.S sNextCh ;Start first character sNextBand MOVE.W glyphID(A6), D5 ;put glyphID into d5 for renderIt BRA doBand ;take care of the band sMiss IF HAS_COLOR | SCRIPT_CHAR_EXTRA THEN ;<7> CEL CMP.B #32,D5 ;IS IT A SPACE ? BEQ.S sSPACECH ;YES, HANDLE IT ADD.L characterExtra(A6),D4 ;add in character extra, if any sSPACECH ENDIF ADD.L D4, CHARLOC(A6) ;Add fixed point width to CharLoc sSKIPCH SUBQ.W #1,countCopy(A6) ;decrement partial draw character count BLE STRDONE ;QUIT IF CHARCOUNT <= 0 sNextCh TST.B nextBand(A6) ;another char band then call retrieve!!! BNE.S sNextBand ;do the next char band MOVEQ #0, D5 ;get ready for byte MOVE.B (A1)+,D5 ;GET NEXT CHAR if (hasDoubleByte) then move.b d5,highByte(a6) ; save the high byte for later use clr.b lowByte(a6) ; clear the low byte for now tst.l encodingTable(a6) ; is this a double byte font? beq.s @normalFont ; no, skip low byte loading move.l encodingTable(a6),a0 ; grab pointer to high byte mapping table tst.b 0(a0,d5.w) ; is this a double byte character? beq @normalCharacter ; no, skip low byte loading tst.w countCopy(a6) ; more bytes left in text? ble.s @remapCharacterToNull ; no, remap the high byte subq.w #1,countCopy(a6) ; decrement the character count clr.w d0 ; clear high byte of low word move.b (a1)+,d0 ; grab the low byte and bump the text pointer adda.w #256,a0 ; offset to the low byte encoding table tst.b 0(a0,d0.w) ; is this a valid low byte? beq @remapCharacterToNull ; no, remap the high byte character move.b d0,lowByte(a6) ; save the valid low byte for later use bra @normalCharacter ; continue normally @remapCharacterToNull move.b #1,d5 ; remap the high byte character to the missing glyph move.b d5,highByte(a6) ; save the remapped value in the stack @normalCharacter @normalFont endif MOVE.L widTabPtr(A6),A0 ;Point to the width table MOVE.L 0(A0,D5*4),D4 ;GET FIXED POINT WIDTH MOVE.L glyphArray(A6), A0 ;Get array of glyphs into A0 MOVE.L 0(A0,D5*4),D0 ;Get offset to glyph in D3 BGT isCached ;———————————————————————————————————————————————————————————————————————————————————————————————— ; calling _sbRetrieveGlyph ;———————————————————————————————————————————————————————————————————————————————————————————————— errorOrNotCached BTST.L #30, D0 ;Check if there is an error BNE.S sMiss ;Got an error so skip character doBand MOVEM.L A1/D2,-(SP) ;Save off all registers before JSR SUBQ #4,SP ;make room for result MOVE D5, glyphID(A6) ;put glyphID into sp_Glyph if (hasDoubleByte) then tst.l encodingTable(a6) ; is this a double byte font? beq.s @singleByteFont ; no, skip loading low byte move.b highByte(a6),glyphID(a6) ; save the high byte move.b lowByte(a6),glyphID+1(a6) ; save the low byte @singleByteFont endif MOVE.L WidthTabHandle, -(SP) ;2) Push the Width Table Handle onto the stack PEA fontID(A6) ;1) Push the Glyph Rec Ptr TST.B FASTFLAG(A6) ;WERE WE GOING DIRECT TO SCREEN ? BEQ.S @skip32 ;NO, CONTINUE TST.B needs32bit(A6) ;running 32 bit clean BEQ.S @skip32 ;NOPE, so skip it move.b MMUsave(a6),d0 ;get previous MMU state in d0 _rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2) _sbRetrieveGlyph ;Call the routine via SplineDispatch moveq #true32b,d0 ;switch to 32 bit addressing _rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2) BRA.S @skip24 @skip32 _sbRetrieveGlyph ;Call the routine via SplineDispatch @skip24 ;—————————————————————— ; Re-establish pointers ;—————————————————————— MOVE.L WidthTabHandle,A0 ;Get the handle MOVE.L (A0),widTabPtr(A6) ;restore the width table pointer ;The cacheHand may have change if we got ;Memory somewhere else ;—————————————————————— ; May have banded for memory ; restore advance width ;—————————————————————— MOVE.L widTabPtr(A6),A0 ;Point to the width table MOVE.L 0(A0,D5*4),D4 ;GET FIXED POINT WIDTH ;—————————————————————— MOVE.L expandMem,A0 ; get low memory expand pointer. MOVE.L ExpandMemRec.emSplineKey(A0),A0 ; get handle to splineKey globals. MOVE.L (A0), A0 ; get pointer to splineKey globals. MOVE.L splineKeyRec.cacheHand(A0),A0 ; Get the handle in case it changed. MOVE.L A0, cacheHand(A6) ;restore cacheHand MOVE.L (A0), D0 ;pointer to the cache _StripAddress ;Make sure it is the right mode MOVE.L D0, cachePtr(A6) ;restore cache pointer MOVE.L D0, A2 LEA cache.glyphArray(A2), A0 ;Get array of glyphs into A0 MOVE.L A0, glyphArray(A6) ;restore the glyph array pointer ;—————————————————————— TST.L (SP)+ ;Any Errors MOVEM.L (SP)+, A1/D2 ;Restore all registers on return BNE sMiss ;No bitmap so print missing character MOVE.L entryOffset(A6), D0 ADD.L D0, A2 ;Point to the data MOVE.L srcAddr(A6), A4 ;Get the address TST.B needs32bit(A6) ;running 32 bit clean BEQ.S @no32 ;=>IF NOT, JUST RETURN MOVEM.L A0-A1/D0-D2,-(SP) ;Save off all registers before JSR MOVE.L A4, D0 ;get 24 bit base addr _rTranslate24To32 ;mask off high byte MOVE.L D0,A4 ;SAVE FOR LATER MOVEM.L (SP)+, A0-A1/D0-D2 ;Restore all registers on return @no32 MOVE.W yMax(A6), D6 ;Save yMax in D6 MOVE.W scan(A6), D7 ;Save the scan lines MOVE.W yMin(A6), D3 ;Get ymin for later MOVE.L srcRow(A6), D5 ;byteWidth in D5 for now <45-CEL> BRA.S noClipping ;———————————————————————————————————————————————————————————————————————————————————————————————— ; End _sbRetrieveGlyph call ;———————————————————————————————————————————————————————————————————————————————————————————————— isCached MOVE.L cachePtr(A6), A2 ;Get pointer to cache ADD.L D0, A2 ;add offset and point to glyph data if (hasDoubleByte) then clr.l d0 ; clear a long for the character code move.b lowByte(a6),d0 ; double byte character? beq.s @haveGlyphRecord ; no, skip this move.l 0(a2,d0.w*4),d0 ; load glyph record offset ble errorOrNotCached ; fall into common error case move.l cachePtr(a6),a2 ; load pointer to cache add.l d0,a2 ; add offfset for glyph pointer @haveGlyphRecord endif LEA glyph.cacheData(A2), A4 ;Get address MOVE.W glyph.yMax(A2), D6 ;Save yMax in D6 MOVE.W glyph.scan(A2), D7 ;Save the scan lines MOVE.W glyph.yMin(A2), D3 ;Save the scan lines MOVE.L glyph.byteWidth(A2), D5 ;byteWidth in D2 for now <45-CEL> TST.B clipVert(A6) ;are we clipping BEQ.S noClipping ;nope so continue MOVEQ #0, D1 ;d1 long ready MOVE.W D6, D1 ;Get the bottom clipping area SUB.W topClip(A6), D1 ;clipping value = yMax - topClip BLE.S @noTopClip ;Top not clipped MOVE.W topClip(A6), D6 ;New yMax from topclip value MOVE.L glyph.byteWidth(A2), D0 ; MULU D0, D1 ;Get Adjusment to srcAddr ADD.L D1, A4 ;Add adjustment to top @noTopClip CMP.W botClip(A6), D3 ;get the bottom clipping value BGE.S @noBotClip MOVE.W botClip(A6), D3 ;get new ymin @noBotClip MOVE.W D6, D7 ;Get the YMax value SUB.W D3, D7 ;scan = yMax - yMin noClipping SUBQ.W #1, D7 ; BMI sMiss ;nothing to blit so skip character MOVE.L CHARLOC(A6), D3 ;D3 = DestLeft (LSB + CharLoc) SWAP D3 ;Only use low order word ADD.W glyph.devLSB(A2), D3 ;Get integralized left side bearing TST.B nextBand(A6) ;skip the advance??? BNE.S @noAdvance ; ;••• spot for skipping advance if char banding!!! IF HAS_COLOR | SCRIPT_CHAR_EXTRA THEN ;<7> CEL ADD.L characterExtra(A6),D4 ;add in character extra, if any ENDIF ADD.L D4, CHARLOC(A6) ;Add fixed point width to CharLoc @noAdvance MOVE.W glyph.bitWidth(A2), D2 ; MOVE.L D5, A2 ;byteWidth in A2 <45-CEL> MOVE.W topAdjust(A6), D4 ;Use the topadjust previous calculated SUB.W D6, D4 ;D4 is dest adjustment MOVE.W D2, charWidth(A6) ;Save for later ADD.W D3, D2 ;DSTRIGHT := DSTLEFT + WIDTH MOVEQ #0, D1 ;D1 = SrcLeft for blit equals 0 ;———————————————————————————————————————————————————————————————————————————————————————————————— ; On Entry ; Registers On Entry: ; D0 = scratch A0 = xxxxxxx ; D1 = SrcLeft.w A1 = xxxxxxx ; D2 = DstRight.w A2 = srcRow.l ; D3 = DstLeft.w A3 = xxxxxxx ; D4 = DstAdjust .w A4 = srcAddr.l ; D5 = xxxxxxx A5 = xxxxxxx ; D6 = yMax.w A6 = stack frame ; D7 = scan A7 = xxxxxxx ; ;———————————————————————————————————————————————————————————————————————————————————————————————— ;$$$ Horizontal Clipping TST.B FastFlag(A6) ;ARE WE GOING FAST ? BEQ.S sHORIZOK ;NO, DON'T CLIP CMP MINRECT+LEFT(A6),D3 ;IS DSTLEFT < MINRECT.LEFT ? BGE.S sLEFTOK ;NO, CONTINUE CMP MINRECT+LEFT(A6),D2 ;IS DSTRIGHT <= MINRECT.LEFT ? BLE sSKIPCH ;YES, SKIP THIS CHAR sTRIMLFT 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 sfixCharWidth ;NO, CONTINUE BRA.S sTRIMRT ;YES, TRIM RIGHT sLEFTOK CMP MINRECT+RIGHT(A6),D2 ;IS DSTRIGHT <= MINRECT.RIGHT ? BLE.S sHORIZOK ;YES, CONTINUE CMP MINRECT+RIGHT(A6),D3 ;IS DSTLEFT >= MINRECT.RIGHT ? BGE STRDONE ;YES, IGNORE REST OF STRING sTRIMRT MOVE MINRECT+RIGHT(A6),D2 ;NO, TRIM DSTRIGHT sfixCharWidth MOVE D2,D0 ;char width has been trimmed left, right, or both SUB D3,D0 ;so recalculate char width to draw MOVE D0,charWidth(A6) ;and save this tidbit of info. for later sHORIZOK ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Blit loop for the 68020+ machines ; ; Inputs to local block CharBlt: ; ; Registers Use: ; D0 = xxxxxxx A0 = xxxxxxx ; D1 = SrcLeft.l A1 = TextPtr.l ; D2 = DstRight.w A2 = srcRow.l ; D3 = DstLeft.w A3 = dstRow.w ; D4 = DstAdjust .w A4 = srcAddr.l ; D5 = xxxxxxx A5 = dstPtr.l ; D6 = yMax.w A6 = stack frame.l ; D7 = scan.w A7 = stack pointer.l ; ; dstLeft relative to buffer ; dstRight relative to buffer, > dstLeft ; ; CLOBBERS: D0,D1,D2,D3,D4,D5,D6,D7,A0,A2,A3,A4,A5 ; PRESERVES: A1,A6,A7 ; ; ;———————————————————————————————————————————————————————————————————————————————————————————————— MOVEM D1-D3,maskBlts(A6) MOVE.B textCopyMode(A6),orNotOK(A6) ;if copy or if mask mode, do bit moves instead of OR ST notMaskPass(A6) ;use the bitDepth this pass MOVE BUFROW(A6),A3 MOVE.L bufStart(A6), A5 ;BufStart (dst bitmap) smaskBlt ; sfnt adjustment of the destination pointer MOVE A3,D0 ;get dstRow in D-reg MULS.W D4,D0 ;calc charTop * dstRow ADD.L D0,A5 ;add to dstPtr ; Put glyph height - 1 into D7 for blit loop ; ENDIF ;hasSplineFonts ;———————————————————————————————————————————————————————————————————————————————————————————————— ;———————————————————————————————————————————————————————————————————————————————————————————————— ; Setup shift count in D5 (relative shift between src and dst) ; ;———————————————————————————————————————————————————————————————————————————————————————————————— pastBitMapPointers ;skipped past bitmap pointer setup ; ; figure alignment offset in source so that dest is long aligned ; MOVEQ #$1F,D0 ;get a 5 bit mask, needed later MOVE.L D1,D5 ; ; Setup dstPtr in A5, address of leftmost dst word ; MOVE.W D3,D6 ;GET A COPY OF DSTLEFT ASR #5,D6 ;CONVERT FROM DOTS TO LONGS MOVE.W D6,D4 ;copy dest left in longs for later LSL #2,D6 ;quad for bytes ADD.W D6,A5 ;move dest pointer to start of character ; ; figure number of longs to move ; MOVE.W D2,D6 ;copy dstRight ASR #5,D6 SUB.W D4,D6 ;if same, it fits into a single long BEQ fitsInLong ;most 1 bit deep characters fit into a long ;—————————————————————————————————————————————————————————————————————————————————————— ; SPANS LONG ; ; Character spans long in destination, so it must be moved in pieces. ; ; Registers Use: ; D0 = 5 bit mask.w A0 = xxxxxxx ; D1 = SrcLeft.w A1 = TextPtr.l ; D2 = DstRight.w A2 = srcRow.l ; D3 = DstLeft.w A3 = destRow.l ; D4 = xxxxxxx A4 = srcRowPtr.l ; D5 = SrcLeft.w A5 = dstPtr.l ; D6 = longs to move.w A6 = stack frame.l ; D7 = scan.w A7 = stack pointer.l ;—————————————————————————————————————————————————————————————————————————————————————— NEG D3 ;negate for bit counting AND D0,D3 ;get bottom 5 bits of dstLeft BNE.S @skip32 MOVEQ #32,D3 ;if 0, make it 32 @skip32 MOVE.W D6,D4 ;total longs (not including left part) LSL #2,D4 ;make it a byte count SUB D4,A2 ;adjust source bump count SUB D4,A3 ;adjust dest. bump count SUBQ.W #1,D6 ;number of whole longs, less left & right parts ADD D3,D1 ;the right hand start MOVEQ #32,D4 SUB.L D4,D1 ; ; if not 1 bit font & mode is not srcOr, do moves instead ; TST.B orNotOK(A6) BNE.S DoMove ; ; OR words to the screen; set up right mask ; AND D0,D2 ;get bottom 5 bits of dstRight MOVEQ #1,D4 ROR.L #1,D4 ;set the high bit ASR.L D2,D4 ;$80000000 to $FFFFFFFF ASL.L #1,D4 ;$00000000 to $FFFFFFFE MOVE.W D6,D2 ;initialize whole long count MOVE.W D6,A0 ;save long count for later MOVE.L D5,D6 ADD.W D3,D6 MOVEQ #32,D0 SUB.L D0,D6 ;—————————————————————————————————————————————————————————————————— ; SLOW LOOP ; ; Slow loop only taken in wierd cases where dst wider than a long. ; Or the more common case that the font is more than 1 bit deep ;—————————————————————————————————————————————————————————————————— MAIN1 BFEXTU (A4){D5:D3},D0 ;GET SRC FROM BITMAP BRA.S @checkLong ;see if there is some number of longs to do @main2 BFEXTU (A4){D6:0},D0 ;GET SRC FROM BITMAP @checkLong OR.L D0,(A5)+ ;OR SRC INTO DST ADDQ #4,A4 ;BUMP SRCPTR RIGHT DBRA D2,@main2 ;LOOP TILL LAST long BFEXTU (A4){D1:0},D0 ;GET SRC FROM BITMAP AND.L D4,D0 OR.L D0,(A5) ;OR SRC INTO DST ADD.L A2,A4 ;BUMP TO NEXT ROW ADD.L A3,A5 ;BUMP DST TO NEXT ROW WIDE1 MOVE A0,D2 ;GET long count DBRA D7,MAIN1 ;LOOP ALL ROWS BRA decCount ;skip mask blt part ; ; Handle case of drawing into the offscreen bit map in color separately ; DoMove MOVE D2,D4 ;copy dstRight AND D0,D4 ;get bottom 5 bits of dstRight MOVE D6,longCount(A6) ;save # of whole longs MOVE D6,D2 ;set up first loop count MOVE.L bkCol(A6),D6 ;get a long full of the background color BFEXTU D6{0:D3},D0 ;background color & left mask MOVE.L D0,leftBack(A6) ;save for quick compare BFEXTU D6{0:D4},D0 ;background color & right mask MOVE.L D0,rightBack(A6) ;right mask color compare MOVE bitDepth(A6),D0 ;bits in a single pixel BFEXTU D6{0:D0},D0 ;get a single pixel of the background color MOVE D0,bkCol1(A6) ;a single background color for quick compare MOVEQ #32,D6 ; SUB D3,D6 ; MOVE.L D5,A0 ADD D3,A0 SUB #32,A0 ;set up center move offset ; ; Slow loop taken in cases where dst wider than a long (common for fonts more than 1 bit ; deep.) Need to move only the pixels that are not colored same as background. ; MoveLeft BFEXTU (A5){D6:D3},D0 ;get current background of destination CMP.L leftBack(A6),D0 ;compare it against the background color AND leftMask BNE.S leftOnePix ;if different, must move 1 pixel at a time ; ; Here the destination has only background color pixels, so the whole thing can be moved ; BFEXTU (A4){D5:D3},D0 ;GET SRC FROM BITMAP BFINS D0,(A5){D6:D3} checkLong EXG A0,D5 ;set up center move offset midChkLong ADDQ #4,A5 ;bump destination BRA.S checkMLong ;see if there is some number of longs to do MoveMid MOVE.L bkCol(A6),D0 CMP.L (A5),D0 ;same as background color? BNE.S midOnePix ;if different, move 1 at a time BFEXTU (A4){D5:0},D0 ;GET SRC FROM BITMAP MOVE.L D0,(A5)+ ;OR SRC INTO DST checkMLong ADDQ #4,A4 ;BUMP SRCPTR RIGHT DBRA D2,MoveMid ;LOOP TILL LAST WORD MoveRight EXG A0,D5 ;set up left move offset TST D4 BEQ.S nextRow BFEXTU (A5){0:D4},D0 ;look at the destination CMP.L rightBack(A6),D0 ;compare it against the background AND rightMask BNE.S rightOnePix ;if different, must move 1 pixel at a time ; ; Here the destination has only background color pixels, so the whole thing can be moved ; BFEXTU (A4){D1:D4},D0 ;get the right part of the character BFINS D0,(A5){0:D4} ;move it to the destination nextRow ADD.L A2,A4 ;BUMP TO NEXT ROW ADD.L A3,A5 ;BUMP DST TO NEXT ROW offMove MOVE longCount(A6),D2 ;GET long count DBRA D7,MoveLeft ;LOOP ALL ROWS BRA decCount ;out of here for next char ; ; need to move only the pixels that are not colored same as background ; leftOnePix MOVEM.L D1/D3-D6,-(SP) ;save temporary registers MOVEM bkCol1(A6),D0/D1 ;D0 = back color D1 = pixel width @nxtPixel BFEXTU (A4){D5:D1},D4 ;pick up a source pixel CMP D4,D0 ;is it the same as the back color? BEQ.S @skipInsert ;if so, don’t add to destination BFINS D4,(A5){D6:D1} ;if not, copy it to the destination @skipInsert ADD.L D1,D5 ;move to next source pixel ADD D1,D6 ;move to next destination pixel SUB D1,D3 ;decrement count BGT.S @nxtPixel ;do until we’re done MOVEM.L (SP)+,D1/D3-D6 ;restore bkCol, left & right widths, src & dest offsets BRA.S checkLong midOnePix MOVEQ #32,D0 ;full long size in bits MOVEM.L D1/D3-D6,-(SP) ;save temporary registers MOVEQ #0,D6 MOVEM bkCol1(A6),D1/D3 ;D1 = back color D3 = pixel width @nxtPixel BFEXTU (A4){D5:D3},D4 ;pick up a source pixel CMP D4,D1 ;is it the same as the back color? BEQ.S @skipInsert ;if so, don’t add to destination BFINS D4,(A5){D6:D3} ;if not, copy it to the destination @skipInsert ADD.L D3,D5 ;move to next source pixel ADD D3,D6 ;move to next destination pixel SUB D3,D0 ;decrement count BGT.S @nxtPixel ;do until we’re done MOVEM.L (SP)+,D1/D3-D6 ;restore bkCol, left & right widths, src & dest offsets BRA midChkLong rightOnePix MOVEM.L D1/D3-D6,-(SP) ;save temporary registers MOVEQ #0,D6 MOVEM bkCol1(A6),D3/D5 ;D3 = back color D5 = pixel width @nxtPixel BFEXTU (A4){D1:D5},D0 ;pick up a source pixel CMP D0,D3 ;is it the same as the back color? BEQ.S @skipInsert ;if so, don’t add to destination BFINS D0,(A5){D6:D5} ;if not, copy it to the destination @skipInsert ADD.L D5,D1 ;move to next source pixel ADD D5,D6 ;move to next destination pixel SUB D5,D4 ;decrement count BGT.S @nxtPixel ;do until we’re done MOVEM.L (SP)+,D1/D3-D6 ;restore bkCol, left & right widths, src & dest offsets BRA nextRow ;————————————————————————————————————————————————————————————————————————————————————————————————— ; FASTER LOOPS ; ; Here, the character does not cross a long boundary, so faster loops are in order. ; ; Registers Use: ; D0 = 5 bit mask.w A0 = xxxxxxx ; D1 = src Offset.w A1 = TextPtr.l ; D2 = dstRight.w A2 = srcRowSize.l ; D3 = dstLeft.w A3 = destRowPtr.l ; D4 = xxxxxxx A4 = srcRowPtr.l ; D5 = src Offset.w A5 = destRowPtr.l ; D6 = longs to move.w A6 = stack frame.l ; D7 = scan.w A7 = stack Pointer.l ;————————————————————————————————————————————————————————————————————————————————————————————————— fitsInLong MOVE.W charWidth(A6),D3 ;set up character width in bits TST.B notMaskPass(A6) ;if dest is 1 bit, or this is the mask, BEQ.S @skipMul ;then skip the mul scale MOVE bitShift(A6),D4 ;set up bit depth LSL D4,D3 @skipMul TST.B orNotOK(A6) ;can we OR? BNE.S offLong ;if not, bit extract/insert instead ; ; Optimize if dst fits in one long. (most 1 bit deep characters do) ; LONG1 ; ; OR words to the screen; set up right mask MOVE D2,D1 ;copy dest right NEG D1 ;figure not bits from left but bits from right AND D0,D1 ;but only from 0 to 31 ADD D1,D3 ;add right mask to extract width AND D0,D2 ;get bottom 5 bits of dstRight MOVEQ #1,D4 ROR.L #1,D4 ;set the high bit ASR.L D2,D4 ;$80000000 to $FFFFFFFF ASL.L #1,D4 ;$00000000 to $FFFFFFFE ; if D5 + D3 < 32, use a faster set of code: longLoop BFEXTU (A4){D5:D3},D0 ;GET SRC DATA AND.L D4,D0 OR.L D0,(A5) ;OR RESULT INTO DST ADD.L A2,A4 ;BUMP SRCPTR TO NEXT ROW ADD.L A3,A5 ;BUMP DSTPTR TO NEXT ROW DBRA D7,longLoop ;LOOP ALL ROWS BRA decCount ; ; Optimize if dst fits in one long. (most normal characters do) ; offLong MOVE D2,D6 AND.L D0,D6 SUB D3,D6 BFEXTU bkCol(A6){0:D3},D2 MOVEM.L D5/D6,leftOffset(A6) ;save source left, destination left offsets MOVE D5,D0 ;source left offset less ADD D3,D0 ; width of pixels to be moved MOVE D0,longCount(A6) ; determines inner loop bounds MOVE bitDepth(A6),D4 ;get source depth BFEXTU D2{0:D4},D1 ;set up 1 pixel of background color offLongLoop ; check to see if existing destination is untouched (equal to background) so that there is no ; concern about obliterating over a part of a character that kerns into this space. BFEXTU (A5){D6:D3},D0 ;get the existing background CMP.L D2,D0 ;is it background colored? BEQ.S @okToBlast ;if so, it is safe to cut and fill ; inner loop taken if some kerning has occured so that bits can not be moved directly over bkground @nxtPixel BFEXTU (A4){D5:D4},D0 CMP D0,D1 BEQ.S @skipInsert BFINS D0,(A5){D6:D4} @skipInsert ADD D4,D6 ADD D4,D5 CMP longCount(A6),D5 ;where to stop with the mask BLT.S @nxtPixel MOVEM.L leftOffset(A6),D5/D6 ;restore source left, destination left offsets BRA.S @nextRow ; if no kerning, data can be moved without concern for what is already there. @okToBlast BFEXTU (A4){D5:D3},D0 ;GET SRC DATA BFINS D0,(A5){D6:D3} ;move to destination @nextRow ADD.L A2,A4 ;BUMP SRCPTR TO NEXT ROW ADD.L A3,A5 ;BUMP DSTPTR TO NEXT ROW DBRA D7,offLongLoop ;LOOP ALL ROWS ; ; here, set up things for mask blt ; ; BRA.S decCount ;Always Branch ;———————————————————————————————————————————————————————————————————————————————————————————————— ; END Blit loop for the 68020+ machines ;———————————————————————————————————————————————————————————————————————————————————————————————— decCount IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY TST.B isSpline(A6) BEQ.S @1 TST.B nextBand(A6) ;another char band then call retrieve!!! BNE sNextBand ;do the next char band SUBQ.W #1,countCopy(A6) ;decrement partial draw character count BGT sNextCh ;LOOP IF MORE CHARS LEFT BRA.S STRDONE ENDIF @1 SUBQ.W #1,charsRemain(A6) ;decrement total character count SUBQ.W #1,countCopy(A6) ;decrement partial draw character 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 TST.B needs32Bit(A6) ;device need 32-bit addressing <7Apr90 KON> BEQ.S @0 ;=>IF NOT, JUST RETURN move.b MMUsave(a6),d0 ;get previous MMU state in d0 _rSwapMMUMode ;get previous mode in d0.b (can trash a0/a1/a2, d0/d1/d2) @0 tst.b crsrFlag(a6) ;is dst to a screen <7Apr90 KON> beq.s @NoShow ;no, then don't show cursor _SHOWCURSOR ;YES, RESTORE CURSOR @NoShow 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 fmOutFontH(A4),A2 ;GET FONT HANDLE MOVE.L (A2),A2 ;DE-REFERENCE IT ; ; Make buffer bold if necessary: ; CKBOLD CLR D2 ;GET READY FOR BYTE MOVE.B fmOutBold(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.L 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. ; MOVEQ #0,D2 ;GET READY FOR BYTE IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY TST.B isSpline(A6) ;is it a spline BNE.S CHECKUL ;Splines already italic, no italic needed ENDIF ;<1.6-11april89-CEL> MOVE.B fmOutItalic(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 #2,D3 ;LONGCNT:=ROWBYTES DIV 4 SUB #1,D3 ;LONGCOUNT-1 FOR DBRA LOOP MOVE sHeight(A6),D6 ;INIT ROW COUNTER SUB #1,D6 ;Baseline not slanted <38> MOVEQ #0,D4 ;INIT OFFSET BRA.S DOSLANT ;GO TO LOOP START NXTROW ADD.L D2,D4 ;OFFSET:=OFFSET+ITALIC MOVE.L D4,D5 ;COPY OFFSET LSR.L #4,D5 ;DELTA := OFFSET SCALED BY 16 NEG.L D5 ;make negative for BFEXTU MOVE.L A1,A0 ;SRCPTR:=DSTPTR SUB #4,A0 ;POINT TO LAST LONG MOVE D3,D1 ;INIT LOOP TO LONGCNT NXTLONG BFEXTU (A0){D5:0},D0 ;GET A SHIFTED LONG OF SRC SUB #4,A0 ;BUMP SRCPTR LEFT ONE LONG MOVE.L D0,-(A1) ;STORE IN DST AND BUMP DSTPTR DBRA D1,NXTLONG ;LOOP ALL LONG 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 fmOutULThick(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 IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY TST.B isSpline(A6) ;is it a spline BEQ.S @doOldAssign ;Splines already stretch, no stretchbits needed MOVE topClip(A6), D0 ;Use topClip and botClip since this is real size of buffer TST.W D0 BLT.S NOTUL ;If ascent is negative do not do it MOVE botClip(A6), D2 ;Real size of buffer BRA.S @skipOldAssign @doOldAssign ENDIF ;<1.6-11april89-CEL> MOVE sASCENT(A6),D0 ;stack ascent MOVE sDESCENT(A6),D2 ; @skipOldAssign 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 ? BGT.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 ; ; Setup fakeRgn, a dummy rectangular region ; NOTUL MOVE #10,FAKERGN+RGNSIZE(A6) ;SIZE=10 BYTES FOR RECT RGN MOVE.L DSTPIX+BOUNDS(A6),FAKERGN+RGNBBOX(A6) MOVE.L DSTPIX+BOUNDS+4(A6),FAKERGN+RGNBBOX+4(A6) IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY TST.B isSpline(A6) ;is it a spline BEQ.S @skipBandClip ; TST.B clipVert(A6) ;Can we try the fast blitting routine??? BEQ.S @skipBandClip ;go to clipping blit loop MOVE.W TEXTR2(A6), D1 ;get top MOVE.W D1, D2 ;Make a copy MOVE.W sAscent(A6), D0 ;place in reg for compare SUB.W origTopClip(A6), D0 ; BNE.S @topIsClipped ;top is clipped so do not add shadow extra TST.B fmOutShadow(A6) ;no shadowing so skip adjustment for it BEQ.S @noShadowSUB SUB.W #1, D1 ;adding to ymax value @noShadowSUB BRA.S @gotNewTop @topIsClipped ADD.W D0, D1 @gotNewTop MOVE.W D1, FAKERGN+RGNBBOX+TOP(A6) ;Fake top MOVE.W origBotClip(A6), D0 ;get the bottom clip CMP.W sDescent(A6), D0 ;are they the same BNE.S @noExtra ;no extra for shadow TST.B fmOutShadow(A6) ;no shadowing so skip adjustment for it BEQ.S @noExtra SUB.W #2, D0 ;add in for shadow @noExtra MOVE.W sAscent(A6), D1 ;place in reg for compare SUB.W D0, D1 ;subtract bottom clip ADD.W D1, D2 ;Add to TextR2 top MOVE.W D2, FAKERGN+RGNBBOX+BOTTOM(A6) ;Fake bottom ENDIF ; @skipBandClip LEA FAKERGN(A6),A0 ;GET ADDR OF FAKERGN MOVE.L A0,FAKEPTR(A6) ;POINT FAKE MASTERPTR TO IT ; ; SET UP SOURCE BITMAP TO TRANSFER TO SCREEN ; ; SRCPIX := buffer ; LEA SRCBITS(A6),A0 ;POINT TO source bits MOVE.L A0,A1 MOVE.L BUFSTART(A6),(A0)+ ;SET UP BASEADDR MOVE BUFROW(A6),(A0)+ ;SET UP ROWBYTES IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY TST.B isSpline(A6) ;is it a spline BEQ.S @skipAdjust ;Splines already stretch, no stretchbits needed MOVE sAscent(A6), D0 ;Get the ascent in D0 SUB topClip(A6), D0 ;What is the difference for adjustment ADD TEXTRECT+TOP(A6),D0 ;SET UP BOUNDS TOP MOVE D0,(A0)+ ;SET UP BOUNDS TOP BRA.S @skipNorm @skipAdjust MOVE TEXTRECT+TOP(A6),(A0)+ ;SET UP BOUNDS TOP @skipNorm ELSE MOVE TEXTRECT+TOP(A6),(A0)+ ;SET UP BOUNDS TOP ENDIF ;NEW MOVE BUFLEFT(A6),(A0)+ ;SET UP BOUNDS LEFT IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY TST.B isSpline(A6) ;is it a spline BEQ.S @skipTheAdjust ;Splines already stretch, no stretchbits needed MOVE sAscent(A6), D0 ;Get the ascent in D0 SUB topClip(A6), D0 ;What is the difference for adjustment ADD.W TEXTRECT+BOTRIGHT(A6), D0 ;Get the bottom MOVE.W D0,(A0)+ ;SET UP BOTTOM MOVE.W TEXTRECT+RIGHT(A6), (A0)+ ;Set up right BRA.S @skipNormPath @skipTheAdjust MOVE.L TEXTRECT+BOTRIGHT(A6),(A0)+ ;SET UP BOTTOM RIGHT @skipNormPath ELSE ; MOVE.L TEXTRECT+BOTRIGHT(A6),(A0)+ ;SET UP BOTTOM RIGHT ENDIF ; LEA SRCPIX(A6),A2 _BitsToPix TST.B maskFont(A6) BEQ @finishSrcPix ; LEA maskBits(A6),A0 ;POINT TO mask bits MOVE.L maskStart(A6),(A0)+ ;SET UP BASEADDR MOVE mBufRow(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 TST bitShift(A6) ;is the bit depth 1? BEQ.S @finishSrcPix ;————————————————————————————————————————————————————————————————————————————————————————————————— ; make fill loop ; ; Registers Use: ; D0 = xxxxxxx A0 = SrcPtr ; D1 = temp WidthInPixels A1 = DstPtr ; D2 = (2**PixelSize)-1.w A2 = Src rowBytes.l ; D3 = Dst Offset A3 = Dest rowBytes.w ; D4 = Src Offset A4 = xxxxxxx ; D5 = Src PixelSize.w A5 = xxxxxxx ; D6 = Height.w A6 = xxxxxxx ; D7 = Width In Pixels A7 = xxxxxxx ;————————————————————————————————————————————————————————————————————————————————————————————————— MOVE.L A3, -(SP) ;Save A3 MOVE.W bitDepth(A6), D5 ;bits per pixel MOVEQ #1, D2 ;2 to be shifted LSL.W D5, D2 ;2**Pixel Size SUB.W #1, D2 ;(2*PixelSize)-1 MOVE.W sHeight(A6), D6 ; SUB.W #1, D6 ;for the dbra MOVE.W mBufRow(A6), A3 ;row bytes of mask MOVE.W A3,D7 ;Shift by pixel depth LSL.W #3, D7 ;pixels=rowbytes*8 SUB.W #1, D7 ;for dbra MOVE.L bufStart(A6), A0 ;SrcPtr MOVE.L maskStart(A6), A1 ;DstPtr MOVE.W bufRow(A6), A2 ;Src rowBytes @nxtScan MOVE.W D7, D1 ;D1 for loop of the width MOVEQ #0, D3 ;Clear offset MOVEQ #0, D4 ;Clear offset @nxtPix BFEXTU (A0){D4,D5}, D0 ;get a pixel ADD.W D2, D0 ;create a carry bit if non zero LSR.W D5, D0 ;Shift to get black pixel in bottom BFINS D0, (A1){D3,1} ;Insert the bit into the mask ADD.W D5, D4 ;Increment the offset ADDQ #1, D3 ;Increment mask Pixel offset DBRA D1, @nxtPix ;cont to next pixel ADD.L A2, A0 ;bump to next row ADD.W A3, A1 ;bump to next row DBRA D6, @nxtScan ;cont to next scan MOVE.L (SP)+, A3 ;Restore A3 ;————————————————————————————————————————————————————————————————————————————————————————————————— ;————————————————————————————————————————————————————————————————————————————————————————————————— @finishSrcPix TST bitShift(A6) ;is the bit depth 1? BEQ.S @skipColorJam ; MOVE bitDepth(A6),srcPix+pixelSize(A6) ;set up bit depth MOVE bitDepth(A6),srcPix+cmpSize(A6) ;set up bit depth MOVE.L dstPix+pmTable(A6),srcPix+pmTable(A6) ;set up color table TST.B synFont(A6) ;is it a syn font??? BNE.S @skipColorJam ;use the dest color table MOVE.L WidthTabHandle,A0 ;Get the handle MOVE.L (A0), A0 ;Ptr MOVE.L widthNFNT(A0),D0 ;get resource ID in low word, NFNT bit in high word SUBQ #4,SP ;make space for function result MOVE.L #'fctb',-(SP) ;pass resource type MOVE D0,-(SP) ;pass resource ID _GetResource ;only uses D0,A0 MOVE.L (SP)+,D0 ;if it fails, then no color table to pass to MakeScaleTbl BEQ.S @skipColorJam ; MOVE.L D0,srcPix+pmTable(A6) ;set up color table, if any @skipColorJam ; ; check if any shadowing: ; CLR D3 ;GET READY FOR BYTE MOVE.B fmOutShadow(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. ; IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY TST.B isSpline(A6) BEQ.S oldAlloc2 ;Go to old way of allocating MOVE.L currentEnd(A6), A0 ;Get the current end of the buffer CLR.L (A0)+ ;ALLOW ONE LONG OF SLOP MOVE.L A0, buf2Start(A6) ;REMEMBER START OF BUF2 MOVE.L bufStart(A6),A1 ;POINT to first buffer MOVE.L bufSize(A6),D0 ;GET NUMBER OF LONGS IN BUF1 SUB.L #1,D0 ;INIT DBRA COUNTER MOVE.L D0, D1 ;Get copy of size SWAP D1 ;Get high order word for outer loop CpyBuff MOVE.L (A1)+,(A0)+ ;COPY FROM BUF1 TO NEW BUF2 DBRA D0,CpyBuff ;COPY ALL OF BUF1 DBRA D1,CpyBuff ;COPY ALL OF BUF1 CLR.L (A0)+ ;ALLOW ONE LONG OF SLOP MOVE BUFROW(A6),D0 ;GET 4 * NUMBER OF LONGS PER ROW SUB #1,D0 ;INIT LOOP COUNTER clrBuf2 CLR.L (A0)+ ;ALLOCATE AND CLEAR A LONG DBRA D0,clrBuf2 ;CLEAR 4 SCANLINES WORTH MOVE.L A0, buf2End(A6) ;REMEMBER END OF BUF2 CLR.L (A0)+ ;ALLOW ONE LONG OF SLOP BRA.S doneNEW2 oldAlloc2 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.L 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 doneNEW2 ELSE 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.L 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 ENDIF ; ; 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.L BUFSIZE(A6),D1 ;Init for first time of inner loop MOVE.L D1,D4 ;Get copy of bufSize SWAP D4 ;Get high order word SUB D0,D0 ;CLEAR X-BIT outAcross 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 D4,outAcross ;Outer loop for inner loop 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 MOVE SRCBITS+ROWBYTES(A6),D2 ;GET SRC ROWBYTES SUB D2,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.S DOWN2 ;NO, LOOP ALL LONGS DBRA D3,DOWN1 ;BOLD DOWN 2,3, OR 4 TIMES ; XOR the plain text into the shadow buffer MOVE.L bufStart(A6),A0 ;start of plain text MOVE.L A2,A1 ;start of shadowed text ADD D2,A1 ;bump down a line in the shadowed text MOVE.L bufSize(A6),D1 ;size of buffers in longs MOVE.L D1,D2 ;Get a copy of size SWAP D2 ;Get high word of long SUB D0,D0 ;clear x bit @xor MOVE.L (A0)+,D0 ;a line of plain text ROXR.L #1,D0 ;shift it right, extended EOR.L D0,(A1)+ ;combine with shadowed text DBRA D1,@xor ;repeat for all longs DBRA D2,@xor ;repeat outer loop with high order word ; ; 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) ;DSTRECT := SRCRECT MOVE.L TEXTRECT+4(A6),SRCRECT+4(A6) ADD #4,SRCRECT+BOTTOM(A6) ;PLUS 4 SCANS TALLER MOVE.L SRCRECT(A6),DSTRECT(A6) 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) _MAPRECT ;THEN MAPPED FOR SCALING @1 PEA SRCBITS(A6) ;PUSH SRCPIX MOVE.L maskBitsPtr(A6),-(SP) ;a mask? BEQ.S @noMask MOVE.L 4(SP),(SP) ;replace mask with copy of source @noMask PEA PORTBITS(A3) ;TRANSFER TO SCREEN IF Gaudi THEN ;fix intersection if ColorQD and Bass init TST.B isSpline(A6) ;is it a spline BEQ.S @doOld ;skip special stretchbit fix TST.B repeatBands(A6) ;if not banding then do nothing BEQ.S @doOld PEA DSTRECT(A6) ;PUSH DSTRECT = TEXTR2 PEA FAKERGN+RGNBBOX(A6) ; MOVE #2,-(SP) ;PUSH NRECTS=4 PEA FAKERGN+RGNBBOX(A6) ;Place results in FakRgn _RSECT ;CALC INTERSECTION MOVE.L FAKERGN+RGNBBOX(A6), trimSrcRect(A6) MOVE.L FAKERGN+RGNBBOX+4(A6), trimSrcRect+4(A6) PEA trimSrcRect(A6) ;Make new source rect for Banding PEA DSTRECT(A6) PEA SRCRECT(A6) _MAPRECT ;THEN MAPPED FOR SCALING PEA trimSrcRect(A6) ;Make new source rect for Banding IF HAS_COLOR THEN PEA trimSrcRect(A6) ;maskRect same as source rect ENDIF PEA FAKERGN+RGNBBOX(A6) ;Use calculated dst rect BRA.S @contArgs ENDIF @doOld PEA SRCRECT(A6) ;PUSH SRCRECT = TEXTRECT PEA SRCRECT(A6) ;maskRect same as source rect PEA DSTRECT(A6) ;PUSH DSTRECT = TEXTR2 @contArgs MOVE locMode(A6),-(SP) ;PUSH TEXTMODE TST.B doDither(A6) ;Should we add in Dither??? BEQ.S @noDither ; OR.W #$40, (SP) ;Or in the dither bit @noDither CLR.L -(SP) ;NO PATTERN FOR NOW MOVE.L CLIPRGN(A3),-(SP) ;PUSH CLIPRGN HANDLE MOVE.L VISRGN(A3),-(SP) ;PUSH VISRGN HANDLE PEA FAKEPTR(A6) ;PUSH FAKE HANDLE CLR -(SP) ;pass multicolor flag false _StretchBits ;TRANSFER BUFFER TO SCREEN ; if old port, srcOr, draw center part in bic; if bic, in srcOr ; (This is done for compatibility with older applications like MacProject and MacDraw that ; expect to put text on an arbitrary background, relying on the center of the shadow to show.) TST portBits+rowBytes(A3) ;a new port? BMI GOHOME MOVE locMode(A6),D0 CMP #srcOr,D0 BEQ.S @useBic CMP #srcBic,D0 BNE GOHOME @useBic ; restored altered srcBits MOVE.L bufStart(A6),srcBits+baseAddr(A6) SUB #4,srcBits+bounds+bottom(A6) ; adjust params for center portion StretchBits CLR.L maskBitsPtr(A6) ;no mask EOR #2,D0 ;change or to bic, bic to or MOVE D0,locMode(A6) ;adjust textmode ; ; Push params and call StretchBits to transfer buffer to screen ; NOSHAD PEA SRCPIX(A6) ;PUSH SRCBITS MOVE.L maskBitsPtr(A6),-(SP) ;may be 0 if no mask bitmap PEA PORTBITS(A3) ;TRANSFER TO SCREEN IF Gaudi THEN TST.B isSpline(A6) ;is it a spline BEQ @doOld ;skip special stretchbit fix TST.B repeatBands(A6) ;if not banding then do nothing BEQ.S @doOld PEA TEXTR2(A6) ;PUSH DSTRECT = TEXTR2 PEA FAKERGN+RGNBBOX(A6) ; MOVE #2,-(SP) ;PUSH NRECTS=2 PEA FAKERGN+RGNBBOX(A6) ;Place results in FakRgn _RSECT ;CALC INTERSECTION MOVE.L FAKERGN+RGNBBOX(A6), trimSrcRect(A6) MOVE.L FAKERGN+RGNBBOX+4(A6), trimSrcRect+4(A6) PEA trimSrcRect(A6) ;Make new source rect for Banding PEA TEXTR2(A6) PEA TEXTRECT(A6) _MAPRECT ;THEN MAPPED FOR SCALING PEA trimSrcRect(A6) ;Make new source rect for Banding PEA trimSrcRect(A6) ;maskRect same as source rect PEA FAKERGN+RGNBBOX(A6) ;Use calculated dst rect BRA.S @contArgs ENDIF @doOld PEA TEXTRECT(A6) ;PUSH SRCRECT = TEXTRECT PEA TEXTRECT(A6) ;maskRect same as source rect PEA TEXTR2(A6) ;PUSH DSTRECT = TEXTR2 @contArgs MOVE locMode(A6),-(SP) ;PUSH TEXTMODE TST.B doDither(A6) ;Should we add in Dither??? BEQ.S @noDither ; OR.W #$40, (SP) ;Or in the dither bit @noDither CLR.L -(SP) ;NO PATTERN FOR NOW MOVE.L CLIPRGN(A3),-(SP) ;PUSH CLIPRGN HANDLE MOVE.L VISRGN(A3),-(SP) ;PUSH VISRGN HANDLE PEA FAKEPTR(A6) ;PUSH FAKE HANDLE ; <07JUN92 SAH> ; The new way for text. The old multColor is now a bitfield, where bit 0 means that the ; src is Black/White only. multColor is now called drawFlags. moveq #0,d0 ; clear all flags <08JUN92 SAH> tst.b colorSource(a6) ; is it in fact color <08JUN92 SAH> bne.s @setColor ; yes, so set bit color mapped bit <08JUN92 SAH> moveq #1,d0 ; set b/w src bit <08JUN92 SAH> bra.s @callStretch ; and draw it <08JUN92 SAH> @setColor moveq #2,d0 ; set color mapped bit <08JUN92 SAH> @callStretch move.w d0,-(sp) ; push drawFlags <08JUN92 SAH> _StretchBits ;TRANSFER BUFFER TO SCREEN ;—————————————————————————————————————————————————————————————————————————————————————————————————————— ; We are done so let’s cleanup… ;—————————————————————————————————————————————————————————————————————————————————————————————————————— GOHOME MOVE.L saveStk(A6),SP ;throw away the buffers IF (hasSplineFonts) OR (Gaudi) THEN ; <31> DTY TST.B isSpline(A6) ;is it a spline BEQ @checkBitDivide ;skip spline cleanup TST.W repeatBands(A6) ;repeat bands left BEQ @splineClean ;we are done if none MOVE.L clipStorage(A6), SP ;Save Address on variable for later cleanup MOVE.W (SP)+, topClip(A6) ;Get new topClip MOVE.W (SP)+, botClip(A6) ;Get new botClip MOVE.W origCharCount(A6),D1 ;Re-Assign count MOVE.W D1,countCopy(A6) ;Re-Assign count MOVE stackOffset(A6),D0 ;either zero if stack was long aligned, or two if not MOVE.W D1,count(A6,D0) ;Re-Assign count MOVE.L SAVEA5(A6),A5 ;RESTORE GLOBAL PTR MOVE.L grafGlobals(A5),A4 ;set up grafGlobals pointer for getting real width MOVE.L fontPtr(A4),A4 ;POINT TO FMOUTPUT MOVE txMode(A3),D0 AND #$FFF7,D0 ;clear pattern bit (let stretch reject invalid modes) MOVE D0,locMode(A6) ;initialize copy MOVE.L PENLOC(A6), PNLOC(A3) ;RESTORE PNLOC TO ORIGINAL IF hasPenFraction THEN move.l grafGlobals(a5),a0 ; load quickDraw globals. move.w penLocFixed(a6),pnLocFixed(a0) ; restore fractional pen location. ENDIF TST PORTBITS+ROWBYTES(A3) ; is it a new port? BPL.S @useOld3 ; no, no fraction to restore MOVE PenLocHFrac(A6),pnLocHFrac(A3) ;restore fraction if applicable @useOld3 MOVE.B saveHilite(A6),HiliteMode ;restore hilite bit SUBQ.W #1, repeatBands(A6) ;Decrement band count ADDQ.L #4, clipStorage(A6) ;Bump by a long for next top and Bottom clip BRA NOTFAST ;Go and band the sucker encore @splineClean TST.L stackHandle(A6) ;Does it exist BEQ.S @cleanUp MOVE.L stackHandle(A6), A0 ;Get the handle in A0 for dispose routine _HUnlock ;Unlock the baby _DisposHandle ;Get rid of memory BRA.S @cleanUp ENDIF ;<1.6-11april89-CEL> @checkBitDivide MOVE charsRemain(A6),D0 SUB countCopy(A6),D0 MOVE D0,charsRemain(A6) ;if iterative, this will be greater than zero BGT secondHalf ;so there are more characters to draw @cleanUp BSET #hiliteBit,HiliteMode ;reset hilite override, in case colormap was skipped MOVEM.L (SP)+,D0-D7/A1-A4 ;RESTORE REGS TST.W stackOffset(A6) ;was the stack aligned? UNLK A6 BEQ.S @skipAlign ADDQ #2,SP @skipAlign RTD #PARAMSIZE ;Return and pop the stack <1.6-11april89-CEL> ENDPROC CalcCharExtra PROC EXPORT ;------------------------------------------ ; ; CalcCharExtra, given a 4.12 fixed point in D0 for a 1 point font, scales by the ; actual font point size, and by the scaling numerator and denominator returned by ; the font manager. The scaled extra is returned in 16.16 format in D0. Here the ; charExtra * size is scaled by denom/numer, since stretch will scale the resulting ; widths by numer/denom. Called by StdTxWidth, DrawText, TextMeasure. ; ; FMInNumer.h FOutDenom.h ; charExtra = ——————————— * ——————————— * input charExtra * requested pt. size ; FMInDenom.h FOutNumer.h fSize EQU $40E ;sorry, no width table offsets in globals (yet) MOVEM.L D1-D2/A0-A1,-(SP) ;preserve registers SUB.W #8,SP ;make space on stack for final fixMul and first fixMul MOVE.L D0,-(SP) ;push input charExtra MOVE.L WidthPtr,A0 ;point at width table MOVEQ #0,D0 ;zero high word MOVE fSize(A0),D0 ;scale up by requested point size SWAP D0 ;make into a fixed point number MOVE.L D0,-(SP) ;push requested point size _FixMul ;product on stack is charExtra * point size SUB #8,SP ;make room for result of fixRatio and next fixMul MOVE.W CurFMNumer+H,-(SP) ;push x input numer MOVE.W CurFMDenom+H,-(SP) ;push x input denom _FixRatio ;compute ratio input numer/denom SUBQ #4,SP ;make space for result MOVE.W FOutDenom+H,-(SP) ;push x output denom MOVE.W FOutNumer+H,-(SP) ;push x output numer _FixRatio ;compute ratio output denom/numer _FixMul ;calculate scale factor _FixMul ;scale by input charExtra MOVEM.L (SP)+,D0-D2/A0-A1 ;get result in D0, restore registers RTS ;home, James ENDPROC CASE OFF