Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Scramble (arcade game remake)
#51
(03-29-2023, 05:37 PM)RokCoder Wrote:
Code: (Select All)
$LET HI_RES = 1
...
    $IF HI_RES THEN

First, a simple question about this (probably more of a general QB64PE question).
In QB64/PE, isn't the boolean TRUE value -1?
Because the program is setting HI_RES to 1, not -1, and it still evaluates to true.
Did QB64 & QB64PE always evaluate both -1 and 1 to true, and I just never noticed?
Example:
Code: (Select All)
Const FALSE = 0
Const TRUE = Not FALSE
Const HI_RES = 1
Cls
Print "FALSE  = " + _Trim$(Str$(FALSE))
Print "TRUE   = " + _Trim$(Str$(TRUE))
Print "HI_RES = " + _Trim$(Str$(HI_RES))
Print
If HI_RES Then
    Print "HI_RES evaluates to true"
Else
    Print "HI_RES evaluates to false"
End If
Print
Print "press any key to continue"
Sleep
System


(03-29-2023, 05:37 PM)RokCoder Wrote: 3) There was a lot of code scattered around that required tweaking so it wasn't a simple case of increasing TILE_WIDTH and TILE_HEIGHT. To simplify it a little I added a TILE_SCALE so that all the original position placements and calculations didn't need modifying - just the actual rendering to the virtual screen display.
Code: (Select All)
$IF HI_RES THEN
    CONST TILE_SCALE = 2
$ELSE
        CONST TILE_SCALE = 1
$END IF

4) I added a bunch of pre-processor settings so that it's easy to switch gaming modes around. All of your modifications are included in these -

Code: (Select All)
$LET HI_RES = 1
$LET WIDESCREEN = 1
$LET SPEED_CONTROLS = 0
$LET EXTRA_BOMBS = 0
$LET EXTRA_LIVES = 1
$LET FREE_ROAMING_SHIP = 0

So if we want to try x4 resolution, we need to set both TILE_SCALE and HI_RES, right? Like this:
Code: (Select All)
$IF HI_RES THEN
    CONST TILE_SCALE = 4
...
$LET HI_RES = 1

My final question is about the background stars. A few seconds into the game, the sky turns from black to gray. Is this supposed to happen? How can we keep the sky black? 

The game starts out with black skies:
[Image: scramble-with-options-screen-starts-out-black.png]

But then around the time the ship flies over the 2nd hill, this happens:
[Image: scramble-with-options-screen-turns-gray.png]

Like the song says, "Grey skies are gonna clear up, put on a happy face!" LoL

Thanks again for all the work you put into this and your time with helping to customize it!
Reply
#52
(03-30-2023, 01:57 PM)madscijr Wrote: First, a simple question about this (probably more of a general QB64PE question).
In QB64/PE, isn't the boolean TRUE value -1?
Because the program is setting HI_RES to 1, not -1, and it still evaluates to true.
Did QB64 & QB64PE always evaluate both -1 and 1 to true, and I just never noticed?

My assumption is that QB64pe, as with many other languages, has zero as false and non-zero as true. That said, in general I would always define FALSE as zero and TRUE as NOT FALSE.

(03-30-2023, 01:57 PM)madscijr Wrote: So if we want to try x4 resolution, we need to set both TILE_SCALE and HI_RES, right? Like this:
Code: (Select All)
$IF HI_RES THEN
    CONST TILE_SCALE = 4
...
$LET HI_RES = 1

That is true as it currently stands. Setting HI-RES to zero will result in using the original sprite sheet (which will have a TILE_SCALE of 1). Set HI_RES to 1 to use your own sprite sheet and set TILE_ZOOM to whatever factor your sprite sheet is scaled up by from the original.

(03-30-2023, 01:57 PM)madscijr Wrote: My final question is about the background stars. A few seconds into the game, the background turns from black to gray. Is this supposed to happen? How can we keep the background black? 

[Image: scramble-with-options-screen-turns-gray.png]

I imagine the palettes have been messed up somewhere along the line. The way the original works is to update four colours of the eight colour palette when it's doing the palette updates. That's why you have the set of sprites in the sprite sheet that are in four colours of grey - they're the ones that are assigned different colours from time to time. As you're basically updating all of the sprites and disregarding any use of palette switching, you might as well use the HI-RES setting to disable palette switching completely when set to 1.

(03-30-2023, 01:57 PM)madscijr Wrote: Thanks again for all the work you put into this and your time with helping to customize it!

You are more than welcome. I'm thoroughly enjoying watching this variant progress!
RokCoder - dabbling in QB64pe for fun
Reply
#53
(03-30-2023, 02:35 PM)RokCoder Wrote:
(03-30-2023, 01:57 PM)madscijr Wrote: My final question is about the background stars. A few seconds into the game, the background turns from black to gray. Is this supposed to happen? How can we keep the background black? 

I imagine the palettes have been messed up somewhere along the line. The way the original works is to update four colours of the eight colour palette when it's doing the palette updates. That's why you have the set of sprites in the sprite sheet that are in four colours of grey - they're the ones that are assigned different colours from time to time. As you're basically updating all of the sprites and disregarding any use of palette switching, you might as well use the HI-RES setting to disable palette switching completely when set to 1.

Thanks for your quick reply. I think what's happening is when a bomb hits, the screen flashes as part of the explosion effect, but it isn't returning to black. 
^^^ after trying it some more, I don't think that's happening, I am not sure what is turning the screen gray after a few seconds!

I'm not sure where in the code the palette switching is happening, if you get a minute to point out which line(s) need changing, that would be great.
^^^ Update #2: I think I found it, if anything else needs changing let me know:
Code: (Select All)
Sub NextPalette
    $IF HI_RES THEN
    Exit Sub ' UNTIL WE CAN FIX THE SCREEN TURNING GRAY?
    $END IF
    SetPalette (game.currentPalette% + 1) Mod 7
End Sub

Thanks again!
Reply
#54
(03-30-2023, 02:44 PM)madscijr Wrote:
(03-30-2023, 02:35 PM)RokCoder Wrote:
(03-30-2023, 01:57 PM)madscijr Wrote: My final question is about the background stars. A few seconds into the game, the background turns from black to gray. Is this supposed to happen? How can we keep the background black? 

I imagine the palettes have been messed up somewhere along the line. The way the original works is to update four colours of the eight colour palette when it's doing the palette updates. That's why you have the set of sprites in the sprite sheet that are in four colours of grey - they're the ones that are assigned different colours from time to time. As you're basically updating all of the sprites and disregarding any use of palette switching, you might as well use the HI-RES setting to disable palette switching completely when set to 1.

Thanks for your quick reply. I think what's happening is when a bomb hits, the screen flashes as part of the explosion effect, but it isn't returning to black. 
^^^ after trying it some more, I don't think that's happening, I am not sure what is turning the screen gray after a few seconds!

I'm not sure where in the code the palette switching is happening, if you get a minute to point out which line(s) need changing, that would be great.
^^^ Update #2: I think I found it, if anything else needs changing let me know:
Code: (Select All)
Sub NextPalette
    $IF HI_RES THEN
    Exit Sub ' UNTIL WE CAN FIX THE SCREEN TURNING GRAY?
    $END IF
    SetPalette (game.currentPalette% + 1) Mod 7
End Sub

Thanks again!

An alternative would be to put the IF HI_RES THEN around the code in SetPalette. That would ensure you're always using the default palette for everything. I really don't think you're going to want any palette changes in there as they could easily impact the new graphics you're adding.
RokCoder - dabbling in QB64pe for fun
Reply
#55
(03-30-2023, 02:35 PM)RokCoder Wrote:
(03-30-2023, 01:57 PM)madscijr Wrote: So if we want to try x4 resolution, we need to set both TILE_SCALE and HI_RES, right? Like this:
Code: (Select All)
$IF HI_RES THEN
    CONST TILE_SCALE = 4
...
$LET HI_RES = 1

That is true as it currently stands. Setting HI-RES to zero will result in using the original sprite sheet (which will have a TILE_SCALE of 1). Set HI_RES to 1 to use your own sprite sheet and set TILE_ZOOM to whatever factor your sprite sheet is scaled up by from the original.

Last comment for now (I swear, lol) - I tried this with the 4x sprite sheet, and it runs, and looks good, but is slow (at least on this computer, which isn't the newest, an old Microsoft Surface Pro 3 with 8 GB RAM and whatever gen i7 processor from 2014/15). I'm fine with the 2x resolution, but would be curious what else can be done to speed it up. Maybe if the game were updated to use hardware images? About a year ago, I was looking for a way to speed up the graphics in a game I was working on, and SMcNeill showed that hardware images are dramatically faster (you can see the original thread here). Try running the following code, which is a demo of hardware images, and a speed test comparing various methods I was experimenting with to find a faster way to draw multicolored tiles. When you run, you'll see a menu. Press "1" for the speed comparison, and "2" for Steve's hardware images tutorial/demo (the other options were just more tests and demos). You'll see how much faster the hw images are:

Code: (Select All)
' ################################################################################################################################################################
' Speed tests and demos of various methods draw a 2-color 8x8 tile

' From thread:
' Re: fastest way to draw a 2-color 8x8 tile (with variable colors)?
' https://qb64forum.alephc.xyz/index.php?topic=4674.msg140904#msg140904
' ################################################################################################################################################################

' ===============================================================================
' GLOBAL CONSTANTS
' ===============================================================================
' BOOLEAN VALUES
Const FALSE = 0
Const TRUE = Not FALSE

' ===============================================================================
' USER DEFINED TYPES
' ===============================================================================
' UDT TO HOLD COORDINATES FOR DRAWING A RECTANGLE
Type RectangleType
    x1 As Integer ' start x
    y1 As Integer ' start y
    x2 As Integer ' end x
    y2 As Integer ' end y
    PixelCount As Integer
    IsActive As Integer
End Type ' RectangleType

Type DrawCompareType
    IndexList As String
    ShapeCount As Integer
    PixelCount As Integer
    IsActive As Integer
End Type ' DrawCompareType

' UDT FOR PRECALCULATED TILESHEET
Type TileSheetMapType
    xStart As Integer
    xEnd As Integer
    yStart As Integer
    yEnd As Integer
End Type

' UDT FOR PRECALCULATED TILE MAP
Type TileMapType
    xPos As Integer
    yPos As Integer
End Type

' ===============================================================================
' GLOBAL VARIABLES
' ===============================================================================
Dim Shared m_bDebug As Integer: m_bDebug = TRUE ' ENABLES/DISABLES CONSOLE WINDOW AND DebugPrint
Dim Shared m_ProgramPath$: m_ProgramPath$ = Left$(Command$(0), _InStrRev(Command$(0), "\"))
Dim Shared m_ProgramName$: m_ProgramName$ = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1)
Dim Shared m_arrLineTiles(0 To 255, 0 To 32) As RectangleType

' Used for Steve's very different custom screen:
Dim Shared m_TileHw As Long
Dim Shared m_FontHw As Long
Dim Shared m_ScreenArray(99, 74) As _Unsigned Long ' Here, I'm creating a screen array to hold the information of EVERY character I place onto the screen, and its tile

' ===============================================================================
' LOCAL VARIABLES
' ===============================================================================
Dim in$

' ****************************************************************************************************************************************************************
' ACTIVATE DEBUGGING WINDOW
If m_bDebug = TRUE Then
    $Console
    _Delay 4
    _Console On
    _Echo "Started " + m_ProgramName$
    _Echo "Debugging on..."
End If
' ****************************************************************************************************************************************************************

' ===============================================================================
' START THE MAIN ROUTINE
' ===============================================================================
main

' ===============================================================================
' FINISH
' ===============================================================================
Screen 0
Print m_ProgramName$ + " finished."
Input "Press <ENTER> to continue", in$
' ****************************************************************************************************************************************************************
' DEACTIVATE DEBUGGING WINDOW
If m_bDebug = TRUE Then
    _Console Off
End If
' ****************************************************************************************************************************************************************
System ' return control to the operating system
End

' ################################################################################################################################################################
' BEGIN MAIN MENU
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////

Sub main
    Dim RoutineName As String: RoutineName = "main"
    Dim in$
    Dim bFinished As Integer: bFinished = FALSE
    Dim result$: result$ = ""
    Do
        Screen 0: _ScreenMove 0, 0
        Cls
        Print m_ProgramName$
        Print
        Print "RE: fastest way to draw a 2-color 8x8 tile (with variable colors)?"
        Print

        Print "1) DrawingSpeedTest7"
        Print
        Print "2) HardwareImageDemo2"
        Print
        Print "3) GetAllPossibleShapesTest"
        Print "4) FindOptimizedVectorTest - find minimum shapes to draw a tile"
        Print "5) GetVectorTilesTest"
        Print "6) MakePaletteImageTest"
        Print "7) DrawVectorTilePutImageTest"
        Print
        Print "A) TestCustomHardwareScreen1"
        Print "B) ^ instructions"
        Print
        Print "C) TestSoftwareScreen1"
        Print "D) ^ instructions"

        Print "E) TestCustomHardwareScreen2"

        Print
        Print "Q) Exit program"
        Do
            in$ = InKey$
            If UCase$(in$) = "Q" Then
                bFinished = TRUE: Exit Do
            ElseIf UCase$(in$) = "1" Then
                DrawingSpeedTest7: Exit Do
            ElseIf UCase$(in$) = "2" Then
                HardwareImageDemo2: Exit Do
            ElseIf UCase$(in$) = "3" Then
                GetAllPossibleShapesTest: Exit Do
            ElseIf UCase$(in$) = "4" Then
                FindOptimizedVectorTest: Exit Do
            ElseIf UCase$(in$) = "5" Then
                GetVectorTilesTest: Exit Do
            ElseIf UCase$(in$) = "6" Then
                MakePaletteImageTest: Exit Do
            ElseIf UCase$(in$) = "7" Then
                DrawVectorTilePutImageTest: Exit Do
            ElseIf UCase$(in$) = "A" Then
                TestCustomHardwareScreen1: Exit Do
            ElseIf UCase$(in$) = "B" Then
                ShowInstructions (GetInstructions1$): Exit Do
            ElseIf UCase$(in$) = "C" Then
                TestSoftwareScreen1: Exit Do
            ElseIf UCase$(in$) = "D" Then
                ShowInstructions (GetInstructions2$): Exit Do

            ElseIf UCase$(in$) = "E" Then
                TestCustomHardwareScreen2: Exit Do

            End If
        Loop
    Loop Until bFinished = TRUE
End Sub ' main

' ################################################################################################################################################################
' END MAIN MENU
' ################################################################################################################################################################

' ################################################################################################################################################################
' BEGIN DRAWING SPEED TEST
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////

Sub DrawingSpeedTest7
    Dim sError As String: sError = ""
    Dim imgScreen As Long ' the main display
    Dim imgHardwareScreen As Long ' copy of the software screen, transformed into a hardware image
    Dim imgTiles As Long ' original tileset, black on transparent
    Dim imgHardwareTiles As Long ' copy of the tileset, tranformed into a hardware image
    Dim imgTilesRed As Long ' colored tileset copy
    Dim imgTilesGreen As Long ' colored tileset copy
    Dim imgTilesBlue As Long ' colored tileset copy
    Dim imgTilesYellow As Long ' colored tileset copy
    Dim imgColorTiles As Long ' holds 4 copies of tileset in different colors (red, green, blue, yellow)
    Dim imgTilesAllColorsSW As Long ' holds n copies of tileset in all combinations of specified foreground/background colors
    Dim imgTilesAllColorsHW As Long ' copy of the tileset, tranformed into a hardware image

    Dim imgPalette As Long ' contains palette of colors
    Dim imgPaletteHW As Long ' hardware image of palette of colors
    Dim iTileNum As Integer
    Dim iFgColorIndex As Integer: iFgColorIndex = 0
    Dim iBgColorIndex As Integer: iBgColorIndex = 0
    Dim iFirstColor As Integer: iFirstColor = 0
    Dim iLastColor As Integer: iLastColor = 3
    'Dim iCols As Integer
    'Dim iRows As Integer
    Dim iY As Integer
    Dim iX As Integer
    Dim fgColor As _Unsigned Long
    Dim bgColor As _Unsigned Long
    Dim iMinY As Integer
    Dim iMaxY As Integer
    Dim iMinX As Integer
    Dim iMaxX As Integer
    Dim iCount1 As Long
    Dim iCount2 As Long
    Dim iCount3 As Long
    Dim iCount4 As Long
    Dim iCount5 As Long
    Dim iCount6 As Long
    Dim iCount7 As Long
    Dim iCount8 As Long
    Dim t# ' for timer
    Dim arrColor(0 To 5) As _Unsigned Long

    Dim arrColors(-1) As _Unsigned Long ' supported colors for COLORED TILESET COPIES v2
    ReDim arrTileIndex(-1) As Long ' stores x positions for tiles (0-255) for COLORED TILESET COPIES v2
    ReDim arrColorIndex(-1, -1) As Long ' stores y positions for (fgColorIndex, bgColorIndex) for COLORED TILESET COPIES v2
    Dim iFirstColor2 As Integer
    Dim iLastColor2 As Integer

    ' ================================================================================================================================================================
    ' INIT SCREEN
    ' ================================================================================================================================================================
    imgScreen = _NewImage(1024, 768, 32): _ScreenMove 0, 0
    Screen imgScreen
    Cls , cGray

    'iCols = _Width(imgScreen) \ 8
    'iRows = _Height(imgScreen) \ 8

    iMinX = 1: iMaxX = 16
    iMinY = 3: iMaxY = 18

    ' ================================================================================================================================================================
    ' INITIALIZE NEUTRAL COLOR GRAPHICS TILES (BLACK ON TRANSPARENT)
    ' ================================================================================================================================================================
    If Len(sError) = 0 Then
        '' LOAD TILES (16 cols x 16 rows of 8x8 tiles) FROM FILE
        'sFile$ = Left$(Command$(0), _InStrRev(Command$(0), "\")) + "Font_8x8_128x128_v3.png" ' 128x128 pixels, 16 rows x 16 columns of 8x8 tiles
        'imgTiles = _LoadImage(sFile$, 32)

        ' LOAD TILES FROM TEXT DEFINITIONS IN Sub GetTileText
        sError = GetTiles$(imgTiles, cBlack, cEmpty)
    End If

    ' ================================================================================================================================================================
    ' CREATE COLORED TILESET COPIES v1
    ' ================================================================================================================================================================
    If Len(sError) = 0 Then
        MakeColoredTileset imgTiles, imgTilesRed, cRed, cBlack
        MakeColoredTileset imgTiles, imgTilesGreen, cLime, cBlack
        MakeColoredTileset imgTiles, imgTilesBlue, cBlue, cBlack
        MakeColoredTileset imgTiles, imgTilesYellow, cYellow, cBlack

        ' Make one big tileset with all colors
        imgColorTiles = _NewImage(512, 128, 32)
        _PutImage (0, 0), imgTilesRed, imgColorTiles, (0, 0)-(128, 128)
        _PutImage (128, 0), imgTilesGreen, imgColorTiles, (0, 0)-(128, 128)
        _PutImage (256, 0), imgTilesBlue, imgColorTiles, (0, 0)-(128, 128)
        _PutImage (384, 0), imgTilesYellow, imgColorTiles, (0, 0)-(128, 128)

        imgHardwareTiles = _CopyImage(imgColorTiles, 33) ' Copy tilesheet for hardware image
    End If

    ' ================================================================================================================================================================
    ' CREATE COLORED TILESET COPIES v2
    ' ================================================================================================================================================================
    If Len(sError) = 0 Then
        'ReDim arrColors(0 To 4) As _UNSIGNED Long
        'arrColors(0) = cRed
        'arrColors(1) = cLime
        'arrColors(2) = cBlue
        'arrColors(3) = cYellow
        'arrColors(4) = cBlack

        ReDim arrColors(0 To 39) As _Unsigned Long
        arrColors(0) = cRed
        arrColors(1) = cOrangeRed
        arrColors(2) = cDarkOrange
        arrColors(3) = cOrange
        arrColors(4) = cGold
        arrColors(5) = cYellow
        arrColors(6) = cChartreuse
        arrColors(7) = cOliveDrab1
        arrColors(8) = cLime
        arrColors(9) = cMediumSpringGreen
        arrColors(10) = cCyan
        arrColors(11) = cDeepSkyBlue
        arrColors(12) = cDodgerBlue
        arrColors(13) = cSeaBlue
        arrColors(14) = cBlue
        arrColors(15) = cBluePurple
        arrColors(16) = cDeepPurple
        arrColors(17) = cPurple
        arrColors(18) = cPurpleRed
        arrColors(19) = cDarkRed
        arrColors(20) = cBrickRed
        arrColors(21) = cDarkGreen
        arrColors(22) = cGreen
        arrColors(23) = cOliveDrab
        arrColors(24) = cLightPink
        arrColors(25) = cHotPink
        arrColors(26) = cDeepPink
        arrColors(27) = cMagenta
        arrColors(28) = cBlack
        arrColors(29) = cDimGray
        arrColors(30) = cGray
        arrColors(31) = cDarkGray
        arrColors(32) = cSilver
        arrColors(33) = cLightGray
        arrColors(34) = cGainsboro
        arrColors(35) = cWhiteSmoke
        arrColors(36) = cWhite
        arrColors(37) = cDarkBrown
        arrColors(38) = cLightBrown
        arrColors(39) = cKhaki
        iFirstColor2 = LBound(arrColors)
        iLastColor2 = UBound(arrColors)

        ' Make one big tileset with all possible foreground/background color combinations
        MakeColoredTileset2 imgTiles, imgTilesAllColorsSW, arrColors(), arrTileIndex(), arrColorIndex()
        imgTilesAllColorsHW = _CopyImage(imgTilesAllColorsSW, 33) ' Copy tilesheet for hardware image
    End If

    ' ================================================================================================================================================================
    ' VECTOR TILES SETUP
    ' ================================================================================================================================================================
    If Len(sError) = 0 Then
        ' set up vector tiles
        GetVectorTiles

        ' set up colors for vector HW tiles
        arrColor(0) = cRed
        arrColor(1) = cLime
        arrColor(2) = cBlue
        arrColor(3) = cYellow
        arrColor(4) = cBlack
        arrColor(5) = cEmpty
        MakePaletteImage imgPalette, arrColor()
        _Dest imgScreen&

        imgPaletteHW = _CopyImage(imgPalette, 33) ' Copy palette for hardware image
    End If

    ' ================================================================================================================================================================
    ' METHOD #1
    ' _PUTIMAGE with SOFTWARE IMAGES
    ' ================================================================================================================================================================
    If Len(sError) = 0 Then
        Cls , cGray
        Color cWhite, cBlack: Locate 1, 1: Print "Test #1: DrawTile8 routine using 4 tilesets (1 per color) and regular _putimage using using SOFTWARE images..."

        iCount1 = 0
        t# = Timer + 3
        Do
            iCount1 = iCount1 + 1
            iFirstColor = iFirstColor Xor 1
            iFgColorIndex = iFirstColor
            iY = iMinY
            iX = iMinX
            For iTileNum = 0 To 255
                Select Case iFgColorIndex
                    Case 0:
                        DrawTile8 imgTilesRed, iTileNum, imgScreen, iX, iY
                    Case 1:
                        DrawTile8 imgTilesGreen, iTileNum, imgScreen, iX, iY
                    Case 2:
                        DrawTile8 imgTilesBlue, iTileNum, imgScreen, iX, iY
                    Case Else:
                        DrawTile8 imgTilesYellow, iTileNum, imgScreen, iX, iY
                End Select
                iFgColorIndex = iFgColorIndex + 1: If iFgColorIndex > iLastColor Then iFgColorIndex = iFirstColor
                iX = iX + 1: If iX > iMaxX Then iX = iMinX: iY = iY + 1: If iY > iMaxY Then Exit For
            Next iTileNum
            _Display
        Loop Until Timer > t#
        _AutoDisplay
    End If

    ' ================================================================================================================================================================
    ' METHOD #2
    ' COLOR SWAP with SOFTWARE IMAGES
    ' ================================================================================================================================================================
    If Len(sError) = 0 Then
        Cls , cGray
        Color cWhite, cBlack: Locate 1, 1: Print "Test #2: DrawColorTile routine using 1 tileset with DoColorSwap using SOFTWARE images...";

        iCount2 = 0
        t# = Timer + 3
        Do
            iCount2 = iCount2 + 1
            iFirstColor = iFirstColor Xor 1
            iFgColorIndex = iFirstColor
            iY = iMinY
            iX = iMinX
            For iTileNum = 0 To 255
                Select Case iFgColorIndex
                    Case 0:
                        fgColor = cRed: bgColor = cBlack
                    Case 1:
                        fgColor = cLime: bgColor = cBlack
                    Case 2:
                        fgColor = cBlue: bgColor = cBlack
                    Case Else:
                        fgColor = cYellow: bgColor = cBlack
                End Select
                DrawColorTile imgScreen, imgTiles, iTileNum, fgColor, bgColor, iX, iY
                iFgColorIndex = iFgColorIndex + 1: If iFgColorIndex > iLastColor Then iFgColorIndex = iFirstColor
                iX = iX + 1: If iX > iMaxX Then iX = iMinX: iY = iY + 1: If iY > iMaxY Then Exit For
            Next iTileNum
            _Display
        Loop Until Timer > t#
        _AutoDisplay
    End If

    ' ================================================================================================================================================================
    ' METHOD #3
    ' _PUTIMAGE with HARDWARE IMAGES
    ' ================================================================================================================================================================
    If Len(sError) = 0 Then
        Cls , cGray
        Color cWhite, cBlack: Locate 1, 1: Print "Test #3: DrawTileHw8 routine using 1 big multi-tileset and HARDWARE images...";

        imgHardwareScreen = _CopyImage(0, 33)
        _DisplayOrder _Hardware

        iCount3 = 0
        t# = Timer + 3
        Do
            iCount3 = iCount3 + 1
            iFirstColor = iFirstColor Xor 1
            iFgColorIndex = iFirstColor
            iY = iMinY
            iX = iMinX
            _PutImage , imgHardwareScreen
            For iTileNum = 0 To 255
                DrawTileHw8 imgHardwareTiles, iTileNum, imgScreen, iX, iY, iFgColorIndex
                iFgColorIndex = iFgColorIndex + 1: If iFgColorIndex > iLastColor Then iFgColorIndex = iFirstColor
                iX = iX + 1: If iX > iMaxX Then iX = iMinX: iY = iY + 1: If iY > iMaxY Then Exit For
            Next iTileNum
            _Display
        Loop Until Timer > t#
        _AutoDisplay
        _DisplayOrder _Software , _Hardware
        If imgHardwareScreen < -1 Or imgHardwareScreen > 0 Then _FreeImage imgHardwareScreen ' FREE MEMORY
        If imgHardwareTiles < -1 Or imgHardwareTiles > 0 Then _FreeImage imgHardwareTiles ' FREE MEMORY
    End If

    ' ================================================================================================================================================================
    ' METHOD #4
    ' VECTOR-BASED TILES USING LINE
    ' ================================================================================================================================================================
    If Len(sError) = 0 Then
        Cls , cGray
        Color cWhite, cBlack: Locate 1, 1: Print "Test #4: DrawVectorTileLine routine using 1 vector-based tileset drawn with Line shapes...";

        iCount4 = 0
        t# = Timer + 3
        Do
            iCount4 = iCount4 + 1
            iFirstColor = iFirstColor Xor 1
            iFgColorIndex = iFirstColor
            iY = iMinY
            iX = iMinX
            For iTileNum = 0 To 255
                Select Case iFgColorIndex
                    Case 0:
                        fgColor = cRed: bgColor = cBlack
                    Case 1:
                        fgColor = cLime: bgColor = cBlack
                    Case 2:
                        fgColor = cBlue: bgColor = cBlack
                    Case Else:
                        fgColor = cYellow: bgColor = cBlack
                End Select
                'DrawShape iTileNum, iX, iY, fgColor, bgColor
                DrawVectorTileLine iTileNum, iX * 8, iY * 8, fgColor, bgColor

                iFgColorIndex = iFgColorIndex + 1: If iFgColorIndex > iLastColor Then iFgColorIndex = iFirstColor
                iX = iX + 1: If iX > iMaxX Then iX = iMinX: iY = iY + 1: If iY > iMaxY Then Exit For
            Next iTileNum
            _Display
        Loop Until Timer > t#
        _AutoDisplay
        _DisplayOrder _Software , _Hardware
    End If

    ' ================================================================================================================================================================
    ' METHOD #5
    ' VECTOR-BASED TILES USING _PutImage
    ' ================================================================================================================================================================
    If Len(sError) = 0 Then
        Cls , cGray
        Color cWhite, cBlack: Locate 1, 1: Print "Test #5: DrawVectorTilePutImage routine using 1 vector-based tileset drawn with _PutImage...";

        iBgColorIndex = 4

        iCount5 = 0
        t# = Timer + 3
        Do
            iCount5 = iCount5 + 1
            iFirstColor = iFirstColor Xor 1
            iFgColorIndex = iFirstColor
            iY = iMinY
            iX = iMinX
            For iTileNum = 0 To 255
                'DrawVectorTileLine iTileNum, iX*8, iY*8, fgColor, bgColor
                DrawVectorTilePutImage _
                    imgScreen, imgPalette, arrColor(), _
                    iTileNum, iX, iY, _
                    iFgColorIndex, iBgColorIndex
                iFgColorIndex = iFgColorIndex + 1: If iFgColorIndex > iLastColor Then iFgColorIndex = iFirstColor
                iX = iX + 1: If iX > iMaxX Then iX = iMinX: iY = iY + 1: If iY > iMaxY Then Exit For
            Next iTileNum
            _Display
        Loop Until Timer > t#
        _AutoDisplay
    End If

    ' ================================================================================================================================================================
    ' METHOD #6
    ' VECTOR-BASED TILES USING _PutImage with HARDWARE IMAGES
    ' ================================================================================================================================================================
    If Len(sError) = 0 Then
        Cls , cGray
        Color cWhite, cBlack: Locate 1, 1: Print "Test #6: DrawVectorTilePutImageHW routine using 1 vector-based tileset drawn with hardware images...";

        iBgColorIndex = 4
        imgHardwareScreen = _CopyImage(0, 33)
        _DisplayOrder _Hardware

        iCount6 = 0
        t# = Timer + 3
        Do
            iCount6 = iCount6 + 1
            iFirstColor = iFirstColor Xor 1
            iFgColorIndex = iFirstColor
            iY = iMinY
            iX = iMinX
            _PutImage , imgHardwareScreen
            For iTileNum = 0 To 255
                'DrawVectorTileLine iTileNum, iX*8, iY*8, fgColor, bgColor
                DrawVectorTilePutImageHW _
                    imgPaletteHW, arrColor(), _
                    iTileNum, iX, iY, _
                    iFgColorIndex, iBgColorIndex

                iFgColorIndex = iFgColorIndex + 1: If iFgColorIndex > iLastColor Then iFgColorIndex = iFirstColor
                iX = iX + 1: If iX > iMaxX Then iX = iMinX: iY = iY + 1: If iY > iMaxY Then Exit For
            Next iTileNum
            _Display
        Loop Until Timer > t#
        _AutoDisplay
        _DisplayOrder _Software , _Hardware
        If imgHardwareScreen < -1 Or imgHardwareScreen > 0 Then _FreeImage imgHardwareScreen ' FREE MEMORY
        If imgPaletteHW < -1 Or imgPaletteHW > 0 Then _FreeImage imgPaletteHW ' FREE MEMORY
    End If

    ' ================================================================================================================================================================
    ' METHOD #7
    ' SOLID BOXES WITH LINE
    ' ================================================================================================================================================================
    If Len(sError) = 0 Then
        Cls , cGray
        Color cWhite, cBlack: Locate 1, 1: Print "Test #7: Solid boxes with Line...";

        iCount7 = 0
        t# = Timer + 3
        Do
            _Display
            iCount7 = iCount7 + 1
            iFirstColor = iFirstColor Xor 1
            iFgColorIndex = iFirstColor
            iY = iMinY
            iX = iMinX
            For iTileNum = 0 To 255
                Select Case iFgColorIndex
                    Case 0:
                        fgColor = cRed: bgColor = cBlack
                    Case 1:
                        fgColor = cLime: bgColor = cBlack
                    Case 2:
                        fgColor = cBlue: bgColor = cBlack
                    Case Else:
                        fgColor = cYellow: bgColor = cBlack
                End Select

                'DrawShape iTileNum, iX, iY, fgColor, bgColor
                'DrawVectorTileLine iTileNum, iX*8, iY*8, fgColor, bgColor
                Line (iX * 8, iY * 8)-((iX * 8) + 7, (iY * 8) + 7), fgColor, BF ' Draw a solid box

                iFgColorIndex = iFgColorIndex + 1: If iFgColorIndex > iLastColor Then iFgColorIndex = iFirstColor
                iX = iX + 1: If iX > iMaxX Then iX = iMinX: iY = iY + 1: If iY > iMaxY Then Exit For
            Next iTileNum
            _Display
        Loop Until Timer > t#
        _AutoDisplay
    End If


    ' ================================================================================================================================================================
    ' METHOD #8
    ' _PUTIMAGE with HARDWARE IMAGES v2 (ALL COLOR COMBINATIONS)
    ' ================================================================================================================================================================
    If Len(sError) = 0 Then
        Cls , cGray
        Color cWhite, cBlack: Locate 1, 1: Print "Test #8: DrawColorTileHw8 routine using 1 big multi-tileset and HARDWARE images...";

        ''_PutImage (xDest%, yDest%), imgTiles&, imgScreen&, (sx1%, sy1%)-(sx2%, sy2%)
        '_PutImage (0, 0), imgTilesAllColorsSW, imgScreen
        'sleep
        'IF TRUE=FALSE THEN
        imgHardwareScreen = _CopyImage(0, 33)
        _DisplayOrder _Hardware

        iCount8 = 0
        t# = Timer + 3
        Do
            iCount8 = iCount8 + 1
            iFirstColor2 = iFirstColor2 Xor 1
            iFgColorIndex = iFirstColor2
            iBgColorIndex = iFgColorIndex + 1: If iBgColorIndex > iLastColor2 Then iBgColorIndex = iFirstColor2

            iY = iMinY
            iX = iMinX
            _PutImage , imgHardwareScreen
            For iTileNum = 0 To 255
                DrawColorTileHw8 imgTilesAllColorsHW, iTileNum, imgScreen, iX, iY, iFgColorIndex, iBgColorIndex, arrTileIndex(), arrColorIndex()
                iFgColorIndex = iFgColorIndex + 1
                If iFgColorIndex > iLastColor2 Then
                    iFgColorIndex = iFirstColor2
                    iBgColorIndex = iBgColorIndex + 1
                    If iBgColorIndex > iLastColor2 Then
                        iBgColorIndex = iFirstColor2
                    End If
                End If

                iX = iX + 1: If iX > iMaxX Then iX = iMinX: iY = iY + 1: If iY > iMaxY Then Exit For
            Next iTileNum
            _Display
        Loop Until Timer > t#
        _AutoDisplay
        _DisplayOrder _Software , _Hardware
        If imgHardwareScreen < -1 Or imgHardwareScreen > 0 Then _FreeImage imgHardwareScreen ' FREE MEMORY
        'END IF
        If imgTilesAllColorsHW < -1 Or imgTilesAllColorsHW > 0 Then _FreeImage imgTilesAllColorsHW ' FREE MEMORY
    End If



    ' ================================================================================================================================================================
    ' SHOW RESULTS
    ' ================================================================================================================================================================
    Cls , cGray
    Color cWhite, cBlack: Locate 1, 1
    Print ""
    Print "RESULTS:"
    Print Using "DrawTile8                ###,###,###,###,###,### refreshes in 3 seconds."; iCount1
    Print Using "DrawColorTile            ###,###,###,###,###,### refreshes in 3 seconds."; iCount2
    Print Using "DrawTileHw8              ###,###,###,###,###,### refreshes in 3 seconds."; iCount3
    Print Using "DrawVectorTileLine       ###,###,###,###,###,### refreshes in 3 seconds."; iCount4
    Print Using "DrawVectorTilePutImage   ###,###,###,###,###,### refreshes in 3 seconds."; iCount5
    Print Using "DrawVectorTilePutImageHW ###,###,###,###,###,### refreshes in 3 seconds."; iCount6
    Print Using "Solid boxes with Line    ###,###,###,###,###,### refreshes in 3 seconds."; iCount7
    Print Using "DrawColorTileHw8         ###,###,###,###,###,### refreshes in 3 seconds."; iCount8
    Print "PRESS ANY KEY TO CONTINUE"
    Sleep

    ' ================================================================================================================================================================
    ' CLEANUP AND EXIT
    ' ================================================================================================================================================================
    Screen 0 ' RETURN TO TEXT SCREEN
    If imgScreen < -1 Or imgScreen > 0 Then _FreeImage imgScreen ' FREE MEMORY
    'If imgHardwareScreen < -1 Or imgHardwareScreen > 0 Then _FreeImage imgHardwareScreen ' FREE MEMORY
    If imgTiles < -1 Or imgTiles > 0 Then _FreeImage imgTiles ' FREE MEMORY
    'If imgHardwareTiles < -1 Or imgHardwareTiles > 0 Then _FreeImage imgHardwareTiles ' FREE MEMORY
    If imgTilesRed < -1 Or imgTilesRed > 0 Then _FreeImage imgTilesRed ' FREE MEMORY
    If imgTilesGreen < -1 Or imgTilesGreen > 0 Then _FreeImage imgTilesGreen ' FREE MEMORY
    If imgTilesBlue < -1 Or imgTilesBlue > 0 Then _FreeImage imgTilesBlue ' FREE MEMORY
    If imgTilesYellow < -1 Or imgTilesYellow > 0 Then _FreeImage imgTilesYellow ' FREE MEMORY
    If imgColorTiles < -1 Or imgColorTiles > 0 Then _FreeImage imgColorTiles ' FREE MEMORY
    If imgTilesAllColorsSW < -1 Or imgTilesAllColorsSW > 0 Then _FreeImage imgTilesAllColorsSW ' FREE MEMORY
    'If imgTilesAllColorsHW < -1 Or imgTilesAllColorsHW > 0 Then _FreeImage imgTilesAllColorsHW ' FREE MEMORY
    If imgPalette < -1 Or imgPalette > 0 Then _FreeImage imgPalette ' FREE MEMORY
    'If imgPaletteHW < -1 Or imgPaletteHW > 0 Then _FreeImage imgPaletteHW ' FREE MEMORY

End Sub ' DrawingSpeedTest7

' ################################################################################################################################################################
' END DRAWING SPEED TEST
' ################################################################################################################################################################









































' ################################################################################################################################################################
' BEGIN Steve's very different custom screen
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////

Sub TestCustomHardwareScreen2
    Dim sError As String: sError = ""
    Dim in$
    Dim arrColors(255) As _Unsigned Long ' an array to hold all my color values
    Dim imgDisplay As Long
    Dim imgTile As Long
    Dim imgFont As Long
    Dim imgTempScreen256 As Long
    Dim iLoop As Integer
    Dim iColor As Integer
    Dim iTile As Integer
    Dim iX As Integer
    Dim iY As Integer
    Dim count&
    Dim t## ' _FLOAT

    Randomize Timer

    imgDisplay = _NewImage(800, 600, 32) ' my main screenwich is 100 by 75 characters with 8x8 font.
    imgTile = _NewImage(8 * 256, 8, 32) ' 8x8 tiles in 256 colors
    imgFont = _NewImage(8 * 256, 8 * 256, 32) ' 256 characters of an 8x8 font, in all 256 possible colors.

    ' Set the main screen for starters so it'll go ahead
    ' and create itself properly while I'm working on making my tiles and fonts
    Screen imgDisplay

    ' very tiny 256 color screen, just to borrow the palette from
    imgTempScreen256 = _NewImage(10, 10, 256)
    ' 40 colors
    For iLoop = 0 To 255
        ' since I don't know your color palette, I'll just copy the QB64 256 color palette.  ;)
        arrColors(iLoop) = _RGB32(_Red(iLoop, imgTempScreen256), _Green(iLoop, imgTempScreen256), _Blue(iLoop, imgTempScreen256))
    Next iLoop
    If imgTempScreen256 < -1 Or imgTempScreen256 > 0 Then _FreeImage imgTempScreen256 ' FREE MEMORY

    ' Create my software tiles of 256 colors
    _Dest imgTile
    For iLoop = 0 To 255 ' 256 tiles, one for each color
        ' all drawn sequentially onto a sprite sheet
        Line (iLoop * 8, 0)-Step(8, 8), arrColors(iLoop), BF
    Next iLoop

    ' I'm just going to use the built in QB64 8x8 font for quick and easy sheet creation.
    _Dest imgFont
    _Font 8
    For iColor = 0 To 255 ' 256 colors
        Color arrColors(iColor), 0 ' make our font the proper color
        For iTile = 0 To 255 ' 256 characters
            ' print the characters row by row to the screen
            _PrintString (iTile * 8, iColor * 8), Chr$(iTile)
        Next iTile
    Next iColor
    _Dest imgDisplay

    'Sleep ' View the blank screen  until a key is hit

    Screen imgTile ' View the tiles
    DebugPrint "Viewing the tiles (imgTile) - press any key to continue"
    Sleep ' until a key is hit

    Screen imgFont ' view the fonts
    DebugPrint "Viewing the fonts (imgFont) - press any key to continue"
    Sleep ' until a key is hit

    Screen imgDisplay ' and back to the normal blank screen
    _Delay .2 ' time to remove finger from key
    'Dim Shared As Long m_TileHw, m_FontHw

    m_TileHw = _CopyImage(imgTile, 33) ' hardware copy of the tile image
    m_FontHw = _CopyImage(imgFont, 33) ' hardware copy of the font image

    If imgTile < -1 Or imgTile > 0 Then _FreeImage imgTile ' FREE MEMORY 'free unused images when done with them
    If imgFont < -1 Or imgFont > 0 Then _FreeImage imgFont ' FREE MEMORY 'free unused images when done with them

    ' From this point onwards, I'm *ONLY* going to use my hardware layer
    _DisplayOrder _Hardware

    '' Here, I'm creating a screen array to hold the information
    '' of EVERY character I place onto the screen, and its tile
    'Dim Shared m_ScreenArray(99, 74) As _Unsigned Long

    ' To start with, let's put all 256 chracters on the screen,
    ' on a color 40 tile (red), in a color 3 font (cyan)
    iX = 0: iY = 0
    For iLoop = 0 To 255
        ' 40 tile color, 3 font color, iLoop is the character
        iX = iX + 1: If iX > 99 Then iX = 0: iY = iY + 1
        m_ScreenArray(iX, iY) = SetAll(40, 3, iLoop)
    Next iLoop

    ' And then let's show these results on the screen.
    ' Take a moment to open task manager and see how little resources we're using here.
    DebugPrint "Viewing the whole screen full of these tiles + characters"
    DebugPrint "press ENTER to continue"
    Do
        ' Draw a whole screen full of these tiles + characters
        ScreenRender
        _Limit 30
    Loop Until _KeyDown(13) ' until we hit ENTER

    _Delay .2 ' time to lift up the key so we don't instantly blow past the next loop

    iX = 0: iY = 0
    ' and here I'm going to set all these tiles to have incremental background tile colors
    For iLoop = 0 To 255
        ' from left to right, top to bottom
        iX = iX + 1: If iX > 99 Then iX = 0: iY = iY + 1
        SetArrayTile iX, iY, iLoop ' set each tile to become an ever increasing color value
    Next iLoop

    ' And then let's show these results on the screen.
    DebugPrint "Viewing the screen with incremental colors"
    DebugPrint "press ENTER to continue"
    Do
        ' Draw a whole screen full of these tiles + characters
        ScreenRender
        _Limit 30
    Loop Until _KeyDown(13) ' until we hit ENTER

    ' And to finish up, let's do a quick count of how many loops per second
    ' we *could* process, with the whole screen being redrawn over and over like this
    DebugPrint "Counting how many loops per second for 3 seconds..."
    t## = Timer + 3
    count& = 0
    Do
        count& = count& + 1
        ScreenRender
    Loop Until Timer > t##

    ' Return to normal software screen
    DebugPrint "Returning to normal software screen"
    _DisplayOrder _Software
    _AutoDisplay

    _KeyClear: _Delay 1 ' clear keyboard buffer

    Screen 0: Cls
    Print "Whole screen rendering of color tile + color font = "; count&; " times in 3 seconds."
    Print
    Input "PRESS <ENTER> TO CONTINUE"; in$

    If imgDisplay < -1 Or imgDisplay > 0 Then _FreeImage imgDisplay ' FREE MEMORY

End Sub ' TestCustomHardwareScreen2

' /////////////////////////////////////////////////////////////////////////////

Sub TestCustomHardwareScreen1
    Dim sError As String: sError = ""
    Dim in$
    Dim arrColors(255) As _Unsigned Long ' an array to hold all my color values
    Dim imgDisplay As Long
    Dim imgTile As Long
    Dim imgFont As Long
    Dim imgTempScreen256 As Long
    Dim iLoop As Integer
    Dim iColor As Integer
    Dim iTile As Integer
    Dim iX As Integer
    Dim iY As Integer
    Dim count&
    Dim t## ' _FLOAT

    Cls
    Print "Custom hardware screen test. Press <ENTER> to proceed through each step."
    Input "PRESS <ENTER> TO START"; in$

    Randomize Timer

    imgDisplay = _NewImage(800, 600, 32) ' my main screenwich is 100 by 75 characters with 8x8 font.
    imgTile = _NewImage(8 * 256, 8, 32) ' 8x8 tiles in 256 colors
    imgFont = _NewImage(8 * 256, 8 * 256, 32) ' 256 characters of an 8x8 font, in all 256 possible colors.

    ' Set the main screen for starters so it'll go ahead
    ' and create itself properly while I'm working on making my tiles and fonts
    Screen imgDisplay

    ' very tiny 256 color screen, just to borrow the palette from
    imgTempScreen256 = _NewImage(10, 10, 256)
    For iLoop = 0 To 255 ' 40 colors
        ' since I don't know your color palette, I'll just copy the QB64 256 color palette.  ;)
        arrColors(iLoop) = _RGB32(_Red(iLoop, imgTempScreen256), _Green(iLoop, imgTempScreen256), _Blue(iLoop, imgTempScreen256))
    Next iLoop
    If imgTempScreen256 < -1 Or imgTempScreen256 > 0 Then _FreeImage imgTempScreen256 ' FREE MEMORY

    ' Create my software tiles of 256 colors
    _Dest imgTile
    For iLoop = 0 To 255 ' 256 tiles, one for each color
        Line (iLoop * 8, 0)-Step(8, 8), arrColors(iLoop), BF ' all drawn sequentially onto a sprite sheet
    Next iLoop

    ' I'm just going to use the built in QB64 8x8 font for quick and easy sheet creation.
    _Dest imgFont
    _Font 8
    For iColor = 0 To 255 ' 256 colors
        Color arrColors(iColor), 0 ' make our font the proper color
        For iTile = 0 To 255 ' 256 characters
            _PrintString (iTile * 8, iColor * 8), Chr$(iTile) ' print the characters row by row to the screen
        Next iTile
    Next iColor
    _Dest imgDisplay

    Sleep ' View the blank screen  until a key is hit

    Screen imgTile ' View the tiles
    Sleep ' until a key is hit

    Screen imgFont ' view the fonts
    Sleep ' until a key is hit

    Screen imgDisplay ' and back to the normal blank screen
    _Delay .2 ' time to remove finger from key
    'Dim Shared As Long m_TileHw, m_FontHw

    m_TileHw = _CopyImage(imgTile, 33) ' hardware copy of the tile image
    m_FontHw = _CopyImage(imgFont, 33) ' hardware copy of the font image

    If imgTile < -1 Or imgTile > 0 Then _FreeImage imgTile ' FREE MEMORY 'free unused images when done with them
    If imgFont < -1 Or imgFont > 0 Then _FreeImage imgFont ' FREE MEMORY 'free unused images when done with them

    ' From this point onwards, I'm *ONLY* going to use my hardware layer
    _DisplayOrder _Hardware

    '' Here, I'm creating a screen array to hold the information
    '' of EVERY character I place onto the screen, and its tile
    'Dim Shared m_ScreenArray(99, 74) As _Unsigned Long

    ' To start with, let's put all 256 chracters on the screen,
    ' on a color 40 tile (red), in a color 3 font (cyan)
    iX = 0: iY = 0
    For iLoop = 0 To 255
        ' 40 tile color, 3 font color, iLoop is the character
        iX = iX + 1: If iX > 99 Then iX = 0: iY = iY + 1
        m_ScreenArray(iX, iY) = SetAll(40, 3, iLoop)
    Next iLoop

    ' And then let's show these results on the screen.
    ' Take a moment to open task manager and see how little resources we're using here.
    Do
        ' Draw a whole screen full of these tiles + characters
        ScreenRender
        _Limit 30
    Loop Until _KeyDown(13) ' until we hit ENTER

    _Delay .2 ' time to lift up the key so we don't instantly blow past the next loop

    iX = 0: iY = 0
    ' and here I'm going to set all these tiles to have incremental background tile colors
    For iLoop = 0 To 255
        ' from left to right, top to bottom
        iX = iX + 1: If iX > 99 Then iX = 0: iY = iY + 1
        SetArrayTile iX, iY, iLoop ' set each tile to become an ever increasing color value
    Next iLoop

    ' And then let's show these results on the screen.
    Do
        ' Draw a whole screen full of these tiles + characters
        ScreenRender
        _Limit 30
    Loop Until _KeyDown(13) ' until we hit ENTER

    ' And to finish up, let's do a quick count of how many loops per second
    ' we *could* process, with the whole screen being redrawn over and over like this
    t## = Timer + 3
    count& = 0
    Do
        count& = count& + 1
        ScreenRender
    Loop Until Timer > t##

    ' Return to normal software screen
    _DisplayOrder _Software
    _AutoDisplay

    _KeyClear: _Delay 1 ' clear keyboard buffer

    Screen 0: Cls
    Print "Whole screen rendering of color tile + color font = "; count&; " times in 3 seconds."

    Print
    Input "PRESS <ENTER> TO CONTINUE"; in$

    If imgDisplay < -1 Or imgDisplay > 0 Then _FreeImage imgDisplay ' FREE MEMORY

End Sub ' TestCustomHardwareScreen1

' /////////////////////////////////////////////////////////////////////////////

Sub ScreenRender
    Dim tileColor As _Unsigned Long
    Dim fontColor As _Unsigned Long
    Dim character As _Unsigned Long
    Dim iX As Integer
    Dim iY As Integer

    For iX = 0 To 99
        For iY = 0 To 74
            tileColor = m_ScreenArray(iX, iY) \ (256 * 256)
            fontColor = (m_ScreenArray(iX, iY) - tileColor * 256 * 256) \ 256
            character = m_ScreenArray(iX, iY) Mod 256
            _PutImage (iX * 8, iY * 8)-Step(7, 7), m_TileHw, , (tileColor * 8, 0)-Step(7, 7)
            _PutImage (iX * 8, iY * 8)-Step(7, 7), m_FontHw, , (character * 8, fontColor * 8)-Step(7, 7)
        Next iY
    Next iX
    _Display
End Sub ' ScreenRender

' /////////////////////////////////////////////////////////////////////////////

Function SetAll&& (tile, fontcolor, character)
    SetAll&& = tile * 256 * 256 + fontcolor * 256 + character
End Function ' SetAll&&

' /////////////////////////////////////////////////////////////////////////////

Sub SetArrayTile (iX, iY, newTileColor)
    Dim temp&&
    Dim oldTile&&

    temp&& = m_ScreenArray(iX, iY)
    oldTile&& = temp&& \ (256 * 256)
    m_ScreenArray(iX, iY) = temp&& - oldTile&& + newTileColor * 256 * 256
End Sub ' SetArrayTile

' /////////////////////////////////////////////////////////////////////////////

Sub SetArrayFontColor (iX, iY, newFontColor)
    Dim temp&&
    Dim oldTile&&
    Dim oldFont&&

    temp&& = m_ScreenArray(iX, iY)
    oldTile&& = temp&& \ (256 * 256)
    oldFont&& = (temp&& - oldTile&&) \ 256
    m_ScreenArray(iX, iY) = temp&& - oldFont&& + newFontColor * 256
End Sub ' SetArrayFontColor

' /////////////////////////////////////////////////////////////////////////////

Sub SetArrayCharacter (iX, iY, newCharacter)
    Dim temp&&
    Dim oldCharacter&&

    temp&& = m_ScreenArray(iX, iY)
    oldCharacter&& = temp&& Mod 256
    m_ScreenArray(iX, iY) = temp&& - oldCharacter&& + newCharacter
End Sub ' SetArrayCharacter

' ################################################################################################################################################################

' Re: fastest way to draw a 2-color 8x8 tile (with variable colors)?
' https://qb64forum.alephc.xyz/index.php?topic=4674.msg140904#msg140904

' SMcNeill, QB64 Developer
' Reply #18 on: Yesterday at 05:08:58 pm
'
' One thing that would be *very* different with all hardware images vs what
' you're doing currently, is the fact that you have to remember:
' Hardware images display once and then flush themselves from the GPU buffer.
'
' You can't just print to a tile, and then read the information for the color of
' that tile, and instantly turn that color into another one.  You have write
' access to hardware images, but not read access -- and the images aren't
' persistent like the software images are.
'
' For something like this to work for a whole screen in hardware image mode,
' you'd have to sort out some sort of way to store your screen's info and then
' constantly redraw everything over and over again to keep it refreshed on the
' display.
'
' The way I'd go about doing something like this would be to make myself a
' custom SCREEN 0-style memory array.  Screen 0 stores all our information for
' each character in 2 bytes -- one for color, one for character.  I'd basically
' do the same, but with 3 bytes -- one for tile color, one for font color, one
' for character.
'
' Let me toss a simple demo of this line of thinking for you:
' (TestCustomHardwareScreen1)
'
' I tried to comment the heck out of the code to help explain what it's doing
' from line to line, so I hope this isn't too hard to sort out and understand.
'
' The beginning is nothing more than initializing things and making 2 different
' sprite sheets that I'll make use of later -- one for the tiles and one for the
' characters.
'
' Then there's the mid section where you can SLEEP step through and view the
' various resource sheets.
'
' Then an example of all the characters in a cyan font, resting atop a red tile.
' (You have to hit ENTER to move on from this screen.)
'
' Then an example of all those tiles that go under the characters being replaced
' with sequential colored tiles.  (A lot of these tiles are simply BLACK, but
' that's the nature of the 256 color palette as those multiple blacks are there
' to be replaced with custom color values instead.)
'
' Once more, you'll have to hit ENTER to continue.
'
' And then I do a quick time loop to count how many times we can redraw the whole
' screen of tiles + characters in 3 seconds.
'
' For an 800x600 screen (100 x 75 characters and tiles), my laptop does a max of
' about 1800 refreshes in that time.  That's around 600 FPS, which would be more
' than enough for any sort of game display or use that I think I could come up
' with, and that's without me trying to optimize math or any such things to
' reduce calculations and speed the process up any more.  (Keep in mind, this is
' 1800 full pages of a 800x600 screen -- if your screen has a lower overall
' resolution, then you'd draw more loops with less to process, but a higher
' resolution screen would draw fewer loops with more to process.)
'
' No _MEM access.  No optimization work.  Just 600 FPS rendering of a whole page
' of tiles and colored characters.  (And, YES, it is a whole page being rendered
' repeatedly -- even if I didn't bother to fill in the vast majority of that page
' with anything more than black tiles, black fonts, and chr$(0) blank spaces...)
'
' It's a completely different approach to displaying stuff than what you've been
' doing, but it seems as if what you've been doing isn't working as it must be
' running too slow for you.  You wouldn't be able to use the normal PRINT
' statements to display to the faux screen memory array I've created; you'd have
' to write your own.
'
' For a quick speed comparison, here's the same type process ran using PRINT
' and a software screen of the same size:
' (TestSoftwareScreen1)

' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////

Function GetInstructions1$
    Dim in$
    in$ = ""
    in$ = in$ + "Re: fastest way to draw a 2-color 8x8 tile (with variable colors)?" + Chr$(13)
    in$ = in$ + "https://qb64forum.alephc.xyz/index.php?topic=4674.msg140904#msg140904" + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "SMcNeill, QB64 Developer" + Chr$(13)
    in$ = in$ + "Reply #18 on: Yesterday at 05:08:58 pm" + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "One thing that would be *very* different with all hardware images vs what " + Chr$(13)
    in$ = in$ + "you're doing currently, is the fact that you have to remember:  " + Chr$(13)
    in$ = in$ + "Hardware images display once and then flush themselves from the GPU buffer. " + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "You can't just print to a tile, and then read the information for the color of " + Chr$(13)
    in$ = in$ + "that tile, and instantly turn that color into another one.  You have write " + Chr$(13)
    in$ = in$ + "access to hardware images, but not read access -- and the images aren't " + Chr$(13)
    in$ = in$ + "persistent like the software images are." + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "For something like this to work for a whole screen in hardware image mode, " + Chr$(13)
    in$ = in$ + "you'd have to sort out some sort of way to store your screen's info and then " + Chr$(13)
    in$ = in$ + "constantly redraw everything over and over again to keep it refreshed on the " + Chr$(13)
    in$ = in$ + "display." + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "The way I'd go about doing something like this would be to make myself a " + Chr$(13)
    in$ = in$ + "custom SCREEN 0-style memory array.  Screen 0 stores all our information for " + Chr$(13)
    in$ = in$ + "each character in 2 bytes -- one for color, one for character.  I'd basically " + Chr$(13)
    in$ = in$ + "do the same, but with 3 bytes -- one for tile color, one for font color, one " + Chr$(13)
    in$ = in$ + "for character." + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "Let me toss a simple demo of this line of thinking for you:" + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "I tried to comment the heck out of the code to help explain what it's doing " + Chr$(13)
    in$ = in$ + "from line to line, so I hope this isn't too hard to sort out and understand." + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "The beginning is nothing more than initializing things and making 2 different " + Chr$(13)
    in$ = in$ + "sprite sheets that I'll make use of later -- one for the tiles and one for the " + Chr$(13)
    in$ = in$ + "characters." + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "Then there's the mid section where you can SLEEP step through and view the " + Chr$(13)
    in$ = in$ + "various resource sheets." + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "Then an example of all the characters in a cyan font, resting atop a red tile.  " + Chr$(13)
    in$ = in$ + "(You have to hit ENTER to move on from this screen.)" + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "Then an example of all those tiles that go under the characters being replaced " + Chr$(13)
    in$ = in$ + "with sequential colored tiles.  (A lot of these tiles are simply BLACK, but " + Chr$(13)
    in$ = in$ + "that's the nature of the 256 color palette as those multiple blacks are there " + Chr$(13)
    in$ = in$ + "to be replaced with custom color values instead.)" + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "Once more, you'll have to hit ENTER to continue." + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "And then I do a quick time loop to count how many times we can redraw the whole " + Chr$(13)
    in$ = in$ + "screen of tiles + characters in 3 seconds." + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "For an 800x600 screen (100 x 75 characters and tiles), my laptop does a max of " + Chr$(13)
    in$ = in$ + "about 1800 refreshes in that time.  That's around 600 FPS, which would be more " + Chr$(13)
    in$ = in$ + "than enough for any sort of game display or use that I think I could come up " + Chr$(13)
    in$ = in$ + "with, and that's without me trying to optimize math or any such things to " + Chr$(13)
    in$ = in$ + "reduce calculations and speed the process up any more.  (Keep in mind, this is " + Chr$(13)
    in$ = in$ + "1800 full pages of a 800x600 screen -- if your screen has a lower overall " + Chr$(13)
    in$ = in$ + "resolution, then you'd draw more loops with less to process, but a higher " + Chr$(13)
    in$ = in$ + "resolution screen would draw fewer loops with more to process.)" + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "No _MEM access.  No optimization work.  Just 600 FPS rendering of a whole page " + Chr$(13)
    in$ = in$ + "of tiles and colored characters.  (And, YES, it is a whole page being rendered " + Chr$(13)
    in$ = in$ + "repeatedly -- even if I didn't bother to fill in the vast majority of that page " + Chr$(13)
    in$ = in$ + "with anything more than black tiles, black fonts, and chr$(0) blank spaces...)" + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "It's a completely different approach to displaying stuff than what you've been " + Chr$(13)
    in$ = in$ + "doing, but it seems as if what you've been doing isn't working as it must be " + Chr$(13)
    in$ = in$ + "running too slow for you.  You wouldn't be able to use the normal PRINT " + Chr$(13)
    in$ = in$ + "statements to display to the faux screen memory array I've created; you'd have " + Chr$(13)
    in$ = in$ + "to write your own." + Chr$(13)
    GetInstructions1$ = in$
End Function ' GetInstructions1$

' /////////////////////////////////////////////////////////////////////////////

Function GetInstructions2$
    Dim in$
    in$ = ""
    in$ = in$ + "Re: fastest way to draw a 2-color 8x8 tile (with variable colors)?" + Chr$(13)
    in$ = in$ + "https://qb64forum.alephc.xyz/index.php?topic=4674.msg140904#msg140904" + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "SMcNeill, QB64 Developer" + Chr$(13)
    in$ = in$ + "Reply #18 on: Yesterday at 05:08:58 pm" + Chr$(13)
    in$ = in$ + " " + Chr$(13)
    in$ = in$ + "For a quick speed comparison, here's the same type process ran using PRINT " + Chr$(13)
    in$ = in$ + "and a software screen of the same size:" + Chr$(13)
    GetInstructions2$ = in$
End Function ' GetInstructions2$

' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////

Sub TestSoftwareScreen1
    Dim in$
    Dim t## ' _FLOAT
    Dim count As Integer
    Dim iX As Integer
    Dim iY As Integer
    Dim iTile As Integer

    Screen _NewImage(800, 600, 32)
    _ControlChr Off

    _Font 8
    t## = Timer + 3
    count = 0
    Do
        count = count + 1
        For iX = 1 To 100
            For iY = 1 To 75
                iTile = (iTile + 1) Mod 256
                Color _RGB32(Rnd * 255, Rnd * 255, Rnd * 255), _RGB32(Rnd * 255, Rnd * 255, Rnd * 255)
                Locate iY, iX: Print Chr$(iTile);
            Next iY
        Next iX
    Loop Until Timer > t##

    _KeyClear: _Delay 1
    Screen 0: Cls
    Print count; "total screen replacements in 3 seconds."
    Print
    Input "PRESS <ENTER> TO CONTINUE"; in$
End Sub ' TestSoftwareScreen1

' ################################################################################################################################################################
' END Steve's very different custom screen
' ################################################################################################################################################################





































































' ################################################################################################################################################################
' BEGIN VECTOR-BASED TILE ROUTINES
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////

Sub DrawVectorTilePutImageTest
    Dim imgPalette As Long ' contains palette of colors
    Dim imgScreen As Long ' the main display
    Dim MyString As String
    Dim iLoop As Integer
    Dim iTileNum As Integer
    Dim arrColor(0 To 8) As _Unsigned Long
    Dim arrColorNames(0 To 8) As String
    Dim iMinFgColorIndex As Integer: iMinFgColorIndex = 0
    Dim iMaxFgColorIndex As Integer: iMaxFgColorIndex = 7
    Dim iMinBgColorIndex As Integer: iMinBgColorIndex = 0
    Dim iMaxBgColorIndex As Integer: iMaxBgColorIndex = 8
    Dim iFgColorIndex As Integer: iFgColorIndex = iMinFgColorIndex
    Dim iBgColorIndex As Integer: iBgColorIndex = iMinBgColorIndex
    Dim iX As Integer
    Dim iY As Integer
    Dim iMinX As Integer
    Dim iMaxX As Integer
    Dim iMinY As Integer
    Dim iMaxY As Integer

    ' Initialize colors
    arrColor(0) = cBlack
    arrColor(1) = cRed
    arrColor(2) = cYellow
    arrColor(3) = cLime
    arrColor(4) = cCyan
    arrColor(5) = cBlue
    arrColor(6) = cPurple
    arrColor(7) = cMagenta
    arrColor(8) = cEmpty

    ' Initialize color names (for test output)
    arrColorNames(0) = "cBlack"
    arrColorNames(1) = "cRed"
    arrColorNames(2) = "cYellow"
    arrColorNames(3) = "cLime"
    arrColorNames(4) = "cCyan"
    arrColorNames(5) = "cBlue"
    arrColorNames(6) = "cPurple"
    arrColorNames(7) = "cMagenta"
    arrColorNames(8) = "cEmpty"

    ' Set up screen
    imgScreen = _NewImage(1024, 768, 32): _ScreenMove 0, 0
    Screen imgScreen
    Cls , cGray

    ' Generate color palette
    MakePaletteImage imgPalette, arrColor()

    '' Draw palette on screen:
    ''_PutImage (xDest%, yDest%), imgSource&, imgDest&, (sx1%, sy1%)-(sx2%, sy2%)
    '_PutImage (400, 300), imgPalette, imgScreen, (0,0)-(_WIDTH(imgPalette), _HEIGHT(imgPalette))

    ' Set up tiles
    GetVectorTiles

    ' Set up screen boundaries, initial colors, etc.
    iMinX = 0: iMaxX = _Width(0) \ 8
    iMinY = 0: iMaxY = _Height(0) \ 8
    DebugPrint "iMaxX = _Width(0) = " + cstr$(iMaxX)
    DebugPrint "iMaxY = _Height(0) = " + cstr$(iMaxY)

    iFgColorIndex = iMinFgColorIndex - 1

    ' Freeze dislay
    _Display

    ' Test text
    'MyString = "#"
    'MyString = "BOO!"
    MyString = "HELLO WORLD " + chr$(147) + " " + chr$(154) + " " + chr$(191) + chr$(13) + _
        "HELLO WORLD " + chr$(147) + " " + chr$(154) + " " + chr$(191) + chr$(13) + _
        "HELLO WORLD " + chr$(147) + " " + chr$(154) + " " + chr$(191) + chr$(13) + _
        "THIS IS A TEST!"

    iY = 5
    iX = 5
    For iLoop = 1 To Len(MyString)
        iFgColorIndex = iFgColorIndex + 1: If iFgColorIndex > iMaxFgColorIndex Then iFgColorIndex = iMinFgColorIndex
        iBgColorIndex = iBgColorIndex + 1: If iBgColorIndex > iMaxBgColorIndex Then iBgColorIndex = iMinBgColorIndex
        iTileNum = Asc(Mid$(MyString, iLoop, 1))
        If iTileNum = 13 Then
            ' Linebreak = go to a new line
            iX = iMinX: iY = iY + 1: If iY > iMaxY Then iY = iMinY
        Else
            DrawVectorTilePutImage _
                imgScreen, imgPalette, arrColor(), _
                iTileNum, iX, iY, _
                iFgColorIndex, iBgColorIndex
            iX = iX + 1: If iX > iMaxX Then iX = iMinX: iY = iY + 1: If iY > iMaxY Then iY = iMinY
            'iX = iX + 1: iY = iY + 1
            If iX > iMaxX Then iX = iMinX
            If iY > iMaxY Then iY = iMinY
        End If
    Next iLoop

    ' Resume display
    _Display
    _AutoDisplay

    ' Promput user
    Color cWhite, cBlack: Locate 22, 1
    Print "Press any key to continue";
    Sleep

    Screen 0 ' RETURN TO TEXT SCREEN
    If imgScreen < -1 Or imgScreen > 0 Then _FreeImage imgScreen ' FREE MEMORY
End Sub ' DrawVectorTilePutImageTest

' /////////////////////////////////////////////////////////////////////////////
' Draw the shape with _PutImage commands using hardware images:

' Requires that this global shared variable be declared:
'     Dim Shared m_arrLineTiles(0 To 255, 0 To 32) As RectangleType
' containing
'     m_arrLineTiles({iTileNum}, {iShapeNum})
' where for each tile, dimension 2 index 0:
'     m_arrLineTiles({iTileNum}, 0).PixelCount
' holds the last used {iShapeNum} index.

' Receives:
' imgScreen& = image handle of the screen to draw to
' imgPalette& = image handle of the palette containing 8x8 squares each with the desired color
' arrColor() = array containing _UNSIGNED Long RGB color values
' iTileNum% = 0-255, number of the tile in m_arrLineTiles to draw
' iX, iY = x/y position to draw 8x8 tile to (multiplied by 8 to get screen position)
' fgColor, bgColor = index for foreground/background color in arrColor (which contains the actual RGB values)

Sub DrawVectorTilePutImage( _
    imgScreen&, imgPalette&, arrColor() as _UNSIGNED Long, _
    iTileNum As Integer, iX As Integer, iY As Integer, _
    fgColorIndex As Integer, bgColorIndex As Integer)

    Dim iLoop As Integer

    Dim sc% ' source column on tile sheet
    Dim sr% ' source row on tile sheet
    Dim sx1% ' source start x
    Dim sx2% ' source end x
    Dim sy1% ' source start y
    Dim sy2% ' source end y
    Dim xDest% ' destination x
    Dim yDest% ' destination y

    ' Copy from palette
    _Source imgPalette&

    ' Draw to screen
    _Dest imgScreen&

    ' GET THE ROW OF TILE # TileNum% ON THE SOURCE TILE SHEET
    sr% = 0 ' TileNum% \ rows%

    ' GET THE START Y COORDINATE ON THE SOURCE TILE SHEET
    sy1% = sr% * 8

    ' draw background if not transparent
    If bgColorIndex >= LBound(arrColor) Then
        If bgColorIndex <= UBound(arrColor) Then
            If arrColor(bgColorIndex) <> cEmpty Then
                ' GET THE COLUMN OF TILE # TileNum% ON THE SOURCE TILE SHEET
                sc% = bgColorIndex ' TileNum% Mod rows%

                ' GET THE START X COORDINATE ON THE SOURCE TILE SHEET
                sx1% = sc% * 8

                ' GET THE END X COORDINATE ON THE SOURCE TILE SHEET
                sx2% = sx1% + 7

                ' GET THE END y COORDINATE ON THE SOURCE TILE SHEET
                sy2% = sy1% + 7

                ' GET THE DESTINATION X COORDINATE ON THE SCREEN
                xDest% = iX * 8 ' dx% * 8

                ' GET THE DESTINATION Y COORDINATE ON THE SCREEN
                yDest% = iY * 8 ' (dy% * 8) '+ yOffset%

                ' Copy portion of source to the top-left corner of the destination page
                _PutImage (xDest%, yDest%), _
                    imgPalette&, imgScreen&, _
                    (sx1%, sy1%)-(sx2%, sy2%)
            End If
        End If
    End If

    If fgColorIndex >= LBound(arrColor) Then
        If fgColorIndex <= UBound(arrColor) Then
            For iLoop = 1 To m_arrLineTiles(iTileNum, 0).PixelCount
                ' GET THE COLUMN OF TILE # TileNum% ON THE SOURCE TILE SHEET
                sc% = fgColorIndex ' TileNum% Mod rows%

                ' GET THE START X COORDINATE ON THE SOURCE TILE SHEET
                sx1% = sc% * 8

                ' GET THE END X COORDINATE ON THE SOURCE TILE SHEET
                'sx2% = sx1% + 7
                sx2% = sx1% + (m_arrLineTiles(iTileNum, iLoop).x2 - m_arrLineTiles(iTileNum, iLoop).x1)

                ' GET THE END y COORDINATE ON THE SOURCE TILE SHEET
                'sy2% = sy1% + 7
                sy2% = sy1% + (m_arrLineTiles(iTileNum, iLoop).y2 - m_arrLineTiles(iTileNum, iLoop).y1)

                ' GET THE DESTINATION X COORDINATE ON THE SCREEN
                xDest% = (iX * 8) + m_arrLineTiles(iTileNum, iLoop).x1 ' dx% * 8

                ' GET THE DESTINATION Y COORDINATE ON THE SCREEN
                yDest% = (iY * 8) + m_arrLineTiles(iTileNum, iLoop).y1 ' (dy% * 8) '+ yOffset%

                ' Copy portion of source to the top-left corner of the destination page
                _PutImage (xDest%, yDest%), _
                    imgPalette&, imgScreen&, _
                    (sx1%, sy1%)-(sx2%, sy2%)

            Next iLoop
        End If
    End If
End Sub ' DrawVectorTilePutImage

' /////////////////////////////////////////////////////////////////////////////
' (Same as DrawVectorTilePutImage but uses hardware images.)

' Draw the shape with _PutImage commands using hardware images:

' Requires that this global shared variable be declared:
'     Dim Shared m_arrLineTiles(0 To 255, 0 To 32) As RectangleType
' containing
'     m_arrLineTiles({iTileNum}, {iShapeNum})
' where for each tile, dimension 2 index 0:
'     m_arrLineTiles({iTileNum}, 0).PixelCount
' holds the last used {iShapeNum} index.

' Receives:
' imgScreen& = image handle of hardware image for the screen to draw to
' imgPalette& = image handle of hardware image for palette containing 8x8 squares each with the desired color
' arrColor() = array containing _UNSIGNED Long RGB color values
' iTileNum% = 0-255, number of the tile in m_arrLineTiles to draw
' iX, iY = x/y position to draw 8x8 tile to (multiplied by 8 to get screen position)
' fgColor, bgColor = index for foreground/background color in arrColor (which contains the actual RGB values)

Sub DrawVectorTilePutImageHW( _
    imgPalette&, arrColor() as _UNSIGNED Long, _
    iTileNum As Integer, iX As Integer, iY As Integer, _
    fgColorIndex As Integer, bgColorIndex As Integer)

    Dim iLoop As Integer
    Dim sc% ' source column on tile sheet
    Dim sr% ' source row on tile sheet
    Dim sx1% ' source start x
    Dim sx2% ' source end x
    Dim sy1% ' source start y
    Dim sy2% ' source end y
    Dim xDest% ' destination x
    Dim yDest% ' destination y

    ' GET THE ROW OF TILE # TileNum% ON THE SOURCE TILE SHEET
    sr% = 0 ' TileNum% \ rows%

    ' GET THE START Y COORDINATE ON THE SOURCE TILE SHEET
    sy1% = sr% * 8

    ' draw background if not transparent
    If bgColorIndex >= LBound(arrColor) Then
        If bgColorIndex <= UBound(arrColor) Then
            If arrColor(bgColorIndex) <> cEmpty Then
                ' GET THE COLUMN OF TILE # TileNum% ON THE SOURCE TILE SHEET
                sc% = bgColorIndex ' TileNum% Mod rows%

                ' GET THE START X COORDINATE ON THE SOURCE TILE SHEET
                sx1% = sc% * 8

                ' GET THE END X COORDINATE ON THE SOURCE TILE SHEET
                sx2% = sx1% + 7

                ' GET THE END y COORDINATE ON THE SOURCE TILE SHEET
                sy2% = sy1% + 7

                ' GET THE DESTINATION X COORDINATE ON THE SCREEN
                xDest% = iX * 8

                ' GET THE DESTINATION Y COORDINATE ON THE SCREEN
                yDest% = iY * 8

                ' Copy portion of source to the top-left corner of the destination page
                _PutImage (xDest%, yDest%), _
                    imgPalette&, , _
                    (sx1%, sy1%)-(sx2%, sy2%)
            End If
        End If
    End If

    If fgColorIndex >= LBound(arrColor) Then
        If fgColorIndex <= UBound(arrColor) Then
            For iLoop = 1 To m_arrLineTiles(iTileNum, 0).PixelCount
                ' GET THE COLUMN/ROW OF TILE # TileNum% ON THE SOURCE TILE SHEET
                sc% = fgColorIndex ' TileNum% Mod rows%

                ' GET THE START X COORDINATE ON THE SOURCE TILE SHEET
                sx1% = sc% * 8

                ' GET THE END X COORDINATE ON THE SOURCE TILE SHEET
                sx2% = sx1% + (m_arrLineTiles(iTileNum, iLoop).x2 - m_arrLineTiles(iTileNum, iLoop).x1)

                ' GET THE END y COORDINATE ON THE SOURCE TILE SHEET
                sy2% = sy1% + (m_arrLineTiles(iTileNum, iLoop).y2 - m_arrLineTiles(iTileNum, iLoop).y1)

                ' GET THE DESTINATION X COORDINATE ON THE SCREEN
                xDest% = (iX * 8) + m_arrLineTiles(iTileNum, iLoop).x1

                ' GET THE DESTINATION Y COORDINATE ON THE SCREEN
                yDest% = (iY * 8) + m_arrLineTiles(iTileNum, iLoop).y1

                ' Copy portion of source to the top-left corner of the destination page
                _PutImage (xDest%, yDest%), _
                    imgPalette&, , _
                    (sx1%, sy1%)-(sx2%, sy2%)
            Next iLoop
        End If
    End If
End Sub ' DrawVectorTilePutImageHW

' /////////////////////////////////////////////////////////////////////////////
' Receives an array of _Unsigned Long RGB color values
' and returns a new image imgNew
' containing 8x8 squares with each color

' Usage:
' MakePaletteImage imgNew, arrColorRGB()

Sub MakePaletteImage (imgNew As Long, arrColorRGB() As _Unsigned Long)
    Dim tw% ' width/height of tile
    Dim iCount As Integer
    Dim iY As Integer
    Dim iX As Integer
    Dim iLoop1 As Integer

    tw% = 8 ' SIZE OF TILE

    If imgNew < -1 Or imgNew > 0 Then _FreeImage imgNew ' FREE MEMORY

    iY = tw%
    iX = ((UBound(arrColorRGB) - LBound(arrColorRGB)) + 1) * tw%
    If iX > 0 Then
        imgNew = _NewImage(iX, iY, 32)
        _Dest imgNew&

        iY = 0
        iCount = -1
        For iLoop1 = LBound(arrColorRGB) To UBound(arrColorRGB)
            iCount = iCount + 1
            iX = iCount * tw%
            Line (iX, iY)-(iX + 7, iY + 7), arrColorRGB(iCount), BF
        Next iLoop1
    End If
End Sub ' MakePaletteImage

' /////////////////////////////////////////////////////////////////////////////

Sub MakePaletteImageTest
    Dim arrColor(0 To 7) As _Unsigned Long
    Dim imgPalette As Long ' contains palette of colors
    Dim imgScreen As Long ' the main display

    arrColor(0) = cBlack
    arrColor(1) = cRed
    arrColor(2) = cYellow
    arrColor(3) = cLime
    arrColor(4) = cCyan
    arrColor(5) = cBlue
    arrColor(6) = cPurple
    arrColor(7) = cMagenta
    'arrColor(8) = cEmpty

    imgScreen = _NewImage(1024, 768, 32): _ScreenMove 0, 0
    Screen imgScreen
    Cls , cGray

    MakePaletteImage imgPalette, arrColor()

    ' Draw palette on screen:
    '_PutImage (xDest%, yDest%), imgSource&, imgDest&, (sx1%, sy1%)-(sx2%, sy2%)
    _PutImage (400, 300), imgPalette, imgScreen, (0, 0)-(_Width(imgPalette), _Height(imgPalette))

    ' Promput user
    _Dest imgScreen
    Color cWhite, cBlack
    'PrintString1 15, 1, "Press any key to continue"
    Locate 15, 1: Print "Press any key to continue";
    Sleep

    Screen 0 ' RETURN TO TEXT SCREEN
    If imgScreen < -1 Or imgScreen > 0 Then _FreeImage imgScreen ' FREE MEMORY

End Sub ' MakePaletteImage

' /////////////////////////////////////////////////////////////////////////////
' Draw the shape with Line commands:

' Requires that this global shared variable be declared:
'     Dim Shared m_arrLineTiles(0 To 255, 0 To 32) As RectangleType
' containing
'     m_arrLineTiles({iTileNum}, {iShapeNum})
' where for each tile, dimension 2 index 0:
'     m_arrLineTiles({iTileNum}, 0).PixelCount
' holds the last used {iShapeNum} index.

Sub DrawVectorTileLine (iTileNum As Integer, iX As Integer, iY As Integer, fgColor As _Unsigned Long, bgColor As _Unsigned Long)
    If bgColor <> cEmpty Then
        Line (iX, iY)-(iX + 7, iY + 7), bgColor, BF
    End If
    Dim iLoop As Integer
    For iLoop = 1 To m_arrLineTiles(iTileNum, 0).PixelCount
        Line (iX+m_arrLineTiles(iTileNum, iLoop).x1, _
            iY+m_arrLineTiles(iTileNum, iLoop).y1 _
            )-(iX+m_arrLineTiles(iTileNum, iLoop).x2, _
            iY+m_arrLineTiles(iTileNum, iLoop).y2), _
            fgColor, BF
    Next iLoop
End Sub ' DrawVectorTileLine

' /////////////////////////////////////////////////////////////////////////////
' Get line drawing coordinates for 8x8 tileset.

' Requires that this global shared variable be declared:
'     Dim Shared m_arrLineTiles(0 To 255, 0 To 32) As RectangleType
' containing
'     m_arrLineTiles({iTileNum}, {iShapeNum})
' where for each tile, dimension 2 index 0:
'     m_arrLineTiles({iTileNum}, 0).PixelCount
' holds the last used {iShapeNum} index.

' VECTOR TILE DRAWING EXPERIMENT

' Translates an 8x8 raster tileset into a set of (hopefully)
' optimized rectangle coordinates that can be quickly drawn to
' the screen with Line.

' GOAL: Optimize for each shape by determining how to draw it with the
' minimum number of line commands.
'
' For example this:
'     ' DRAW WITH HORIZONTAL LINES
'     Line (iX + 6, iY + 3)-(iX + 6, iY + 3), fgColor
'     Line (iX + 6, iY + 4)-(iX + 6, iY + 4), fgColor
' could be replaced with:
'     ' DRAW WITH VERTICAL LINES
'     Line (iX + 6, iY + 3)-(iX + 6, iY + 4), fgColor

' For each tile, we store a list of line coordinates (x1,y1,x2,y2)
' in a 2D array, and draw using a simple drawing routine that
' receives the list of coordinates, fgColor and bgColor,
' and draws all shapes (solid rectangles) with Line.
' If bgColor is not transparent and if we want a background color
' then we first draw an 8x8 bgColor rectangle first and then
' draw the shape on top of that.

' Rather than compute this on the fly, we could precompute it and
' for each given tile, store the list of those rectangle coordinates
' (x1,y1,x2,y2) for drawing it indexed by the tile's definition in
' hexidecimal where 16-bits (0-F) defines the bit pattern for each
' row in the tile, therefore a tile's definition can be stored by
' 8 characters (or less if we use base 64). Perhaps build a utility
' that will compute the optimal drawing pattern for every possible
' combination of an 8x8 grid, and index them all by the tile's 8-byte
' hexidecimal definition. It might take a while to run, but once it
' does, we will have a database of every possible tile's optimized
' drawing instructions that can be quickly looked up.
' Then we only pull out those definitions for the tiles that our
' given program uses, so the data would be relatively small
' (even smaller if we encode it with base-64).

' TODO: maybe optimize with linked list?

Sub GetVectorTiles
    Dim RoutineName As String: RoutineName = "GetVectorTiles"
    ReDim arrTileText(0 To 255) As String
    ReDim arrShapes1(-1) As RectangleType
    Dim iTileNum As Integer
    Dim iLoop1 As Integer
    Dim sLine As String
    Dim iLen As Integer

    '' DEBUG
    'Dim sStartTime As String : sStartTime = "TBD"
    'Dim sEndTime As String : sEndTime = "TBD"
    'sStartTime = CurrentDateTime$
    'DebugPrint CurrentDateTime$ + " started " + RoutineName

    ' Get raster tiles as a string array
    GetTileText arrTileText()

    ' Get minimum set of Line coordinates for each tile
    For iTileNum = 0 To 255
        FindOptimizedVector arrTileText(iTileNum), arrShapes1()

        ' If we have coordinates, add it to the database
        If UBound(arrShapes1) > -1 Then

            'DebugPrint "#   x1   y1   x2   y2   Pixels    IsActive"
            'for iLoop1 = lbound(arrShapes1) to ubound(arrShapes1)
            '    sLine = ""
            '    sLine = sLine + left$(cstr$(iLoop1) + String$(4, " "), 4)
            '    sLine = sLine + left$(cstr$(arrShapes1(iLoop1).x1) + String$(2, " "), 2) + "   "
            '    sLine = sLine + left$(cstr$(arrShapes1(iLoop1).y1) + String$(2, " "), 2) + "   "
            '    sLine = sLine + left$(cstr$(arrShapes1(iLoop1).x2) + String$(2, " "), 2) + "   "
            '    sLine = sLine + left$(cstr$(arrShapes1(iLoop1).y2) + String$(2, " "), 2) + "   "
            '    sLine = sLine + left$(cstr$(arrShapes1(iLoop1).PixelCount) + String$(7, " "), 7) + "   "
            '    sLine = sLine + TrueFalse$(arrShapes1(iLoop1).IsActive)
            '    DebugPrint sLine
            'next iLoop1

            ' SAVE SHAPES TO TILE
            iLen = 0
            For iLoop1 = LBound(arrShapes1) To UBound(arrShapes1)
                If arrShapes1(iLoop1).IsActive = TRUE Then
                    iLen = iLen + 1

                    ' NOTE: we do -1 because FindOptimizedVector does it 1-based,
                    '       don't ask me why, i was confused and don't want to
                    '       spend time right now to fix it,
                    '       but it saves math later to do 0-based
                    m_arrLineTiles(iTileNum, iLen).x1 = arrShapes1(iLoop1).x1 - 1
                    m_arrLineTiles(iTileNum, iLen).y1 = arrShapes1(iLoop1).y1 - 1
                    m_arrLineTiles(iTileNum, iLen).x2 = arrShapes1(iLoop1).x2 - 1
                    m_arrLineTiles(iTileNum, iLen).y2 = arrShapes1(iLoop1).y2 - 1

                    m_arrLineTiles(iTileNum, iLen).PixelCount = arrShapes1(iLoop1).PixelCount
                    m_arrLineTiles(iTileNum, iLen).IsActive = arrShapes1(iLoop1).IsActive
                End If
            Next iLoop1

            ' MARK TILE (ubound 2, index 0) AS HAVING SHAPES + SAVE COUNT
            m_arrLineTiles(iTileNum, 0).IsActive = TRUE
            m_arrLineTiles(iTileNum, 0).PixelCount = iLen ' (iTileNum, 0).PixelCount stores the # of shapes

            ' DISABLE ANY REMAINING ENTRIES
            For iLoop1 = (iLen + 1) To UBound(m_arrLineTiles, 2)
                m_arrLineTiles(iTileNum, iLoop1).IsActive = FALSE
            Next iLoop1

        Else
            ' This tile must have been blank
            'DebugPrint "*** NO SHAPES TO DRAW THIS TILE ***"

            ' MARK THIS TILE AS HAVING NO SHAPES
            m_arrLineTiles(iTileNum, 0).IsActive = FALSE
            m_arrLineTiles(iTileNum, 0).PixelCount = 0 ' (iTileNum, 0).PixelCount stores the # of shapes
        End If
    Next iTileNum

    '' DEBUG
    'sEndTime = CurrentDateTime$
    'DebugPrint RoutineName + " finished:"
    'DebugPrint "    started  at: " + sStartTime
    'DebugPrint "    finished at: " + sEndTime
End Sub ' GetVectorTiles

' /////////////////////////////////////////////////////////////////////////////
' 254 solid
' 253 empty
' 252 shaded
' 241 bricks
' 191 checker
' 194 - 197 arrows u/d/l/r
' 169 top left corner
' 154 diamond
' 155 +
' 151 empty circle
' 145 solid circle
' 147 heart

Sub GetVectorTilesTest
    Dim imgScreen As Long ' the main display
    Dim MyString As String
    Dim iLoop As Integer
    Dim iTileNum As Integer
    Dim arrColor(0 To 8) As _Unsigned Long
    Dim iMinFgColorIndex As Integer: iMinFgColorIndex = 0
    Dim iMaxFgColorIndex As Integer: iMaxFgColorIndex = 7
    Dim iMinBgColorIndex As Integer: iMinBgColorIndex = 0
    Dim iMaxBgColorIndex As Integer: iMaxBgColorIndex = 8
    Dim iFgColorIndex As Integer: iFgColorIndex = iMinFgColorIndex
    Dim iBgColorIndex As Integer: iBgColorIndex = iMinBgColorIndex
    Dim iX As Integer
    Dim iY As Integer
    Dim iMinX As Integer
    Dim iMaxX As Integer
    Dim iMinY As Integer
    Dim iMaxY As Integer

    ' Initialize colors
    arrColor(0) = cBlack
    arrColor(1) = cRed
    arrColor(2) = cYellow
    arrColor(3) = cLime
    arrColor(4) = cCyan
    arrColor(5) = cBlue
    arrColor(6) = cPurple
    arrColor(7) = cMagenta
    arrColor(8) = cEmpty

    ' Set up screen
    imgScreen = _NewImage(1024, 768, 32): _ScreenMove 0, 0
    Screen imgScreen
    Cls , cGray

    ' Set up tiles
    GetVectorTiles

    ' Test text
    MyString = "HELLO WORLD " + chr$(147) + " " + chr$(154) + " " + chr$(191) + chr$(13) + _
        "HELLO WORLD " + chr$(147) + " " + chr$(154) + " " + chr$(191) + chr$(13) + _
        "HELLO WORLD " + chr$(147) + " " + chr$(154) + " " + chr$(191) + chr$(13) + _
        "THIS IS A TEST!"

    ' Set up screen boundaries, initial colors, etc.
    iMinX = 0: iMaxX = _Width(0) \ 8
    iMinY = 0: iMaxY = _Height(0) \ 8
    iFgColorIndex = iMinFgColorIndex - 1
    iY = 5
    iX = 5
    For iLoop = 1 To Len(MyString)
        iFgColorIndex = iFgColorIndex + 1: If iFgColorIndex > iMaxFgColorIndex Then iFgColorIndex = iMinFgColorIndex
        iBgColorIndex = iBgColorIndex + 1: If iBgColorIndex > iMaxBgColorIndex Then iBgColorIndex = iMinBgColorIndex

        iTileNum = Asc(Mid$(MyString, iLoop, 1))
        If iTileNum = 13 Then
            ' Linebreak = go to a new line
            iX = iMinX: iY = iY + 1: If iY > iMaxY Then iY = iMinY
        Else
            'DrawVectorTileLine iTileNum, iX*8, iY*8, arrColor(iFgColorIndex), cEmpty
            DrawVectorTileLine iTileNum, iX * 8, iY * 8, arrColor(iFgColorIndex), arrColor(iBgColorIndex)
            iX = iX + 1: If iX > iMaxX Then iX = iMinX: iY = iY + 1: If iY > iMaxY Then iY = iMinY
        End If

    Next iLoop

    ' Promput user
    Color cWhite, cBlack: Locate 22, 1
    Print "Press any key to continue";
    Sleep

    Screen 0 ' RETURN TO TEXT SCREEN
    If imgScreen < -1 Or imgScreen > 0 Then _FreeImage imgScreen ' FREE MEMORY
End Sub ' GetVectorTilesTest

' /////////////////////////////////////////////////////////////////////////////
' Calculates and returns the coordinates for every possible rectangle shape
' from 1-8 pixels high, and 1-8 pixels wide.

Sub GetAllPossibleShapes (arrShapes1() As RectangleType)
    ReDim arrShapes1(-1) As RectangleType
    Dim iLoopRows As Integer
    Dim iLoopCols As Integer
    Dim iIndex As Integer
    Dim iLoopY As Integer
    Dim iLoopX As Integer

    For iLoopRows = 1 To 8
        For iLoopCols = 1 To 8
            ' Add next shape to array
            iIndex = UBound(arrShapes1) + 1
            ReDim _Preserve arrShapes1(0 To iIndex) As RectangleType

            ' Save coordinates
            arrShapes1(iIndex).x1 = 1
            arrShapes1(iIndex).y1 = 1
            arrShapes1(iIndex).x2 = iLoopCols
            arrShapes1(iIndex).y2 = iLoopRows
            arrShapes1(UBound(arrShapes1)).PixelCount = 0

            ' Count Pixels
            For iLoopY = 1 To 8
                For iLoopX = 1 To 8
                    if _
                        iLoopY >= arrShapes1(iIndex).y1 _
                        and _
                        iLoopY <= arrShapes1(iIndex).y2 _
                        and _
                        iLoopX >= arrShapes1(iIndex).x1 _
                        and _
                        iLoopX <= arrShapes1(iIndex).x2 _
                        then

                        'sLine = sLine + "#"
                        arrShapes1(UBound(arrShapes1)).PixelCount = arrShapes1(UBound(arrShapes1)).PixelCount + 1
                    Else
                        'sLine = sLine + "."
                    End If
                Next iLoopX
                'DebugPrint sLine
            Next iLoopY

        Next iLoopCols
    Next iLoopRows
End Sub ' GetAllPossibleShapes

' /////////////////////////////////////////////////////////////////////////////
' Tests GetAllPossibleShapes to retrieve the coordinates for every possible
' rectangle shape from 1-8 pixels high, and 1-8 pixels wide,
' and uses Line to draw them on the screen.

Sub GetAllPossibleShapesTest
    ReDim arrShapes1(-1) As RectangleType
    Dim arrColor(0 To 7) As _Unsigned Long
    Dim iLoopShape As Integer
    Dim iOffsetY As Integer
    Dim iOffsetX As Integer
    Dim iColorIndex As Integer
    Dim iMinColorIndex As Integer: iMinColorIndex = 1
    Dim iMaxColorIndex As Integer: iMaxColorIndex = 7
    Dim in$
    Dim iX As Integer
    Dim iY As Integer
    Dim iSizeW As Integer
    Dim iSizeH As Integer
    Dim fgColor As _Unsigned Long
    Dim iMinX As Integer
    Dim iMinY As Integer
    Dim iMaxX As Integer
    Dim iMaxY As Integer

    Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0
    iMinX = 0
    iMinY = 17
    iMaxX = (_Width(0) / 8) ' iMaxX = _Width(0) - 16
    iMaxY = _Height(0) - 16
    iOffsetY = iMinY
    iOffsetX = iMinX

    arrColor(0) = cBlack
    arrColor(1) = cRed
    arrColor(2) = cYellow
    arrColor(3) = cLime
    arrColor(4) = cCyan
    arrColor(5) = cBlue
    arrColor(6) = cPurple
    arrColor(7) = cMagenta

    GetAllPossibleShapes arrShapes1()

    iColorIndex = iMinColorIndex
    For iLoopShape = 0 To UBound(arrShapes1)
        DebugPrint _
            "(" + cstr$(arrShapes1(iLoopShape).x1) + ", " + cstr$(arrShapes1(iLoopShape).y1) + ")-" + _
            "(" + cstr$(arrShapes1(iLoopShape).x2) + ", " + cstr$(arrShapes1(iLoopShape).y2) + ") " + _
            cstr$(arrShapes1(iLoopShape).PixelCount) + " pixels"

        iX = arrShapes1(iLoopShape).x1 + iOffsetX
        iY = arrShapes1(iLoopShape).y1 + iOffsetY
        iSizeW = (arrShapes1(iLoopShape).x2 - arrShapes1(iLoopShape).x1) + 1
        iSizeH = (arrShapes1(iLoopShape).y2 - arrShapes1(iLoopShape).y1) + 1
        fgColor = arrColor(iColorIndex)
        DrawRectSolid iX, iY, iSizeW, iSizeH, fgColor

        iOffsetX = iOffsetX + 16: If iOffsetX > iMaxX Then iOffsetX = iMinX: iOffsetY = iOffsetY + 16: If iOffsetY > iMaxY Then iOffsetY = iMinY
        iColorIndex = iColorIndex + 1: If iColorIndex > iMaxColorIndex Then iColorIndex = iMinColorIndex
    Next iLoopShape

    Locate 1, 1
    Color cWhite, cBlack
    Input "PRESS <ENTER> TO CONTINUE"; in$
    Screen 0
End Sub ' GetAllPossibleShapes

' /////////////////////////////////////////////////////////////////////////////

Sub DumpNextShape (oShape As RectangleType, sVarName As String)
    Dim iLoopY As Integer
    Dim iLoopX As Integer
    Dim sLine As String

    If Len(sVarName) > 0 Then
        DebugPrint sVarName + ":"
    Else
        DebugPrint "RectangleType:"
    End If

    DebugPrint _
        "(" + cstr$(oShape.x1) + ", " + cstr$(oShape.y1) + ")-" + _
        "(" + cstr$(oShape.x2) + ", " + cstr$(oShape.y2) + ") " + _
        cstr$(oShape.PixelCount) + " pixels, " + _
        "IsActive=" + TrueFalse$(oShape.IsActive)

    For iLoopY = 1 To 8
        sLine = ""
        For iLoopX = 1 To 8
            if _
                iLoopY >= oShape.y1 _
                and _
                iLoopY <= oShape.y2 _
                and _
                iLoopX >= oShape.x1 _
                and _
                iLoopX <= oShape.x2 _
                then

                sLine = sLine + "#"
            Else
                sLine = sLine + "."
            End If
        Next iLoopX
        DebugPrint sLine
    Next iLoopY
    DebugPrint ""
End Sub ' DumpNextShape

' /////////////////////////////////////////////////////////////////////////////
' Dump all shapes in array.

' {i} in sVarName is replaced by array index

Sub DumpShapeList (arrShapes() As RectangleType, sVarName As String)
    Dim iLoop1 As Integer
    Dim sNextVarName As String

    For iLoop1 = 0 To UBound(arrShapes3)
        sNextVarName = Replace$(sVarName, "{i}", cstr$(iLoop1))
        DumpNextShape arrShapes(iLoop1), sVarName
    Next iLoop1
End Sub ' DumpShapeList

' /////////////////////////////////////////////////////////////////////////////
' Receives an array of shapes
'
Sub GetActiveShapes (arrShapes2() As RectangleType, arrShapes3() As RectangleType)
    Dim iLoopShape As Integer
    Dim iIndex As Integer
    ReDim arrShapes3(-1) As RectangleType
    For iLoopShape = 0 To UBound(arrShapes2)
        If arrShapes2(iLoopShape).IsActive = TRUE Then
            iIndex = UBound(arrShapes3) + 1
            ReDim _Preserve arrShapes3(0 To iIndex) As RectangleType
            arrShapes3(iIndex).y1 = arrShapes2(iLoopShape).y1
            arrShapes3(iIndex).x1 = arrShapes2(iLoopShape).x1
            arrShapes3(iIndex).y2 = arrShapes2(iLoopShape).y2
            arrShapes3(iIndex).x2 = arrShapes2(iLoopShape).x2
            arrShapes3(iIndex).PixelCount = arrShapes2(iLoopShape).PixelCount
            arrShapes3(iIndex).IsActive = arrShapes2(iLoopShape).IsActive
        End If
    Next iLoopShape
End Sub ' GetActiveShapes

' /////////////////////////////////////////////////////////////////////////////

Function DelimIntegerListsAreEqual% (sList1 As String, sList2 As String, sDelim As String)
    Dim bResult As Integer: bResult = FALSE
    Dim arrList1(-1) As Integer
    Dim arrList2(-1) As Integer
    Dim iLoop1 As Integer
    Dim iLoop2 As Integer
    Dim bFound As Integer

    ' Convert delimited lists into integer arrays
    GetIntegerArrayFromDelimList sList1, sDelim, 0, arrList1()
    GetIntegerArrayFromDelimList sList2, sDelim, 0, arrList2()

    ' Are lists same size?
    If UBound(arrList1) = UBound(arrList2) Then
        bResult = TRUE
    End If

    ' Check list #2 against list #1
    If bResult = TRUE Then
        ' Are all items in list #1 in list #2?
        For iLoop1 = LBound(arrList1) To UBound(arrList1)
            bFound = FALSE
            For iLoop2 = LBound(arrList2) To UBound(arrList2)
                If arrList2(iLoop2) = arrList1(iLoop1) Then
                    bFound = TRUE
                    Exit For
                End If
            Next iLoop2
            If bFound = FALSE Then
                ' not found, lists not equal
                bResult = FALSE
                Exit For
            End If
        Next iLoop1
    End If

    ' Check list #1 against list #2
    If bResult = TRUE Then
        For iLoop1 = LBound(arrList2) To UBound(arrList2)
            bFound = FALSE
            For iLoop2 = LBound(arrList1) To UBound(arrList1)
                If arrList1(iLoop2) = arrList2(iLoop1) Then
                    bFound = TRUE
                    Exit For
                End If
            Next iLoop2
            If bFound = FALSE Then
                ' not found, lists not equal
                bResult = FALSE
                Exit For
            End If
        Next iLoop1
    End If

    ' Return results
    DelimIntegerListsAreEqual% = bResult
End Function ' DelimIntegerListsAreEqual%

' /////////////////////////////////////////////////////////////////////////////

' DumpTileFromShapes arrShapes1(), bIncludeInactive, bShowRowsAndColumns

Sub DumpTileFromShapes (arrShapes1() As RectangleType, bIncludeInactive As Integer, bShowRowsAndColumns As Integer)
    ReDim arrTile1(1 To 8, 1 To 8) As String
    Dim iDestY As Integer
    Dim iDestX As Integer
    Dim iLoop1 As Integer
    Dim sLine As String

    ' Initialize next tile
    For iDestY = 1 To 8: For iDestX = 1 To 8: arrTile1(iDestY, iDestX) = ".": Next iDestX: Next iDestY

    ' Draw all (active) shapes onto tile
    For iLoop1 = LBound(arrShapes1) To UBound(arrShapes1)
        If arrShapes1(iLoop1).IsActive = TRUE Or bIncludeInactive = TRUE Then
            For iDestY = 1 To 8
                For iDestX = 1 To 8
                    If iDestY >= arrShapes1(iLoop1).y1 Then
                        If iDestY <= arrShapes1(iLoop1).y2 Then
                            If iDestX >= arrShapes1(iLoop1).x1 Then
                                If iDestX <= arrShapes1(iLoop1).x2 Then
                                    arrTile1(iDestY, iDestX) = "#"
                                End If
                            End If
                        End If
                    End If
                Next iDestX
            Next iDestY
        End If
    Next iLoop1

    ' Output the shape
    If bShowRowsAndColumns = TRUE Then DebugPrint " 12345678"
    For iDestY = 1 To 8
        sLine = ""
        If bShowRowsAndColumns = TRUE Then sLine = sLine + cstr$(iDestY)
        For iDestX = 1 To 8
            sLine = sLine + arrTile1(iDestY, iDestX)
        Next iDestX
        If bShowRowsAndColumns = TRUE Then sLine = sLine + cstr$(iDestY)
        DebugPrint sLine
    Next iDestY
    If bShowRowsAndColumns = TRUE Then DebugPrint " 12345678"

End Sub ' DumpTileFromShapes

' /////////////////////////////////////////////////////////////////////////////

' DumpTile arrTile1(), bShowRowsAndColumns

Sub DumpTile (arrTile1( 1 To 8 , 1 To 8) As String, bShowRowsAndColumns As Integer)
    Dim iDestY As Integer
    Dim iDestX As Integer
    Dim sLine As String

    ' Output the tile
    If bShowRowsAndColumns = TRUE Then DebugPrint " 12345678"
    For iDestY = 1 To 8
        sLine = ""
        If bShowRowsAndColumns = TRUE Then sLine = sLine + cstr$(iDestY)
        For iDestX = 1 To 8
            sLine = sLine + arrTile1(iDestY, iDestX)
        Next iDestX
        If bShowRowsAndColumns = TRUE Then sLine = sLine + cstr$(iDestY)
        DebugPrint sLine
    Next iDestY
    If bShowRowsAndColumns = TRUE Then DebugPrint " 12345678"
End Sub ' DumpTile

' /////////////////////////////////////////////////////////////////////////////
' Receives an 8x8 raster tile definition and returns a list of coordinates
' for the minimum number of rectangles to draw that tile.

' This version uses a brute force method, ie draw every size rectangle
' from 1x1 up to 8x8 (which can themselves be precalculated) in every
' available location in the 8x8 grid (where no part of any rectangle falls
' off the grid), then tries every combination of those rectangles to find
' the combination where the the minimum number of rectangles cover all
' points (or if 2 combinations have the same # of rectangles, the one that
' covers the lesser total points).

' (You can try searching for "rectangular decomposition of binary images"
' and similar to find a better algorithm.)

' Receives:
' TileString (String) = contains 8x8 raster tile definition as a string, where
'                       empty space represended by ".",
'                       pixel represented by any non-whitespace character,
'                       each row separated by chr$(13).
' Returns (byref):
' arrOptimizedShapes (array of RectangleType) = array of rectangle coordinates
'                       defining the shapes that will draw the tile.
'
' Return value = empty string if successful, error message if not.

Sub FindOptimizedVector (TileString As String, arrShapes1() As RectangleType)
    Dim RoutineName As String: RoutineName = "FindOptimizedVector"
    Dim bContinue As Integer: bContinue = TRUE
    ReDim arrTile1(1 To 8, 1 To 8) As String
    ReDim arrTile2(1 To 8, 1 To 8) As String
    ReDim arrShapes2(-1) As RectangleType
    ReDim arrCompare(-1) As DrawCompareType
    Dim oShapeSet As DrawCompareType
    Dim iLoopY As Integer
    Dim iLoopX As Integer
    Dim iDestY As Integer
    Dim iDestX As Integer
    Dim iSizeY As Integer
    Dim iSizeX As Integer
    Dim iEndY As Integer
    Dim iEndX As Integer
    Dim iTestY As Integer
    Dim iTestX As Integer
    Dim bShapeFits As Integer
    Dim iLoop1 As Integer
    Dim iLoop2 As Integer
    Dim iIndex As Integer
    Dim sItemList As String
    Dim iShapeCount As Integer
    Dim iPixelCount As Integer
    Dim bFinished As Integer
    Dim sCompare As String
    ReDim arrTestIndex(-1) As Integer
    Dim iShapeIndex As Integer
    Dim iRound As Integer
    Dim sLine As String

    '' ****************************************************************************************************************************************************************
    '' DEBUG:
    'Dim sStartTime As String : sStartTime = CurrentDateTime$
    'Dim sEndTime As String : sEndTime = ""
    'DebugPrint sStartTime + " started " + RoutineName
    '' ****************************************************************************************************************************************************************

    ' =============================================================================
    ' INITIALIZE
    If bContinue = TRUE Then
        ' -----------------------------------------------------------------------------
        ' Init results
        ReDim arrShapes1(-1) As RectangleType

        ' -----------------------------------------------------------------------------
        ' Turn tile into 2D array
        StringTo2dArray arrTile1(), TileString

        ' -----------------------------------------------------------------------------
        ' Count pixels
        iPixelCount = 0
        For iLoopY = LBound(arrTile1, 1) To UBound(arrTile1, 1)
            For iLoopX = LBound(arrTile1, 2) To UBound(arrTile1, 2)
                If arrTile1(iLoopY, iLoopX) <> "." Then
                    iPixelCount = iPixelCount + 1
                End If
            Next iLoopX
        Next iLoopY

        ' If shape is blank no need to continue looking
        ' we can just return an empty array
        If iPixelCount = 0 Then
            bContinue = FALSE
        End If
    End If

    ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    ' BEGIN LOOK FOR MINIMUM COMBINATION OF SHAPES TO DRAW TILE
    If bContinue = TRUE Then
        ' =============================================================================
        ' Get a set of every size shape (rectangle) from 1x1 up to 8x8
        GetAllPossibleShapes arrShapes1()
        'DebugPrint "ALL POSSIBLE SHAPES:"
        'DumpShapeList arrShapes1(), "arrShapes1{i}"

        ' =============================================================================
        ' Try each shape in every location on the tile, to see which fit
        For iLoop1 = 0 To UBound(arrShapes1)
            ' Try plotting next shape in every position
            For iDestY = 1 To 8
                For iDestX = 1 To 8
                    ' Track whether shape is fully on the tile at this position
                    bShapeFits = FALSE

                    ' Does shape fit at this Y position?
                    iSizeY = arrShapes1(iLoop1).y2 - arrShapes1(iLoop1).y1
                    iEndY = iDestY + iSizeY
                    If iEndY < 9 Then
                        ' Does shape fit at this X position?
                        iSizeX = arrShapes1(iLoop1).x2 - arrShapes1(iLoop1).x1
                        iEndX = iDestX + iSizeX
                        If iEndX < 9 Then
                            ' The shape is fully on the tile here
                            bShapeFits = TRUE

                            ' Now see if any of shape's pixels fall outside of tile's pixels?
                            For iTestY = iDestY To iEndY
                                For iTestX = iDestX To iEndX
                                    If arrTile1(iTestY, iTestX) = "." Then
                                        ' No pixel here, shape fails
                                        bShapeFits = FALSE
                                        Exit For
                                    End If
                                Next iTestX
                                If bShapeFits = FALSE Then Exit For
                            Next iTestY
                        End If
                    End If

                    ' If shape fits, add it to the list of shapes/positions that work for the tile
                    If bShapeFits = TRUE Then
                        iIndex = UBound(arrShapes2) + 1
                        ReDim _Preserve arrShapes2(0 To iIndex) As RectangleType
                        arrShapes2(iIndex).y1 = iDestY
                        arrShapes2(iIndex).x1 = iDestX
                        arrShapes2(iIndex).y2 = iEndY
                        arrShapes2(iIndex).x2 = iEndX
                        arrShapes2(iIndex).PixelCount = arrShapes1(iLoop1).PixelCount
                        arrShapes2(iIndex).IsActive = TRUE
                    End If
                Next iDestX
            Next iDestY
        Next iLoop1

        ' Eliminate non-active shapes
        GetActiveShapes arrShapes2(), arrShapes1()

        'DebugPrint "ALL SHAPES/LOCATIONS THAT MATCHED + FIT:"
        'DumpShapeList arrShapes2(), "arrShapes2{i}"

        ' =============================================================================
        ' Remove redundant shapes (any where another shape covers more points)

        For iLoop1 = 0 To UBound(arrShapes1)
            ' make sure shape #1 was not eliminated
            If arrShapes1(iLoop1).IsActive = TRUE Then
                ' compare shape #1 against all other shapes
                For iLoop2 = 0 To UBound(arrShapes1)
                    ' don't compare against itself
                    If iLoop2 <> iLoop1 Then
                        ' make sure shape #2 was not eliminated
                        If arrShapes1(iLoop2).IsActive = TRUE Then
                            ' can shape #2 do what shape #1 can do? (covers all points shape #1 does)
                            if _
                                arrShapes1(iLoop1).y1 >= arrShapes1(iLoop2).y1 _
                                and _
                                arrShapes1(iLoop1).y2 <= arrShapes1(iLoop2).y2 _
                                and _
                                arrShapes1(iLoop1).x1 >= arrShapes1(iLoop2).x1 _
                                and _
                                arrShapes1(iLoop1).x2 <= arrShapes1(iLoop2).x2 _
                                then

                                ' does shape #2 do it better? (cover more points than shape #1)
                                If arrShapes1(iLoop2).PixelCount >= arrShapes1(iLoop1).PixelCount Then
                                    ' Remove shape #1
                                    arrShapes1(iLoop1).IsActive = FALSE
                                End If
                            End If
                        End If
                    End If
                Next iLoop2
            End If
        Next iLoop1

        ' Eliminate non-active shapes
        GetActiveShapes arrShapes1(), arrShapes2()

        'DebugPrint "SHAPES THAT MATCHED + FIT, NON-REDUNDANT LEVEL 1:"
        'DumpShapeList arrShapes2(), "arrShapes2{i}"

    End If

    ' =============================================================================
    ' Can we do without any?
    ' Compare all combinations subtractively:

    ' 1. Count enabled shapes + total pixels for full list of shapes "set A".
    ' 2. Save "set A" to the "contender list",
    '    with the shape count and total pixel count.
    ' 3. For each shape "x":
    '    a) see if full tile can still be drawn without "x"
    '       (where the set of shapes minus "x" is "set y").
    '    b) If full tile can be drawn, save "set y" to the "contender list"
    '       with the shape count and total pixel count.
    ' 4. When done, identify the winner "set z" that can draw the full tile
    '    using the minimum shape coverage.
    '    a) The set with the smallest tile count wins.
    '    b) In the event of a tie, the set with the least total pixel count wins.
    '    c) In the event of another tie, just use the first finalist.
    ' 5. Disable all shapes NOT in the winning "set z".
    ' 6. Save list of enabled shapes to "last winner".
    ' 7. Repeat steps 1-5 until, comparing the list of enabled shapes to
    '    the list "last winner". When the list stops changing (lists are equal),
    '    we have gone as far as we can go.
    ' 8. Return shapes in "last winner" as final result.

    If bContinue = TRUE Then

        ' -----------------------------------------------------------------------------
        ' Start with all
        ' 1. Count enabled shapes + total pixels for full list of shapes "set A".
        ' 2. Save "set A" to the "contender list",
        '    with the shape count and total pixel count.
        sItemList = ""
        iShapeCount = 0
        iPixelCount = 0
        For iLoop1 = LBound(arrShapes2) To UBound(arrShapes2)
            sItemList = sItemList + IIFSTR$(Len(sItemList) = 0, "", ",") + cstr$(iLoop1)
            iShapeCount = iShapeCount + 1
            iPixelCount = iPixelCount + arrShapes2(iLoop1).PixelCount
        Next iLoop1

        oShapeSet.IndexList = sItemList
        oShapeSet.ShapeCount = iShapeCount
        oShapeSet.PixelCount = iPixelCount
        oShapeSet.IsActive = TRUE

        ' -----------------------------------------------------------------------------
        ' Now see which combinations can draw the tile

        iRound = 0
        bFinished = FALSE
        Do
            ' At the top of the loop, oShapeSet contains the latest set of shapes
            iRound = iRound + 1

            ' Get the list of shapes (indexes pointing to each shape in arrShapes2)
            ' All this packing and unpacking probably wastes cycles
            ' It might not be necessary if we had arrays inside of types!
            GetIntegerArrayFromDelimList oShapeSet.IndexList, ",", 0, arrTestIndex()

            ' Clear the list of contenders
            ReDim arrCompare(-1) As DrawCompareType

            '' ****************************************************************************************************************************************************************
            'DebugPrint "################################################################################################################################################################"
            'DebugPrint "Round " + cstr$(iRound) + " shapes to dedupe:"
            'for iLoop2 = lbound(arrTestIndex) to ubound(arrTestIndex)
            '    iIndex = arrTestIndex(iLoop2)
            '    DumpNextShape arrShapes2(iIndex), "Shape " + cstr$(iIndex) + " round " + cstr$(iRound) + ""
            '    DebugPrint ""
            'Next iLoop2
            'DebugPrint "################################################################################################################################################################"
            '' ****************************************************************************************************************************************************************

            ' 3. For each shape "x":
            '    a) see if full tile can still be drawn without "x"
            '       (where the set of shapes minus "x" is "set y").
            '    b) If full tile can be drawn, save "set y" to the "contender list"
            '       with the shape count and total pixel count.
            For iLoop1 = LBound(arrTestIndex) To UBound(arrTestIndex)

                ''DEBUG:
                'DebugPrint "????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????"
                'DebugPrint "Can we eliminate " + cstr$(iLoop1) ' this shape?"
                'DumpNextShape arrShapes2(iLoop1), "arrShapes2(" + cstr$(iLoop1) + ")"
                'DebugPrint "????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????"
                'DebugPrint ""

                ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                ' Clear test tile
                ReDim arrTile2(1 To 8, 1 To 8) As String
                For iDestY = 1 To 8
                    For iDestX = 1 To 8
                        arrTile2(iDestY, iDestX) = "."
                    Next iDestX
                Next iDestY

                ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                ' Try drawing next combination of shapes in the test tile
                sItemList = ""
                iShapeCount = 0
                iPixelCount = 0
                For iLoop2 = LBound(arrTestIndex) To UBound(arrTestIndex)

                    ' Make sure it's not shape "x"
                    If iLoop2 <> iLoop1 Then
                        iIndex = arrTestIndex(iLoop2)

                        sItemList = sItemList + IIFSTR$(Len(sItemList) = 0, "", ",") + cstr$(iIndex)
                        iShapeCount = iShapeCount + 1
                        iPixelCount = iPixelCount + arrShapes2(iIndex).PixelCount

                        For iDestY = 1 To 8
                            For iDestX = 1 To 8
                                If iDestY >= arrShapes2(iIndex).y1 Then
                                    If iDestY <= arrShapes2(iIndex).y2 Then
                                        If iDestX >= arrShapes2(iIndex).x1 Then
                                            If iDestX <= arrShapes2(iIndex).x2 Then
                                                arrTile2(iDestY, iDestX) = "#"
                                            End If
                                        End If
                                    End If
                                End If
                            Next iDestX
                        Next iDestY
                    End If
                Next iLoop2

                ''DebugPrint "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
                ''DebugPrint "Attempted drawing tile without " + cstr$(iLoop1) ' item #" + cstr$(iLoop1)
                ''DumpTile arrTile2(), TRUE
                'DebugPrint "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
                'DebugPrint ""
                'DebugPrint "RESULT$:"
                iShapeIndex = arrTestIndex(iLoop1)

                ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                ' Does the test tile match the real tile?
                sCompare = TilesAreEqual$(arrTile1(), arrTile2())
                If Len(sCompare) = 0 Then
                    ' Add to the list of contenders
                    iIndex = UBound(arrCompare) + 1
                    ReDim _Preserve arrCompare(0 To iIndex) As DrawCompareType
                    arrCompare(iIndex).IndexList = sItemList
                    arrCompare(iIndex).ShapeCount = iShapeCount
                    arrCompare(iIndex).PixelCount = iPixelCount
                    arrCompare(iIndex).IsActive = TRUE

                    'DebugPrint "*******************************************************************************"
                    'DebugPrint "YES: Tile can be drawn without shape " + cstr$(iShapeIndex) + " round " + cstr$(iRound)
                    'DebugPrint "arrCompare(" + cstr$(iIndex) + ").IndexList  = " + sItemList
                    'DebugPrint "arrCompare(" + cstr$(iIndex) + ").ShapeCount = " + cstr$(iShapeCount)
                    'DebugPrint "arrCompare(" + cstr$(iIndex) + ").PixelCount = " + cstr$(PixelCount)
                    'DebugPrint "*******************************************************************************"

                    'else
                    'DebugPrint "*******************************************************************************"
                    'DebugPrint "NOPE: Tile cannot be drawn without shape " + cstr$(iShapeIndex) + " round " + cstr$(iRound)
                    'DebugPrint sCompare
                    'DebugPrint "Attempted with:"
                    'DebugPrint ".IndexList  = " + sItemList
                    'DebugPrint ".ShapeCount = " + cstr$(iShapeCount)
                    'DebugPrint ".PixelCount = " + cstr$(PixelCount)
                    'DebugPrint "*******************************************************************************"
                End If

            Next iLoop1

            ' =============================================================================
            ' Identify the best combination that uses the least # of shapes + pixels

            ' DEDUPE IF THERE ARE >1 GROUPS
            If UBound(arrCompare) > LBound(arrCompare) Then

                '' ****************************************************************************************************************************************************************
                ''DEBUG:
                'DebugPrint "RESULTS BEFORE DEDUPE:"
                'sLine = ","
                'for iLoop2 = lbound(arrCompare) to ubound(arrCompare)
                '    if arrCompare(iLoop2).IsActive = TRUE then
                '        sLine = sLine + cstr$(iLoop2) + ","
                '        DebugPrint "-------------------------------------------------------------------------------"
                '        DebugPrint "arrCompare(" + cstr$(iLoop2) + ").IndexList  = " + arrCompare(iLoop2).IndexList
                '        DebugPrint "arrCompare(" + cstr$(iLoop2) + ").ShapeCount = " + cstr$(arrCompare(iLoop2).ShapeCount)
                '        DebugPrint "arrCompare(" + cstr$(iLoop2) + ").PixelCount = " + cstr$(arrCompare(iLoop2).PixelCount)
                '        DebugPrint "arrCompare(" + cstr$(iLoop2) + ").IsActive   = " + TrueFalse$(arrCompare(iLoop2).IsActive)
                '    end if
                'next iLoop2
                'DebugPrint ""
                '' ****************************************************************************************************************************************************************

                For iLoop1 = LBound(arrCompare) To UBound(arrCompare)
                    For iLoop2 = LBound(arrCompare) To UBound(arrCompare)
                        If iLoop1 <> iLoop2 Then
                            If arrCompare(iLoop1).IsActive = TRUE Then
                                If arrCompare(iLoop2).IsActive = TRUE Then
                                    If arrCompare(iLoop2).ShapeCount < arrCompare(iLoop1).ShapeCount Then
                                        arrCompare(iLoop1).IsActive = FALSE
                                    ElseIf arrCompare(iLoop2).ShapeCount > arrCompare(iLoop1).ShapeCount Then
                                        arrCompare(iLoop2).IsActive = FALSE
                                    Else
                                        If arrCompare(iLoop2).PixelCount < arrCompare(iLoop1).PixelCount Then
                                            arrCompare(iLoop1).IsActive = FALSE
                                        ElseIf arrCompare(iLoop2).PixelCount > arrCompare(iLoop1).PixelCount Then
                                            arrCompare(iLoop2).IsActive = FALSE
                                        Else
                                            arrCompare(iLoop2).IsActive = FALSE
                                        End If
                                    End If
                                End If
                            End If
                        End If
                    Next iLoop2
                Next iLoop1

                '' ****************************************************************************************************************************************************************
                ''DEBUG:
                'DebugPrint "RESULTS AFTER DEDUPE:"
                'for iLoop2 = lbound(arrCompare) to ubound(arrCompare)
                '    if InStr(1, sLine, "," + cstr$(iLoop2) + ",") > 0 then
                '        DebugPrint "-------------------------------------------------------------------------------"
                '        DebugPrint "arrCompare(" + cstr$(iLoop2) + ").IndexList  = " + arrCompare(iLoop2).IndexList
                '        DebugPrint "arrCompare(" + cstr$(iLoop2) + ").ShapeCount = " + cstr$(arrCompare(iLoop2).ShapeCount)
                '        DebugPrint "arrCompare(" + cstr$(iLoop2) + ").PixelCount = " + cstr$(arrCompare(iLoop2).PixelCount)
                '        DebugPrint "arrCompare(" + cstr$(iLoop2) + ").IsActive   = " + TrueFalse$(arrCompare(iLoop2).IsActive)
                '    end if
                'next iLoop2
                'DebugPrint ""
                '' ****************************************************************************************************************************************************************

            End If

            ' =============================================================================
            ' Identify the winner!
            ' Look at the list of indexes that make up the winning shape combination,
            ' and pick the first one.

            'DebugPrint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
            'DebugPrint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
            'DebugPrint "LOOK FOR THE WINNER, END ROUND " + cstr$(iRound)
            'DebugPrint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
            'DebugPrint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
            iIndex = -1

            'DebugPrint "arrCompare(" + cstr$(lbound(arrCompare)) + " To " + cstr$(ubound(arrCompare)) + ")"
            'DebugPrint ""

            'DebugPrint "Group   Status"
            'DebugPrint "-----   ----------"
            For iLoop1 = LBound(arrCompare) To UBound(arrCompare)
                If arrCompare(iLoop1).IsActive = TRUE Then
                    If iIndex = -1 Then
                        iIndex = iLoop1
                        Exit For
                        '            DebugPrint left$(cstr$(iLoop1) + "     ", 5) + "   " + "IsActive WINNER"
                        '        else
                        '            DebugPrint left$(cstr$(iLoop1) + "     ", 5) + "   " + "IsActive"
                    End If
                    '    else
                    '        DebugPrint left$(cstr$(iLoop1) + "     ", 5) + "   " + "(disabled)"
                End If
            Next iLoop1
            'DebugPrint ""

            ' =============================================================================
            ' Has it changed from the last round?
            'DebugPrint "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////"
            'DebugPrint "Has it changed from the last round?"
            'DebugPrint "iIndex=" + cstr$(iIndex)
            'DebugPrint "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////"
            'DebugPrint ""

            If iIndex > -1 Then
                'DebugPrint "Comparing arrCompare(" + cstr$(iIndex) + ").IndexList: " + arrCompare(iIndex).IndexList
                'DebugPrint "       to oShapeSet.IndexList: " + oShapeSet.IndexList
                'DebugPrint ""

                If DelimIntegerListsAreEqual%(arrCompare(iIndex).IndexList, oShapeSet.IndexList, ",") = TRUE Then
                    'DebugPrint "DelimIntegerListsAreEqual% returns TRUE"
                    'DebugPrint "FOUND WINNER (Group #" + cstr$(iIndex) + ") exiting..."
                    ' no change, we have reduced as much as possible, exit
                    bFinished = TRUE
                Else
                    'DebugPrint "DelimIntegerListsAreEqual% returns FALSE"
                    'DebugPrint "None yet, try next data"
                    'DebugPrint "Replacing old best set: "
                    'DebugPrint "    IndexList=" + oShapeSet.IndexList
                    'DebugPrint "    ShapeCount=" + cstr$(oShapeSet.ShapeCount)
                    'DebugPrint "    PixelCount=" + cstr$(oShapeSet.PixelCount)
                    'DebugPrint "    IsActive  =" + TrueFalse$(oShapeSet.IsActive)
                    'DebugPrint "with arrCompare(" + cstr$(iIndex) + ")"
                    'DebugPrint "    IndexList=" + arrCompare(iIndex).IndexList
                    'DebugPrint "    ShapeCount=" + cstr$(arrCompare(iIndex).ShapeCount)
                    'DebugPrint "    PixelCount=" + cstr$(arrCompare(iIndex).PixelCount)
                    'DebugPrint "    IsActive  =" + TrueFalse$(arrCompare(iIndex).IsActive)
                    'DebugPrint "and continuing to compare..."

                    ' Continue reducing with the latest set
                    oShapeSet.IndexList = arrCompare(iIndex).IndexList
                    oShapeSet.ShapeCount = arrCompare(iIndex).ShapeCount
                    oShapeSet.PixelCount = arrCompare(iIndex).PixelCount
                    oShapeSet.IsActive = TRUE
                End If
            Else
                'DebugPrint "(NONE FOUND THAT WORKED, USE THE EXISTING oShapeSet)"
                'DebugPrint "Replacing old best set: "
                'DebugPrint "    oShapeSet.IndexList=" + oShapeSet.IndexList
                'DebugPrint "    oShapeSet.ShapeCount=" + cstr$(oShapeSet.ShapeCount)
                'DebugPrint "    oShapeSet.PixelCount=" + cstr$(oShapeSet.PixelCount)
                'DebugPrint "    oShapeSet.IsActive  =" + TrueFalse$(oShapeSet.IsActive)
                ' none found that works, exit
                bFinished = TRUE
            End If

        Loop Until bFinished = TRUE

        ' =============================================================================
        ' Build results

        ' Get the list of shapes (indexes pointing to each shape in arrShapes1)
        GetIntegerArrayFromDelimList oShapeSet.IndexList, ",", 0, arrTestIndex()

        ' Initialize the final output
        ReDim arrShapes1(-1) As RectangleType

        ' Add the shapes to the final list
        For iLoop2 = LBound(arrTestIndex) To UBound(arrTestIndex)
            iShapeIndex = arrTestIndex(iLoop2)

            iIndex = UBound(arrShapes1) + 1
            ReDim _Preserve arrShapes1(0 To iIndex) As RectangleType

            'DebugPrint "Copying arrShapes2(" + cstr$(iShapeIndex) + ") to arrShapes1(" + cstr$(iIndex) + "):"

            If arrShapes2(iShapeIndex).IsActive = TRUE Then
                arrShapes1(iIndex).x1 = arrShapes2(iShapeIndex).x1
                arrShapes1(iIndex).y1 = arrShapes2(iShapeIndex).y1
                arrShapes1(iIndex).x2 = arrShapes2(iShapeIndex).x2
                arrShapes1(iIndex).y2 = arrShapes2(iShapeIndex).y2
                arrShapes1(iIndex).PixelCount = arrShapes2(iShapeIndex).PixelCount
                arrShapes1(iIndex).IsActive = arrShapes2(iShapeIndex).IsActive

                ''DEBUG:
                'DumpNextShape arrShapes1(iIndex), "arrShapes1(" + cstr$(iIndex) + ")"

            End If
        Next iLoop2

    End If
    ' END LOOK FOR MINIMUM COMBINATION OF SHAPES TO DRAW TILE
    ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

    '' ****************************************************************************************************************************************************************
    '' DEBUG:
    'DumpTileFromShapes arrShapes1(), FALSE, TRUE
    '
    'sEndTime = CurrentDateTime$
    'DebugPrint RoutineName + " finished:"
    'DebugPrint "    started  at: " + sStartTime
    'DebugPrint "    finished at: " + sEndTime
    '' ****************************************************************************************************************************************************************

End Sub ' FindOptimizedVector

' /////////////////////////////////////////////////////////////////////////////
' Test routine for the FindOptimizedVector routine.

Sub FindOptimizedVectorTest
    Dim RoutineName As String: RoutineName = "FindOptimizedVectorTest"
    Dim sError As String: sError = ""
    Dim in$
    ReDim arrTileText(0 To 255) As String
    Dim sTestList As String
    ReDim arrTestIndex(-1) As Integer
    Dim iLoop1 As Integer
    Dim iLoop2 As Integer
    Dim iIndex As Integer
    ReDim arrOptimizedShapes(-1) As RectangleType
    Dim sLine As String

    ' Start output
    DebugPrint "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
    DebugPrint "Testing tiles: " + sTestList
    DebugPrint ""

    ' Get raster tiles as a string array
    GetTileText arrTileText()

    ' List of tiles to test
    'sTestList = "254,253,247,32,238,241,225,233,213,214,212,203,194,193,192,169,154,151,145,147,129,115,114,84,65,46,44,35,252"
    'sTestList = "46,35"
    'sTestList = "84,253,192,151,147,114,65"
    'sTestList = "43,44,45,46"
    'sTestList = "60,62" ' 84 + 192 work, the rest don't
    'sTestList = "254,252"
    sTestList = "84,60,62,75,141,142,150,207,217,252,192" ' 84 + 192 work, the rest don't
    'sTestList = "60,62,75,141,142,150,207,217,252" ' 84 + 192 work, the rest don't
    'sTestList="75"
    'DebugPrint "GETTING LIST OF TILES..."
    GetIntegerArrayFromDelimList sTestList, ",", 0, arrTestIndex()

    ' Test tiles
    For iIndex = 0 To 255
        'for iLoop1 = lbound(arrTestIndex) to ubound(arrTestIndex)
        '    iIndex = arrTestIndex(iLoop1)
        DebugPrint "----------------------------------------------------------------------------------------------------------------------------------------------------------------"
        DebugPrint "Tile #" + cstr$(iIndex) + ":"
        DebugPrint arrTileText(iIndex)
        DebugPrint ""

        ' Process next tile and generate line drawing routines
        FindOptimizedVector arrTileText(iIndex), arrOptimizedShapes()

        If Len(sError) = 0 Then
            If UBound(arrOptimizedShapes) > -1 Then
                DebugPrint "#   x1   y1   x2   y2   Pixels    IsActive"
                For iLoop2 = LBound(arrOptimizedShapes) To UBound(arrOptimizedShapes)
                    sLine = ""
                    sLine = sLine + Left$(cstr$(iLoop2) + String$(4, " "), 4)
                    sLine = sLine + Left$(cstr$(arrOptimizedShapes(iLoop2).x1) + String$(2, " "), 2) + "   "
                    sLine = sLine + Left$(cstr$(arrOptimizedShapes(iLoop2).y1) + String$(2, " "), 2) + "   "
                    sLine = sLine + Left$(cstr$(arrOptimizedShapes(iLoop2).x2) + String$(2, " "), 2) + "   "
                    sLine = sLine + Left$(cstr$(arrOptimizedShapes(iLoop2).y2) + String$(2, " "), 2) + "   "
                    sLine = sLine + Left$(cstr$(arrOptimizedShapes(iLoop2).PixelCount) + String$(7, " "), 7) + "   "
                    sLine = sLine + TrueFalse$(arrOptimizedShapes(iLoop2).IsActive)
                    DebugPrint sLine
                Next iLoop2
            Else
                DebugPrint "*** NO SHAPES TO DRAW THIS TILE ***"
            End If
        Else
            DebugPrint "ERROR FOR TILE #" + cstr$(iIndex) + ": " + sError
        End If
        DebugPrint ""
        'next iLoop1
    Next iIndex

    ' DONE
    DebugPrint RoutineName + " finished."
    'Input "PRESS <ENTER> TO CONTINUE";in$
End Sub ' FindOptimizedVectorTest

' /////////////////////////////////////////////////////////////////////////////
' Receives two 2D string arrays and compares the dimensions
' and makes sure that the any blank pixel value "." matches
' (any other non-whitespace characters are considered a pixel
' as long as they are not "." they are considered a match).
' Returns empty string if they match, else returns a difference report.

Function TilesAreEqual$ (arrTile1() As String, arrTile2() As String)
    Dim sResult As String: sResult = ""
    Dim iLoopY As Integer
    Dim iLoopX As Integer
    Dim sTemp As String
    Dim bMatch As Integer
    Dim iY As Integer

    If LBound(arrTile1, 1) = LBound(arrTile2, 1) Then
        If UBound(arrTile1, 1) = UBound(arrTile2, 1) Then
            If LBound(arrTile1, 2) = LBound(arrTile2, 2) Then
                If UBound(arrTile1, 2) = UBound(arrTile2, 2) Then
                    bMatch = TRUE
                    sTemp = " 12345678 " + Chr$(13)
                    iY = 0
                    For iLoopY = LBound(arrTile1, 1) To UBound(arrTile1, 1)
                        iY = iY + 1
                        sTemp = sTemp + cstr$(iY)
                        For iLoopX = LBound(arrTile1, 2) To UBound(arrTile1, 2)
                            If arrTile1(iLoopY, iLoopX) = "." And arrTile2(iLoopY, iLoopX) <> "." Then
                                bMatch = FALSE
                                sTemp = sTemp + "?"
                            ElseIf arrTile1(iLoopY, iLoopX) <> "." And arrTile2(iLoopY, iLoopX) = "." Then
                                bMatch = FALSE
                                sTemp = sTemp + "?"
                            Else
                                sTemp = sTemp + arrTile1(iLoopY, iLoopX)
                            End If
                        Next iLoopX
                        sTemp = sTemp + cstr$(iY) + Chr$(13)
                    Next iLoopY
                    sTemp = sTemp + " 12345678 " + Chr$(13)
                    If bMatch = FALSE Then
                        sResult = sTemp
                    End If
                Else
                    sResult = "ubound(arrTile1, 2)=" + cstr$(ubound(arrTile1, 2)) + _
                        " <> " + _
                        "ubound(arrTile2, 2)=" + cstr$(ubound(arrTile2, 2))
                End If
            Else
                sResult = "lbound(arrTile1, 2)=" + cstr$(lbound(arrTile1, 2)) + _
                    " <> " + _
                    "lbound(arrTile2, 2)=" + cstr$(lbound(arrTile2, 2))

            End If
        Else
            sResult = "ubound(arrTile1, 1)=" + cstr$(ubound(arrTile1, 1)) + _
                " <> " + _
                "ubound(arrTile2, 1)=" + cstr$(ubound(arrTile2, 1))
        End If
    Else
        sResult = "lbound(arrTile1, 1)=" + cstr$(lbound(arrTile1, 1)) + _
            " <> " + _
            "lbound(arrTile2, 1)=" + cstr$(lbound(arrTile2, 1))
    End If
    TilesAreEqual$ = sResult
End Function ' TilesAreEqual$

' ################################################################################################################################################################
' END VECTOR-BASED TILE ROUTINES
' ################################################################################################################################################################

' ################################################################################################################################################################
' BEGIN BOX DRAWING ROUTINES
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////
' DRAW A 2-D BOX (OUTLINE)
' https://www.qb64.org/wiki/LINE

Sub DrawBoxOutline (iX As Integer, iY As Integer, iSize As Integer, fgColor As _Unsigned Long)
    Line (iX, iY)-(iX + (iSize - 1), iY + (iSize - 1)), fgColor, B ' Draw box outline
End Sub ' DrawBoxOutline

' /////////////////////////////////////////////////////////////////////////////
' DRAW A 2-D BOX (SOLID)
' https://www.qb64.org/wiki/LINE

' Renamed DrawBox/DrawBoxLine to DrawSolidBox

Sub DrawBoxSolid (iX As Integer, iY As Integer, iSize As Integer, fgColor As _Unsigned Long)
    Line (iX, iY)-(iX + (iSize - 1), iY + (iSize - 1)), fgColor, BF ' Draw a solid box
End Sub ' DrawBoxSolid

' /////////////////////////////////////////////////////////////////////////////
' DRAW A 2-D RECTANGLE (OUTLINE)

Sub DrawRectOutline (iX As Integer, iY As Integer, iSizeW As Integer, iSizeH As Integer, fgColor As _Unsigned Long)
    Line (iX, iY)-(iX + (iSizeW - 1), iY + (iSizeH - 1)), fgColor, B ' Draw rectangle outline
End Sub ' DrawRectOutline

' /////////////////////////////////////////////////////////////////////////////
' DRAW A 2-D RECTANGLE (SOLID)

Sub DrawRectSolid (iX As Integer, iY As Integer, iSizeW As Integer, iSizeH As Integer, fgColor As _Unsigned Long)
    Line (iX, iY)-(iX + (iSizeW - 1), iY + (iSizeH - 1)), fgColor, BF ' Draw a solid rectangle
End Sub ' DrawRectSolid

' /////////////////////////////////////////////////////////////////////////////
' DRAW A 2-D BOX (OUTLINE)
' https://www.qb64.org/wiki/LINE

' The style parameter 0-255 doesn't seem to have a solid line?
' For that, use DrawOutlineBox.

' LINE [STEP] [(column1, row1)]-[STEP] (column2, row2), color[, [{B|BF}], style%]
' B creates a box outline with each side parallel to the program screen sides. BF creates a filled box.
' The style% signed INTEGER value sets a dotted pattern to draw the line or rectangle outline.

Sub DrawStyledOutlineBox (iX%, iY%, iSize%, iColor~&, iStyle%)
    Line (iX%, iY%)-(iX% + (iSize% - 1), iY% + (iSize% - 1)), iColor~&, B , iStyle%
End Sub ' DrawStyledOutlineBox

' /////////////////////////////////////////////////////////////////////////////
' DRAW A 2-D BOX (OUTLINE) WITH A SOLID LINE

Sub DrawOutlineBox (iX%, iY%, iSize2%, iColor~&, iWeight2%)
    Dim iFromX%
    Dim iFromY%
    Dim iToX%
    Dim iToY%
    iSize% = iSize2% - 1
    iWeight% = iWeight2% - 1
    If iWeight% = 0 Then
        ' TOP LINE
        iFromX% = iX%
        iFromY% = iY%
        iToX% = iX% + iSize%
        iToY% = iY%
        Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF

        ' BOTTOM LINE
        iFromX% = iX%
        iFromY% = iY% + iSize%
        iToX% = iX% + iSize%
        iToY% = iY% + iSize%
        Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF

        ' LEFT LINE
        iFromX% = iX%
        iFromY% = iY%
        iToX% = iX%
        iToY% = iY% + iSize%
        Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF

        ' RIGHT LINE
        iFromX% = iX% + iSize%
        iFromY% = iY%
        iToX% = iX% + iSize%
        iToY% = iY% + iSize%
        Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF
    ElseIf iWeight% > 0 Then
        ' TOP LINE
        For iFromY% = iY% To (iY% + iWeight%)
            iFromX% = iX%
            'iFromY% = iY%
            iToX% = iX% + iSize%
            iToY% = iFromY%
            Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF
        Next iFromY%

        ' BOTTOM LINE
        For iFromY% = ((iY% + iSize%) - iWeight%) To (iY% + iSize%)
            iFromX% = iX%
            'iFromY% = iY% + iSize%
            iToX% = iX% + iSize%
            iToY% = iFromY%
            Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF
        Next iFromY%

        ' LEFT LINE
        For iFromX% = iX% To (iX% + iWeight%)
            'iFromX% = iX%
            iFromY% = iY%
            iToX% = iFromX%
            iToY% = iY% + iSize%
            Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF
        Next iFromX%

        ' RIGHT LINE
        For iFromX% = ((iX% + iSize%) - iWeight%) To (iX% + iSize%)
            'iFromX% = iX% + iSize%
            iFromY% = iY%
            iToX% = iFromX%
            iToY% = iY% + iSize%
            Line (iFromX%, iFromY%)-(iToX%, iToY%), iColor~&, BF
        Next iFromX%
    End If
End Sub ' DrawOutlineBox

' ################################################################################################################################################################
' END BOX DRAWING ROUTINES
' ################################################################################################################################################################

' ################################################################################################################################################################
' BEGIN DRAW TILES, COLOR SWAP with HARDWARE IMAGES
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////
' Same as DrawColorTile but using hardware images.

' Receives:
' imgTiles& = handle to 16x16 tile sheet of 16x16 pixel tiles colored black (256 tiles)
' TileNum% = ordinal number of tile on tile sheet to draw (0-255)
' TileColor~& = color to use for tile
' imgScreen& = handle to screen to draw tile on
' dx% = column # to draw tile at (where each column is 16 pixels wide)
' dy% = row # to draw tile at (where each row is 16 pixels high)
' xOffset% = offset tile this many columns over
' yOffset% = offset tile this many rows down

Sub DrawColorTileHW ( _
    imgHardwareScreen As Long, _
    imgTiles As Long, _
    iTileNum As Integer, _
    fgColor As _UNSIGNED Long, _
    bgColor As _UNSIGNED Long, _
    dx As Integer, _
    dy As Integer)

    Dim cols%
    Dim rows%
    Dim sc%
    Dim sr%
    Dim sx1%
    Dim sy1%
    Dim sx2%
    Dim sy2%
    Dim xDest%
    Dim yDest%
    Dim imgColorSprite As Long
    Dim imgUniversalSprite As Long
    Dim imgColorSpriteHW As Long
    Dim imgUniversalSpriteHW As Long

    ' # OF COLUMNS / ROWS ON SOURCE TILE SHEET
    cols% = 16
    rows% = 16

    ' GET THE COLUMN/ROW OF TILE # iTileNum ON THE SOURCE TILE SHEET
    sc% = iTileNum Mod rows%
    sr% = iTileNum \ rows%

    ' GET THE START X COORDINATE ON THE SOURCE TILE SHEET
    sx1% = sc% * 8

    ' GET THE START Y COORDINATE ON THE SOURCE TILE SHEET
    sy1% = sr% * 8

    ' GET THE END X COORDINATE ON THE SOURCE TILE SHEET
    sx2% = sx1% + 7

    ' GET THE END y COORDINATE ON THE SOURCE TILE SHEET
    sy2% = sy1% + 7

    ' GET THE DESTINATION X COORDINATE ON THE SCREEN
    xDest% = dx * 8

    ' GET THE DESTINATION Y COORDINATE ON THE SCREEN
    yDest% = dy * 8

    ' IS THERE A BACKGROUND COLOR?
    If bgColor <> cEmpty Then
        imgColorSprite = _NewImage(8, 8, 32)
        imgColorSpriteHW = _CopyImage(imgColorSprite, 33) ' Copy for hardware image
        '_Dest imgColorSprite
        _Dest imgColorSpriteHW
        Cls , bgColor

        ' COPY THE TEMPORARY TILE TO THE SCREEN imgHardwareScreen
        '_Source imgColorSprite
        _Source imgColorSpriteHW
        _Dest imgHardwareScreen

        'SOFTWARE IMAGE:
        '_PutImage (xDest%, yDest%), imgColorSprite, imgHardwareScreen, (0, 0)-(7, 7) ' portion of source to the top-left corner of the destination page

        'HARDWARE IMAGE:
        _PutImage (xDest%, yDest%), imgColorSpriteHW, , (0, 0)-(7, 7) ' portion of source to the top-left corner of the destination page
    End If

    ' CREATE A TEMPORARY TILE TO COLOR
    imgUniversalSprite = _NewImage(8, 8, 32)

    ' COPY THE TILE TO THE TEMPORARY ONE
    _Source imgHardwareTiles
    _Dest imgUniversalSprite
    'SOFTWARE IMAGE:
    '_PutImage (0, 0), imgTiles, imgUniversalSprite, (sx1%, sy1%)-(sx2%, sy2%)

    'HARDWARE IMAGE:
    _PutImage (0, 0), imgHardwareTiles, , (sx1%, sy1%)-(sx2%, sy2%)

    ' COLOR IN THE TEMPORARY TILE
    ' REPLACING BLACK (THE SOURCE COLOR) WITH THE TILE COLOR

    'SOFTWARE IMAGE:
    'IF imgColorSprite < -1 OR imgColorSprite > 0 THEN _FreeImage imgColorSprite
    'DoColorSwap imgUniversalSprite, cBlack, fgColor, imgColorSprite

    'HARDWARE IMAGE:
    DoColorSwapHW imgUniversalSpriteHW, cBlack, fgColor, imgColorSpriteHW

    ' COPY THE TEMPORARY TILE TO THE SCREEN imgHardwareScreen
    _Source imgColorSpriteHW
    _Dest imgHardwareScreen

    'SOFTWARE IMAGE:
    '_PutImage (xDest%, yDest%), imgColorSprite, , (0, 0)-(7, 7)

    'HARDWARE IMAGE:
    _PutImage (xDest%, yDest%), imgColorSprite, , (0, 0)-(7, 7)

    ' ADDED PER FellipeHeitor
    If imgHardwareTiles < -1 Or imgHardwareTiles > 0 Then _FreeImage imgHardwareTiles
    If imgColorSprite < -1 Or imgColorSprite > 0 Then _FreeImage imgColorSprite
    If imgColorSpriteHW < -1 Or imgColorSpriteHW > 0 Then _FreeImage imgColorSpriteHW
    If imgUniversalSprite < -1 Or imgUniversalSprite > 0 Then _FreeImage imgUniversalSprite
    If imgUniversalSpriteHW < -1 Or imgUniversalSpriteHW > 0 Then _FreeImage imgUniversalSpriteHW

End Sub ' DrawColorTileHW

' /////////////////////////////////////////////////////////////////////////////
' Same as DoColorSwap but using hardware images.

' Latest version with NOVARSEG's changes.
' Based on code from:
' Image color swap?
' https://www.qb64.org/forum/index.php?topic=2312.0

' Like Function swapcolor& except returns new image in a parameter
' in case being a function causes a memory leak?

Sub DoColorSwapHW ( _
    imgOriginalHW As Long, _
    oldColor As _UNSIGNED Long, _
    newColor As _UNSIGNED Long, _
    imgNewHW As Long)

    Dim m As _MEM
    Dim a As _Offset
    Dim c As _Unsigned Long
    Dim imgNew As Long

    a = 0
    imgNew = _CopyImage(imgOriginalHW, 32)
    m = _MemImage(imgNewHW)
    Do Until a = m.SIZE - 4
        a = a + 4
        c = _MemGet(m, m.OFFSET + a, _Unsigned Long)
        If c = oldColor Then
            _MemPut m, m.OFFSET + a, newColor
        End If
    Loop
    _MemFree m
End Sub ' DoColorSwapHW

' ################################################################################################################################################################
' END DRAW TILES, COLOR SWAP with HARDWARE IMAGES
' ################################################################################################################################################################

' ################################################################################################################################################################
' BEGIN DRAW TILES, COLOR SWAP with SOFTWARE IMAGES
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////
' Simple version which calculates coordinates on tile sheet and destination
' screen every time. For a faster version uses precalculated coordinates,
' see DrawColorTileFast. This version does not support offsetX, offsetY.

' Receives:
' imgScreen& = handle to screen to draw tile on
' imgTiles& = handle to 16x16 tile sheet of 8x8 pixel tiles colored black (256 tiles)
' TileNum% = ordinal number of tile on tile sheet to draw (0-255)
' TileColor~& = foreground color to use for tile
' BackColor~& = background color to use for tile
' dx% = column # to draw tile at (where each column is 8 pixels wide)
' dy% = row # to draw tile at (where each row is 8 pixels high)

' Usage:
' DrawColorTile imgScreen&, imgTiles&, TileNum%, TileColor~&, BackColor~&, dx%, dy%

Sub DrawColorTile (imgScreen&, imgTiles&, TileNum%, TileColor~&, BackColor~&, dx%, dy%)
    Dim cols%
    Dim rows%
    Dim sc%
    Dim sr%
    Dim sx1%
    Dim sy1%
    Dim sx2%
    Dim sy2%
    Dim xDest%
    Dim yDest%
    Dim ColorSprite&
    Dim UniversalSprite&

    ' # OF COLUMNS / ROWS ON SOURCE TILE SHEET
    cols% = 16
    rows% = 16

    ' GET THE COLUMN/ROW OF TILE # TileNum% ON THE SOURCE TILE SHEET
    sc% = TileNum% Mod rows%
    sr% = TileNum% \ rows%

    ' GET THE START X COORDINATE ON THE SOURCE TILE SHEET
    sx1% = sc% * 8

    ' GET THE START Y COORDINATE ON THE SOURCE TILE SHEET
    sy1% = sr% * 8

    ' GET THE END X COORDINATE ON THE SOURCE TILE SHEET
    sx2% = sx1% + 7

    ' GET THE END y COORDINATE ON THE SOURCE TILE SHEET
    sy2% = sy1% + 7

    ' GET THE DESTINATION X COORDINATE ON THE SCREEN
    xDest% = dx% * 8

    ' GET THE DESTINATION Y COORDINATE ON THE SCREEN
    yDest% = dy% * 8

    ' IS THERE A BACKGROUND COLOR?
    If BackColor~& <> cEmpty Then
        ColorSprite& = _NewImage(8, 8, 32)
        _Dest ColorSprite&
        Cls , BackColor~&

        ' COPY THE TEMPORARY TILE TO THE SCREEN imgScreen&
        _Source ColorSprite&
        _Dest imgScreen&
        _PutImage (xDest%, yDest%), ColorSprite&, imgScreen&, (0, 0)-(7, 7) ' portion of source to the top-left corner of the destination page
    End If

    ' CREATE A TEMPORARY TILE TO COLOR
    UniversalSprite& = _NewImage(8, 8, 32)

    ' COPY THE TILE TO THE TEMPORARY ONE
    _Source imgTiles&
    _Dest UniversalSprite&
    _PutImage (0, 0), imgTiles&, UniversalSprite&, (sx1%, sy1%)-(sx2%, sy2%)

    ' COLOR IN THE TEMPORARY TILE
    ' REPLACING BLACK (THE SOURCE COLOR) WITH THE TILE COLOR
    If ColorSprite& < -1 Or ColorSprite& > 0 Then _FreeImage ColorSprite&
    DoColorSwap UniversalSprite&, cBlack, TileColor~&, ColorSprite&

    ' COPY THE TEMPORARY TILE TO THE SCREEN imgScreen&
    _Source ColorSprite&
    _Dest imgScreen&
    _PutImage (xDest%, yDest%), ColorSprite&, imgScreen&, (0, 0)-(7, 7) ' portion of source to the top-left corner of the destination page

    ' ADDED PER FellipeHeitor
    If ColorSprite& < -1 Or ColorSprite& > 0 Then _FreeImage ColorSprite&
    If UniversalSprite& < -1 Or UniversalSprite& > 0 Then _FreeImage UniversalSprite&
End Sub ' DrawColorTile

' /////////////////////////////////////////////////////////////////////////////
' Latest version with NOVARSEG's changes.

' Based on code from:

' Image color swap?
' https://www.qb64.org/forum/index.php?topic=2312.0

' Like Function swapcolor& except returns new image in a parameter
' in case being a function causes a memory leak?

Sub DoColorSwap (imgOriginal&, oldcolor~&, newcolor~&, imgNew&)
    Dim m As _MEM
    Dim a As _Offset
    Dim c As _Unsigned Long
    a = 0
    imgNew& = _CopyImage(imgOriginal&, 32)
    m = _MemImage(imgNew&)
    Do Until a = m.SIZE - 4
        a = a + 4
        c = _MemGet(m, m.OFFSET + a, _Unsigned Long)
        If c = oldcolor~& Then
            _MemPut m, m.OFFSET + a, newcolor~&
        End If
    Loop
    _MemFree m
End Sub ' DoColorSwap&

' ################################################################################################################################################################
' END DRAW TILES, COLOR SWAP with SOFTWARE IMAGES
' ################################################################################################################################################################

' ################################################################################################################################################################
' BEGIN DRAW TILES, _PUTIMAGE with SOFTWARE IMAGES
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////
' Draws an 8x8 tile at the specified column/row dx%, dy%

' Original version which calculates coordinates on tile sheet and destination
' screen every time. For a faster version uses precalculated coordinates,
' see DrawTileFast.

' tw% = tile width/height (in pixels)

' DIV and MOD:
' c% = a% \ b% ' DIV (INTEGER DIVISION)
' d% = a% MOD b% ' MODULO (DIVISION REMAINDER)

'_PUTIMAGE (0, 0), i ' places image at upper left corner of window w/o stretching it
'_PUTIMAGE (dx1, dy1), sourceHandle&, destHandle&, (sx1, sy1)-(sx2, sy2) ' portion of source to the top-left corner of the destination page
'_PUTIMAGE (64,  128), imgTiles&,      imgScreen&,   (128, 128)-(164, 164) ' portion of source to the top-left corner of the destination page
'_PutImage (64, 128), imgTiles&, imgScreen&, (128, 128)-(164, 164) ' portion of source to the top-left corner of the destination page

Sub DrawTile8 (imgTiles&, TileNum%, imgScreen&, dx%, dy%)
    Dim tw% ' width/height of tile
    Dim tw_minus1% ' width/height of tile -1
    Dim cols% ' # tiles across on tile sheet
    Dim rows% ' # tile rows on tile sheet
    Dim sc% ' source column on tile sheet
    Dim sr% ' source row on tile sheet
    Dim sx1% ' source start x
    Dim sx2% ' source end x
    Dim sy1% ' source start y
    Dim sy2% ' source end y
    Dim xDest% ' destination x
    Dim yDest% ' destination y

    ' SIZE OF TILE
    tw% = 8
    tw_minus1% = 7

    ' # OF COLUMNS / ROWS ON SOURCE TILE SHEET
    cols% = 16
    rows% = 16

    ' GET THE COLUMN/ROW OF TILE # TileNum% ON THE SOURCE TILE SHEET
    sc% = TileNum% Mod rows%
    sr% = TileNum% \ rows%

    'Print "Tile#" + cstr$(TileNum%) + " at sc%=" + cstr$(sc%) + ",sr%=" + cstr$(sr%)

    ' GET THE START X COORDINATE ON THE SOURCE TILE SHEET
    sx1% = sc% * tw%

    ' GET THE START Y COORDINATE ON THE SOURCE TILE SHEET
    sy1% = sr% * tw%

    ' GET THE END X COORDINATE ON THE SOURCE TILE SHEET
    sx2% = sx1% + tw_minus1%

    ' GET THE END y COORDINATE ON THE SOURCE TILE SHEET
    sy2% = sy1% + tw_minus1%

    ' GET THE DESTINATION X COORDINATE ON THE SCREEN
    xDest% = dx% * tw%

    ' GET THE DESTINATION Y COORDINATE ON THE SCREEN
    yDest% = (dy% * tw%) '+ yOffset%

    'Print "Tile#" + cstr$(TileNum%) + _
    '    " at r" + cstr$(sr%) + "c" + cstr$(sc%) + _
    '    " pixel location r" + cstr$(sy1%) + "c" + cstr$(sx1%) + _
    '    " through r" + cstr$(sy2%) + "c" + cstr$(sx2%)

    _Dest imgScreen&

    ' portion of source to the top-left corner of the destination page
    _PutImage (xDest%, yDest%), imgTiles&, imgScreen&, (sx1%, sy1%)-(sx2%, sy2%)

End Sub ' DrawTile8

' ################################################################################################################################################################
' END DRAW TILES, _PUTIMAGE with SOFTWARE IMAGES
' ################################################################################################################################################################

' ################################################################################################################################################################
' BEGIN DRAW TILES, _PUTIMAGE with HARDWARE IMAGES
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////
' Draws an 8x8 tile at the specified column/row dx%, dy%
' using hardware images

' Usage:
' Dim imgHardwareTiles As Long ' the hardware image copy of the tileset
' imgHardwareTiles = _CopyImage(imgTiles, 33) ' Copy tilesheet for hardware image
' DrawTileHw8 imgHardwareTiles, iTileNum, imgScreen, iColumn, iRow, iSubTileset

' where iSubTileset% = iFgColorIndex

Sub DrawTileHw8 (imgHardwareTiles&, TileNum%, imgScreen&, dx%, dy%, iSubTileset%)
    Dim tw% ' width/height of tile
    Dim tw_minus1% ' width/height of tile -1
    Dim cols% ' # tiles across on tile sheet
    Dim rows% ' # tile rows on tile sheet
    Dim sc% ' source column on tile sheet
    Dim sr% ' source row on tile sheet
    Dim sx1% ' source start x
    Dim sx2% ' source end x
    Dim sy1% ' source start y
    Dim sy2% ' source end y
    Dim xDest% ' destination x
    Dim yDest% ' destination y
    Dim xOffset%

    ' CALCULATE OFFSET
    xOffset% = 128 * iSubTileset%

    ' SIZE OF TILE
    tw% = 8
    tw_minus1% = 7

    ' # OF COLUMNS / ROWS ON SOURCE TILE SHEET
    cols% = 16
    rows% = 16

    ' GET THE COLUMN/ROW OF TILE # TileNum% ON THE SOURCE TILE SHEET
    sc% = TileNum% Mod rows%
    sr% = TileNum% \ rows%

    'Print "Tile#" + cstr$(TileNum%) + " at sc%=" + cstr$(sc%) + ",sr%=" + cstr$(sr%)

    ' GET THE START X COORDINATE ON THE SOURCE TILE SHEET
    sx1% = (sc% * tw%) + xOffset%

    ' GET THE START Y COORDINATE ON THE SOURCE TILE SHEET
    sy1% = sr% * tw%

    ' GET THE END X COORDINATE ON THE SOURCE TILE SHEET
    sx2% = sx1% + tw_minus1%

    ' GET THE END y COORDINATE ON THE SOURCE TILE SHEET
    sy2% = sy1% + tw_minus1%

    ' GET THE DESTINATION X COORDINATE ON THE SCREEN
    xDest% = dx% * tw%

    ' GET THE DESTINATION Y COORDINATE ON THE SCREEN
    yDest% = (dy% * tw%) '+ yOffset%

    'Print "Tile#" + cstr$(TileNum%) + _
    '    " at r" + cstr$(sr%) + "c" + cstr$(sc%) + _
    '    " pixel location r" + cstr$(sy1%) + "c" + cstr$(sx1%) + _
    '    " through r" + cstr$(sy2%) + "c" + cstr$(sx2%)

    _Dest imgScreen&

    ' portion of source to the top-left corner of the destination page
    '_PutImage (xDest%, yDest%), imgHardwareTiles&, imgScreen&, (sx1%, sy1%)-(sx2%, sy2%)
    '_PutImage (200, 100)-Step(100, 100), imgHardwareTiles&, , (0, 0)-(40, 40)
    _PutImage (xDest%, yDest%), imgHardwareTiles&, , (sx1%, sy1%)-(sx2%, sy2%)

End Sub ' DrawTileHw8

' /////////////////////////////////////////////////////////////////////////////
' Receives an image imgTiles of 8x8 tiles
' colored black on transparent background
' and returns a new image imgNew
' copied from the tiles in imgTiles,
' except colored to foreground color fgColor,
' and background color bgColor

' Usage:
' MakeColoredTileset imgTiles, imgNew, fgColor, bgColor

Sub MakeColoredTileset (imgTiles As Long, imgNew As Long, fgColor As _Unsigned Long, bgColor As _Unsigned Long)
    Dim iTileNum As Integer
    Dim iY As Integer
    Dim iX As Integer
    If imgNew < -1 Or imgNew > 0 Then _FreeImage imgNew ' FREE MEMORY
    imgNew = _NewImage(_Width(imgTiles), _Height(imgTiles), 32)
    iTileNum = 0
    For iY = 0 To (_Height(imgTiles) \ 8) - 1
        For iX = 0 To (_Width(imgTiles) \ 8) - 1
            DrawColorTile imgNew, imgTiles, iTileNum, fgColor, bgColor, iX, iY
            iTileNum = iTileNum + 1
            If iTileNum > 255 Then Exit For
        Next iX
        If iTileNum > 255 Then Exit For
    Next iY
End Sub ' MakeColoredTileset

' /////////////////////////////////////////////////////////////////////////////
' Receives an image imgTiles of 8x8 tiles
' colored black on transparent background
' and an array of colors,
' and returns a new image imgNew
' copied from the tiles in imgTiles,
' with every combination of the colors in the array
' as the foreground/background color.

' Usage:
' MakeColoredTileset2 imgTiles, imgNew, arrColor(), arrTileIndex(), arrColorIndex()

' Input: iTileNum, bgColor, fgColor
' X Index: arrTileIndex(iTileNum) = returns x position for iTileNum
' Y Index: arrColorIndex(fgColor, bgColor) = returns y position for fgColor, bgColor

Sub MakeColoredTileset2 ( _
    imgTiles As Long, _
    imgNew As Long, _
    arrColor() As _Unsigned Long, _
    arrTileIndex() As Long, _
    arrColorIndex() As Long)

    Dim iTileNum As Integer
    Dim iY As Integer
    Dim iX As Integer
    Dim iFG As Integer
    Dim iBG As Integer
    Dim iWidth As Long
    Dim iHeight As Long
    Dim iColorCount As Long
    Dim iDestX As Long
    Dim iDestY As Long
    Dim fgColor As _Unsigned Long
    Dim bgColor As _Unsigned Long

    If imgNew < -1 Or imgNew > 0 Then _FreeImage imgNew ' FREE MEMORY

    ' FIGURE OUT SIZE OF TARGET IMAGE
    iColorCount = (UBound(arrColor) - LBound(arrColor)) + 1
    iHeight = (iColorCount * iColorCount) * 8
    iWidth = 256 * 8

    ' CREATE TARGET IMAGE
    'imgNew = _NewImage(_Width(imgTiles), _Height(imgTiles), 32)
    imgNew = _NewImage(iWidth, iHeight, 32)

    ' INITIALIZE X POSITION INDEX
    ReDim arrTileIndex(0 To 255) As Long

    ' INITIALIZE Y POSITION INDEX
    ReDim arrColorIndex(LBound(arrColor) To UBound(arrColor), LBound(arrColor) To UBound(arrColor)) As Long

    ' POPULATE X POSITION INDEX
    iX = 0
    For iTileNum = 0 To 255
        arrTileIndex(iTileNum) = iX
        iX = iX + 8
    Next iTileNum

    ' CREATE TILE MAP FOR ALL COMBINATIONS OF FOREGROUND + BACKGROUND COLORS
    ' AND POPULATE Y POSITION INDEX
    iY = 0
    For iFG = LBound(arrColor) To UBound(arrColor)
        For iBG = LBound(arrColor) To UBound(arrColor)
            For iTileNum = 0 To 255
                iX = arrTileIndex(iTileNum)
                fgColor = arrColor(iFG)
                bgColor = arrColor(iBG)
                DrawColorTile imgNew, imgTiles, iTileNum, fgColor, bgColor, iX \ 8, iY \ 8
                arrColorIndex(iFG, iBG) = iY
            Next iTileNum
            iY = iY + 8
        Next iBG
    Next iFG

End Sub ' MakeColoredTileset2

' /////////////////////////////////////////////////////////////////////////////
' Draws an 8x8 tile at the specified column/row dx%, dy%
' in the specified foreground/background color
' using hardware images.

' Usage:
' Dim imgHardwareTiles As Long ' the hardware image copy of the tileset
' imgHardwareTiles = _CopyImage(imgTiles, 33) ' Copy tilesheet for hardware image
' DrawTileHw8 imgHardwareTiles, iTileNum, imgScreen, iColumn, iRow, iSubTileset

' THIS:
' DrawColorTileHw8 imgTilesAllColorsHW, iTileNum, imgScreen, iX, iY, iFgColorIndex, iBgColorIndex, arrTileIndex(), arrColorIndex()

Sub DrawColorTileHw8 (imgHardwareTiles&, TileNum%, imgScreen&, dx%, dy%, _
    iFgColorIndex As Integer, _
    iBgColorIndex As Integer, _
    arrTileIndex() As Long, _
    arrColorIndex() As Long)

    Dim tw% ' width/height of tile
    Dim tw_minus1% ' width/height of tile -1
    Dim cols% ' # tiles across on tile sheet
    Dim rows% ' # tile rows on tile sheet
    Dim sc% ' source column on tile sheet
    Dim sr% ' source row on tile sheet
    Dim sx1% ' source start x
    Dim sx2% ' source end x
    Dim sy1% ' source start y
    Dim sy2% ' source end y
    Dim xDest% ' destination x
    Dim yDest% ' destination y
    Dim xOffset%

    '' CALCULATE OFFSET
    'xOffset% = 128 * iSubTileset%

    ' SIZE OF TILE
    tw% = 8
    tw_minus1% = 7

    '' # OF COLUMNS / ROWS ON SOURCE TILE SHEET
    'cols% = 16
    'rows% = 16

    '' GET THE COLUMN/ROW OF TILE # TileNum% ON THE SOURCE TILE SHEET
    'sc% = TileNum% Mod rows%
    'sr% = TileNum% \ rows%

    'Print "Tile#" + cstr$(TileNum%) + " at sc%=" + cstr$(sc%) + ",sr%=" + cstr$(sr%)

    ' GET THE START X COORDINATE ON THE SOURCE TILE SHEET
    'sx1% = (sc% * tw%) + xOffset%
    sx1% = arrTileIndex(TileNum%)

    ' GET THE START Y COORDINATE ON THE SOURCE TILE SHEET
    'sy1% = sr% * tw%
    sy1% = arrColorIndex(iFgColorIndex, iBgColorIndex)

    ' GET THE END X COORDINATE ON THE SOURCE TILE SHEET
    sx2% = sx1% + tw_minus1%

    ' GET THE END y COORDINATE ON THE SOURCE TILE SHEET
    sy2% = sy1% + tw_minus1%

    ' GET THE DESTINATION X COORDINATE ON THE SCREEN
    xDest% = dx% * tw%

    ' GET THE DESTINATION Y COORDINATE ON THE SCREEN
    yDest% = (dy% * tw%) '+ yOffset%

    'Print "Tile#" + cstr$(TileNum%) + _
    '    " at r" + cstr$(sr%) + "c" + cstr$(sc%) + _
    '    " pixel location r" + cstr$(sy1%) + "c" + cstr$(sx1%) + _
    '    " through r" + cstr$(sy2%) + "c" + cstr$(sx2%)

    _Dest imgScreen&

    ' portion of source to the top-left corner of the destination page
    '_PutImage (xDest%, yDest%), imgHardwareTiles&, imgScreen&, (sx1%, sy1%)-(sx2%, sy2%)
    '_PutImage (200, 100)-Step(100, 100), imgHardwareTiles&, , (0, 0)-(40, 40)
    _PutImage (xDest%, yDest%), imgHardwareTiles&, , (sx1%, sy1%)-(sx2%, sy2%)

End Sub ' DrawColorTileHw8

' ################################################################################################################################################################
' END DRAW TILES, _PUTIMAGE with HARDWARE IMAGES
' ################################################################################################################################################################

' ################################################################################################################################################################
' BEGIN TILE PRECALCULATION UTILITIES
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////
' Precalculates the tile locations ahead of time to save time copying them
' to the screen.

' Requires the following types be declared:
'
'     Type TileSheetMapType ' UDT FOR PRECALCULATED TILESHEET
'         xStart As Integer
'         xEnd As Integer
'         yStart As Integer
'         yEnd As Integer
'     End Type
'     Type TileMapType ' UDT FOR PRECALCULATED TILE MAP
'         xPos As Integer
'         yPos As Integer
'     End Type
'
' EXAMPLE USAGE:
'
'     Dim TileCount%
'     Dim TilesheetCols%
'     Dim TilesheetRows%
'     Dim tileHeightPx%
'     Dim tileWidthPx%
'     Dim xOffset%
'     Dim yOffset%
'     Dim numTilesX%
'     Dim numTilesY%
'     REDIM arrTileSheetMap(255) AS TileSheetMapType
'     REDIM arrTileMap(20, 20) AS TileMapType
'     TileCount% = 256 ' TOTAL # OF TILES
'     TilesheetCols% = 16 ' # OF COLUMNS ON SOURCE TILE SHEET
'     TilesheetRows% = 16 ' # OF ROWS    ON SOURCE TILE SHEET
'     tileHeightPx% = 32 ' TILE HEIGHT
'     tileWidthPx% = 32 ' TILE WIDTH
'     xOffset% = 0 ' SCREEN OFFSET X
'     yOffset% = 64 ' SCREEN OFFSET Y
'     numTilesX% = 20 ' HOW MANY TILES ACROSS (ON DESTINATION)
'     numTilesY% = 20 ' HOW MANY TILES UP/DOWN (ON DESTINATION)
'     ComputeTileLocations arrTileSheetMap(), arrTileMap(), TileCount%, _
'         TilesheetCols%, TilesheetRows%, tileWidthPx%, tileHeightPx%, _
'         xOffset%, yOffset%, numTilesX%, numTilesY%

' TODO: this can be simplified & optimized:
'       - we don't need x/y offsets
'       - tile height/width can be hardcoded
'       - etc.

Sub ComputeTileLocations (arrTileSheetMap() As TileSheetMapType, arrTileMap() As TileMapType, TileCount%, TilesheetCols%, TilesheetRows%, tileWidthPx%, tileHeightPx%, xOffset%, yOffset%, numTilesX%, numTilesY%)
    Dim TileNum%
    Dim sc%
    Dim sr%
    Dim sx1%
    Dim sx2%
    Dim sy1%
    Dim sy2%

    Dim dx%
    Dim dy%
    Dim xDest%
    Dim yDest%

    ' -----------------------------------------------------------------------------
    ' CALCULATE TILE SHEET COORDINATES FOR TILES 0-255

    For TileNum% = 0 To (TileCount% - 1)

        ' GET THE COLUMN/ROW OF TILE # TileNum% ON THE SOURCE TILE SHEET
        sc% = TileNum% Mod TilesheetCols%
        sr% = TileNum% \ TilesheetRows%

        'Print "Tile#" + cstr$(TileNum%) + " at sc%=" + cstr$(sc%) + ",sr%=" + cstr$(sr%)

        ' GET THE START X COORDINATE ON THE SOURCE TILE SHEET
        'sx1% = sc% * tw%
        sx1% = sc% * tileWidthPx%

        ' GET THE START Y COORDINATE ON THE SOURCE TILE SHEET
        'sy1% = sr% * tw%
        sy1% = sr% * tileHeightPx%

        ' GET THE END X COORDINATE ON THE SOURCE TILE SHEET
        'sx2% = sx1% + (tw% - 1)
        sx2% = sx1% + (tileWidthPx% - 1)

        ' GET THE END y COORDINATE ON THE SOURCE TILE SHEET
        'sy2% = sy1% + (tw% - 1)
        sy2% = sy1% + (tileHeightPx% - 1)

        ' SAVE THE COORDINATES FOR TileNum% IN THE ARRAY
        arrTileSheetMap(TileNum%).xStart = sx1%
        arrTileSheetMap(TileNum%).xEnd = sx2%
        arrTileSheetMap(TileNum%).yStart = sy1%
        arrTileSheetMap(TileNum%).yEnd = sy2%

    Next TileNum%

    ' -----------------------------------------------------------------------------
    ' CALCULATE SCREEN COORDINATES FOR TILES

    For dx% = 0 To (numTilesX% - 1)
        For dy% = 0 To (numTilesY% - 1)

            ' GET THE DESTINATION X COORDINATE ON THE SCREEN
            'xDest% = dx% * tw%
            xDest% = (dx% * tileWidthPx%) + xOffset%

            ' GET THE DESTINATION Y COORDINATE ON THE SCREEN
            'yDest% = (dy% * tw%) + 64
            yDest% = (dy% * tileHeightPx%) + yOffset%

            'Print "Tile#" + cstr$(TileNum%) + " at r" + cstr$(sr%) + "c" + cstr$(sc%) + " pixel location r" + cstr$(sy1%) + "c" + cstr$(sx1%) + " through r" + cstr$(sy2%) + "c" + cstr$(sx2%)

            ' SAVE THE SCREEN PIXEL COORDINATES FOR dx%, dy% IN THE ARRAY
            ' WHERE dx% and dy% ARE 1-BASED
            arrTileMap(dx% + 1, dy% + 1).xPos = xDest%
            arrTileMap(dx% + 1, dy% + 1).yPos = yDest%

        Next dy%
    Next dx%

End Sub ' ComputeTileLocations

' ################################################################################################################################################################
' END TILE PRECALCULATION UTILITIES
' ################################################################################################################################################################

' ################################################################################################################################################################
' BEGIN TILE TO IMAGE ROUTINES
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////
' Loads tileset of 256 8x8 tiles into a 128x128 image (16 columns x 16 rows)
' where tiles are a single color.

' Parameters:
' imgTiles& = contains the resulting tileset image
' fgColor = tile color
' bgColor = tile background color

Function GetTiles$ (imgTiles&, fgColor As _Unsigned Long, bgColor As _Unsigned Long)
    Dim RoutineName As String: RoutineName = "GetTiles$"
    Dim sResult As String: sResult = ""
    ReDim arrTileText(0 To 255) As String

    Dim iTileNum As Integer

    ReDim arrLines(-1) As String
    Dim iFromX As Integer
    Dim iFromY As Integer
    Dim sLine As String
    Dim sChar As String

    Dim iTileX As Integer
    Dim iTileY As Integer
    Dim iToX As Integer
    Dim iToY As Integer
    Dim pixelColor As _Unsigned Long
    Dim bFinished As Integer

    ' Do not try to free image handles currently being used as the active SCREEN. Change screen modes first.
    ' _DISPLAY turns off the auto refresh screen default _AUTODISPLAY behavior. Prevents screen flickering.
    If imgTiles& < -1 Or imgTiles& > 0 Then _FreeImage imgTiles&
    imgTiles& = _NewImage(128, 128, 32)
    '    Cls , cEmpty ' set the background color as transparent

    'Screen imgTiles&
    'Cls , bgColor ' set the background color as transparent
    _Dest imgTiles&
    'DrawRect 0, 0, 128, 128, cEmpty
    'DrawBox 0, 0, 128, cWhite
    Cls , cEmpty ' set the background color as transparent

    GetTileText arrTileText()
    iTileX = 0
    iTileY = 0
    bFinished = FALSE
    For iTileNum = 0 To 255
        split arrTileText(iTileNum), Chr$(13), arrLines()
        iToY = iTileY * 8
        If (iToY > _Height(imgTiles&)) Then
            sResult = "iToY value " + cstr$(iToY) + " " + _
                "exceeded image height " + cstr$(_Height(imgTiles&)) + ". " + _
                "Exiting " + RoutineName + " at iTileNum=" + cstr$(iTileNum) + "."
            bFinished = TRUE
            Exit For
        End If

        For iFromY = LBound(arrLines) To UBound(arrLines)
            sLine = arrLines(iFromY)
            If Len(sLine) > 0 Then
                iToX = iTileX * 8
                For iFromX = 1 To Len(sLine)
                    sChar = Mid$(sLine, iFromX, 1)
                    If sChar = "." Then
                        pixelColor = bgColor ' cEmpty ' POINT(iFromX, iFromY)
                    Else
                        pixelColor = fgColor ' cBlack
                    End If
                    PSet (iToX, iToY), pixelColor
                    iToX = iToX + 1
                    If (iToX > _Width(imgTiles&)) Then
                        sResult = "iToX value " + cstr$(iToX) + " " + _
                            "exceeded image width " + cstr$(_Width(imgTiles&)) + ". " + _
                            "Exiting " + RoutineName + " at iTileNum=" + cstr$(iTileNum) + "."
                        bFinished = TRUE
                        Exit For
                    End If
                Next iFromX
                iToY = iToY + 1
                If bFinished = TRUE Then Exit For
            End If
        Next iFromY
        If bFinished = TRUE Then Exit For

        iTileX = iTileX + 1
        If iTileX > 15 Then
            iTileX = 0
            iTileY = iTileY + 1
            'if iTileY > 15 then
            '    sResult = "Exceeded max 16 rows of tiles." + _
            '        "Exiting " + RoutineName + " at iTileNum=" + cstr$(iTileNum) + "."
            '    bFinished = TRUE
            '    exit for
            'end if
        End If
    Next iTileNum

    GetTiles$ = sResult
End Function ' GetTiles$

' /////////////////////////////////////////////////////////////////////////////
' Loads tileset of 256 8x8 tiles into a 2048 x 8 image
' (256 8x8 pixel tiles organized left to right)
' where tiles are a single color.

' Parameters:
' imgTiles& = contains the resulting tileset image
' fgColor = tile color
' bgColor = tile background color

Function GetTiles2$ (imgTiles&, fgColor As _Unsigned Long, bgColor As _Unsigned Long)
    Dim RoutineName As String: RoutineName = "GetTiles2$"
    Dim sResult As String: sResult = ""
    ReDim arrTileText(0 To 255) As String

    Dim iTileNum As Integer

    ReDim arrLines(-1) As String
    Dim iFromX As Integer
    Dim iFromY As Integer
    Dim sLine As String
    Dim sChar As String

    Dim iTileX As Integer
    Dim iTileY As Integer
    Dim iToX As Integer
    Dim iToY As Integer
    Dim pixelColor As _Unsigned Long
    Dim bFinished As Integer

    ' Do not try to free image handles currently being used as the active SCREEN. Change screen modes first.
    ' _DISPLAY turns off the auto refresh screen default _AUTODISPLAY behavior. Prevents screen flickering.
    If imgTiles& < -1 Or imgTiles& > 0 Then _FreeImage imgTiles&
    imgTiles& = _NewImage(2048, 8, 32)
    '    Cls , cEmpty ' set the background color as transparent

    'Screen imgTiles&
    'Cls , bgColor ' set the background color as transparent
    _Dest imgTiles&
    'DrawRect 0, 0, 128, 128, cEmpty
    'DrawBox 0, 0, 128, cWhite
    Cls , cEmpty ' set the background color as transparent

    GetTileText arrTileText()
    iTileX = 0
    iTileY = 0
    iToY = 0
    bFinished = FALSE
    For iTileNum = 0 To 255
        split arrTileText(iTileNum), Chr$(13), arrLines()
        iToY = iTileY * 8
        If (iToY > _Height(imgTiles&)) Then
            sResult = "iToY value " + cstr$(iToY) + " " + _
                "exceeded image height " + cstr$(_Height(imgTiles&)) + ". " + _
                "Exiting " + RoutineName + " at iTileNum=" + cstr$(iTileNum) + "."
            bFinished = TRUE
            Exit For
        End If

        For iFromY = LBound(arrLines) To UBound(arrLines)
            sLine = arrLines(iFromY)
            If Len(sLine) > 0 Then
                iToX = iTileX * 8
                For iFromX = 1 To Len(sLine)
                    sChar = Mid$(sLine, iFromX, 1)
                    If sChar = "." Then
                        pixelColor = bgColor ' cEmpty ' POINT(iFromX, iFromY)
                    Else
                        pixelColor = fgColor ' cBlack
                    End If
                    PSet (iToX, iToY), pixelColor
                    iToX = iToX + 1
                    If (iToX > _Width(imgTiles&)) Then
                        sResult = "iToX value " + cstr$(iToX) + " " + _
                            "exceeded image width " + cstr$(_Width(imgTiles&)) + ". " + _
                            "Exiting " + RoutineName + " at iTileNum=" + cstr$(iTileNum) + "."
                        bFinished = TRUE
                        Exit For
                    End If
                Next iFromX
                iToY = iToY + 1
                If bFinished = TRUE Then Exit For
            End If
        Next iFromY
        If bFinished = TRUE Then Exit For

        iTileX = iTileX + 1
        'If iTileX > 15 Then
        '    iTileX = 0
        '    iTileY = iTileY + 1
        'End If
    Next iTileNum

    GetTiles2$ = sResult
End Function ' GetTiles2$

' ################################################################################################################################################################
' END TILE TO IMAGE ROUTINES
' ################################################################################################################################################################

' ################################################################################################################################################################
' BEGIN TILE DEFINITIONS
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////
' Returns an array of 256 8x8 tiles defined in text
' where each tile is defined by "." as blank and anything else is a pixel
' and each row is delimited by chr$(13)

Sub GetTileText (arrTileText() As String)
    ReDim arrTileText(0 To 255) As String

    m$ = ""
    m$ = m$ + "22....22" + Chr$(13)
    m$ = m$ + "2..22..2" + Chr$(13)
    m$ = m$ + "2..2...2" + Chr$(13)
    m$ = m$ + "2...2..2" + Chr$(13)
    m$ = m$ + "2..22..2" + Chr$(13)
    m$ = m$ + "2..22..2" + Chr$(13)
    m$ = m$ + "22....22" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(0) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(1) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(2) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(3) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(4) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(5) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(6) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(7) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(8) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(9) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(10) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(11) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(12) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(13) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(14) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(15) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(16) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(17) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(18) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(19) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(20) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(21) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(22) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(23) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(24) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(25) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(26) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(27) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(28) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(29) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(30) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(31) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(32) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(33) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(34) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(35) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(36) = m$

    m$ = ""
    m$ = m$ + ".22...2." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".2...22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(37) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + ".22..222" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(38) = m$

    m$ = ""
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(39) = m$

    m$ = ""
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(40) = m$

    m$ = ""
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(41) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(42) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(43) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    arrTileText(44) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(45) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(46) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(47) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22.222." + Chr$(13)
    m$ = m$ + ".222.22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(48) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(49) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(50) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(51) = m$

    m$ = ""
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + "...2222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(52) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(53) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(54) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(55) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(56) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(57) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(58) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    arrTileText(59) = m$

    m$ = ""
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(60) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(61) = m$

    m$ = ""
    m$ = m$ + ".222...." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + ".222...." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(62) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(63) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22.222." + Chr$(13)
    m$ = m$ + ".22.222." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22...2." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(64) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(65) = m$

    m$ = ""
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(66) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(67) = m$

    m$ = ""
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(68) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(69) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(70) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22.222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(71) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(72) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(73) = m$

    m$ = ""
    m$ = m$ + "...2222." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(74) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".222...." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(75) = m$

    m$ = ""
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(76) = m$

    m$ = ""
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + ".222.222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".22.2.22" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(77) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".222.22." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22.222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(78) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(79) = m$

    m$ = ""
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(80) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(81) = m$

    m$ = ""
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(82) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(83) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(84) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(85) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(86) = m$

    m$ = ""
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + ".22.2.22" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".222.222" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(87) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(88) = m$

    m$ = ""
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(89) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(90) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(91) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(92) = m$

    m$ = ""
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(93) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(94) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(95) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(96) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(97) = m$

    m$ = ""
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(98) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(99) = m$

    m$ = ""
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(100) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(101) = m$

    m$ = ""
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(102) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(103) = m$

    m$ = ""
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(104) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(105) = m$

    m$ = ""
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(106) = m$

    m$ = ""
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(107) = m$

    m$ = ""
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(108) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".22.2.22" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(109) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(110) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(111) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(112) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(113) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(114) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(115) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(116) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(117) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(118) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22...22" + Chr$(13)
    m$ = m$ + ".22.2.22" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "..22.22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(119) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(120) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(121) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(122) = m$

    m$ = ""
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..2....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "..2....." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(123) = m$

    m$ = ""
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(124) = m$

    m$ = ""
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + ".....2.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....2.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(125) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".22....2" + Chr$(13)
    m$ = m$ + "2..2..2." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(126) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(127) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(128) = m$

    m$ = ""
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(129) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(130) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(131) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(132) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(133) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(134) = m$

    m$ = ""
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    arrTileText(135) = m$

    m$ = ""
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    arrTileText(136) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(137) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(138) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(139) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(140) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + ".222...." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    arrTileText(141) = m$

    m$ = ""
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + "....222." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "..222..." + Chr$(13)
    m$ = m$ + ".222...." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    arrTileText(142) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    arrTileText(143) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    arrTileText(144) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(145) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(146) = m$

    m$ = ""
    m$ = m$ + "..22.22." + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(147) = m$

    m$ = ""
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    arrTileText(148) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(149) = m$

    m$ = ""
    m$ = m$ + "22....22" + Chr$(13)
    m$ = m$ + "222..222" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "222..222" + Chr$(13)
    m$ = m$ + "22....22" + Chr$(13)
    arrTileText(150) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(151) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(152) = m$

    m$ = ""
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    arrTileText(153) = m$

    m$ = ""
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + "...222.." + Chr$(13)
    m$ = m$ + "....2..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(154) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(155) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    arrTileText(156) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(157) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "..22222." + Chr$(13)
    m$ = m$ + ".222.22." + Chr$(13)
    m$ = m$ + "..22.22." + Chr$(13)
    m$ = m$ + "..22.22." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(158) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + "..222222" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + ".......2" + Chr$(13)
    arrTileText(159) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(160) = m$

    m$ = ""
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    arrTileText(161) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(162) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(163) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(164) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    arrTileText(165) = m$

    m$ = ""
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    arrTileText(166) = m$

    m$ = ""
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    arrTileText(167) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    arrTileText(168) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "2222222." + Chr$(13)
    m$ = m$ + "222222.." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "2......." + Chr$(13)
    arrTileText(169) = m$

    m$ = ""
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    arrTileText(170) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(171) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    arrTileText(172) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(173) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(174) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(175) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(176) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(177) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(178) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(179) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    arrTileText(180) = m$

    m$ = ""
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    arrTileText(181) = m$

    m$ = ""
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    arrTileText(182) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(183) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(184) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(185) = m$

    m$ = ""
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(186) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    arrTileText(187) = m$

    m$ = ""
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(188) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(189) = m$

    m$ = ""
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(190) = m$

    m$ = ""
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    arrTileText(191) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2.....2" + Chr$(13)
    m$ = m$ + ".2.....2" + Chr$(13)
    m$ = m$ + ".2.....2" + Chr$(13)
    m$ = m$ + ".2.....2" + Chr$(13)
    m$ = m$ + ".2.....2" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    arrTileText(192) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    arrTileText(193) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(194) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "..2222.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(195) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(196) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".....2.." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".2222222" + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".....2.." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(197) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(198) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + "2.2..2.2" + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + "2.2..2.2" + Chr$(13)
    m$ = m$ + "2.2222.2" + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    arrTileText(199) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + "2.2..2.2" + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + "2.2222.2" + Chr$(13)
    m$ = m$ + "2.2..2.2" + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    arrTileText(200) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(201) = m$

    m$ = ""
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + "....22.." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(202) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(203) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    m$ = m$ + "..22...." + Chr$(13)
    arrTileText(204) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(205) = m$

    m$ = ""
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    arrTileText(206) = m$

    m$ = ""
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "2..22..2" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "2..22..2" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    arrTileText(207) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(208) = m$

    m$ = ""
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    arrTileText(209) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(210) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(211) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(212) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    arrTileText(213) = m$

    m$ = ""
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    arrTileText(214) = m$

    m$ = ""
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    arrTileText(215) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    arrTileText(216) = m$

    m$ = ""
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "2..22..2" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    m$ = m$ + "22..22.." + Chr$(13)
    m$ = m$ + "2..22..2" + Chr$(13)
    m$ = m$ + "..22..22" + Chr$(13)
    m$ = m$ + ".22..22." + Chr$(13)
    arrTileText(217) = m$

    m$ = ""
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    arrTileText(218) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(219) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    arrTileText(220) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(221) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(222) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(223) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(224) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(225) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(226) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    arrTileText(227) = m$

    m$ = ""
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    m$ = m$ + "22......" + Chr$(13)
    arrTileText(228) = m$

    m$ = ""
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    m$ = m$ + "222....." + Chr$(13)
    arrTileText(229) = m$

    m$ = ""
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    m$ = m$ + ".....222" + Chr$(13)
    arrTileText(230) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(231) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(232) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(233) = m$

    m$ = ""
    m$ = m$ + ".......2" + Chr$(13)
    m$ = m$ + "......22" + Chr$(13)
    m$ = m$ + ".....22." + Chr$(13)
    m$ = m$ + ".22.22.." + Chr$(13)
    m$ = m$ + ".2222..." + Chr$(13)
    m$ = m$ + ".222...." + Chr$(13)
    m$ = m$ + ".22....." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(234) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    arrTileText(235) = m$

    m$ = ""
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(236) = m$

    m$ = ""
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "...22..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "22222..." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(237) = m$

    m$ = ""
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(238) = m$

    m$ = ""
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "2222...." + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    m$ = m$ + "....2222" + Chr$(13)
    arrTileText(239) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(240) = m$

    m$ = ""
    m$ = m$ + "22222.22" + Chr$(13)
    m$ = m$ + "22222.22" + Chr$(13)
    m$ = m$ + "22222.22" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "22.22222" + Chr$(13)
    m$ = m$ + "22.22222" + Chr$(13)
    m$ = m$ + "22.22222" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(241) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".222222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(242) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(243) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...2222." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(244) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + ".222...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(245) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2222." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(246) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + "...2...." + Chr$(13)
    m$ = m$ + ".222...." + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(247) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(248) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(249) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(250) = m$

    m$ = ""
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    m$ = m$ + "........" + Chr$(13)
    arrTileText(251) = m$

    m$ = ""
    m$ = m$ + "2.2.2.2." + Chr$(13)
    m$ = m$ + ".2.2.2.2" + Chr$(13)
    m$ = m$ + "2.2.2.2." + Chr$(13)
    m$ = m$ + ".2.2.2.2" + Chr$(13)
    m$ = m$ + "2.2.2.2." + Chr$(13)
    m$ = m$ + ".2.2.2.2" + Chr$(13)
    m$ = m$ + "2.2.2.2." + Chr$(13)
    m$ = m$ + ".2.2.2.2" + Chr$(13)
    arrTileText(252) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + "2......2" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(253) = m$

    m$ = ""
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(254) = m$

    m$ = ""
    m$ = ""
    m$ = m$ + "22....22" + Chr$(13)
    m$ = m$ + "2..22..2" + Chr$(13)
    m$ = m$ + "2..22..2" + Chr$(13)
    m$ = m$ + "22.....2" + Chr$(13)
    m$ = m$ + "22222..2" + Chr$(13)
    m$ = m$ + "2..22..2" + Chr$(13)
    m$ = m$ + "22....22" + Chr$(13)
    m$ = m$ + "22222222" + Chr$(13)
    arrTileText(255) = m$

End Sub ' GetTileText

' ################################################################################################################################################################
' END TILE DEFINITIONS
' ################################################################################################################################################################

' ################################################################################################################################################################
' BEGIN COLOR FUNCTIONS
' ################################################################################################################################################################
Function cWhite~& ()
    cWhite = _RGB32(255, 255, 255)
End Function ' cWhite~&

Function cEmpty~& ()
    cEmpty = _RGB32(0, 0, 0, 0)
End Function ' cEmpty~&

Function cBlack~& ()
    cBlack = _RGB32(0, 0, 0)
End Function ' cBlack~&

Function cRed~& ()
    cRed = _RGB32(255, 0, 0)
End Function

Function cYellow~& ()
    cYellow = _RGB32(255, 255, 0)
End Function ' cYellow~&

Function cLime~& ()
    cLime = _RGB32(0, 255, 0)
End Function ' cLime~&

Function cCyan~& ()
    cCyan = _RGB32(0, 255, 255)
End Function ' cCyan~&

Function cBlue~& ()
    cBlue = _RGB32(0, 0, 255)
End Function ' cBlue~&

Function cPurple~& ()
    cPurple = _RGB32(128, 0, 255)
End Function ' cPurple~&

Function cMagenta~& ()
    cMagenta = _RGB32(255, 0, 255)
End Function ' cMagenta~&

Function cOrange~& ()
    cOrange = _RGB32(255, 165, 0)
End Function ' cOrange~&

Function cGray~& ()
    cGray = _RGB32(128, 128, 128)
End Function ' cGray~&
' ################################################################################################################################################################
' END COLOR FUNCTIONS
' ################################################################################################################################################################

' ################################################################################################################################################################
' BEGIN GENERAL PURPOSE ROUTINES
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////
' See also StringTo2dArray

Function Array2dToString$ (MyArray() As String)
    Dim MyString As String
    Dim iY As Integer
    Dim iX As Integer
    Dim sLine As String
    MyString = ""
    For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
        sLine = ""
        For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
            sLine = sLine + MyArray(iY, iX)
        Next iX
        MyString = MyString + sLine + Chr$(13)
    Next iY
    Array2dToString$ = MyString
End Function ' Array2dToString$

' /////////////////////////////////////////////////////////////////////////////

'Function Array2dToStringTest$ (MyArray() As String)
'    Dim MyString As String
'    Dim iY As Integer
'    Dim iX As Integer
'    Dim sLine As String
'    MyString = ""
'    MyString = MyString + "           11111111112222222222333" + Chr$(13)
'    MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
'    For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
'        sLine = ""
'        sLine = sLine + Right$("  " + cstr$(iY), 2)
'        For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
'            sLine = sLine + MyArray(iY, iX)
'        Next iX
'        sLine = sLine + Right$("  " + cstr$(iY), 2)
'        MyString = MyString + sLine + Chr$(13)
'    Next iY
'    MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
'    MyString = MyString + "           11111111112222222222333" + Chr$(13)
'    Array2dToStringTest$ = MyString
'End Function ' Array2dToStringTest$

' /////////////////////////////////////////////////////////////////////////////

Function cstr$ (myValue)
    'cstr$ = LTRIM$(RTRIM$(STR$(myValue)))
    cstr$ = _Trim$(Str$(myValue))
End Function ' cstr$

' /////////////////////////////////////////////////////////////////////////////
' Simple timestamp function

Function CurrentDateTime$
    CurrentDateTime$ = Mid$(Date$, 7, 4) + "-" + _
        Mid$(Date$, 1, 5) + " " + _
        Time$
End Function ' CurrentDateTime$

' /////////////////////////////////////////////////////////////////////////////
' Receives an {sDelim} delimited list {sInput}
' returns the list with all duplicate entries removed.

Function DedupeDelimList$ (sInput As String, sDelim As String)
    ReDim arrLines(-1) As String
    Dim sOutput As String
    Dim iLoop As Integer

    split sInput, sDelim, arrLines()
    sOutput = sDelim
    For iLoop = LBound(arrLines) To UBound(arrLines)
        If InStr(1, sOutput, sDelim + arrLines(iLoop) + sDelim) = 0 Then
            sOutput = sOutput + arrLines(iLoop) + sDelim
        End If
    Next iLoop

    DedupeDelimList$ = sOutput
End Function ' DedupeDelimList$

' /////////////////////////////////////////////////////////////////////////////
' Use with timer functions to avoid "after midnight" bug.

' Re: how to time something (ie do loop for n seconds)
' https://qb64forum.alephc.xyz/index.php?topic=4682.0

' SMcNeill, QB64 Developer
' « Reply #1 on: Today at 11:26:52 am »
'
' One caveat here:  You *can* experience bugs with this after midnight.
'
' Program starts at 23:59:59.
' Add three seconds -- 24:00:02...  (In seconds, and not hours and minutes like this, though hours and minutes are easier to visualize.)
' Clock hits midnight:  0:00:00
'
' At no point will you ever have TIMER become greater than t#.
'
' If you're going to have a program which might run into this issue,
' I'd suggest just plugging in my ExtendedTimer and use it instead:
'
' Most of us write time code to test little snippets for which method might
' be faster for us while we're coding.  The clock resetting on us isn't
' normally such a big deal.  When it is, however, all you have to do is
' swap to the ExtendedTimer function [below]
'
' Returns a value for you based off DAY + TIME, rather than just time alone!
' No midnight clock issues with something like that in our programs.  ;)

' Usage:
'     ' DO SOMETHING FOR 3 SECONDS
'     t# = ExtendedTimer + 3
'     Do
'         '(SOMETHING)
'     Loop Until Timer > t#

Function ExtendedTimer##
    d$ = Date$
    l = InStr(d$, "-")
    l1 = InStr(l + 1, d$, "-")
    m = Val(Left$(d$, l))
    d = Val(Mid$(d$, l + 1))
    y = Val(Mid$(d$, l1 + 1)) - 1970
    For i = 1 To m
        Select Case i 'Add the number of days for each previous month passed
            Case 1: d = d 'January doestn't have any carry over days.
            Case 2, 4, 6, 8, 9, 11: d = d + 31
            Case 3: d = d + 28
            Case 5, 7, 10, 12: d = d + 30
        End Select
    Next
    For i = 1 To y
        d = d + 365
    Next
    For i = 2 To y Step 4
        If m > 2 Then d = d + 1 'add an extra day for leap year every 4 years, starting in 1970
    Next
    d = d - 1 'for year 2000
    s~&& = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
    ExtendedTimer## = (s~&& + Timer)
End Function ' ExtendedTimer##

' /////////////////////////////////////////////////////////////////////////////
' Receives a {sDelimeter} delimited list of numbers {MyString}
' and splits it up into an integer array arrInteger()
' beginning at index {iMinIndex}.

Sub GetIntegerArrayFromDelimList (MyString As String, sDelimiter As String, iMinIndex As Integer, arrInteger() As Integer)
    ReDim arrString(-1) As String
    Dim CleanString As String
    Dim iLoop As Integer
    Dim iCount As Integer: iCount = iMinIndex - 1

    ReDim arrInteger(-1) As Integer

    'DebugPrint "GetIntegerArrayFromDelimList " + _
    '    "MyString=" + chr$(34) + MyString + chr$(34) + ", " + _
    '    "sDelimiter=" + chr$(34) + sDelimiter + chr$(34) + ", " + _
    '    "iMinIndex=" + cstr$(iMinIndex) + ", " + _
    '    "arrInteger()"


    If Len(sDelimiter) > 0 Then
        CleanString = MyString
        If sDelimiter <> " " Then
            CleanString = Replace$(CleanString, " ", "")
        End If

        split CleanString, sDelimiter, arrString()
        iCount = iMinIndex - 1
        For iLoop = LBound(arrString) To UBound(arrString)
            If IsNum%(arrString(iLoop)) = TRUE Then
                iCount = iCount + 1
                ReDim _Preserve arrInteger(iMinIndex To iCount) As Integer
                arrInteger(iCount) = Val(arrString(iLoop))
                'DebugPrint "5633 arrInteger(" + cstr$(iCount) + ") = VAL(arrString(" + cstr$(iLoop) + ")) = " + cstr$(arrInteger(iCount))

            End If
        Next iLoop
    Else
        If IsNum%(MyString) = TRUE Then
            ReDim _Preserve arrInteger(iMinIndex To iMinIndex) As Integer
            arrInteger(iMinIndex) = Val(MyString)
        End If
    End If

    'CleanString=""
    'for iLoop=lbound(arrInteger) to ubound(arrInteger)
    'CleanString = CleanString + iifstr$(iLoop=lbound(arrInteger), "", ",") + cstr$(arrInteger(iLoop))
    'next iLoop
    'DebugPrint "arrInteger=(" + CleanString + ")"

End Sub ' GetIntegerArrayFromDelimList

' /////////////////////////////////////////////////////////////////////////////

Function IIF (Condition, IfTrue, IfFalse)
    If Condition Then IIF = IfTrue Else IIF = IfFalse
End Function

' /////////////////////////////////////////////////////////////////////////////

Function IIFSTR$ (Condition, IfTrue$, IfFalse$)
    If Condition Then IIFSTR$ = IfTrue$ Else IIFSTR$ = IfFalse$
End Function

' /////////////////////////////////////////////////////////////////////////////
' By sMcNeill from https://www.qb64.org/forum/index.php?topic=896.0

Function IsNum% (text$)
    Dim a$
    Dim b$
    a$ = _Trim$(text$)
    b$ = _Trim$(Str$(Val(text$)))
    If a$ = b$ Then
        IsNum% = TRUE
    Else
        IsNum% = FALSE
    End If
End Function ' IsNum%

' /////////////////////////////////////////////////////////////////////////////
' Does a _PrintString at the specified row+column.

' iRow and iCol are 0-based.

Sub PrintString (iRow As Integer, iCol As Integer, MyString As String)
    Dim iX As Integer
    Dim iY As Integer
    iX = _FontWidth * iCol
    iY = _FontHeight * iRow ' (iRow + 1)
    _PrintString (iX, iY), MyString
End Sub ' PrintString

' /////////////////////////////////////////////////////////////////////////////
' Does a _PrintString at the specified row+column.

' iRow and iCol are 1-based.

Sub PrintString1 (iRow As Integer, iCol As Integer, MyString As String)
    Dim iX As Integer
    Dim iY As Integer
    iX = _FontWidth * (iCol - 1)
    iY = _FontHeight * (iRow - 1)
    _PrintString (iX, iY), MyString
End Sub ' PrintString1

' /////////////////////////////////////////////////////////////////////////////
' FROM: String Manipulation
' found at abandoned, outdated and now likely malicious qb64 dot net website
' http://www.qb64.[net]/forum/index_topic_5964-0/
'
'SUMMARY:
'   Purpose:  A library of custom functions that transform strings.
'   Author:   Dustinian Camburides (dustinian@gmail.com)
'   Platform: QB64 (www.qb64.org)
'   Revision: 1.6
'   Updated:  5/28/2012

'SUMMARY:
'[Replace$] replaces all instances of the [Find] sub-string with the [Add] sub-string within the [Text] string.
'INPUT:
'Text: The input string; the text that's being manipulated.
'Find: The specified sub-string; the string sought within the [Text] string.
'Add: The sub-string that's being added to the [Text] string.

Function Replace$ (Text1 As String, Find1 As String, Add1 As String)
    ' VARIABLES:
    Dim Text2 As String
    Dim Find2 As String
    Dim Add2 As String
    Dim lngLocation As Long ' The address of the [Find] substring within the [Text] string.
    Dim strBefore As String ' The characters before the string to be replaced.
    Dim strAfter As String ' The characters after the string to be replaced.

    ' INITIALIZE:
    ' MAKE COPIESSO THE ORIGINAL IS NOT MODIFIED (LIKE ByVal IN VBA)
    Text2 = Text1
    Find2 = Find1
    Add2 = Add1

    lngLocation = InStr(1, Text2, Find2)

    ' PROCESSING:
    ' While [Find2] appears in [Text2]...
    While lngLocation
        ' Extract all Text2 before the [Find2] substring:
        strBefore = Left$(Text2, lngLocation - 1)

        ' Extract all text after the [Find2] substring:
        strAfter = Right$(Text2, ((Len(Text2) - (lngLocation + Len(Find2) - 1))))

        ' Return the substring:
        Text2 = strBefore + Add2 + strAfter

        ' Locate the next instance of [Find2]:
        lngLocation = InStr(1, Text2, Find2)

        ' Next instance of [Find2]...
    Wend

    ' OUTPUT:
    Replace$ = Text2
End Function ' Replace$

' /////////////////////////////////////////////////////////////////////////////
' Split and join strings
' https://www.qb64.org/forum/index.php?topic=1073.0
'
' FROM luke, QB64 Developer
' Date: February 15, 2019, 04:11:07 AM
'
' Given a string of words separated by spaces (or any other character),
' splits it into an array of the words. I've no doubt many people have
' written a version of this over the years and no doubt there's a million
' ways to do it, but I thought I'd put mine here so we have at least one
' version. There's also a join function that does the opposite
' array -> single string.
'
' Code is hopefully reasonably self explanatory with comments and a little demo.
' Note, this is akin to Python/JavaScript split/join, PHP explode/implode.

'Split in$ into pieces, chopping at every occurrence of delimiter$. Multiple consecutive occurrences
'of delimiter$ are treated as a single instance. The chopped pieces are stored in result$().
'
'delimiter$ must be one character long.
'result$() must have been REDIMmed previously.

' Modified to handle multi-character delimiters

Sub split (in$, delimiter$, result$())
    Dim start As Integer
    Dim finish As Integer
    Dim iDelimLen As Integer
    ReDim result$(-1)

    iDelimLen = Len(delimiter$)

    start = 1
    Do
        'While Mid$(in$, start, 1) = delimiter$
        While Mid$(in$, start, iDelimLen) = delimiter$
            'start = start + 1
            start = start + iDelimLen
            If start > Len(in$) Then
                Exit Sub
            End If
        Wend
        finish = InStr(start, in$, delimiter$)
        If finish = 0 Then
            finish = Len(in$) + 1
        End If

        ReDim _Preserve result$(0 To UBound(result$) + 1)

        result$(UBound(result$)) = Mid$(in$, start, finish - start)
        start = finish + 1
    Loop While start <= Len(in$)
End Sub ' split

' /////////////////////////////////////////////////////////////////////////////
' Converts a chr$(13) delimited string
' into a 2-dimensional array.

' Usage:
' Dim StringArray(1 To 48, 1 To 128) As String
' StringTo2dArray StringArray(), GetMap$

' Version 2 with indexed array(row, columm)
' Renamed StringToArray to StringTo2dArray.

' See also: Array2dToString$

Sub StringTo2dArray (MyArray() As String, MyString As String)
    Dim sDelim As String
    ReDim arrLines(0) As String
    Dim iRow As Integer
    Dim iCol As Integer
    Dim sChar As String
    Dim iDim1 As Integer
    Dim iDim2 As Integer
    Dim iIndex1 As Integer
    Dim iIndex2 As Integer

    iDim1 = LBound(MyArray, 1)
    iDim2 = LBound(MyArray, 2)
    sDelim = Chr$(13)
    split MyString, sDelim, arrLines()
    For iRow = LBound(arrLines) To UBound(arrLines)
        If iRow <= UBound(MyArray, 1) Then
            For iCol = 1 To Len(arrLines(iRow))
                If iCol <= UBound(MyArray, 2) Then
                    sChar = Mid$(arrLines(iRow), iCol, 1)

                    If Len(sChar) > 1 Then
                        sChar = Left$(sChar, 1)
                    Else
                        If Len(sChar) = 0 Then
                            sChar = "."
                        End If
                    End If

                    iIndex1 = iRow + iDim1
                    iIndex2 = (iCol - 1) + iDim2
                    MyArray(iIndex1, iIndex2) = sChar
                    'DebugPrint "MyArray(" + cstr$(iIndex1) + ", " + cstr$(iIndex2) + " = " + chr$(34) + sChar + chr$(34)
                Else
                    ' Exit if out of bounds
                    Exit For
                End If
            Next iCol
        Else
            ' Exit if out of bounds
            Exit For
        End If
    Next iRow
End Sub ' StringTo2dArray

' /////////////////////////////////////////////////////////////////////////////

Function TrueFalse$ (myValue)
    If myValue = TRUE Then
        TrueFalse$ = "TRUE"
    Else
        TrueFalse$ = "FALSE"
    End If
End Function ' TrueFalse$

' ################################################################################################################################################################
' END GENERAL PURPOSE ROUTINES
' ################################################################################################################################################################

' ################################################################################################################################################################
' BEGIN HARDWARE IMAGES DEMO #2 (WORKS)
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////
' Re: fastest way to draw a 2-color 8x8 tile (with variable colors)?
' https://qb64forum.alephc.xyz/index.php?topic=4674.0
' madscijr
' « Reply #5 on: Yesterday at 09:46:53 pm »

' Quote from: SMcNeill on Yesterday at 07:56:57 pm:
' Hardware images basically get their speed by being a sort of "Write Only"
' method for images. You can make them, you can put them on the screen,
' but you can't edit them or read information back from them.
' ...
' 2) You don't have to specify where they show up as a destination with putimage.
' ...
' If you have any specific questions, feel free to ask them and I'll do my
' best to answer for you, if I can.  ;)
'
' Thanks for taking the time to explain all that. When I'm back at the PC,
' I'll try out your example.
'
' For now, just one question: if you can't read information from them or even
' specify where on the destination they go, how are they even useful?
' Maybe it will click when I run your example or read up on it, but I just
' don't see what the use of an image would be if you can't control where on
' the screen it is drawn? Or how it would help speed up drawing a map of
' colored tiles to the screen.
'
' Thanks again...

' SMcNeill, QB64 Developer
' « Reply #6 on: Today at 01:14:28 am »
'
' Try this out and see if it doesn't help answer your questions:

Sub HardwareImageDemo2
    $Color:32
    Display = _NewImage(1024, 720, 32)
    Software = _NewImage(1024, 720, 32)

    Screen Display
    Print "First, let's create a normal sortware screen and fill it with 40x40 tiles of random colors."
    Print "Press <ANY KEY> to view this screen."
    Sleep

    _Dest Software
    For y = 0 To 720 Step 40
        For x = 0 To 1024 Step 40
            Line (x, y)-Step(40, 40), &HFF000000 + Rnd * &HFFFFFF, BF
        Next
    Next

    _Dest Display
    _PutImage , Software
    Print
    Print "As you can see, this is a simple software screen."
    Print "Now, I'm going to copy that software screen and make it a hardware screen."
    Print "Press <ANY KEY> for me to do so!"
    Sleep

    Hardware = _CopyImage(Software, 33)
    Cls
    Print "Now, I'm back to my blank screen, but I now have a hardware screen to work with."
    Print
    Print "To keep things simple, let's showcase the differences between using _putimage with a software screen, and then with the hardware screen."
    Print
    Print "First, the software screen!  Press <ANY KEY> to continue."
    Sleep

    _PutImage (0, 100)-Step(100, 100), Software, Display, (0, 0)-(40, 40)
    Print: Print: Print: Print: Print: Print: Print
    Print "As you can see, all I did here was copy a single tile from the software screen and then scale it to fit upon the current screen."
    Print
    Print "Press <ANY KEY> to continue, as I'll now do the same with a hardware image."
    Sleep: _KeyClear

    _PutImage (200, 100)-Step(100, 100), Hardware, , (0, 0)-(40, 40)
    Print
    Print "As you can see from the above, we have the same tile copied and scaled onto the screen, just to the right of the software image."
    Print
    Print "Doesn't really seem to be very different at all, now does it?"
    Print
    Print "Press <ANY KEY> to continue."
    _Display
    Sleep

    _AutoDisplay
    Print
    Color Red
    Print "BUT WAIT A MOMENT!!  What the heck happened to our hardware tile??!!??"
    Color White
    Print
    Print "It's no longer on the screen, as it was previously.  Why??"
    Print
    Print "Because it was never on the software screen at all, but was instead on it's own hardware layer ABOVE the software screen."
    Print
    Print "Hardware images only display ONCE, once _DISPLAY is called, and then they flush from the graphics buffer."
    Print "Draw.  Display.  Flush.  <-- that's the basic process of how a hardware image works."
    Print
    Print "If we want one to remain on the screen, we have to do it either by:"
    Print "1) Not updating the screen after we draw and display the image, as I did above with the tile I displayed."
    Print "2) Refresh displaying the image in our main loop (which is what we do even with software images for most games and such)."
    Print
    Print "Press <ANY KEY> to continue."
    Sleep

    Cls
    Print
    Print "So, as you can see, hardware images have a few drawbacks to them, with the most obvious being they only display once,"
    Print "then flush from memory.  If you want persistant hardware images, they're best used in a loop."
    Print
    Print "But, if they've got drawbacks, then one has to ask, 'What's the advantages to using them?'"
    Print "Press <ANY KEY> to find out!"
    Sleep

    't# = ExtendedTimer + 3
    t# = Timer + 3
    Do
        count = count + 1
        _PutImage (0, 100)-Step(100, 100), Software, Display, (x, y)-Step(40, 40)
        x = x + 40
        If x > 1024 Then x = 0: y = y + 40
        If y > 720 Then x = 0: y = 0
        _Display
    Loop Until Timer > t#
    _AutoDisplay

    Print: Print: Print: Print: Print: Print: Print: Print
    Print "See lots of flashing tiles on the screen for the last three seconds?"
    Print "That was us using _PUTIMAGE with the software screen, and we put"; count; "tiles on the screen in those 3 seconds."
    Print
    Print "Now press <ANY KEY> and we'll do the exact same thing with hardware images."
    Sleep

    count = 0: x = 0: y = 0
    t# = Timer + 3
    tempScreen = _CopyImage(Display, 33)
    _DisplayOrder _Hardware
    Do
        count = count + 1
        _PutImage , tempScreen
        _PutImage (300, 100)-Step(100, 100), Hardware, , (x, y)-Step(40, 40)
        x = x + 40
        If x > 1024 Then x = 0: y = y + 40
        If y > 720 Then x = 0: y = 0
        _Display
    Loop Until Timer > t#

    _FreeImage tempScreen
    _AutoDisplay
    _DisplayOrder _Hardware , _Software
    Print
    Print "Didn't seem very different at the rate of which we were running things, now did it?"
    Print "Would you be surprised to find out that we put"; count * 2; "hardware images on the screen in those same 3 seconds?"
    Print
    Print "And if you look close, I counted each loop twice, as we didn't just put the hardware image to the screen, but also a"
    Print "complete copy of the original software screen as well!"
    Print
    Print "The reason why I did this?"
    Print
    Print "So I could completely elimimate all software iamges and JUST work with the much faster hardware layer!"
    Print
    Print "Press <ANY KEY> to continue"
    Sleep

    Cls
    Print "So, as you can see, hardware images are multiple times faster to display and render than software images."
    Print
    Print "But here's something else for you to notice -- I'm going to update the screen with constant, limitless tile refeshes."
    Print "To start with, I'm going to do this in a LOOP with the software images."
    Print "CTRL-TAB out of this demo program, open your task manager, and see how much memory and CPU processing power the program uses."
    Print "Then TAB back to this program and hit <ESC> to do the same with the hardware images."

    Do
        _PutImage (0, 100)-(1024, 720), Software, Display, (x, y)-Step(40, 40)
        x = x + 40
        If x > 1024 Then x = 0: y = y + 40
        If y > 720 Then x = 0: y = 0
        _Limit 60
        _Display
    Loop Until _KeyDown(27)

    Cls , 0
    Print "PRESS <SPACE BAR> to stop the hardware iamges!!"
    tempImage = _CopyImage(Display, 33)
    x = 0: y = 0
    _DisplayOrder _Hardware
    Do
        _PutImage , tempImage
        _PutImage (0, 100)-(1023, 719), Hardware, , (x, y)-Step(40, 40)
        x = x + 40
        If x > 1024 Then x = 0: y = y + 40
        If y > 720 Then x = 0: y = 0
        _Limit 60
        _Display
    Loop Until _KeyDown(32)

    _DisplayOrder _Software , _Hardware
    _AutoDisplay
    Cls
    Print "On my laptop, these two methods use the following amounts of CPU power:"
    Print "Software, 60 FPS -- 3% CPU"
    Print "Hardware, 60 FPS -- 0.1% CPU"
    Print
    Print "If I go in and change the limits to something much higher, these are the results (test them for yourselves, please):"
    Print "Software, 600 FPS -- 10.3% CPU"
    Print "Hardware, 600 FPS -- 0.1% CPU"
    Print
    Print
    Print "So, as you can see, the disadvantage to hardware images are they display once, then flush from memory."
    Print
    Print "While the advantages to their usage is MUCH faster processing times, and an immense reduction on CPU usage.  (The GPU picks up the work for us!)"
    Print
    Print
    Print "You basically use them just like you would any other normal image, though you have to keep in mind that they render"
    Print "to their own hardware layer, which you can specify to go on below or above your software screen."
    Print
    Print "(Or, you can _DISPLAYORDER _HARDWARE and *only* display the hardware layer, removing software rendering completely!)"
    Print
    Print "And THAT, my friends, is basically the lowdown on hardware vs software images.  ;)"
    Print
    Print
    Print "And this was another Steve(tm) Tutorial!  Enjoy!!"
End Sub ' HardwareImageDemo2

' ################################################################################################################################################################
' END HARDWARE IMAGES DEMO #2 (WORKS)
' ################################################################################################################################################################

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN DEBUGGING ROUTINES #DEBUGGING
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Sub DebugPrint (MyString As String)
    If m_bDebug = TRUE Then
        '_Echo MyString

        ReDim arrLines(-1) As String
        Dim iLoop As Integer
        split MyString, Chr$(13), arrLines()
        For iLoop = LBound(arrLines) To UBound(arrLines)
            _Echo arrLines(iLoop)
        Next iLoop
    End If
End Sub ' DebugPrint

' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END DEBUGGING ROUTINES @DEBUGGING
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

' ################################################################################################################################################################
' BEGIN MENU HELPER ROUTINES
' ################################################################################################################################################################

' /////////////////////////////////////////////////////////////////////////////

Sub ShowInstructions (in$)
    Dim iLoop As Integer
    Dim iCount As Integer: iCount = 0
    Dim iRows As Integer: iRows = _Height(0) '\ _FontHeight ' GET # OF AVAILABLE TEXT ROWS
    ReDim arrLines(-1) As String
    Cls
    split in$, Chr$(13), arrLines() ' SPLIT OUTPUT INTO LINES
    For iLoop = LBound(arrLines) To UBound(arrLines)
        Print arrLines(iLoop)
        iCount = iCount + 1
        If iCount > (iRows - 5) Then
            'INPUT "PRESS <ENTER> TO CONTINUE"; in$
            Sleep
            iCount = 0
        End If
    Next iLoop
    Print
    Input "PRESS <ENTER> TO CONTINUE"; in$
End Sub ' ShowInstructions

' ################################################################################################################################################################
' END MENU HELPER ROUTINES
' ################################################################################################################################################################


' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' #REFERENCE

' =============================================================================
' SOME USEFUL STUFF FOR REFERENCE:

' Type Name               Type suffix symbol   Minimum value                  Maximum value                Size in Bytes
' ---------------------   ------------------   ----------------------------   --------------------------   -------------
' _BIT                    `                    -1                             0                            1/8
' _BIT * n                `n                   -128                           127                          n/8
' _UNSIGNED _BIT          ~`                   0                              1                            1/8
' _BYTE                   %%                   -128                           127                          1
' _UNSIGNED _BYTE         ~%%                  0                              255                          1
' INTEGER                 %                    -32,768                        32,767                       2
' _UNSIGNED INTEGER       ~%                   0                              65,535                       2
' LONG                    &                    -2,147,483,648                 2,147,483,647                4
' _UNSIGNED LONG          ~&                   0                              4,294,967,295                4
' _INTEGER64              &&                   -9,223,372,036,854,775,808     9,223,372,036,854,775,807    8
' _UNSIGNED _INTEGER64    ~&&                  0                              18,446,744,073,709,551,615   8
' SINGLE                  ! or none            -2.802597E-45                  +3.402823E+38                4
' DOUBLE                  #                    -4.490656458412465E-324        +1.797693134862310E+308      8
' _FLOAT                  ##                   -1.18E-4932                    +1.18E+4932                  32(10 used)
' _OFFSET                 %&                   -9,223,372,036,854,775,808     9,223,372,036,854,775,807    Use LEN
' _UNSIGNED _OFFSET       ~%&                  0                              18,446,744,073,709,551,615   Use LEN
' _MEM                    none                 combined memory variable type  N/A                          Use LEN

' div: int1% = num1% \ den1%
' mod: rem1% = num1% MOD den1%

' @REFERENCE
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

(I started updating my game to use them, but got hung up on how to manage changing tile colors on the fly, and it went on the backburner, something I will eventually get back to, because it was a pretty neat game.)
Reply
#56
(03-30-2023, 03:41 PM)madscijr Wrote: Last comment for now (I swear, lol) - I tried this with the 4x sprite sheet, and it runs, and looks good, but is slow (at least on this computer, which isn't the newest, an old Microsoft Surface Pro 3 with 8 GB RAM and whatever gen i7 processor from 2014/15). I'm fine with the 2x resolution, but would be curious what else can be done to speed it up. Maybe if the game were updated to use hardware images?

Hardware images? Yes, that would absolutely be the way to get most performance from the game. I played around with these briefly on an earlier 3D morphing project that I made in QB64pe. It would take some fiddling around but probably not all that much. Most of the game would just work as-is almost I would imagine. Can you blit a portion of a sprite sheet to the screen with hardware images? If so then it'll be fine. The only area that would need a little extra work would be the background strips. These are created on the fly and cached but you could still create them on the fly to a temporary software handle and then copy them over to hardware images. I doubt I'll have time to look into this tonight but maybe tomorrow evening or over the weekend. Let me know if you get it sorted in the meantime though!
RokCoder - dabbling in QB64pe for fun
Reply
#57
(03-30-2023, 05:39 PM)RokCoder Wrote:
(03-30-2023, 03:41 PM)madscijr Wrote: Last comment for now (I swear, lol) - I tried this with the 4x sprite sheet, and it runs, and looks good, but is slow (at least on this computer, which isn't the newest, an old Microsoft Surface Pro 3 with 8 GB RAM and whatever gen i7 processor from 2014/15). I'm fine with the 2x resolution, but would be curious what else can be done to speed it up. Maybe if the game were updated to use hardware images?

Hardware images? Yes, that would absolutely be the way to get most performance from the game. I played around with these briefly on an earlier 3D morphing project that I made in QB64pe. It would take some fiddling around but probably not all that much. Most of the game would just work as-is almost I would imagine. Can you blit a portion of a sprite sheet to the screen with hardware images? If so then it'll be fine. The only area that would need a little extra work would be the background strips. These are created on the fly and cached but you could still create them on the fly to a temporary software handle and then copy them over to hardware images. I doubt I'll have time to look into this tonight but maybe tomorrow evening or over the weekend. Let me know if you get it sorted in the meantime though!

Yes, you can absolutely copy a portion of the sprite sheet to the screen. 
I haven't touched the hardware image code in a year, and I wasn't that comfortable with it to begin with. 
Also I'm not too familiar with how your game draws graphics (the palette stuff is particularly alien to me), so I probably will leave it to you. 
But I look forward to seeing the results whenever you get around to it - it should speed things up considerably.

From what I recall, if you wanted to display a given tile in more than one color, with hw images, you can't do stuff like change the palette on the fly. Instead, you would create a tilesheet for each color (or a giant multi-tilesheet tilesheet) and then locate the tile in the given color and copy it over. 
(DISCLAIMER: my grasp on this stuff is shaky at best, if you have questions Steve or the other folks here should be able to help.)
I'm not sure about the background, I think you would just pre-render copies ahead of time of whatever images, in whatever colors you will need, and then in the game, copy the given background in the right color, and then copy the tiles over that? I'm really not sure, but the guys here can definitely help with that.

Happy hunting!
Reply
#58
LOL
I am  not able to go throught the 3000 scores!
Reply
#59
(03-30-2023, 07:43 PM)madscijr Wrote:
(03-30-2023, 05:39 PM)RokCoder Wrote:
(03-30-2023, 03:41 PM)madscijr Wrote: Last comment for now (I swear, lol) - I tried this with the 4x sprite sheet, and it runs, and looks good, but is slow (at least on this computer, which isn't the newest, an old Microsoft Surface Pro 3 with 8 GB RAM and whatever gen i7 processor from 2014/15). I'm fine with the 2x resolution, but would be curious what else can be done to speed it up. Maybe if the game were updated to use hardware images?

Hardware images? Yes, that would absolutely be the way to get most performance from the game. I played around with these briefly on an earlier 3D morphing project that I made in QB64pe. It would take some fiddling around but probably not all that much. Most of the game would just work as-is almost I would imagine. Can you blit a portion of a sprite sheet to the screen with hardware images? If so then it'll be fine. The only area that would need a little extra work would be the background strips. These are created on the fly and cached but you could still create them on the fly to a temporary software handle and then copy them over to hardware images. I doubt I'll have time to look into this tonight but maybe tomorrow evening or over the weekend. Let me know if you get it sorted in the meantime though!

Yes, you can absolutely copy a portion of the sprite sheet to the screen. 
I haven't touched the hardware image code in a year, and I wasn't that comfortable with it to begin with. 
Also I'm not too familiar with how your game draws graphics (the palette stuff is particularly alien to me), so I probably will leave it to you. 
But I look forward to seeing the results whenever you get around to it - it should speed things up considerably.

From what I recall, if you wanted to display a given tile in more than one color, with hw images, you can't do stuff like change the palette on the fly. Instead, you would create a tilesheet for each color (or a giant multi-tilesheet tilesheet) and then locate the tile in the given color and copy it over. 
(DISCLAIMER: my grasp on this stuff is shaky at best, if you have questions Steve or the other folks here should be able to help.)
I'm not sure about the background, I think you would just pre-render copies ahead of time of whatever images, in whatever colors you will need, and then in the game, copy the given background in the right color, and then copy the tiles over that? I'm really not sure, but the guys here can definitely help with that.

Happy hunting!

Well, there were a handful of caveats to dance around but it's up and running with hardware sprites now. I've set your x8 detail sprites as the default. Try setting $LET HARDWARE_SPRITES = 0 and you'll see the difference that it makes!

I've totally disabled the palette switching code when $LET HI_RES = 1 is set. You'll need different batches of sprites for different colours if you want to re-implement that. As you hated the garish colours, you could just repaint the default grey sprites with colours that you like.

Give me a shout if you run across any problems or have any questions.

.zip   ScrambleTest.zip (Size: 9.68 MB / Downloads: 29)
RokCoder - dabbling in QB64pe for fun
Reply
#60
(03-31-2023, 08:12 PM)RokCoder Wrote:
(03-30-2023, 07:43 PM)madscijr Wrote:
(03-30-2023, 05:39 PM)RokCoder Wrote: Hardware images? Yes, that would absolutely be the way to get most performance from the game. I played around with these briefly on an earlier 3D morphing project that I made in QB64pe. It would take some fiddling around but probably not all that much. Most of the game would just work as-is almost I would imagine. Can you blit a portion of a sprite sheet to the screen with hardware images? If so then it'll be fine. The only area that would need a little extra work would be the background strips. These are created on the fly and cached but you could still create them on the fly to a temporary software handle and then copy them over to hardware images. I doubt I'll have time to look into this tonight but maybe tomorrow evening or over the weekend. Let me know if you get it sorted in the meantime though!

Yes, you can absolutely copy a portion of the sprite sheet to the screen. 
I haven't touched the hardware image code in a year, and I wasn't that comfortable with it to begin with. 
Also I'm not too familiar with how your game draws graphics (the palette stuff is particularly alien to me), so I probably will leave it to you. 
But I look forward to seeing the results whenever you get around to it - it should speed things up considerably.

From what I recall, if you wanted to display a given tile in more than one color, with hw images, you can't do stuff like change the palette on the fly. Instead, you would create a tilesheet for each color (or a giant multi-tilesheet tilesheet) and then locate the tile in the given color and copy it over. 
(DISCLAIMER: my grasp on this stuff is shaky at best, if you have questions Steve or the other folks here should be able to help.)
I'm not sure about the background, I think you would just pre-render copies ahead of time of whatever images, in whatever colors you will need, and then in the game, copy the given background in the right color, and then copy the tiles over that? I'm really not sure, but the guys here can definitely help with that.

Happy hunting!

Well, there were a handful of caveats to dance around but it's up and running with hardware sprites now. I've set your x8 detail sprites as the default. Try setting $LET HARDWARE_SPRITES = 0 and you'll see the difference that it makes!

I've totally disabled the palette switching code when $LET HI_RES = 1 is set. You'll need different batches of sprites for different colours if you want to re-implement that. As you hated the garish colours, you could just repaint the default grey sprites with colours that you like.

Give me a shout if you run across any problems or have any questions.

Fantastic! I'm away from the PC but look forward to trying this out over the weekend!
Reply




Users browsing this thread: 3 Guest(s)