;*   Prg. draw_text.asm
;*   Autor: Stephan Laage                                                                                           SteLa
;*   (c) MAXON COMPUTER GmbH 1989                                                                                                       Februar/Maerz 1988
;*   KICKSTART 1989

                        cseg

                        public  _GfxBase, _draw_text

;* Offsets der Graphics-Bibliothek

LVODraw                 equ             -246
LVOMove                 equ             -240

;* Offsets der RastPort-Struktur

rp_linpntcnt    equ             $1f
rp_Flags                equ             $20
rp_LinePtrn             equ             $22
rp_cp_x                 equ             $24
rp_cp_y                 equ             $26
rp_Font                 equ             $34

;* Offsets der TextFont-Struktur

tf_YSize                equ             $14
tf_XSize                equ             $18
tf_Baseline             equ             $1a
tf_LoChar               equ             $20
tf_HiChar               equ             $21
tf_CharData             equ             $22
tf_Modulo               equ             $26
tf_CharLoc              equ             $28
tf_CharSpace    equ             $2c
tf_CharKern     equ             $30

;* Offsets der Uebergabe-Parameter

rp                              equ             8                               ;Zeiger auf den RastPort
str                             equ             rp+4                    ;Zeiger auf den auszugebenden Text
dir                             equ             str+4                   ;Ausgaberichtung

;* Offsets der lokalen Variablen

char_len                equ             -4                              ;Laenge des Zeichens
pat_len                 equ             char_len - 2    ;Laenge des Musters
x_len                   equ             pat_len - 2             ;Zeichenlaenge in X-Richtung
y_len                   equ             x_len - 2               ;Zeichenlaenge in Y-Richtung
x_step                  equ             y_len - 2               ;Linienabstand in X-Richtung
y_step                  equ             x_step - 2              ;Linienabstand in Y-Richtung
x_he                    equ             y_step - 2              ;Hoehe in X-Richtung
y_he                    equ             x_he - 2                ;Hoehe in Y-Richtung
x_korr                  equ             y_he - 2                ;X-Korrektur
y_korr                  equ             x_korr - 2              ;Y-Korrektur

;* Konstanten

FRST_DOT                equ             $01


;* DRAW_TEXT *************************************************************
;* zeichnet einen Text in beliebige Richtungen
;* Syntax: draw_text(rp, s, d)
;*                              struct RastPort *rp             Zeiger auf den RastPort (32 Bit)
;*                              char *s                                 Zeiger auf den Text (32 Bit)
;*                              int d                                   Ausgabe-Richtung (16 Bit)

_draw_text      link    a5,#-24                                 ;lokaler Speicher: 10 Worte
                        movem.l a2-a4/d2-d7,-(sp)               ;alle Register sichern
                        movea.l _GfxBase,a6                             ;GfxBase laden
                        movea.l rp(a5),a1                               ;Adresse des RastPorts -> a1
                        move.b  #15,rp_linpntcnt(a1)    ;16-Punkte Linienmuster
                        or.b    #FRST_DOT,rp_Flags(a1)  ;Musterbeginn beim ersten Punkt
                        moveq   #0,d2                                   ;d2 und d3 loeschen
                        moveq   #0,d3
                        move.w  rp_cp_x(a1),d2                  ;aktuelle X-Position -> d2
                        move.w  rp_cp_y(a1),d3                  ;aktuelle Y-Position -> d3
                        movea.l rp_Font(a1),a2                  ;Adresse des Fonts -> a2
                        move.w  tf_XSize(a2),d0
                        subq.w  #1,d0
                        move.w  d0,char_len(a5)                 ;char_len = tf_XSize - 1
                        movea.l str(a5),a3                              ;Adresse des Strings -> a3
                        moveq   #0,d6                                   ;Kern-Groesse loeschen
                        cmpi.w  #8,dir(a5)                              ;Ausgaberichtung >= 7 ?
                        bcc             drawexit                                ;wenn ja, Routine verlassen
                        lea             datatab(pc),a0                  ;Adresse der Datentabelle -> a0
                        move.w  dir(a5),d0                              ;Ausgaberichtung -> d0
                        asl.w   #3,d0                                   ;multiplitzieren mit 8
                        adda.w  d0,a0                                   ;Tabellenposition berechnen
                        move.w  (a0)+,x_step(a5)                ;Schrittweite aus der Tabelle
                        move.w  (a0)+,y_step(a5)                ;laden
                        move.w  (a0)+,x_korr(a5)                ;Korrektur-Abstand aus der
                        move.w  (a0)+,y_korr(a5)                ;Tabelle laden
                        move.w  tf_YSize(a2),d0
                        move.w  d0,d1
                        muls    x_step(a5),d0
                        neg.w   d0
                        move.w  d0,x_he(a5)                             ;X-Zeichenhoehe berechnen
                        muls    y_step(a5),d1
                        neg.w   d1
                        move.w  d1,y_he(a5)                             ;Y-Zeichenhoehe berechnen
                        move.w  char_len(a5),d0
                        move.w  d0,d1
                        muls    y_step(a5),d0
                        move.w  d0,x_len(a5)                    ;X-Zeichenlaenge berechnen
                        muls    x_step(a5),d1
                        neg.w   d1
                        move.w  d1,y_len(a5)                    ;Y-Zeichenlaenge berechnen
                        move.w  tf_Baseline(a2),d0              ;tf_Baseline -> d1
                        move.w  d0,d1                                   ;tf_Baseline -> d0
                        muls    x_step(a5),d0
                        sub.w   d0,d2                                   ;X-Startposition korrigieren
                        muls    y_step(a5),d1
                        sub.w   d1,d3                                   ;Y-Startposition korrigieren

mainloop        moveq   #0,d4                                   ;d4 loeschen
                        move.b  (a3)+,d4                                ;aktuelles Zeichen -> d4
                        beq             drawend                                 ;Textende markiert durch '\0'
                        cmp.b   tf_LoChar(a2),d4                ;Zeichenwert zu klein ?
                        bcs.s   corrchar                                ;wenn ja, Sprung
                        cmp.b   tf_HiChar(a2),d4                ;Zeichenwert zu gross ?
                        bcs.s   charokay                                ;wenn nicht, Sprung
corrchar        move.b  tf_HiChar(a2),d4
                        addq    #1,d4                                   ;Joker fuer ungueltige Zeichen
charokay        sub.b   tf_LoChar(a2),d4
                        asl.w   #2,d4                                   ;Zeichenwert * 4 -> d4
                        movea.l tf_CharLoc(a2),a0               ;Adresse der Loc-Tabelle -> a0
                        move.w  (a0,d4),d5                              ;Offset des Musters -> d5
                        move.w  2(a0,d4),pat_len(a5)    ;Laenge des Musters -> pat_len
                        lsr.w   #1,d4                                   ;Zeichenwert * 2 -> d4
                        movea.l tf_CharKern(a2),a0              ;Adresse der Kern-Tabelle -> a0
                        cmp.l   #0,a0                                   ;existiert die Kern-Tabelle ?
                        beq.s   testprop                                ;Sprung, wenn nicht
                        move.w  (a0,d4),d6                              ;Kern-Abstand laden
testprop        movea.l tf_CharSpace(a2),a0             ;Adresse der Space-Tabelle -> a0
                        cmp.l   #0,a0                                   ;existiert die Tabelle ?
                        beq.s   nospace                                 ;Sprung, wenn nicht
                        move.w  (a0,d4),d0
                        add.w   d6,d0                                   ;char_len =
                        subq.w  #1,d0                                   ;  tf_CharSpace + tf_CharKern - 1
                        move.w  d0,char_len(a5)
                        muls    y_step(a5),d0
                        move.w  d0,x_len(a5)                    ;x_len = char_len * x_step
                        move.w  char_len(a5),d0
                        muls    x_step(a5),d0
                        neg.w   d0
                        move.w  d0,y_len(a5)                    ;y_len = - char_len * y_step
nospace         movea.l tf_CharData(a2),a4              ;Adresse der Datentabelle -> a4
                        move.w  d5,d1                                   ;Offset -> d1
                        lsr.w   #3,d1                                   ;Division / 8
                        adda.w  d1,a4                                   ;a4 zeigt auf die aktuellen Daten
                        move.w  tf_YSize(a2),d7                 ;Texthoehe (Schleifenz.) -> d7
                        subq.w  #1,d7

intloop         move.b  (a4),d0                                 ;erstes Datenbyte laden
                        asl.l   #8,d0
                        move.b  1(a4),d0                                ;zweites Datenbyte laden
                        asl.l   #8,d0
                        move.b  2(a4),d0                                ;evtl. drittes Datenbyte laden
                        asl.l   #8,d0
                        move.w  d5,d1                                   ;Offset -> d1
                        andi.w  #$0007,d1                               ;Offset modulo d1
                        asl.l   d1,d0
                        lsr.l   d6,d0                                   ;Kern-Abstand herstellen
                        move.w  #$ffff,d1                               ;Maske in d1 aufbauen
                        move.w  pat_len(a5),d0
                        add.w   d6,d0                                   ;Kern-Abstand addieren
                        lsr.w   d0,d1                                   ;0-Bits einschieben
                        not.w   d1                                              ;Maske invertieren
                        swap    d0                                              ;Muster in das untere Wort
                        and.w   d1,d0                                   ;ueberzaehlige Bits ausblenden
                        movea.l rp(a5),a1                               ;Adresse des RastPorts
                        move.w  d0,rp_LinePtrn(a1)              ;Muster setzen
                        move.l  d2,d0                                   ;X-Position -> d0
                        move.l  d3,d1                                   ;Y-Position -> d1
                        jsr             LVOMove(a6)
                        move.l  d2,d0                                   ;X-Position -> d0
                        add.w   x_len(a5),d0                    ; + Zeichenlaenge
                        move.l  d3,d1                                   ;Y-Position -> d1
                        add.w   y_len(a5),d1                    ; + Zeichenlaenge
                        movea.l rp(a5),a1                               ;Adresse des RastPorts
                        jsr             LVODraw(a6)
                        add.w   x_step(a5),d2                   ;X-Position heraufzaehlen
                        add.w   y_step(a5),d3                   ;Y-Position heraufzaehlen
                        adda.w  tf_Modulo(a2),a4                ;Datenzeiger heraufzaehlen
                        dbf             d7,intloop

                        add.w   x_he(a5),d2                             ;X-Position zuruecksetzen
                        add.w   y_he(a5),d3                             ;Y-Position zuruecksetzen
                        add.w   x_len(a5),d2                    ;X-Position + Zeichenlaenge
                        add.w   y_len(a5),d3                    ;Y-Position + Zeichenlaenge
                        add.w   x_korr(a5),d2                   ;Vorruecken zum naechsten
                        add.w   y_korr(a5),d3                   ;Zeichen
                        bra             mainloop

drawend         move.w  #$ffff,rp_LinePtrn(a1)  ;Liniemuster zuruecksetzen
                        move.w  tf_Baseline(a2),d0              ;tf_Baseline -> d1
                        move.w  d0,d1                                   ;tf_Baseline -> d0
                        muls    x_step(a5),d0
                        add.w   d0,d2                                   ;X-Position korrigieren
                        muls    y_step(a5),d1
                        add.w   d1,d3                                   ;Y-Position korrigieren
                        move.w  d2,d0
                        move.w  d3,d1
                        jsr             LVOMove(a6)                             ;neue Position setzen

drawexit        movem.l (sp)+,a2-a4/d2-d7               ;alle Register wiederherstellen
                        unlk    a5                                              ;lokalen Speicher freigeben
                        rts

;* Die Tabelle enthaelt die Werte fuer x_step, y_step, x_korr und y_kor
;* jeweils fuer die Ausgaberichtungen 0 bis 7

datatab         dc.w     0,  1,  1,  0                  ;0 = nach rechts
                        dc.w     1,  1,  1, -1                  ;1 = aufwaerts und nach rechts
                        dc.w     1,  0,  0, -1                  ;2 = aufwaerts
                        dc.w     1, -1, -1, -1                  ;3 = aufwaerts und nach links
                        dc.w     0, -1, -1,  0                  ;4 = nach links
                        dc.w    -1, -1, -1,  1                  ;5 = abwaerts und nach links
                        dc.w    -1,  0,  0,  1                  ;6 = abwaerts
                        dc.w    -1,  1,  1,  1                  ;7 = abwaerts und nach rechts

