Author Topic: QPrint (falcon.h simplified)  (Read 3998 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
QPrint (falcon.h simplified)
« on: February 17, 2021, 10:46:20 am »
There's several programs out there that make use of falcon.h by now, but I wanted to take a shot at tossing in my own personal version of a simplified wrapper for the command -- QPRINT.

Code: QB64: [Select]
  1. DECLARE LIBRARY "falcon"
  2.     SUB uprint_extra (BYVAL x&, BYVAL y&, BYVAL chars%&, BYVAL length%&, BYVAL kern&, BYVAL do_render&, txt_width&, BYVAL charpos%&, charcount&, BYVAL colour~&, BYVAL max_width&)
  3.     FUNCTION uprint (BYVAL x&, BYVAL y&, chars$, BYVAL txt_len&, BYVAL colour~&, BYVAL max_width&)
  4.     FUNCTION uprintwidth (chars$, BYVAL txt_len&, BYVAL max_width&)
  5.     FUNCTION uheight& ()
  6.     FUNCTION uspacing& ()
  7.     FUNCTION uascension& ()
  8.  
  9. SCREEN _NEWIMAGE(640, 480, 32)
  10. _FONT _LOADFONT("cyberbit.ttf", 20)
  11.  
  12. LOCATE 1, 100
  13. QPrint "This is a whole bunch of crap." + CHR$(10) + "What happens to my crap, when there's too much crap to be printed on the screen, as I told it to be?  Will it wrap, or be truncated? Or what the heck will happen to my text when I have a crapload of it to print to the screen?"
  14. SLEEP: QPrint "And what happens if I follow up with another line of crap?  Will it print below the other as it should, or is my positioning all wrong?"
  15. SLEEP: QPrint "This is a whole bunch of crap.  What happens to my crap, when there's too much crap to be printed on the screen, as I told it to be?  Will it wrap, or be truncated? Or what the heck will happen to my text when I have a crapload of it to print to the screen?"
  16. SLEEP: QPrint "And what happens if I follow up with another line of crap?  Will it print below the other as it should, or is my positioning all wrong?"
  17. SLEEP: QPrint "This is a whole bunch of crap.  What happens to my crap, when there's too much crap to be printed on the screen, as I told it to be?  Will it wrap, or be truncated? Or what the heck will happen to my text when I have a crapload of it to print to the screen?"
  18. SLEEP: QPrint "And what happens if I follow up with another line of crap?  Will it print below the other as it should, or is my positioning all wrong?"
  19. SLEEP: QPrint "This is a whole bunch of crap.  What happens to my crap, when there's too much crap to be printed on the screen, as I told it to be?  Will it wrap, or be truncated? Or what the heck will happen to my text when I have a crapload of it to print to the screen?"
  20. SLEEP: QPrint "And what happens if I follow up with another line of crap?  Will it print below the other as it should, or is my positioning all wrong?"
  21.  
  22. QPrint "This is a whole bunch of crap.  What happens to my crap, when there's too much crap to be printed on the screen, as I told it to be?  Will it wrap, or be truncated? Or what the heck will happen to my text when I have a crapload of it to print to the screen?"
  23. QPrint "And what happens if I follow up with another line of crap?  Will it print below the other as it should, or is my positioning all wrong?"
  24.  
  25.  
  26. LOCATE 7, 1
  27. COLOR _RGB32(255, 255, 0), _RGB32(0, 0, 255) 'Yellow on Blue
  28. QPrint "Foo"
  29. COLOR _RGB32(255, 0, 0) 'Red
  30. QPrint "Bar"
  31. COLOR _RGB32(0, 255, 0) ' Green
  32. LOCATE 15, 1: PRINT "(For comparison, a normal PRINT statement)  ";
  33.  
  34. PRINT "This is a whole bunch of crap.  What happens to my crap, when there's too much crap to be printed on the screen, as I told it to be?  Will it wrap, or be truncated? Or what the heck will happen to my text when I have a crapload of it to print to the screen?"
  35.  
  36. COLOR _RGB(255, 0, 0), 0 '_RGB32(0, 0, 0)
  37. FOR i = 1 TO 15
  38.     SLEEP
  39.     LOCATE i, 1
  40.     QPrint STR$(i) + "To showcase locate at work with p's and q's and t's"
  41.  
  42.  
  43. SUB QPrint (temp$)
  44.     STATIC m AS _MEM: m = _MEMIMAGE(0)
  45.     DIM BreakPoint AS STRING
  46.     BreakPoint = ",./- ;:!" 'I consider all these to be valid breakpoints.  If you want something else, change them.
  47.     text$ = _TRIM$(temp$)
  48.     count = -1
  49.     DO
  50.         'first find the natural length of the line
  51.         x = POS(0): IF _FONTWIDTH THEN x = x * _FONTWIDTH
  52.         y = CSRLIN
  53.         wide% = _WIDTH - x - 1
  54.         FOR i = 1 TO LEN(text$)
  55.             IF ASC(text$, i) = 10 OR ASC(text$, i) = 13 THEN i = i - 1: EXIT FOR
  56.             p = uprintwidth(text$, i, 0)
  57.             IF p > wide% THEN EXIT FOR
  58.         NEXT
  59.         'IF i < LEN(text$) THEN lineend = i - 1 ELSE
  60.         lineend = i
  61.  
  62.         t$ = RTRIM$(LEFT$(text$, lineend)) 'at most, our line can't be any longer than what fits the screen.
  63.         FOR i = lineend TO 1 STEP -1
  64.             IF INSTR(BreakPoint, MID$(text$, i, 1)) THEN lineend = i: EXIT FOR
  65.         NEXT
  66.         out$ = RTRIM$(LEFT$(text$, lineend))
  67.         text$ = LTRIM$(MID$(text$, lineend + 1))
  68.         IF LEFT$(text$, 2) = CHR$(13) + CHR$(10) THEN text$ = MID$(text$, 3)
  69.         IF LEFT$(text$, 2) = CHR$(10) + CHR$(13) THEN text$ = MID$(text$, 3)
  70.         IF LEFT$(text$, 1) = CHR$(13) THEN text$ = MID$(text$, 2)
  71.         IF LEFT$(text$, 1) = CHR$(10) THEN text$ = MID$(text$, 2)
  72.         IF _BACKGROUNDCOLOR <> 0 THEN
  73.             LINE (x - 1, (y - 1) * uheight)-STEP(uprintwidth(out$, LEN(out$), 0), uheight), _BACKGROUNDCOLOR, BF
  74.         END IF
  75.         w& = uprint(x - 1, (y - 1) * uheight, out$, LEN(out$), _DEFAULTCOLOR, 0)
  76.         x = 1
  77.         IF y + 1 >= _HEIGHT / uheight THEN 'scroll up
  78.             w = uheight * _WIDTH * 4
  79.             t$ = SPACE$(m.SIZE - w)
  80.             _MEMGET m, m.OFFSET + w, t$
  81.             CLS , 0
  82.             _MEMPUT m, m.OFFSET, t$
  83.             LOCATE y, x
  84.         ELSE
  85.             LOCATE y + 1, x
  86.         END IF
  87.  
  88.     LOOP UNTIL text$ = ""
  89.     clean_exit:
  90.  

Instead of trying to track all sorts of parameters for uprint  -- (x&, y&, chars$, txt_len&, colour~&, max_width&)  -- I've written a wrapper to break it down to one little command QPrint text$.

If you want colors, simply use QB64's normal COLOR command.  If you want to position your text, simply use LOCATE, like you normally would with your code.  It word wraps automatically, as well as scrolls the screen for us if we end up printing down on the bottom line of the screen.   Basically, use it more or less like you would a simplified PRINT statement that can only handle a single string output.

The advantage to this little command?  (And to falcon.h, in general?)

No cutting off parts of your characters.  Some fonts are terrible about having half the letter cut off (I was using a script font the other day that lost the whole top half of my T's and F's, and their flourishes.), and you should be able to see the difference and the problem with the example code, which relies on cyberbit.ttf. 

One thing of note here:  QB64 v1.4 comes with cyberbit.ttf packaged with it.  V1.5 (the latest development build) doesn't.  If you're running the latest development build, you may want to download the file below and toss it in your folder for testing purposes. 

NOTE 2:  QPrint's LOCATE and PRINT's LOCATE are two completely different areas of your screen.  Don't expect the two to match at all for you.   With the example, QPRINT is printing a character 26 pixels high, whereas PRINT cuts off segments of it and only prints a character 20 pixels high... That difference is going to naturally lead to the rows being at different heights, so don't expect to LOCATE y,x and then QPRINT, and then LOCATE y,x and PRINT, and have the numbers match up at all.
* falcon.h (Filesize: 8.21 KB, Downloads: 249)
* cyberbit.ttf (Filesize: 12.74 MB, Downloads: 243)
« Last Edit: February 19, 2021, 01:16:36 am by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SpriggsySpriggs

  • Forum Resident
  • Posts: 1145
  • Larger than life
    • View Profile
    • GitHub
Re: QPrint (falcon.h simplified)
« Reply #1 on: February 17, 2021, 10:57:09 am »
Ooooo I shall save this for use when I decide to start making graphical applications again haha
Shuwatch!

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: QPrint (falcon.h simplified)
« Reply #2 on: February 17, 2021, 12:45:07 pm »
Ooooo I shall save this for use when I decide to start making graphical applications again haha

Go to the dark side and leave SCREEN 0? No way!

Well I can finally say, I ran one of Steve's programs, and it was full of crap! :D :D :D

Next time, use foo. I think that's Latin for crap.

Pete

Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: QPrint (falcon.h simplified)
« Reply #3 on: February 23, 2021, 07:44:57 pm »
Now that I'm finally home and able to work on things once again, here's an updated version of QPrint, and a couple of screenshots showcasing it:

Code: QB64: [Select]
  1. $IF FALCON = UNDEFINED THEN
  2.     $LET FALCON = TRUE
  3.     DECLARE LIBRARY "falcon"
  4.         SUB uprint_extra (BYVAL x&, BYVAL y&, BYVAL chars%&, BYVAL length%&, BYVAL kern&, BYVAL do_render&, txt_width&, BYVAL charpos%&, charcount&, BYVAL colour~&, BYVAL max_width&)
  5.         FUNCTION uprint (BYVAL x&, BYVAL y&, chars$, BYVAL txt_len&, BYVAL colour~&, BYVAL max_width&)
  6.         FUNCTION uprintwidth (chars$, BYVAL txt_len&, BYVAL max_width&)
  7.         FUNCTION uheight& ()
  8.         FUNCTION uspacing& ()
  9.         FUNCTION uascension& ()
  10.     END DECLARE
  11.     DIM SHARED QPrintTextType AS STRING
  12.     QPrintTextType = "ASCII"
  13.  
  14.  
  15. SCREEN _NEWIMAGE(1024, 720, 32)
  16. _FONT _LOADFONT("cyberbit.ttf", 16, "monospace")
  17.  
  18. QPrintTextType = "UTF8"
  19.  
  20. OPEN "test.txt" FOR INPUT AS #1
  21.     LINE INPUT #1, temp$
  22.     QPrint temp$
  23.     SLEEP
  24.  
  25.  
  26. FOR y = 0 TO 15
  27.     FOR x = 0 TO 15
  28.         QPrintString x * 30, y * uheight, CHR$(count)
  29.         count = count + 1
  30.     NEXT
  31.  
  32. SUB QPrint (temp$)
  33.     STATIC m AS _MEM: m = _MEMIMAGE(0)
  34.     DIM BreakPoint AS STRING
  35.     BreakPoint = ",./- ;:!" 'I consider all these to be valid breakpoints.  If you want something else, change them.
  36.     IF QPrintTextType = "ASCII" OR QPrintTextType = "" THEN text$ = _TRIM$(AnsiTextToUtf8Text$(temp$)) ELSE text$ = temp$
  37.     count = -1
  38.     DO
  39.         'first find the natural length of the line
  40.         x = POS(0): IF _FONTWIDTH THEN x = x * _FONTWIDTH
  41.         y = CSRLIN
  42.         wide% = _WIDTH - x - 1
  43.         FOR i = 1 TO LEN(text$)
  44.             IF ASC(text$, i) = 10 OR ASC(text$, i) = 13 THEN i = i - 1: EXIT FOR
  45.             p = uprintwidth(text$, i, 0)
  46.             IF p > wide% THEN EXIT FOR
  47.         NEXT
  48.         'IF i < LEN(text$) THEN lineend = i - 1 ELSE
  49.         lineend = i
  50.  
  51.         t$ = RTRIM$(LEFT$(text$, lineend)) 'at most, our line can't be any longer than what fits the screen.
  52.         FOR i = lineend TO 1 STEP -1
  53.             IF INSTR(BreakPoint, MID$(text$, i, 1)) THEN lineend = i: EXIT FOR
  54.         NEXT
  55.         out$ = RTRIM$(LEFT$(text$, lineend))
  56.         text$ = LTRIM$(MID$(text$, lineend + 1))
  57.         IF LEFT$(text$, 2) = CHR$(13) + CHR$(10) THEN text$ = MID$(text$, 3)
  58.         IF LEFT$(text$, 2) = CHR$(10) + CHR$(13) THEN text$ = MID$(text$, 3)
  59.         IF LEFT$(text$, 1) = CHR$(13) THEN text$ = MID$(text$, 2)
  60.         IF LEFT$(text$, 1) = CHR$(10) THEN text$ = MID$(text$, 2)
  61.         IF _BACKGROUNDCOLOR <> 0 THEN
  62.             LINE (x - 1, (y - 1) * uheight)-STEP(uprintwidth(out$, LEN(out$), 0), uheight), _BACKGROUNDCOLOR, BF
  63.         END IF
  64.         w& = uprint(x - 1, (y - 1) * uheight, out$, LEN(out$), _DEFAULTCOLOR, 0)
  65.         x = 1
  66.         IF y + 1 >= _HEIGHT / uheight THEN 'scroll up
  67.             h = uheight * _WIDTH * 4
  68.             t$ = SPACE$(m.SIZE - h)
  69.             _MEMGET m, m.OFFSET + h, t$
  70.             CLS , 0
  71.             _MEMPUT m, m.OFFSET, t$
  72.             LOCATE y, x
  73.         ELSE
  74.             LOCATE y + 1, x
  75.         END IF
  76.  
  77.     LOOP UNTIL text$ = ""
  78.     clean_exit:
  79.  
  80. FUNCTION QPrintWidth& (out$)
  81.     QPrintWidth = uprintwidth(out$, LEN(out$), 0)
  82.  
  83. FUNCTION QFontHeight
  84.     QFontHeight = uheight
  85.  
  86. SUB QPrintString (x, y, text$)
  87.     IF QPrintTextType = "ASCII" OR QPrintTextType = "" THEN temp$ = _TRIM$(AnsiTextToUtf8Text$(text$)) ELSE temp$ = text$
  88.         LINE (x, y)-STEP(uprintwidth(temp$, LEN(temp$), 0), uheight), _BACKGROUNDCOLOR, BF
  89.     END IF
  90.     w& = uprint(x, y, temp$, LEN(temp$), _DEFAULTCOLOR, 0)
  91.  
  92. FUNCTION AnsiTextToUtf8Text$ (text$)
  93.     DIM chi&, ascii%, unicode&, aci%
  94.     FOR chi& = 1 TO LEN(text$)
  95.         '--- get ANSI char code, reset Unicode ---
  96.         unicode& = _MAPUNICODE(ASC(text$, chi&))
  97.         IF unicode& = 0 THEN unicode& = 65533 'replacement character
  98.         AnsiTextToUtf8Text$ = AnsiTextToUtf8Text$ + UnicodeToUtf8Char$(unicode&)
  99.     NEXT chi&
  100.  
  101. FUNCTION UnicodeToUtf8Char$ (unicode&)
  102.     '--- option _explicit requirements ---
  103.     DIM uc&, first%, remain%, conti%
  104.     '--- UTF-8 encoding ---
  105.     IF unicode& < 128 THEN
  106.         '--- standard ASCII (0-127) goes as is ---
  107.         UnicodeToUtf8Char$ = CHR$(unicode&)
  108.         EXIT FUNCTION
  109.     ELSE
  110.         '--- encode the Unicode into UTF-8 notation ---
  111.         UnicodeToUtf8Char$ = "": uc& = unicode& 'avoid argument side effect
  112.         first% = &B10000000: remain% = 63
  113.         DO
  114.             first% = &B10000000 OR (first% \ 2): remain% = (remain% \ 2)
  115.             conti% = &B10000000 OR (uc& AND &B00111111): uc& = uc& \ 64
  116.             UnicodeToUtf8Char$ = CHR$(conti%) + UnicodeToUtf8Char$
  117.             IF uc& <= remain% THEN
  118.                 first% = (first% OR uc&): uc& = 0
  119.             END IF
  120.         LOOP UNTIL uc& = 0
  121.         UnicodeToUtf8Char$ = CHR$(first%) + UnicodeToUtf8Char$
  122.     END IF
  123.  

 
Side-by-Side Comparison.png


 
ASCII chart.png


Now, the first image above, is using QPrint to print Unicode (UTF-8) formatted text.  The image on the left is test.txt opened in Microsoft Word, and the image on the right is what we generate using QPrint.  As you can see, the font sizes and windows might be a little different resolution, but all the characters are displaying and matching properly for us.  We're printing valid unicode to the screen.

The second image, you guys might recognize as our ASCII chart.  It's the whole ASCII range of characters mapped over and converted from QB64's codepages over to UTF8 format, and then printed to the screen for us. 

By default, QPrint is set to print ASCII-code pages, but it can be converted to use UTF-8 code pages with a simple variable change:

QPrintTextType = "ASCII"  <-- This sets us to our default printing using the ASCII code page.  (Or just leave it blank as "" does the same.)

QPrintTextType = <ANYTHING ELSE> and we try to print it as UTF-8 formatted text. 

Change the global variable, change how you're printing...

It's now THAT simple to display UTF-8 code on to the screen.


NOTE:  To use QPrint, you have to load a custom font with it.  QB64's in-built fonts currently aren't working as you'd think they should with it, so be certain to load your own font.



Now all I need to do is tie these into my Extended Keyboard library, and add them to our functionality there, and we'll not only have a way to print the full UTF8 character set, but also a means to input from keyboards which use such extended keys.  (That is, after someone takes the time to map the proper keys to their specific keyboard layout.  At the moment, the library only supports US, German, Italian, and UK keyboard layouts, if I remember correctly.)

File test.txt is included below for those who'd like to test it for themselves.  ;)

* test.txt (Filesize: 4.99 KB, Downloads: 262)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: QPrint (falcon.h simplified)
« Reply #4 on: October 29, 2021, 11:00:13 am »
Code: QB64: [Select]
  1. $If FALCON = UNDEFINED Then
  2.     $Let FALCON = TRUE
  3.     Declare Library "./falcon"
  4.         Sub uprint_extra (ByVal x&, Byval y&, Byval chars%&, Byval length%&, Byval kern&, Byval do_render&, txt_width&, Byval charpos%&, charcount&, Byval colour~&, Byval max_width&)
  5.         Function uprint (ByVal x&, Byval y&, chars$, Byval txt_len&, Byval colour~&, Byval max_width&)
  6.         Function uprintwidth (chars$, Byval txt_len&, Byval max_width&)
  7.         Function uheight& ()
  8.         Function uspacing& ()
  9.         Function uascension& ()
  10.     End Declare
  11.     Dim Shared QPrintTextType As String
  12.     QPrintTextType = "ASCII"
  13.  
  14.  
  15. Screen _NewImage(1024, 720, 32)
  16. f = _LoadFont("cyberbit.ttf", 20, "monospace")
  17.  
  18.  
  19. QPrintTextType = "ASCII"
  20.  
  21.  
  22.  
  23. For y = 0 To 15
  24.     For x = 0 To 15
  25.         QPrintString x * 30, y * uheight, Chr$(count)
  26.         count = count + 1
  27.     Next
  28.  
  29. Sub QPrint (temp$)
  30.     Static m As _MEM: m = _MemImage(0)
  31.     Dim BreakPoint As String
  32.     BreakPoint = ",./- ;:!" 'I consider all these to be valid breakpoints.  If you want something else, change them.
  33.     If QPrintTextType = "ASCII" Or QPrintTextType = "" Then text$ = _Trim$(AnsiTextToUtf8Text$(temp$)) Else text$ = temp$
  34.     count = -1
  35.     Do
  36.         'first find the natural length of the line
  37.         x = Pos(0) - 1: If _FontWidth Then x = x * _FontWidth
  38.         y = CsrLin
  39.         wide% = _Width - x - 1
  40.         For i = 1 To Len(text$)
  41.             If Asc(text$, i) = 10 Or Asc(text$, i) = 13 Then i = i - 1: Exit For
  42.             p = uprintwidth(text$, i, 0)
  43.             If p > wide% Then Exit For
  44.         Next
  45.         'IF i < LEN(text$) THEN lineend = i - 1 ELSE
  46.         lineend = i
  47.  
  48.         t$ = RTrim$(Left$(text$, lineend)) 'at most, our line can't be any longer than what fits the screen.
  49.         For i = lineend To 1 Step -1
  50.             If InStr(BreakPoint, Mid$(text$, i, 1)) Then lineend = i: Exit For
  51.         Next
  52.         out$ = RTrim$(Left$(text$, lineend))
  53.         text$ = LTrim$(Mid$(text$, lineend + 1))
  54.         If Left$(text$, 2) = Chr$(13) + Chr$(10) Then text$ = Mid$(text$, 3)
  55.         If Left$(text$, 2) = Chr$(10) + Chr$(13) Then text$ = Mid$(text$, 3)
  56.         If Left$(text$, 1) = Chr$(13) Then text$ = Mid$(text$, 2)
  57.         If Left$(text$, 1) = Chr$(10) Then text$ = Mid$(text$, 2)
  58.         If _BackgroundColor <> 0 Then
  59.             Line (x - 1, (y - 1) * uheight)-Step(uprintwidth(out$, Len(out$), 0), uheight), _BackgroundColor, BF
  60.         End If
  61.         w& = uprint(x - 1, (y - 1) * uheight, out$, Len(out$), _DefaultColor, 0)
  62.         x = 1
  63.         If y + 1 >= _Height / uheight Then 'scroll up
  64.             h = uheight * _Width * 4
  65.             t$ = Space$(m.SIZE - h)
  66.             _MemGet m, m.OFFSET + h, t$
  67.             Cls , 0
  68.             _MemPut m, m.OFFSET, t$
  69.             Locate y, x
  70.         Else
  71.             Locate y + 1, x
  72.         End If
  73.  
  74.     Loop Until text$ = ""
  75.     clean_exit:
  76.  
  77. Function QPrintWidth& (out$)
  78.     QPrintWidth = uprintwidth(out$, Len(out$), 0)
  79.  
  80. Function QFontHeight
  81.     QFontHeight = uheight
  82.  
  83. Sub QPrintString (x, y, text$)
  84.     If QPrintTextType = "ASCII" Or QPrintTextType = "" Then temp$ = _Trim$(AnsiTextToUtf8Text$(text$)) Else temp$ = text$
  85.         Line (x, y)-Step(uprintwidth(temp$, Len(temp$), 0), uheight), _BackgroundColor, BF
  86.     End If
  87.     w& = uprint(x, y, temp$, Len(temp$), _DefaultColor, 0)
  88.  
  89. Function AnsiTextToUtf8Text$ (text$)
  90.     Dim chi&, ascii%, unicode&, aci%
  91.     For chi& = 1 To Len(text$)
  92.         '--- get ANSI char code, reset Unicode ---
  93.         unicode& = _MapUnicode(Asc(text$, chi&))
  94.         If unicode& = 0 Then unicode& = 65533 'replacement character
  95.         temp$ = temp$ + UnicodeToUtf8Char$(unicode&)
  96.     Next chi&
  97.     AnsiTextToUtf8Text$ = temp$
  98.  
  99. Function UnicodeToUtf8Char$ (unicode&)
  100.     '--- option _explicit requirements ---
  101.     Dim uc&, first%, remain%, conti%
  102.     '--- UTF-8 encoding ---
  103.     If unicode& < 128 Then
  104.         '--- standard ASCII (0-127) goes as is ---
  105.         UnicodeToUtf8Char$ = Chr$(unicode&)
  106.         Exit Function
  107.     Else
  108.         '--- encode the Unicode into UTF-8 notation ---
  109.         temp$ = "": uc& = unicode& 'avoid argument side effect
  110.         first% = &B10000000: remain% = 63
  111.         Do
  112.             first% = &B10000000 Or (first% \ 2): remain% = (remain% \ 2)
  113.             conti% = &B10000000 Or (uc& And &B00111111): uc& = uc& \ 64
  114.             temp$ = Chr$(conti%) + temp$
  115.             If uc& <= remain% Then
  116.                 first% = (first% Or uc&): uc& = 0
  117.             End If
  118.         Loop Until uc& = 0
  119.         UnicodeToUtf8Char$ = Chr$(first%) + temp$
  120.     End If
  121.  

Functions updated to work in version 2.0+, without any glitches from the recursive function fix causing things to error out on us.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!