; Description:  Outline font test, doing everything fully, so that the
;               correct engine for that font can be used to ceate the
;               characters, rather than just use them as is.
;
;                I had to use ASM to call the correct library routines
;               for non-bullet fonts, as FDConvert only does for one
;               library, not interchangable ones.
;
; Requires:     amigalibs.res with OS3.1 includes (from NewCommandSet1.70)
;               Probably OS3+, maybe OS2+
;
; To do:        Write functions for the following:
;                   Use of bold, italic, underlined fonts
;                   Anything else that seems a good idea at the time
;                   Carrige returns in the print string
;                   Rather than copy then BltTemplate_, I need to do a fast ASM version
;
; Type:         SYSTEM
;
; Author:       David McMinn <dmcminn@house-of-mojo.freeserve.co.uk>

WBStartup
DEFTYPE.w




; ############################################################################
; ####################### START OF OUTLINE ROUTINES ##########################
; ############################################################################
NEWTYPE.GlyphInfo
    *gi_otag.TagItem        ; Pointer to the location of the otag file in memory
    *gi_library.Library     ; Pointer to the library used for this type of font
    *gi_engine.GlyphEngine  ; Pointer to the engine within the library
    gi_xdpi.w               ; X dpi of the target output device
    gi_ydpi.w               ; Y dpi of the target output device
    gi_pointsize.q          ; Current pointsize
    gi_angle.w              ; Current rotation
    gi_spacewidth.l         ; The width of a space in stupid measurement units
End NEWTYPE


; ----------------------------------------------------------------------------


; -----------------------------------------------------------------------------
; NAME:
;       Glyph_CloseEngine
;
; SYNOPSIS:
;       Glyph_CloseEngine{*gi}
;
;       Glyph_CloseEngine{.GlyphInfo}
;
; FUNCTION:
;        This function releases all resources that are contained within the
;       GlyphInfo newtype specified in the pointer passed as a parameter.
;       Specifically, this closes the glyph engine, the library it came
;       from and then frees the .otag file from memory.
;
; INPUTS:
;       *gi.GlyphInfo -- a pointer to a GlyphInfo newtype. It is safe to call
;                        this function with a NULL pointer
;
; RESULT:
;       Resources are freed
;
; BUGS:
;       None
;
; SEE ALSO:
;       Glyph_OpenEngine
;
;-----------------------------------------------------------------------------
Statement Glyph_CloseEngine{*gi.GlyphInfo}
    ; If a non-NULL pointer is passed in
    If *gi
        ; Try to free the engine
        If *gi\gi_engine
;            CloseEngine_ *gi\gi_engine
            MOVEA.l -4(a4),a0               ; Get *gi into a0
            MOVEA.l 4(a0),a6                ; Get proper library base into a6
            MOVEA.l 8(a0),a0                ; Glyph Engine into a0
            JSR     -$24(a6)                ; JSR to CloseEngine_
            *gi\gi_engine = 0
        End If

        ; Try to free the library
        If *gi\gi_library
            CloseLibrary_ *gi\gi_library
            *gi\gi_library = 0
        End If

        ; Try to free the otag file from memory
        If *gi\gi_otag
            FreeVec_ *gi\gi_otag
            *gi\gi_otag = 0
        End If
    End If
End Statement


; ----------------------------------------------------------------------------


; -----------------------------------------------------------------------------
; NAME:
;       Glyph_OpenEngine
;
; SYNOPSIS:
;       success = Glyph_OpenEngine{*gi, fontname}
;
;       long = Glyph_OpenEngine{.GlyphInfo, string}
;
; FUNCTION:
;        This function tries to open all the required resources for rendering
;       glyphs from the specified font.
;
; INPUTS:
;       *gi.GlyphInfo -- Pointer to a GlyphInfo newtype. This should not be
;                        initialised before calling this function, if it
;                        has been used before make sure you free all resources
;                        by calling Glyph_CloseEngine first.
;       fontname$ -- The name of the font you wish to open. This is
;                    specified as the full path to the font and the name of it,
;                    minus the .otag extension, i.e. "FONTS:CGTimes"
;
; RESULT:
;        On success this function returns TRUE. On failure, it will
;       return FALSE.
;
; BUGS:
;       None
;
; SEE ALSO:
;       Glyph_CloseEngine
;
;-----------------------------------------------------------------------------
Function.l Glyph_OpenEngine{*gi.GlyphInfo,fontname$}
    DEFTYPE.b           *enptr      ; Pointer to the start of the engine name string
    DEFTYPE.l           *ge         ; The glyph engine for this font
    DEFTYPE.s           sename      ; The name of the scaling engine
    DEFTYPE.s           selib       ; The name of the library for this engine
    DEFTYPE.s           otpath      ; The full path and name of the font + .otag
    DEFTYPE.w           ge_ok       ; Flag to show if the glyph engine was set up OK

    DEFTYPE.TagItem     *otag       ; Pointer to the otag data in memory
    DEFTYPE.l           otagsize    ; Size of the .otag file for this font
    DEFTYPE.w           dfh_id      ; The ID field from the diskfontcontents structure (.font file)
    DEFTYPE.TagItem     *ptr        ; Working pointer, for use with the OTAG taglist

    Dim tag.TagItem(3)              ; The taglist used to set options in the glyph engine

    ; Initialise pointer to .otag file in memory
    *gi\gi_otag = 0

    ; Try to read the font contents file (.font file) from FONTS:
    If ReadFile(0,fontname$+".font")
        FileInput 0
        ; If we could open it, read the first two bytes into a word, for recognition
        ReadMem 0,&dfh_id,2
        PopInput
        CloseFile 0
    End If

    ; Check if the font is an outline font
    If dfh_id=#OFCH_ID
        ; If it is then we read the contents of the .otag file (Outline TAG file)
        If ReadFile(0,fontname$+".otag")
            FileInput 0
            otagsize.l = Lof(0)
            *gi\gi_otag = AllocVec_(otagsize, #MEMF_CLEAR|#MEMF_PUBLIC)
            If(*gi\gi_otag) Then ReadMem 0,*gi\gi_otag,otagsize
            PopInput
            CloseFile 0
        End If
    End If

    ; If the otag file was read into memory, this pointer will be valid
    ; and we can process it that little bit extra (sort out OT_Indirects
    ; (which are ti_Datas that are supposed to be pointers, but are specified
    ; as offsets.
    If *gi\gi_otag
        If *gi\gi_otag\ti_Tag<>#OT_FileIdent OR *gi\gi_otag\ti_Data<>otagsize
            ; This must be the first tag and data, it is to verify that the otag file is valid
            Glyph_CloseEngine{*gi}
        Else
            ; Now we have the .otag file and it is valid, we can begin processing it
            ; Start from the second tag (as we know that #OT_FileIdent is the
            ; first tag)
            *ptr = *gi\gi_otag + SizeOf.TagItem
            While *ptr\ti_Tag
                ; For all the tags check if the indirect flag is set, and if it is
                ; add the base address of the data block to the tag data.
                ; That is because the tag data specifies an offset not an address.
                If *ptr\ti_Tag & #OT_Indirect Then *ptr\ti_Data=*ptr\ti_Data+*gi\gi_otag
                *ptr = *ptr + SizeOf.TagItem
            Wend
        End If
    End If


    ;  Return a failure if we do not have a valid outline taglist
    If *gi\gi_otag=0 Then Function Return 0


    ; Try to get pointer to the engine name string, from the taglist
    *enptr = GetTagData_(#OT_Engine, 0, *gi\gi_otag)
    If *enptr=0
        ; If we couldn't find the name string then we need to return a
        ; failure
        Glyph_CloseEngine{*gi}
        Function Return 0
    End If


    ; Try to get the width of a space character in ridiculous units
    *gi\gi_spacewidth = GetTagData_(#OT_SpaceWidth, 0, *gi\gi_otag)


    ; Get the name of the engine and append ".library" to get the name of the
    ; library that the engine resides in. Try to open the library, return a
    ; failure if we couldn't
    sename = Peek$(*enptr)
    selib = sename+".library"
    *gi\gi_library = OpenLibrary_(&selib, 0)
    If *gi\gi_library=0
        Glyph_CloseEngine{*gi}
        Function Return 0
    End If


    ; Try to open the engine. If we could, then we tell it the location of
    ; the ".otag" file on disk and the address of the .otag file in memory.
    ge_ok = 0
;    *gi\gi_engine = OpenEngine_
    MOVEA.l -4(a4),a0   ; *gi -> a0
    MOVEA.l 4(a0),a6    ; *gi\gi_library -> a6
    JSR     -$1E(a6)    ; JSR to OpenEngine_
    MOVEA.l -4(a4),a0   ; *gi -> a0
    MOVE.l  d0,8(a0)    ; Result -> *gi\gi_engine
    If *gi\gi_engine
        ; Tell the glyph engine what font we are using
        otpath = fontname$ + ".otag"
        tag(0)\ti_Tag=#OT_OTagList,*gi\gi_otag
        tag(1)\ti_Tag=#OT_OTagPath,&otpath
        tag(2)\ti_Tag=#TAG_DONE
;        If SetInfoA_(*gi\gi_engine, &tag(0))=#OTERR_Success Then ge_ok=-1
        MOVEA.l -48(a4),a1          ; &tag(0) -> a1
        MOVEA.l -4(a4),a0           ; *gi -> a0
        MOVEA.l 4(a0),a6            ; proper library -> a6
        MOVEA.l 8(a0),a0            ; glyph engine -> a0
        JSR     -$2A(a6)            ; JSR to SetInfoA_
        CMP.l   #OTERR_Success,d0   ; Check if function returned success
        BNE     ge_not_ok           ; branch if it didn't
        MOVE.w  #-1,-30(a4)         ; otherwise, ge_ok=-1
        ge_not_ok:
    End If

    ; If we couldn't set up the glyph engine properly, close everything
    ; and return a failure
    If ge_ok=0
        Glyph_CloseEngine{*gi}
        Function Return 0
    End If

    Function Return -1
End Function


; ----------------------------------------------------------------------------


; -----------------------------------------------------------------------------
; NAME:
;       Glyph_SetFont
;
; SYNOPSIS:
;       error = Glyph_SetFont{*gi, pointsize, xdpi, ydpi}
;
;       long = Glyph_SetFont{.GlyphInfo, word, word, word}
;
; FUNCTION:
;        Sets some basic measurements for the font. YOU MUST CALL THIS FUNCTION
;       BEFORE ANY OTHERS, AFTER OPENING THE ENGINE, OR BAD THINGS WILL
;       PRObABLY HAPPEN.
;
; INPUTS:
;       *gi.GlyphInfo -- Pointer to a glyph info newtype. DON't CALL THIS
;                        FUNCTION IF THE RESULT TO Glyph_OpenEngine WAS NOT
;                        A SUCCESS.
;       pointsize.w -- The desired pointsize of the font, bearing in mind
;                      that there are 72 points in an inch, although on the
;                      Amiga, they never quite work out at the correct size.
;                      Can NOT be zero!
;       xdpi.w -- The resolution of the output device horizontally, in DPI
;                 Can NOT be zero!
;       ydpi.w -- The resolution of the output device vertically, in DPI
;                 Can NOT be zero!
;
; RESULT:
;        On success, this function will return #OTERR_Success. For a failure,
;       it will return a specific error code (see diskfont/oterrors.h)
;
; BUGS:
;       None
;
; SEE ALSO:
;       Glyph_OpenEngine, diskfont/oterrors.h
;
;-----------------------------------------------------------------------------
Function.l Glyph_SetFont{*gi.GlyphInfo, pointsize.q, xdpi.w, ydpi.w}
    Dim tag.TagItem(3)      ; Tags used to set pointsize and resolution

    ; DPI of font is set with x as the upper word and y as the lower word
    tag(0)\ti_Tag = #OT_DeviceDPI, (xdpi LSL 16) | ydpi
    ; Need to do this to stop Blitz2 rounding the quick to fit it into a long
    tag(1)\ti_Tag = #OT_PointHeight, Peek.l(&pointsize)
    tag(2)\ti_Tag = #TAG_DONE

    ; Keep a copy of our settings, as we need them in the Text function
    *gi\gi_xdpi      = xdpi
    *gi\gi_ydpi      = ydpi
    *gi\gi_pointsize = pointsize

;    Function Return SetInfoA_(*gi\gi_engine, &tag(0))
    MOVEA.l -4(a4),a0   ; *gi -> a0
    MOVEA.l -16(a4),a1  ; &tag(0) -> a1
    MOVEA.l 4(a0),a6    ; *gi\gi_library -> a6
    MOVEA.l 8(a0),a0    ; *gi\gi_engine -> a0
    JSR     -$2A(a6)    ; JSR SetInfoA_
    AsmExit             ; Return the value of call
End Function


; ---------------------------------------------------------------------------


; Like graphics.library/Text_, this prints a string (pointed To be '*string')
; of Length 'count', To the specified RastPort (*rp). You also need To pass
; the appropriate GlyphInfo
; This function just plots the glyphs in a straight horizontal line
; -----------------------------------------------------------------------------
; NAME:
;       Glyph_Text
;
; SYNOPSIS:
;       Glyph_Text{*gi, *rp, *string, strlen, followangle}
;
;       Glyph_Text{.GlyphInfo, .RastPort, byte, word, word}
;
; FUNCTION:
;        Similar to the graphics.library routine Text_, this function uses
;       the previously loaded font and renders a string of characters to
;       a specific rastport, using the current rastport settings. Currently
;       this function uses the blitter.
;
; INPUTS:
;       *gi.GlyphInfo -- Pointer to a valid GlyphInfo newtype (valid meaning
;                        that the result from Glyph_OpenEngine was
;                        successful).
;       *rp.RastPort -- Pointer to the rastport you want to render the string
;                       to. This function uses the current settings from the
;                       rastport.
;       *string.b -- Pointer to a string of characters to render.
;       strlen.w -- Length of the above string (or number of characters you
;                   want to print
;       followangle.w -- Flag to show whether the text should follow the
;                        currently set baseline rotation (TRUE) or not (FALSE)
;
; RESULT:
;        If everything goes well, then the string that was passed in should
;       have been drawn onto the rastport.
;
; BUGS:
;        None. Only problem is that the routine is quite slow, as currently,
;       the glyphs are copied into chip memory and are then blitted onto
;       the desired rastport. This was the chosen method so that the
;       current settings of the rastport would be used while rendering the
;       string.
;
; SEE ALSO:
;       Glyph_OpenEngine, graphics.library/Text_
;
;-----------------------------------------------------------------------------
Statement Glyph_Text{*gi.GlyphInfo, *rp.RastPort, *string.b, strlen.w, followangle.w}
    DEFTYPE.q   kern                ; Kerning distance in a fraction of an M
    DEFTYPE.w   newwidth            ; Width to advance after printing a character
    DEFTYPE.b   *bmp                ; Temporary bitmap to render glyph to then blit to rastport
    DEFTYPE.l   emwidth, emheight   ; Width and height of the glyph in M's
    DEFTYPE.w   x, y                ; Current x and y position while printing
    DEFTYPE.w   start_x, start_y    ; Starting x and y positions (for carridge returns)
    DEFTYPE.GlyphMap *gm            ; Holds data about glyph soon to be rendered
    DEFTYPE.q   sine, cosine        ; Sine and cosine of the rotation angle
    DEFTYPE.l   char1, char2        ; The current and next character, to find proper kerning values
    Dim tag.TagItem(3)

    If followangle
        sine = -Sin(*gi\gi_angle * Pi / 180)
        cosine = Cos(*gi\gi_angle * Pi / 180)
    Else
        sine=0
        cosine=1
    End If

    emwidth = (*gi\gi_pointsize * *gi\gi_xdpi) / 72
    emheight = (*gi\gi_pointsize * *gi\gi_ydpi) / 72

    x = *rp\cp_x
    y = *rp\cp_y + emheight
    start_x = x
    start_y = y

    For i.w=0 To strlen-1
        char1 = Peek.b(*string + i) & $FF
        char2 = Peek.b(*string + i + 1) & $FF

        If char1 = $20 Then char1 = $25A1

        tag(0)\ti_Tag = #OT_GlyphCode,char1
        tag(1)\ti_Tag = #OT_GlyphCode2,char2
        tag(2)\ti_Tag = #TAG_DONE
;        If SetInfoA_(*gi\gi_engine, &tag(0))=#OTERR_Success
        MOVEA.l -66(a4),a1          ; &tag(0) -> a1
        MOVEA.l -4(a4),a0           ; *gi -> a0
        MOVEA.l 4(a0),a6            ; *gi\gi_library -> a6
        MOVEA.l 8(a0),a0            ; *gi\gi_engine -> a0
        JSR     -$2A(a6)            ; JSR to SetInfoA_
        CMP.l   #OTERR_Success,d0   ; Check for success
        BNE     endif_sia1          ; Branch past loop if not
            kern = 0
            tag(0)\ti_Tag = #OT_TextKernPair,&kern
            tag(1)\ti_Tag = #TAG_DONE
;            ObtainInfoA_ *gi\gi_engine,&tag(0)
            MOVEA.l -66(a4),a1          ; &tag(0) -> a1
            MOVEA.l -4(a4),a0           ; *gi -> a0
            MOVEA.l 4(a0),a6            ; *gi\gi_library -> a6
            MOVEA.l 8(a0),a0            ; *gi\gi_engine -> a0
            JSR     -$30(a6)            ; JSR to ObtainInfoA_

            tag(0)\ti_Tag = #OT_GlyphMap,&*gm
            tag(1)\ti_Tag = #TAG_DONE
;            If ObtainInfoA_(*gi\gi_engine, &tag(0))=#OTERR_Success
            MOVEA.l -66(a4),a1          ; &tag(0) -> a1
            MOVEA.l -4(a4),a0           ; *gi -> a0
            MOVEA.l 4(a0),a6            ; *gi\gi_library -> a6
            MOVEA.l 8(a0),a0            ; *gi\gi_engine -> a0
            JSR     -$30(a6)            ; JSR to ObtainInfoA_
            CMP.l   #OTERR_Success,d0   ; Check for success
            BNE     endif_oia1          ; Branch past loop if not
                *bmp = AllocRaster_(*gm\glm_BMModulo * 8,*gm\glm_BMRows)
                If *bmp
                    If char1 = $25A1
                        newwidth = (*gi\gi_spacewidth * *gi\gi_pointsize * *gi\gi_xdpi) / (2540 * 250)
                    Else
                        newwidth = ((*gm\glm_Width - kern) * emwidth)/65536
                        CopyMem_ *gm\glm_BitMap,*bmp,*gm\glm_BMModulo * *gm\glm_BMRows
                        temp1.l = *bmp + *gm\glm_BMModulo * *gm\glm_BlackTop + ((*gm\glm_BlackLeft LSR 4) LSL 1)
                        temp2.w = *gm\glm_BlackLeft & $F
                        temp3.w = *gm\glm_BMModulo
                        temp4.w = x - *gm\glm_X0 + *gm\glm_BlackLeft
                        temp5.w = y - *gm\glm_Y0 + *gm\glm_BlackTop
                        temp6.w = *gm\glm_BlackWidth
                        temp7.w = *gm\glm_BlackHeight
                        BltTemplate_ temp1, temp2, temp3, *rp, temp4, temp5, temp6, temp7
                    End If
                    x = x + newwidth * cosine
                    y = y + newwidth * sine
                    tag(0)\ti_Tag = #OT_GlyphMap, *gm
                    tag(1)\ti_Tag = #TAG_DONE
;                    ReleaseInfoA_ *gi\gi_engine,&tag(0)
                    MOVEA.l -66(a4),a1  ; &tag(0) -> a1
                    MOVEA.l -4(a4),a0   ; *gi -> a0
                    MOVEA.l 4(a0),a6    ; *gi\gi_library -> a6
                    MOVEA.l 8(a0),a0    ; *gi\gi_engine -> a0
                    JSR     -$36(a6)    ; JSR to ReleaseInfoA_
                    FreeRaster_ *bmp,*gm\glm_BMModulo * 8,*gm\glm_BMRows
                End If
            ;End If
            endif_oia1:
;        End If
        endif_sia1:
    Next

    Move_ *rp,x,y   ; Update the position in the rastport (so it is like Text_)
End Statement


; ----------------------------------------------------------------------------


; -----------------------------------------------------------------------------
; NAME:
;       Glyph_SetRotate
;
; SYNOPSIS:
;       error = Glyph_SetRotate{*gi, angle}
;
;       long = Glyph_SetRotate{.GlyphInfo, word}
;
; FUNCTION:
;        Sets the baseline rotation of the font to the specified angle.
;
; INPUTS:
;       *gi.GlyphInfo -- Pointer to a valid GlyphInfo newtype (valid in that
;                        Glyph_OpenEngine returned success)
;       angle.w -- The angle in degrees which you want to rotate the font.
;                  Negative angles specify a clockwise rotation.
;
; RESULT:
;        On success, this function will return #OTERR_Success. On failure
;       it will return a specific error code (see diskfont/oterrors.h)
;
; BUGS:
;       None
;
; SEE ALSO:
;       Glyph_OpenEngine, diskfont/oterrors.h
;
;-----------------------------------------------------------------------------
Function.l Glyph_SetRotate{*gi.GlyphInfo, angle.w}
    DEFTYPE.q   sine,cosine
    Dim tag.TagItem(3)

    sine = Sin(angle * Pi / 180)    ; Could replace "Pi / 180" with "0.017453292" for speed
    cosine = Cos(angle * Pi / 180)

    ; Need to get the values using Peek.l(&var) because the data fields
    ; of the tag are longs, and Blitz would round off the quicks, but we
    ; do actually want the quick value stored
    tag(0)\ti_Tag = #OT_RotateSin,Peek.l(&sine)
    tag(1)\ti_Tag = #OT_RotateCos,Peek.l(&cosine)
    tag(2)\ti_Tag = #TAG_DONE

    *gi\gi_angle = angle

;    Function Return SetInfoA_(*gi\gi_engine,&tag(0))
    MOVEA.l -4(a4),a0   ; *gi -> a0
    MOVEA.l -18(a4),a1  ; &tag(0) -> a1
    MOVEA.l 4(a0),a6    ; *gi\gi_library -> a6
    MOVEA.l 8(a0),a0    ; *gi\gi_engine -> a0
    JSR     -$2A(a6)    ; JSR SetInfoA_
    AsmExit             ; Return value of call
End Function


; ---------------------------------------------------------------------------


; FUTURE functions
;
;   Glyph_SetShear (for italics)
;   Glyph_SetBold (for bold, duh)
;   Glyph_SetDotSize (similar to DPI, but different???)
;   Glyph_SetFactor (stretches the width)
;   Glyph_SetWidth (sets a constant width for glyphs if <> 0)



; ---------------------------------------------------------------------------


; ############################################################################
; ######################### END OF OUTLINE ROUTINES ##########################
; ############################################################################



;
;
; DEMO !!!
;
;
; The font name and size we want to load
DEFTYPE.s       fontname: fontname = "FONTS:cgtimes"
DEFTYPE.q       fontsize: fontsize = 72

DEFTYPE.Window *win    ; OS structure for the window that we open
DEFTYPE.l       modeid  ; Screen mode ID that we have opened window on
DEFTYPE.DisplayInfo di  ; Display information for the above mode

DEFTYPE.w       xdpi    : xdpi = 68 ; Some default x and y dpi values, in case
DEFTYPE.w       ydpi    : ydpi = 27 ; we can't get then from the screenmode
                                    ; (these are for standard hires screen)

DEFTYPE.GlyphInfo gi    ; A variable to hold our information about the glyphs and engine


If Glyph_OpenEngine{&gi, fontname}
    ; Hardcoded for a 30 point font with the default x and y dpi of a standard hires screen
    WbToScreen 0
    WBenchToFront_
    Window 0,0,0,640,200,$100f,"Glyph output",-1,-1
    DefaultOutput
    *win = Peek.l(Addr Window(0))

    ; Try to find the x and y resolution of the screen we have opened on
    modeid = GetVPModeID_(&*win\WScreen\ViewPort)
    If GetDisplayInfoData_(0, &di, SizeOf.DisplayInfo, #DTAG_DISP, modeid)
        xdpi = di\Resolution\x
        ydpi = di\Resolution\y
    End If

    ; Must be the first function called after Glyph_OpenEngine
    dummy.l = Glyph_SetFont{&gi, fontsize, xdpi, ydpi}

    ; Set up string to print and the rastport settings
    a$="Test glyphs"
    SetAPen_ *win\RPort,1
    SetDrMd_ *win\RPort,#JAM1
    Move_ *win\RPort,20,20

    ; Draw some text horizontally
    Glyph_Text{&gi, *win\RPort, &a$, Len(a$), False}

    ; Set new rastport stuff
    SetAPen_ *win\RPort,2
    Move_ *win\RPort,20,60

    ; Draw some text, with each letter rotated 45 degrees clockwise
    dummy.l=Glyph_SetRotate{&gi,-15}
    Glyph_Text{&gi,*win\RPort,&a$,Len(a$),False}

    ; Set the final set of rastport settings
    SetAPen_ *win\RPort,3
    Move_ *win\RPort,20,100

    ; Remembering that the font is still rotated, draw the whole string rotated
    Glyph_Text{&gi, *win\RPort, &a$, Len(a$), True}

    ; Wait for user to quit program
    While ev.l<>#IDCMP_CLOSEWINDOW
        ev = WaitEvent
    Wend

    ; Finally shut down glyph stuff
    Glyph_CloseEngine{&gi}
End If
End

