home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d1xx
/
d107
/
prosuite.lha
/
ProSuite
/
XText
/
xtext.asm
< prev
next >
Wrap
Assembly Source File
|
1987-10-31
|
19KB
|
611 lines
* *** xtext.asm *************************************************************
*
* XText -- The XText Routine
* (from the FastText algorithms created in January, 1986)
* from Book 1 of the Amiga Programmers' Suite by RJ Mical
*
* Copyright (C) 1986, 1987, Robert J. Mical
* All Rights Reserved.
*
* Created for Amiga developers.
* Any or all of this code can be used in any program as long as this
* entire copyright notice is retained, ok? Thanks.
*
* The Amiga Programmer's Suite Book 1 is copyrighted but freely distributable.
* All copyright notices and all file headers must be retained intact.
* The Amiga Programmer's Suite Book 1 may be compiled and assembled, and the
* resultant object code may be included in any software product. However, no
* portion of the source listings or documentation of the Amiga Programmer's
* Suite Book 1 may be distributed or sold for profit or in a for-profit
* product without the written authorization of the author, RJ Mical.
*
* HISTORY Name Description
* ------------ --------------- -------------------------------------------
* 27 Oct 86 RJ Mical >:-{)* Translated this file.
*
* ***************************************************************************
INCLUDE "xtext.i"
IFND AZTEC ; If AZTEC not defined, do it the standard way
XDEF _XText
XREF _custom
XREF _GfxBase
ENDC
IFD AZTEC ; If AZTEC defined, do it the non-standard way (sigh)
PUBLIC _XText
PUBLIC _custom
PUBLIC _GfxBase
ENDC
_XText:
* ***************************************************************************
* These FastText algorithms were created by =Robert J. Mical= in January 1986
* Copyright (C) 1986, =Robert J. Mical=
* All Rights Reserved
*
* This is my brute-force XText() routine.
* It presumes many things about text: that the characters come in
* pairs, that the characters are 8-bits wide (this one is not easily
* undone), and more.
*
* The theory of operation here is that I will build a single plane of
* normal characters (character data bits set, background bits clear)
* in the Normal Text Plane, using the data from the Output Characters
* Buffer. As needed, I will invert this plane (character bits clear,
* background bits set) into the Inverted Text Plane. There's two other
* globally accessible (pre-initialized) planes used: an AllClearPlane plane
* of all bits clear, and an AllSetPlane plane of all bits set.
*
* Using these four planes, I can construct a bitmap of all possible pen
* settings for the foreground and background. If corresponding bits
* in the FgPen and BgPen are:
* ----- -----
* 0 0 Use All Clear Plane
* 0 1 Use Inverted Text Plane
* 1 0 Use Normal Text Plane
* 1 1 Use All Set Plane
*
* Note that if FgPen and BgPen are equal, I don't have to bother
* constructing the Normal or Inverted Text Planes, since they'll
* never be used.
*
* An optimization that evolves out of this fact is that you can fill a line
* or part of a line of your text with spaces (blank characters) much more
* quickly by setting the foreground pen equal to the background pen. The
* trick with this optimization is to not spend too much time detecting
* whether or not an area of text is all blank, for you may lose the
* increased performance during the handling of normal text lines.
*
* A further optimization is that I'm guessing that many text calls
* will not require the inverted plane, so I won't make it until I
* discover that I need it. If programmers follow the
* Intuition-encouraged standard of pen 1 for foreground and pen 0
* for background, then the bits are: FgPen -- 00001
* BgPen -- 00000
* In fact, if the text is *any* color against a background of zero,
* this optimization works.
*
* For example, the plain PC monochrome text turns out to be pen 1 on
* pen 0. No need to invert here!
*
* So I won't bother constructing the inverted plane until I discover
* that it's needed. The cost of this is that I have to check a flag
* once per time that I find an inverted bit plane is called for (6 times
* maximum (though of course Dale would say 8 times maximum)), and the
* savings is avoiding an unnecessary inversion.
*
* Note that this routine works with character pairs while building the
* buffer. If you specify an odd number of characters, this routine will
* round up the character count to the next higher even number, and then
* build the buffer with that many characters. However, only the number
* of characters you specify will actually be printed to the screen.
*
* ON ENTRY (on stack):
* ARG0 = address of the XTextSupport structure
* ARG1 = address of the text string
* ARG2 = character count
* ARG3 = x position for text output
* ARG4 = y position for text output
DREGS EQU 0 ; Offset to the pushed D-Registers
DREGCOUNT EQU 6 ; How many D-Registers were pushed
AREGS EQU (DREGS+(DREGCOUNT*4)) ; Offset to the pushed A-Registers
AREGCOUNT EQU 5
FRONTPEN EQU (AREGS+(AREGCOUNT*4)) ; Local variable
BACKPEN EQU (FRONTPEN+2) ; Local variable
DRAWMODE EQU (BACKPEN+2) ; Local variable
XBLTSIZE EQU (DRAWMODE+2)
RETADDR EQU (XBLTSIZE+2) ; Our return address
ARG0 EQU (RETADDR+4) ; Offset to passed arguments
ARG1 EQU (ARG0+4)
ARG2 EQU (ARG1+4)
ARG3 EQU (ARG2+4)
ARG4 EQU (ARG3+4)
LEA -8(SP),SP ; Reserve memory for local variables
MOVEM.L A2-A6/D2-D7,-(SP)
MOVE.L ARG0(SP),A2 ; Get the XTextSupport structure address
MOVE.L #_custom,A5 ; Get the address of the custom chip
MOVE.L _GfxBase,A6 ; Load up A6 for graphics calls
* Check the character count.
* If it's zero, then split as there's nothing to do.
* If it's less than zero, this is the signal that the programmer
* wants *us* to figure out how long the string is. Nice touch, eh?
* If it's greater than zero, then presume it's valid.
MOVE.W ARG2+2(SP),D2 ; Get the character count
BEQ RETURN ; and split if there's none to do
BGT GOT_TEXT_COUNT ; If greater than zero, then it's real
MOVE.L ARG1(SP),A4 ; Address of text string
MOVEQ.L #-1,D2 ; Start with less than no characters
10$ ADDQ.W #1,D2 ; Increment character count
TST.B (A4)+ ; Test if next is end of text
BNE 10$ ; Branch if not
MOVE.W D2,ARG2+2(SP) ; Save as character count
GOT_TEXT_COUNT:
* The result of the following 3 instructions is created by the 2 below
* I include this commentary to keep things from getting confusing
* ADDQ #1,D2 ; to round up
* LSR.B #1,D2 ; Turn the char count into a pair count
* SUBQ.W #1,D2 ; (-1 for DBRA of PAIRLOOP below)
SUBQ.B #1,D2
LSR.B #1,D2
CALLSYS OwnBlitter ; Get that blitter
* Get local copies of the pens, jazzed around to take the DrawMode into
* account. Namely, if JAM1 then the background pen is automatically zero,
* and if the INVERSVID flag is set then swap the foreground/background pens
CLEAR D3 ; Save them as words
MOVE.B xt_FrontPen(A2),D3 ; Load up the local front pen
CLEAR D4 ; Start out presuming that back is zero
MOVE.B xt_DrawMode(A2),D5 ; Test the draw mode
MOVE.B D5,D6 ; Save a copy
ANDI.W #3,D5 ; Strip off INVERSVID (and any other) bit
MOVE.W D5,DRAWMODE(SP) ; and save the true drawmode
CMP.B #RP_JAM1,D5 ; Is it JAM1?
BEQ 1$ ; If it's JAM1, leave the local back as zero
MOVE.B xt_BackPen(A2),D4 ; else load up the local back pen
1$ ANDI.B #RP_INVERSVID,D6 ; Was INVERSVID bit set?
BEQ 2$ ; and skip if not
EXG D3,D4 ; else exchange the pen registers
2$
MOVE.W D3,FRONTPEN(SP) ; Save the local front pen
MOVE.W D4,BACKPEN(SP) ; Save the local back pen
MOVE.W xt_CharHeight(A2),D6 ; Build the bltsize word
LSL.W #6,D6 ; Height is shifted over as blitter likes it
MOVE.W D6,XBLTSIZE(SP) ; Save this partial for later
CMP.W D3,D4 ; Are the pens equal?
BEQ PLANESET ; If so, skip building the planes
* Wait 'til any blitting is done, and then initialize
* the blitter for my personal use ...
CALLSYS WaitBlit ; and wait for that baby to be free!
CLEAR D3
MOVE.W D3,bltamod(A5) ; Set up the SRCA and SRCB modulos
MOVE.W D3,bltbmod(A5)
SUBI.W #1,D3
MOVE.W D3,bltafwm(A5) ; Masks are all set
MOVE.W D3,bltalwm(A5)
CLEAR D3
MOVE.B xt_MaxTextWidth(A2),D3
SUBQ.W #2,D3
MOVE.W D3,bltdmod(A5)
MOVE.W #$0DFC,bltcon0(A5) ; Use ABD, minterm is A or B, don't
MOVE.W #$8000,bltcon1(A5) ; shift A, shift B by 8
MOVE.L xt_NormalTextPlane(A2),D3 ; Address of the normal text plane
MOVE.W xt_FontSelect(A2),D6 ; Get the address of the font data
LSL.W #2,D6
LEA xt_FontData(A2),A3
ADD.W D6,A3
MOVE.L (A3),A3
MOVE.L ARG1(SP),A4 ; Address of text string
MOVE.W xt_CharHeight(A2),D7
MOVE.W xt_Flags(A2),D6 ; Get the Flags
ANDI #SLIM_XTEXT,D6 ; and test if the programmer wants SLIM_XTEXT
BNE SLIM_CHARS ; and go build the text the "slim" way if so
; else we're doing text the faster "fat" way
MOVE.W XBLTSIZE(SP),D6 ; Get the blit size partial
ORI #1,D6 ; and make blit size one word wide
CMPI #8,D7 ; Can we do fast building?
BNE SLOW_PAIRLOOP ; If not 8, do it the "slow" way
PAIRLOOP:
* The normal text plane is constructed here.
* Do as much pre-calculating as possible before actually waiting for the
* blitter to be ready for re-use.
CLEAR D4 ; Get the address of the font data of
MOVE.B (A4)+,D4 ; the next character
LSL.W #4,D4 ; (This presumes that each char is 16 bytes)
ADD.L A3,D4
CLEAR D5 ; Get font data of next in pair (if there's
MOVE.B (A4)+,D5 ; not really a second character (odd-numbered
LSL.W #4,D5 ; string lengths) then this second move of
ADD.L A3,D5 ; data will be unnecessary, but at least is
; harmless since the buffer is *always*
; pair-sized and the speed improvement is
; great when handling two characters at once)
CALLSYS WaitBlit ; (this is redundant the first time through)
MOVE.L D4,bltapt(A5)
MOVE.L D5,bltbpt(A5)
MOVE.L D3,bltdpt(A5)
MOVE.W D6,bltsize(A5) ; Bombs away!
ADDQ.L #2,D3 ; Advance destination pointer to next word
DBRA D2,PAIRLOOP
* Done, so go start setting up the planes
BRA PLANESET
SLOW_PAIRLOOP:
* The normal text plane is constructed here.
* Done the "slow" way using a MULU because the character height isn't 8.
* Do as much pre-calculating as possible before actually waiting for the
* blitter to be ready for re-use.
CLEAR D4 ; Get the address of the font data of
MOVE.B (A4)+,D4 ; the next character
ADD.W D4,D4
MULU D7,D4 ; Offset * 2 * CharHeight
ADD.L A3,D4
CLEAR D5 ; Get font data of next in pair (if there's
MOVE.B (A4)+,D5 ; not really a second character (odd-numbered
ADD.W D5,D5 ; string lengths) then this second move of
MULU D7,D5
ADD.L A3,D5 ; data will be unnecessary, but at least is
; harmless since the buffer is *always*
; pair-sized and the speed improvement is
; great when handling two characters at once)
CALLSYS WaitBlit ; (this is redundant the first time through)
MOVE.L D4,bltapt(A5)
MOVE.L D5,bltbpt(A5)
MOVE.L D3,bltdpt(A5)
MOVE.W D6,bltsize(A5) ; Bombs away!
ADDQ.L #2,D3 ; Advance destination pointer to next word
DBRA D2,SLOW_PAIRLOOP
* Done, so go start setting up the planes
BRA PLANESET
SLIM_CHARS:
* OK, the programmer asked for SLIM_XTEXT, which is the half-size memory
* buffer for text to be built using the processor rather than the blitter
MOVE.L A5,-(SP) ; Save A5 during the SLIM build
CLEAR D0 ; Build the byte-size modulo
MOVE.B xt_MaxTextWidth(A2),D0
SUBQ #1,D0
MOVE.W D7,D1 ; Build the line height (-1 for DBRA)
SUBQ #1,D1
CMPI #8,D7 ; Can we do fast building?
BNE SLIM_SLOW_PAIRLOOP ; If not 8, do it the "slow" way
SLIM_PAIRLOOP:
* The normal "slim" text plane is constructed here.
CLEAR D4 ; Get the address of the font data of
MOVE.B (A4)+,D4 ; the next character
LSL.W #3,D4 ; (This presumes that each char is 8 bytes)
ADD.L A3,D4
MOVE.L D4,A0
CLEAR D5 ; Get font data of next in pair (if there's
MOVE.B (A4)+,D5 ; not really a second character (odd-numbered
LSL.W #3,D5 ; string lengths) then this second move of
ADD.L A3,D5 ; data will be unnecessary, but at least is
MOVE.L D5,A1
; harmless since the buffer is *always*
; pair-sized and the speed improvement is
; great when handling two characters at once)
MOVE.W D1,D6 ; Build the bltsize word
MOVE.L D3,A5
SLIM_BUILD:
MOVE.B (A0)+,(A5)+
MOVE.B (A1)+,(A5)
ADD.L D0,A5
DBRA D6,SLIM_BUILD
ADDQ.L #2,D3 ; Advance destination pointer to next word
DBRA D2,SLIM_PAIRLOOP ; Count down the character pairs to print
MOVE.L (SP)+,A5 ; Restore A5 at end of SLIM_BUILD
* Done, so go start setting up the planes
BRA PLANESET
SLIM_SLOW_PAIRLOOP:
* The normal "slim" text plane is slowly constructed here, slow because
* the characters are other than 8 lines tall.
CLEAR D4 ; Get the address of the font data of
MOVE.B (A4)+,D4 ; the next character
MULU D7,D4
ADD.L A3,D4
MOVE.L D4,A0
CLEAR D5 ; Get font data of next in pair (if there's
MOVE.B (A4)+,D5 ; not really a second character (odd-numbered
MULU D7,D5 ; string lengths) then this second move
ADD.L A3,D5 ; will be unnecessary, but at least is
MOVE.L D5,A1
; harmless since the buffer is *always*
; pair-sized and the speed improvement is
; great when handling two characters at once)
MOVE.W D1,D6 ; Build the bltsize word
MOVE.L D3,A5
SLIM_SLOW_BUILD:
MOVE.B (A0)+,(A5)+
MOVE.B (A1)+,(A5)
ADD.L D0,A5
DBRA D6,SLIM_SLOW_BUILD
ADDQ.L #2,D3 ; Advance destination pointer to next word
DBRA D2,SLIM_SLOW_PAIRLOOP ; Count down the pairs to print
MOVE.L (SP)+,A5 ; Restore A5 at end of SLIM_BUILD
* Done, so fall into starting setting up the planes
PLANESET:
* Well, that was quick, wasn't it. Here all of the required planes (except
* the bothersome Inverted Text Plane) are ready to go. So let's figure
* out how to initialize the plane pointers in the BitMap ...
LEA xt_TextBitMap(A2),A3
LEA bm_Planes(A3),A4 ; Get address of first plane pointer
CLEAR D0 ; Set up the pen-test mask
MOVE.W FRONTPEN(SP),D1 ; Fetch the foreground pen
MOVE.W BACKPEN(SP),D2 ; and the background pen
CLEAR D3
MOVE.B bm_Depth(A3),D3 ; Get the BitMap depth ...
SUBQ.W #1,D3 ; ... and set the loop count for DBRA
CLEAR D4 ; Clear the Inverted flag
PLANELOOP:
* First, find out if the foreground/background pattern for this plane
* is 00, 01, 10 or 11. based on the pattern, select the associated
* plane pointer for the BitMap
BTST D0,D1 ; If the bit is set in the foreground pen
BNE PAT_ONE ; then go process 1x combinations
* Else we have a 0x combination. Which one is it?
BTST D0,D2 ; This time test the background pen
BNE PAT_01 ; and if set then our pattern is 01
PAT_00:
MOVE.L xt_AllClearPlane(A2),A3 ; This plane is the 00 plane
BRA PLANE_STUFF
PAT_01:
* The dreaded Inverse Text Plane selector. If it doesn't exist yet,
* I have to create it now.
MOVE.L xt_InverseTextPlane(A2),A3 ; This plane is the inverse plane
TST.B D4 ; Test our Inverted Plane flag
BNE PLANE_STUFF ; and skip this mess if it's already set
; else we'll have to invert it.
ADDQ.B #1,D4 ; Set the inversion flag
* OK, so use the blitter inversion algorithm: Dest = NOT SRC.
CLEAR D5
MOVE.B xt_MaxTextWidth(A2),D5 ; Build the Group-of-2 values:
MOVE.W ARG2+2(SP),D6
ADDQ.W #1,D6 ; Get the first multiple of 2 that's greater
ANDI.W #$FFFE,D6 ; than or equal to the character count, and
SUB.W D6,D5 ; subtract that from the total buffer width
; to make the Group-of-2 row modulo
LSR.W #1,D6 ; Turn char count into pair count
OR.W XBLTSIZE(SP),D6 ; and prepare for starting the blitter
MOVEM.L D0-D1,-(SP)
CALLSYS WaitBlit ; Wait for the blitter before I jam it.
MOVEM.L (SP)+,D0-D1
MOVE.L xt_NormalTextPlane(A2),bltbpt(A5)
MOVE.L A3,bltdpt(A5)
MOVE.W D5,bltbmod(A5) ; Set up the SRCB and DEST modulos
MOVE.W D5,bltdmod(A5)
MOVE.W #$0533,bltcon0(A5)
MOVE.W #$0000,bltcon1(A5)
MOVE.W D6,bltsize(A5) ; Bombs away!
BRA PLANE_STUFF
PAT_ONE:
* We've got a 1x pattern. Which one do you suppose it is? Hmm ...
BTST D0,D2 ; This time, test the back pen only
BNE PAT_11
PAT_10:
* Normal Text Plane? No problem.
MOVE.L xt_NormalTextPlane(A2),A3
BRA PLANE_STUFF
PAT_11:
MOVE.L xt_AllSetPlane(A2),A3 ; This plane must have all bits set
* and fall into ...
PLANE_STUFF:
* OK, so A3 has the address of this plane's data. Stuff that baby
* into the BitMap structure.
MOVE.L A3,(A4)+
ADDQ #1,D0 ; Advance our mask to the next position
DBRA D3,PLANELOOP ; Loop on the depth of the BitMap
* Now, all done with the private use of the blitter. Here, I would prefer
* to retain exclusive use of the blitter even throughout the call to
* BlitBMRP below, but the system won't let me. Too bad!
CALLSYS DisownBlitter
* Well, now the BitMap is all ready to blast out our new line
* of text. Wasn't that fun? Now the simple final stroke: zap that
* data into the RastPort, using the ever-popular, cleverly-named
* BltBitMapRastPort function (if Dale wasn't so good, I'd suggest
* that we take him out and shoot him for that name).
*
* BlitBMRP wants:
*
* A0 = Source BitMap
* A1 = Destination RastPort
* A6 = GfxBase
*
* D0 = Source X
* D1 = Source Y
* D2 = Destination X
* D3 = Destination Y
* D4 = Pixel Width of block to be moved
* D5 = Scan-line Height of block to be moved
* D6 = Minterm
CLEAR D5
MOVE.W xt_CharHeight(A2),D5 ; Height of transfer
MOVE.W #XTEXT_CHARWIDTH,D4 ; Create the blit width ...
MOVE.W ARG2+2(SP),D3 ; Character count
MULU D3,D4 ; Width of transfer (creates LONG)
MOVE.L ARG4(SP),D3 ; Get the Y position into D3
MOVE.L ARG3(SP),D2 ; Get the X position into D2
CLEAR D1 ; Source x and y are 0
CLEAR D0
MOVE.L xt_OutputRPort(A2),A1 ; and get the RPort of the display
LEA xt_TextBitMap(A2),A0 ; Get the address of the BitMap arg
* The DrawMode defines what minterm we use and which routine we call.
CMP.W #RP_JAM1,DRAWMODE(SP) ; Are we doing JAM1?
BEQ DO_JAM1
* The DrawMode can be JAM2 or COMPLEMENT. Which is it, hmm?
MOVE.L #$C0,D6 ; Minterm (simple transfer) for JAM2
CMP.W #RP_JAM2,DRAWMODE(SP) ; Is it really JAM2?
BEQ BBMRP ; Branch if so
MOVE.L #$60,D6 ; Only other is complement mode
BBMRP:
CALLSYS BltBitMapRastPort ; Do the normal (fast) BBMRP
BRA RETURN
DO_JAM1:
* Call BltMaskBitMapRastPort, which is the same as BBMRP except that a
* mask is used to cookie-cut the source into the destination.
* JAM1 requires a mask, because JAM1 is cookie-cut!
* The mask goes into A2. If either pen was non-zero then we built
* the normal plane so use that as the mask,
* else use the AllZeroPlane for the mask (which produces zip imagery!).
* The minterm sez: cut me in, daddio.
MOVE.B xt_DrawMode(A2),D6 ; Was this inverse video?
ANDI.B #RP_INVERSVID,D6
BNE 1$ ; If so, use inverse JAM1 minterm
MOVE.L #$E0,D6 ; else use normal JAM1 minterm
BRA 2$
1$ MOVE.L #$B0,D6
2$ TST.W FRONTPEN(SP) ; Was the front pen zero?
BNE 3$ ; If not then get Normal for mask
TST.W BACKPEN(SP) ; Was the back pen zero?
BNE 3$ ; If not then get Normal for mask
MOVE.L xt_AllClearPlane(A2),A2 ; AllClearPlane is the mask
BRA 4$
3$ MOVE.L xt_NormalTextPlane(A2),A2 ; use the plane as the mask
4$ CALLSYS BltMaskBitMapRastPort ; Do the not-as-fast BMBMRP
RETURN:
MOVEM.L (SP)+,A2-A6/D2-D7
LEA 8(SP),SP ; Release memory of local variables
RTS
END