[comp.sources.amiga] Warptext sources

billk@pnet01.UUCP (Bill W. Kelly) (06/27/87)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# Xshar: Extended Shell Archiver.
#	Run the following text with /bin/sh to create:
#	ReadMe
#	warptext.asm
#	warptext.i
# This archive created: Wed Jun 10 13:40:40 1987
# By: Craig Norborg (Purdue University Computing Center)
cat << \SHAR_EOF > ReadMe
Well, after all of this time, I've *finally* finished my WarpText routines.

I'm very sorry it took OVER TWO WEEKS longer than I had originally expected!
(The infamous SCHOOL_FINALS have struck again... :-)

Thanks go to all of you who offered suggestions as to how to do certain things.
I have tried to implement them.  If you don't see what you asked for working
yet, remember this is just a pre-release...  (Geez, someone wanted optional
'word-wrap' -- I don't know...)

Anyway, the following are the two files (source code) that you need to get
WarpText going.  They are separated by ">>>> CUT HERE <<<<" thingies.

I assembled them with the MetaComCo Asembler.

Well, Have fun!!!

P.S. This routine does alot more than my original one, but I didn't sacrifice
much speed.  It seems to spit out about 13,500 characters a second.
Not too shabby, eh? :-)
SHAR_EOF
cat << \SHAR_EOF > warptext.asm
* --------------------------------------------------------------------------
* WarpText.asm -- (PRE-RELEASE!) an ultra-fast,                   Bill Kelly
* super_spiffy text-emitting routine.  :-)                        06/04/87
*
* Copyright 1987 by Bill W. Kelly.
*
* THANKS:
*
*   Many thanks to Hayes C. Haugen for giving me the idea to write
*   these routines-- I took one look at Blitz and thought:
*   "I've *gotta* DO that!"  Well, thanks, Hayes -- I've done it.
*   Now, if I could *only* make a file requestor as nice as yours!!! :-)
*
*   Thanks also to the people who gave me suggestions about ways to improve
*   the WarpText routines I had originally written!  These are much nicer...
*
* COPYRIGHT NOTICE:
*
*   This code, and the name "WarpText," is Copyright 1987 by Bill W. Kelly.
*
* DISTRIBUTION INFORMATION:
*
*   You may distribute this code in any way you want to.  I would prefer
*   that you charge less than $10 for distribution, however, and please
*   leave this whole notice intact.  Please also distribute the file
*   "WarpText.i" together with "WarpText.asm" (this file).  Thanks!
*
*   NOTE: IF YOU ARE GOING TO MODIFY THE CODE, please make a little note
*         containing the date, what the original code was, and anything
*         else you deem necessary...
*
* USING WARPTEXT IN A PROGRAM:
*
*   That's what it's here for!
*
*   If you are going to distribute the source code with your program
*   please follow the restrictions under "DISTRIBUTION INFORMATION."
*
*   It would be neat, especially if you aren't distributing the source
*   with your program, if you could find a place somewhere in your program
*   (the "ABOUT" menu, for instance) to say something like,
*   "Using Bill Kelly's WarpText routines for speed!," however if you
*   don't seem to be able to do this... don't worry about it.  I would
*   really appreciate it, though!  Thanks!
*
*   PLEASE CONTACT ME BEFORE USING THIS CODE IN A COMMERCIAL PROGRAM!
*
* MY ADDRESS:
*
*   NAME: Bill W. Kelly
*   UUCP: {akgua, hplabs!hp-sdd, sdcsvax}!crash!pnet01!billk
*   ARPA: crash!pnet01!billk@nosc
*   INET: billk@pnet01.CTS.COM    | For UUCP, don't do just pnet01!billk;
*   USPS: 2507 Caminito La Paz    | please include the crash!pnet01!billk.
*         La Jolla, CA  92037     | Thanks!
*   FONE: (619) 454-1307
*
* PRE-RELEASE:
*
*   This is a pre-release version of WarpText.  In about half a month or
*   a month I plan to release a version of WarpText that comes with
*   an example program and has any reported bugs fixed.  I will also
*   be adding a real clearscreen (clear 'window') on a formfeed and some
*   other features.  If any of the code looks strange, or you notice
*   that I'm doing something like "moveq #0,dn" where I don't need to...
*   Well, you might mention it to save me time, although I will be going
*   back over the code to look for little things like this...
*   I took as much time as my schedule would permit to write this and get
*   it debugged and out.  There are probably a few strange or unneeded
*   things I've done -- I haven't *really* LOOKED at the code yet,
*   though I have tested it...  Ah well...
*
* GEE, THAT'S ALL VERY NICE, BUT HOW DO I CALL THESE ROUTINES???
*
*   Well, I have given you yet another structure to deal with...
*   Let me introduce you to WarpInfo...
*
*   STRUCTURE   WarpInfo,0      ; ...the <I> denotes internal use.
*       APTR    wi_TextFont     ;     Pointer to a TextFont structure.
*       APTR    wi_BitMap       ;     Pointer to a BitMap structure.
*       WORD    wi_WhichPlane   ;     Which bitplane to render into.
*       WORD    wi_Left         ;     Left edge of 'window' in char loc's.
*       WORD    wi_Top          ;     Top edge of 'window' in char loc's.
*       WORD    wi_Width        ;     Width of 'window' in char loc's.
*       WORD    wi_Height       ;     Height of 'window' in char loc's.
*       APTR    wi_WindowTop    ; <I> Address of top of 'window.'
*       APTR    wi_CurLine      ; <I> Address of start of current line.
*       APTR    wi_LastLine     ; <I> Address of start of last line.
*       WORD    wi_CurX         ; <I> Current X position.
*       WORD    wi_LastX        ; <I> Maximum X position on a line.
*       WORD    wi_BPMod        ; <I> # total possible chars on a line in bp
*       WORD    wi_Modulo       ; <I> Add this to get to next line.
*       LABEL   wi_SIZE
*
*   When you assemble WarpText.asm, it will expect to find this structure
*   in graphics directory of your include files.  It will do:
*   INCLUDE "graphics/warptext.i"   I have already created a file called
*   "WarpText.i" which should be distributed along with this file.
*
*   Now about the routines: there are only four routines that make up
*   WarpText.  You must call the InitWarpInfo routine before calling any
*   of the other three routines.
*
*   Please see each routine for information about how to call them.
*
* OH YEAH, BUG REPORTS:
*
*   What, bugs in *my* code???  (Shut up, Bill...!)
*
*   I would really appreciate hearing about the problems you find in
*   my code!  I welcome your input.  'Ya know, suggestions, questions,
*   comments, flames?, etc...
*
*   Remember, this is a pre-release version of WarpText.  I plan to release
*   a version that *actually* has an EXAMPLE program with it. (Gee...)
*   In this version I will fix all the reported bugs and may make some
*   changes if anyone comes up with any interesting suggestions.
*
*   Anyway,
*
* HAVE FUN!                                                         Bill
* --------------------------------------------------------------------------

    XDEF InitWarpInfo
    XDEF GotoXY
    XDEF GetXY
    XDEF WarpText

            NOLIST  ; I don't want to see all of this junque...

               INCLUDE "graphics/text.i"
               INCLUDE "graphics/gfx.i"
               INCLUDE "graphics/warptext.i"

            LIST    ; Turn listing back on...

* -----------------------------------------
* Seems like a good place to put some code:
* -----------------------------------------

            CODE    ; Ready...FIRE! ...Aim?

* --------------------------------------------------------------------------
* INITWARPINFO NEEDS:
*
* a0 - Pointer to an instance of the WarpInfo structure, with the following
*      fields initialized:
*
*   wi_TextFont:    Pointer to an open font.  (I.e. what OpenFont() returns
*                   to you, other than NULL.)
*   wi_BitMap:      Pointer to an initialized, 'working' BitMap structure.
*                   (E.g. Open a window.  Get the pointer to the screen
*                   out of wd_WScreen.  From there the BitMap structure is
*                   at sc_BitMap, which is an offset, not a pointer, into
*                   the Screen structure.)
*   wi_WhichPlane:  Which bitplane you want the routine to draw into.
*                   Numbering begins at zero.  On the Workbench screen
*                   (or any two-bitplane screen) the possible numbers for
*                   wi_WhichPlane are 0 and 1.
*   wi_Left:        Left edge of the 'window' (in character locations)
*                   you want the routine to write into.
*   wi_Top:         Top edge of the 'window' in character locations.
*   wi_Width:       Width of 'window' (also on character locations).
*   wi_Height:      Height of 'window' -- guess what? Character locations.
*
* REGISTER USAGE FOR INITWARPINFO:
*
* d0 - Left, Top, Width, Height, etc.
* d1 - wi_Modulo
* d2 - Scratch
* d3 - Y size of font
* d4 - Scratch
*
* a0 - Pointer to WarpInfo structure with above fields initialized.
* a1 - Addr of top of bitplane, wi_WindowTop, etc.
* a2 - Scratch
* --------------------------------------------------------------------------

InitWarpInfo:   movem.l d0-d4/a1-a2,-(sp)

                moveq   #0,d4                   ; Clear scratch.
                move.w  d4,wi_CurX(a0)          ; Store it in WarpInfo.

                move.w  wi_Width(a0),wi_LastX(a0)  ; Max X position.

                move.l  wi_BitMap(a0),a1        ; Get some stuff from bmap.

                moveq   #0,d2
                move.w  bm_BytesPerRow(a1),d2   ; #bytes per row in d2
                move.w  d2,wi_BPMod(a0)         ; #bytes per row->wi_BPMod

                move.w  wi_WhichPlane(a0),d4    ; Get bitplane#.
                asl.l   #2,d4                   ; Multiply plane# by four.
                move.l  bm_Planes(a1,d4.l),a1   ; Get address of bitplane.

                moveq   #0,d3
                move.l  wi_TextFont(a0),a2
                move.w  tf_YSize(a2),d3         ; Get YSize of font.

                moveq   #0,d1
                move.l  d2,d1                   ; Copy bytesperrow to d1.
                mulu.w  d3,d1                   ; YSize*BytesPerRow.
                move.w  d1,wi_Modulo(a0)        ; Store it in WarpInfo.

                moveq   #0,d4
                move.l  d1,d4                   ; Copy wi_modulo to scratch.
                mulu.w  wi_Top(a0),d4           ; Mul by Y offset.
                add.w   wi_Left(a0),d4          ; Add X offset.

                move.l  a1,a2                   ; BPlane addr to scratch.
                add.l   d4,a2                   ; Add offset to btpln addr.
                move.l  a2,wi_WindowTop(a0)     ; Stick in WarpInfo.
                move.l  a2,wi_CurLine(a0)       ; Stick in WarpInfo.

                moveq   #0,d2
                move.w  wi_Top(a0),d2           ; Copy Y top to scratch.
                add.w   wi_Height(a0),d2        ; Add Y height to Y top.
                move.l  d1,d4                   ; Copy wi_modulo to scratch.
                mulu.w  d2,d4                   ; Mul by Y offset.
                add.w   wi_Left(a0),d4          ; Add X offset.

                move.l  a1,a2                   ; BPlane addr to scratch.
                add.l   d4,a2                   ; Add offset to btpln addr.
                move.l  a2,wi_LastLine(a0)      ; Stick in WarpInfo.

                movem.l (sp)+,d0-d4/a1-a2

                rts

* --------------------------------------------------------------------------
* GOTOXY NEEDS:
*
* d0 - New X position.          \ All regs. but d1 preserved,
* d1 - New Y position.
*
* a0 - Pointer to initialized WarpInfo structure.
*
* NOTE: These positions are given in character locations, like everything
*       else...  The positions are relative to the 'window' you have
*       defined using InitWarpInfo.  Position 0,0 is the character in the
*       top left corner of the window.
*       This routine does no error checking.  (You're supposed to know
*       how big your window is...)
* --------------------------------------------------------------------------

GotoXY:         move.w  d0,wi_CurX(a0)      ; Set new X position.

                mulu.w  wi_Modulo(a0),d1    ; Make Y an offset into window
                add.l   wi_WindowTop(a0),d1 ; Add this offset to the window
                move.l  d1,wi_CurLine(a0)   ; to make it the new Y position.

                rts

* --------------------------------------------------------------------------
* GETXY NEEDS:
*
* a0 - Pointer to an initialized WarpInfo structure.
*
* It returns the current X position in d0 and the current Y
* position in d1.
* --------------------------------------------------------------------------

GetXY:          move.l  wi_CurLine(a0),d1   ; Get current Y addr
                sub.l   wi_WindowTop(a0),d1 ; Sub window to get Y offset.
                divu.w  wi_Modulo(a0),d1    ; Should not be a remainder.

                moveq   #0,d0
                move.w  wi_CurX(a0),d0      ; Get current X position.

                rts

* --------------------------------------------------------------------------
* WARPTEXT NEEDS:
*
* d0 - Number of characters to type. (count)
*
* a0 - Pointer to an initialized WarpInfo structure.  (See InitWarpInfo)
* a1 - Address of string of characters to type.
*
* REGISTER USAGE FOR WARPTEXT:  (All regs preserved but d0 which will be 0)
*
* d0 - Number of characters to type (count)
* d1 - Character to be emitted
* d2 - LoChar
* d3 - HiChar
* d4 - Current X position
* d5 - Scratch
* d7 - Bitplane modulo: add to get to next raster line in bitplane.
*
* a0 - Pointer to WarpInfo structure
* a1 - Address of string of characters to type
* a2 - Pointer to TextFont structure, address of tf_CharData
* a3 - Addr of Current line.
* a4 - Scratch
* a5 - Scratch
*
* STACK USAGE FOR WARPTEXT:
*
*  0(sp) - Last line
*  4(sp) - Top line
*  8(sp) - tf_YSize
* 12(sp) - tf_Modulo: add it to get to next line in font data
* 16(sp) - wi_Modulo: add it to get to next line in bitplane 'window'
* 20(sp) - Maximum (last) possible X position on a line
* --------------------------------------------------------------------------

sp_LastLine:    equ     0   ; Offsets into stack to get at this data.
sp_TopLine:     equ     4
sp_YSize:       equ     8
sp_tf_Mod:      equ     12
sp_wi_Mod:      equ     16
sp_LastX:       equ     20

NoChar:         equ     256 ; This is where the empty-box char is. ???

WarpText:   movem.l d1-d5/d7/a2-a5,-(sp)

            moveq   #0,d4
            move.w  wi_CurX(a0),d4      ; Get current X position.

            moveq   #0,d5
            move.w  wi_LastX(a0),d5     ; Get maximum X position.
            move.l  d5,-(sp)            ; Stick it on stack.  (1st item)

            move.w  wi_Modulo(a0),d5    ; Get wi_Modulo.
            move.l  d5,-(sp)            ; Stick it on stack.  (2nd item)

            move.l  wi_TextFont(a0),a2  ; Use TextFont to get some stuff:

              moveq   #0,d2
              move.b  tf_LoChar(a2),d2    ; Get tf_LoChar.

              moveq   #0,d3
              move.b  tf_HiChar(a2),d3    ; Get tf_HiChar.

              move.w  tf_Modulo(a2),d5    ; Get tf_Modulo.
              move.l  d5,-(sp)            ; Stick it on stack.  (3rd item)

              move.w  tf_YSize(a2),d5     ; Get tf_YSize
              move.l  d5,-(sp)            ; Stick it on stack.  (4th item)

              move.l  tf_CharData(a2),a2  ; Replace textfont w/ tf_Chardata.

            move.l  wi_WindowTop(a0),a4 ; Get addr of wi_WindowTop.
            move.l  a4,-(sp)            ; Stick it on stack.  (5th item)

            move.l  wi_LastLine(a0),a4  ; Get addr of wi_LastLine.
            move.l  a4,-(sp)            ; Stick it on stack.  (6th item)

            move.l  wi_CurLine(a0),a3   ; Get addr of wi_CurLine.

            moveq   #0,d7
            move.w  wi_BPMod(a0),d7     ; Get wi_BPMod.

            subq    #1,d0               ; Take one from count.
            moveq   #0,d1               ; Clear d1 because using .b size.
            subq    #1,d4               ; Take one from Current X.

DoNextChar:   addq    #1,d4               ; Add 1 to Current X.
DoNextSinAdd: move.b  (a1)+,d1            ; Move char to emit to d1.
              cmpi.b  #32,d1              ; Is it a space?
               beq     Blank
              cmp.b   d2,d1               ; Compare with LoChar.
               blt     BoffoChar           ; May be a LF, FF, CR, etc.
              cmp.b   d3,d1               ; Compare with HiChar.
               blt     DoNoChar

              move.l  a2,a4               ; Copy tf_CharData to scratch.
              sub.l   d2,d1               ; Sub LoChar from char.
              adda.l  d1,a4               ; Add char to tf_CharData.

DoChar:       move.l  a3,a5               ; Copy current line to scratch.
              adda.l  d4,a5               ; Add XPos to current line.

              move.l  sp_YSize(sp),d5     ; YSize is loop count.
              subq.l  #1,d5
MoveChar:       move.b  (a4),(a5)           ; Move line of char to bitplane.
                adda.l  sp_tf_Mod(sp),a4    ; Add tf_Modulo to tf_Chardata.
                adda.l  d7,a5               ; Add wi_BPMod to bitplane.
                 dbra    d5,MoveChar

Blank:        cmp.l   sp_LastX(sp),d4     ; Compare max X and Current X...
               ble     GotoDoNext          ; Do next if current <= max.

DoLF:         moveq   #0,d4               ; Xpos is zero now.

DoCR:         cmpa.l  (sp),a3             ; CMP sp_LastLine with current.
               beq     GotoNSA             ; Wrap on line if equ.

              adda.l  sp_wi_Mod(sp),a3    ; Point at next line.
               bra     GotoNSA             ; Do another character.

DoNoChar:   move.l  a2,a4               ; Copy tf_Chardata to scratch.
            add.l   #NoChar,a4          ; Point at empty-box char.
             bra     DoChar              ; Do the empty-box char.

BoffoChar:  cmpi.l  #10,d1              ; Is is a linefeed?
             beq     DoLF
            cmpi.l  #12,d1              ; Is it a formfeed?
             beq     DoFF
            cmpi.l  #13,d1              ; Is it a CR?
             beq     DoCR
             bra     DoNoChar           ; Fine. Put up the box.

DoFF:       moveq   #0,d4               ; Make X pos zero.  |  It doesn't
            move.l  sp_TopLine(sp),a3   ; Point at top      |  CLS yet.
             bra     GotoNSA

GotoDoNext: dbra    d0,DoNextChar       ; Keep looping?
             bra     WindUp              ; Loop is done. Clean up & bail.

GotoNSA:    dbra    d0,DoNextSinAdd     ; Do NextChar without adding.

WindUp:     addq.l  #8,sp               ; Get rid of stuff kept on stack.
            addq.l  #8,sp
            addq.l  #8,sp

            move.w  d4,wi_CurX(a0)      ; Store current X for next time.
            move.l  a3,wi_CurLine(a0)   ; Store current Y for next time.

            movem.l (sp)+,d1-d5/d7/a2-a5

            rts

        END
SHAR_EOF
cat << \SHAR_EOF > warptext.i
* ------------------------------------------------------------------------
* graphics/WarpText.i -- The include for an ultra-fast,     Bill Kelly
* super_spiffy text-emitting routine.  :-)                  06/01/87
*
* Copyright 1987 by Bill W. Kelly.  All Rights Reserved.
*
* This is meant to go in the Graphics directory of the assembler includes.
* When you assemble WarpText.asm, it includes: "graphics/WarpText.i"
* ------------------------------------------------------------------------

    STRUCTURE   WarpInfo,0      ; ...the <I> denotes internal use.
        APTR    wi_TextFont     ;     Pointer to a TextFont structure.
        APTR    wi_BitMap       ;     Pointer to a BitMap structure.
        WORD    wi_WhichPlane   ;     Which bitplane to render into.
        WORD    wi_Left         ;     Left edge of 'window' in char loc's.
        WORD    wi_Top          ;     Top edge of 'window' in char loc's.
        WORD    wi_Width        ;     Width of 'window' in char loc's.
        WORD    wi_Height       ;     Height of 'window' in char loc's.
        APTR    wi_WindowTop    ; <I> Address of top of 'window.'
        APTR    wi_CurLine      ; <I> Address of start of current line.
        APTR    wi_LastLine     ; <I> Address of start of last line.
        WORD    wi_CurX         ; <I> Current X position.
        WORD    wi_LastX        ; <I> Maximum X position on a line.
        WORD    wi_BPMod        ; <I> # total possible chars on a line in bp
        WORD    wi_Modulo       ; <I> Add this to get to next line.
        LABEL   wi_SIZE
SHAR_EOF