10-22-2025, 08:26 PM
(This post was last modified: 11-08-2025, 08:27 AM by madscijr.
Edit Reason: updated to v2.05 + fixed config template
)
This was a side project that got out of hand. Generates striped patterns like Edward Van Halen's famous guitar and animations & lets you save the images to use as desktop wallpaper or whatever. Enjoy.
v2.5 update: Added flying VH with more config options, fixed file save & it will beep when image is saved.
Download the attached file or see below for the complete code listing.
![[Image: Van-Halenizer-screenshot-1.png]](https://i.ibb.co/q33Qq7LC/Van-Halenizer-screenshot-1.png)
![[Image: vanhalen-20251108-014147.png]](https://i.ibb.co/YB0F0cSw/vanhalen-20251108-014147.png)
![[Image: Van-Halenizer-screenshot-8.png]](https://i.ibb.co/tMSWhS8Y/Van-Halenizer-screenshot-8.png)
![[Image: vanhalen-20251108-014222.png]](https://i.ibb.co/s9pR1VpL/vanhalen-20251108-014222.png)
![[Image: Van-Halenizer-screenshot-6.png]](https://i.ibb.co/9H1wzHZk/Van-Halenizer-screenshot-6.png)
Main program "VanHalenizer2-05.bas":
v2.5 update: Added flying VH with more config options, fixed file save & it will beep when image is saved.
Download the attached file or see below for the complete code listing.
![[Image: Van-Halenizer-screenshot-1.png]](https://i.ibb.co/q33Qq7LC/Van-Halenizer-screenshot-1.png)
![[Image: vanhalen-20251108-014147.png]](https://i.ibb.co/YB0F0cSw/vanhalen-20251108-014147.png)
![[Image: Van-Halenizer-screenshot-8.png]](https://i.ibb.co/tMSWhS8Y/Van-Halenizer-screenshot-8.png)
![[Image: vanhalen-20251108-014222.png]](https://i.ibb.co/s9pR1VpL/vanhalen-20251108-014222.png)
![[Image: Van-Halenizer-screenshot-6.png]](https://i.ibb.co/9H1wzHZk/Van-Halenizer-screenshot-6.png)
Main program "VanHalenizer2-05.bas":
Code: (Select All)
' Van Halenizer v2.05 by Softintheheadware, October 2025.
' This silly little program simulates the striped pattern
' on Edward Van Halen's famous "Frankenstrat" guitars.
' -----------------------------------------------------------------------------
' FEATURES
' -----------------------------------------------------------------------------
' * Draws the Frankenstrat to look how he painted it,
' simulates "taping" on the original black/white design
' which is revealed when the tape is removed.
' * Draws basic stripes for the '78 guitar and Bumblebee colors.
' * Simulates the different sized rolls of tape Ed used for
' different stripes (1/8", 1/4", 1/2", 3/4").
' * Option to save image to JPEG and PNG format.
' * Option for trippy animation.
' -----------------------------------------------------------------------------
' CHANGE LOG
' -----------------------------------------------------------------------------
' Version Date Who What
' ------- ---------- ----------------- ----------------------------------
' v1.0 10/22/2025 Softintheheadware Initial version
' v1.01 10/23/2025 Softintheheadware Minor update, tweaked save image filename
' v2.0 10/25/2025 Softintheheadware Added animation mode + 5 new color schemes
' v2.01 10/26/2025 Softintheheadware Auto-detects screen resolution to size window
' v2.02 10/27/2025 Softintheheadware Always fullscreen at maximum resolution.
' Added auto-cycling options for repaint + color schemes.
' Saves settings to config (.cfg) file + loads at startup.
' v2.03 10/28/2025 Softintheheadware Added config options for screen resolution, delay MS,
' filename template, popup image filename.
' Updated config value names + variable names to match.
' Tweaked to fit menu/title on 640x480 and 800x600 resolutions.
' v2.05 11/01/2025 Softintheheadware Added flying VH! Fixed broken file save. Beeps when saved.
' -----------------------------------------------------------------------------
' CREDITS
' -----------------------------------------------------------------------------
' * VH logo based on the one by ryan.keefer@psybbs.durham.nc
' * Various coding routines by James D. Jarvis, BPlus, Luke,
' Dustinian Camburides, and the folks at qb64phoenix.com
' and QB64.com without whom this would have been impossible!
' -----------------------------------------------------------------------------
' TO DO
' -----------------------------------------------------------------------------
' Things to do that maybe you, the intrepid BASIC programmer,
' can possibly add in a future version:
' * Pull color schemes from config file to allow editing + adding new ones
' without having to touch the code.
' * Option to display the Van Halen logo + band name.
' * Better simulate certain stripe patterns the '78 and Bumblebee had
' (stripes fan out in rays or stripe with parallel pin stripe, etc.)
' * Display info (arrMoreInfo) on each guitar in a sidebar on menu screen.
' * Add options for custom colors, onscreen color picker.
' * Add options for ratio or how many of each size stripe / color.
' (Get stripe name with function StripeName$.)
' * Add the virtual "f-holes" or "mustache" designs, the quarter under the bridge,
' 5-way switch in the middle PU cavity, etc.
' OK we're getting carried away here!
' * Allow multiple layers of paint + tape (currently max is 2).
' e.g., create layer 1: paint coat #1, then add stripes
' create layer 2: Paint coat #2, then add stripes (erase)
' overlay layer 2 over layer 1
' create layer 3: Paint coat #3, then add stripes (erase)
' overlay layer 3 over layer 1
' etc.
' * Visual tool to see stripe size as scale is adjusted.
' * Other designs (Rasta guitar, etc.),
' see https://vctrgtr.com/evh.html
' https://www.angelfire.com/ca2/smithtone/vh_gtrs.html
' https://vintagefloydrose.com/evh-tremolos/
' -----------------------------------------------------------------------------
' MORE INFO
' -----------------------------------------------------------------------------
' About the paint job:
' How did he do it? Edward Van Halen created his iconic "Frankenstrat"
' paint job doing something like this:
' 1. Paint it all black
' 2. Add cris-crossed tape to "mask" the black
' 3. Paint it all white
' 4. Pull off the tape to reveal the black stripes
' 5. Add cris-cross tape again
' 6. Paint it all red
' 7. Pull off the tape to reveal the black/white stripes
' -----------------------------------------------------------------------------
' About Van Halen (if you don't know):
' For more information on Edward Lodewijk Van Halen and his band,
' read "Brothers" by Alex Van Halen,"Van Halen Rising" by Greg Renoff,
' "Running With the Devil" by Noel Monk, visit the Van Halen News Desk
' at www.vhnd.com and listen to some Van Halen records to find out.
' -----------------------------------------------------------------------------
' Stripe info from various sources:
' * The exact widths of the stripes on Eddie Van Halen's Frankenstrat are not
' definitively recorded, as they were applied with tape and applied by hand.
' However, a common approach for replicating the look is to use a combination
' of 1/8", 1/4", 1/2", and 3/4" wide tape, with the final widths up to the
' individual replicating it.
' * Frankenstrat: The original guitar's stripes were applied by hand using tape,
' resulting in a slightly irregular and unique look.
' * DIY Replication: To replicate the striped effect, a combination of
' 1/8", 1/4", 1/2", and 3/4" wide tape can be used. The specific widths can
' be adjusted to achieve a desired final look.
' * Original Material: The original stripes were created with gaffer's tape,
' which allowed for a rough-edge look when applied.
' * Modern Alternatives: While gaffer's tape was used originally, modern options
' like masking tape or specialized "Stripers Tape" are also viable for creating
' the stripes.
' * 3/4 1/2 and 1/8th is all I ever used on the dozens I ever painted.
' And never did the same striping twice.
' * You need 3/4” tape for the black and white taping.
' For the red phase you need 1", 1/2", and 1/4"
' * Instead of obsessing about what stripes the guy put on his guitar,
' try picking up an instrument or a paintbrush and find your own original idea
' that some geek in 20 years will make a computer program about :-)
' -----------------------------------------------------------------------------
$Color:32
' 32-bit color names = Black Blue Green Cyan Red Magenta Brown White Gray LightBlue LightGreen LightCyan LightRed LightMagenta Yellow BrightWhite
'$Dynamic
Option _Explicit
_Title "Van Halenizer v2.05"
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN CONSTANTS #CONST
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' -----------------------------------------------------------------------------
' HARDCODED DEFAULT VALUES
' -----------------------------------------------------------------------------
Const cScreenWidth = 0 ' 0 means _DesktopWidth
Const cScreenHeight = 0 ' 0 means _DesktopHeight
Const cEnableAnimation = _TRUE
Const cDelayMS = 0
Const cMiniMenuIsVisible = _FALSE
Const cFilenameTemplate = "VanHalen_{yyyy}{mm}{dd}_{hh}{nn}{ss}.{ext}"
Const cEnableSaveResultsPopup = _FALSE
Const cCycleEverySeconds = 20
Const cRepaintEverySeconds = 8
Const cColorSchemeIndex = 0
Const cBaseStripeCount = 25
Const cStripeVariance = 5
' -----------------------------------------------------------------------------
Const cEnableFlyingVH = _TRUE
Const cNumVectors = 7 ' 25 100
Const cVectorEveryMS = 3000 ' 100 ' 50 ' 250 ' 2000
Const cMinDX = 150 ' 50 1
Const cMaxDX = 250 ' 100 5
Const cMaxScale = 250 ' 300
Const cScaleIncrement = 2500
' -----------------------------------------------------------------------------
' COLOR SCHEME DEFINITONS
' -----------------------------------------------------------------------------
' TODO: MOVE DEFINTIONS INTO CFG
Const cFrankenstrat = 0
Const c78 = 1
Const cBumbleebee = 2
Const cBlueFrankenstrat = 3
Const cInverse78 = 4
Const cInverseBumbleebee = 5
Const cRastaGuitar1 = 6
Const cRastaGuitar2 = 7
' -----------------------------------------------------------------------------
' FOR STRIPE WIDTH
' -----------------------------------------------------------------------------
Const cStripe_1_16 = 0 ' only used for parallel pinstripes
Const cStripe_1_8 = 1
Const cStripe_1_4 = 2
Const cStripe_1_2 = 3
Const cStripe_3_4 = 4
Const cStripe_1_0 = 5 ' 1" = largest, not used vurrently
' -----------------------------------------------------------------------------
' FOR DATA TYPE IN DATA STATEMENTS
' -----------------------------------------------------------------------------
Const cDrawStart = 1 ' starting point of next shape
Const cFillPoint = 2 ' point to do a flood fill from if shape is closed and can be filled
Const cDrawLine = 3 ' line to delta x, delta y
Const cLastLine = 4 ' last point in shape
Const cEndAll = 5 ' end of data
' MAX / MIN VALUES
Const cIntegerMin = -32768
Const cIntegerMax = 32767
Const cSingleMin = -2.802597E-45
Const cSingleMax = 3.402823E+38
' -----------------------------------------------------------------------------
' _KeyDown key codes
' -----------------------------------------------------------------------------
Const cLeftKD = 19200
Const cRightKD = 19712
Const cUpKD = 18432
Const cDownKD = 20480
Const cPageUp = 18688
Const cPageDown = 20736
Const cEsc = 27
Const cEnter = 13
Const cHome = 18176
Const cEnd = 20224
Const cSpace = 32
Const cKey0 = 48
Const cKey1 = 49
Const cKey2 = 50
Const cKey3 = 51
Const cKey4 = 52
Const cKey5 = 53
Const cKey6 = 54
Const cKey7 = 55
Const cKey8 = 56
Const cKey9 = 57
Const cUpperA = 65
Const cUpperB = 66
Const cUpperC = 67
Const cUpperD = 68
Const cUpperE = 69
Const cUpperF = 70
Const cUpperG = 71
Const cUpperH = 72
Const cUpperI = 73
Const cUpperJ = 74
Const cUpperK = 75
Const cUpperL = 76
Const cUpperM = 77
Const cUpperN = 78
Const cUpperO = 79
Const cUpperP = 80
Const cUpperQ = 81
Const cUpperR = 82
Const cUpperS = 83
Const cUpperT = 84
Const cUpperU = 85
Const cUpperV = 86
Const cUpperW = 87
Const cUpperX = 88
Const cUpperY = 89
Const cUpperZ = 90
Const cLowerA = 97
Const cLowerB = 98
Const cLowerC = 99
Const cLowerD = 100
Const cLowerE = 101
Const cLowerF = 102
Const cLowerG = 103
Const cLowerH = 104
Const cLowerI = 105
Const cLowerJ = 106
Const cLowerK = 107
Const cLowerL = 108
Const cLowerM = 109
Const cLowerN = 110
Const cLowerO = 111
Const cLowerP = 112
Const cLowerQ = 113
Const cLowerR = 114
Const cLowerS = 115
Const cLowerT = 116
Const cLowerU = 117
Const cLowerV = 118
Const cLowerW = 119
Const cLowerX = 120
Const cLowerY = 121
Const cLowerZ = 122
' -----------------------------------------------------------------------------
' _Button key codes (just used to track key state)
' -----------------------------------------------------------------------------
Const KeyCode_Left = 332
Const KeyCode_Right = 334
Const KeyCode_Up = 329
Const KeyCode_Down = 337
Const KeyCode_PgUp = 330
Const KeyCode_PgDn = 338
Const KeyCode_Escape = 2
Const KeyCode_Enter = 29
Const KeyCode_Home = 328
Const KeyCode_End = 336
Const KeyCode_Spacebar = 58
Const KeyCode_0 = 12
Const KeyCode_1 = 3
Const KeyCode_2 = 4
Const KeyCode_3 = 5
Const KeyCode_4 = 6
Const KeyCode_5 = 7
Const KeyCode_6 = 8
Const KeyCode_7 = 9
Const KeyCode_8 = 10
Const KeyCode_9 = 11
Const KeyCode_A = 31
Const KeyCode_B = 49
Const KeyCode_C = 47
Const KeyCode_D = 33
Const KeyCode_E = 19
Const KeyCode_F = 34
Const KeyCode_G = 35
Const KeyCode_H = 36
Const KeyCode_I = 24
Const KeyCode_J = 37
Const KeyCode_K = 38
Const KeyCode_L = 39
Const KeyCode_M = 51
Const KeyCode_N = 50
Const KeyCode_O = 25
Const KeyCode_P = 26
Const KeyCode_Q = 17
Const KeyCode_R = 20
Const KeyCode_S = 32
Const KeyCode_T = 21
Const KeyCode_U = 23
Const KeyCode_V = 48
Const KeyCode_W = 18
Const KeyCode_X = 46
Const KeyCode_Y = 22
Const KeyCode_Z = 45
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END CONSTANTS @CONST
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN USER-DEFINED DATA TYPES (UDTs) #UDT
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Type StripeType
' stripe properties
layer As Integer
weight As Single
' TODO: individual stripe colors
fg As _Unsigned Long
' TODO: or even multicolors?
'bg as _UnsignedLong
' starting point location + movement
x1 As Single
y1 As Single
speed1 As Single
'direction1 As Integer ' pointer to arrDirection
wise1 As Integer ' 1 = clockwise, -1 = counterclockwise
mx1 As Integer
my1 As Integer
dx1 As Single
dy1 As Single
side1 As Integer
' ending point location + movement
x2 As Single
y2 As Single
speed2 As Single
'direction2 As Integer ' pointer to arrDirection
wise2 As Integer ' 1 = clockwise, -1 = counterclockwise
mx2 As Integer
my2 As Integer
dx2 As Single
dy2 As Single
side2 As Integer
End Type
Type MotionType
dx As Single
dy As Single
End Type
Type LayerType
Count As Integer
fg As _Unsigned Long
bg As _Unsigned Long
'image1 as long
'image2 as long
End Type
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END USER-DEFINED DATA TYPES (UDTs) @UDT
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN GLOBAL VARIABLES #GLOBAL
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' Program name / path
Dim Shared m_ProgramPath As String: m_ProgramPath = Left$(Command$(0), _InStrRev(Command$(0), "\")) ' executable path
Dim Shared m_ProgramName As String: m_ProgramName = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1) ' executable filename
Dim Shared m_sDebugFile As String: m_sDebugFile = m_ProgramPath$ + m_ProgramName$ + ".txt"
' For tracking keyboard
ReDim Shared arrKeyState(340) As _Byte
' Used by RotoLine
Dim Shared dot&
' How many text rows+columns fit on screen in current resolution
Dim Shared CurrentWidth As Long
Dim Shared CurrentHeight As Long
Dim Shared MaxRow As Long
Dim Shared MaxCol As Long
' Variables loaded from config file
Dim Shared iScreenWidth As Long
Dim Shared iScreenHeight As Long
Dim Shared iScaleToPercent As Integer
Dim Shared bEnableAnimation As _Byte
Dim Shared iDelayMS As Long
Dim Shared bMiniMenuIsVisible As _Byte
Dim Shared sFilenameTemplate As String
Dim Shared bEnableSaveResultsPopup As _Byte
Dim Shared iCycleEverySeconds As Long
Dim Shared iRepaintEverySeconds As Long
Dim Shared iColorSchemeIndex As Integer
Dim Shared iBaseStripeCount As Integer
Dim Shared iStripeVariance As Integer
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
Dim Shared bEnableFlyingVH As _Byte
Dim Shared iNumVectors As Integer
Dim Shared iVectorEveryMS As Long
Dim Shared iMinDX As Integer
Dim Shared iMaxDX As Integer
Dim Shared iMaxScale As Integer
Dim Shared iScaleIncrement As Long
' GENERAL COLORS
ReDim Shared m_SpectrumColorArray(-1) As _Unsigned Long ' grayscale colors
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END GLOBAL VARIABLES @GLOBAL
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' EXECUTION BEGINS HERE #EXE
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' Local vars
Dim sError As String
' Init local
sError = ""
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' BEGIN GET COMMAND LINE ARGS #ARGS
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' Let's have the screen saver check for command line arguments,
' to see if that's how Windows tells it what "mode" to open in,
' i.e., normal screensaver mode, or settings mode
' We observed the following 3 variations in command line arguments:
' When running normally or in preview mode, we get:
' Command$(1) = "/s"
' When [Settings] button is clicked, we get:
' Command$(1) = "/c:13504396"
' When scr is first installed and runs, we get:
' Command$(1) = "/p"
' Command$(2) = "4591630"
If Len(sError) = 0 Then
Dim iLoop As Integer
Dim sNextArgument As String
Dim message As String
Dim NumRows As Integer
Dim NumCols As Integer
NumRows = 0: NumCols = 0
message = "_CommandCount = " + _Trim$(Str$(_CommandCount)) + Chr$(13)
NumRows = 1: NumCols = Len(message)
If _CommandCount > 0 Then
For iLoop = 1 To _CommandCount
message = message + Chr$(13): NumRows = NumRows + 1
message = message + "Command$(" + _Trim$(Str$(iLoop)) + ") = " + Chr$(34) + Command$(iLoop) + Chr$(34)
sNextArgument = LCase$(Left$(Command$(iLoop), 2)) ' look at first 2 chars
If sNextArgument = "/s" Then
message = message + ", /s received when running normally or in preview mode"
ElseIf sNextArgument = "/c" Then
message = message + ", /c received when Settings is opened"
' If we detect this, instead of running the screensaver
' we can display a Settings dialog
' load the values from the Registry
' let the user change values
' and save changes back to the Registry
' for how to do that, see:
' https://qb64phoenix.com/qb64wiki/index.php/Windows_Environment
ElseIf sNextArgument = "/p" Then
message = message + ", /p received when installing or wait time changed"
End If
If Len(message) > NumCols Then NumCols = Len(message)
Next iLoop
End If
End If
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' END GET COMMAND LINE ARGS @ARGS
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' Initialize global vars
If Len(sError) = 0 Then
sError = InitVars$
End If
' Start main
If Len(sError) = 0 Then
VanHalenizer
End If
' Handle errors
If Len(sError) > 0 Then
Screen 0
_AutoDisplay
Print sError
End If
' Cleanup & exit
FreeImage dot&
End
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' EXECUTION ENDS HERE @EXT
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN VECTOR COORDINATE DATA #DATA
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' Each line:
' Data {id}, {type}, {x}, {y}
' where
' {id} = unique ID for that line
' {type} can be:
' 1 = start shape
' 2 = fill point for shape (if shape is closed and can be filled)
' 3 = line from previous point to x, y
' 4 = line from previous point to x, y (last point in shape)
' 5 = end of data marker
' -n = (negative numbers denote a deleted node, which can be ignored)
' {x} and {y} = absolute coordinates at scaling factor of 1 (100%)
DataStart:
' first value in each line is type:
' 1 = cDrawStart = first point, don't draw line
' 2 = cFillPoint = to fill this shape flood fill should start at these coordinates
' 3 = cDrawLine = draw line from last point
' 4 = cLastLine = draw line from last point (final point in this shape)
' 5 = cEndAll = last line of data, quit after this
' V:
Data 1,1,1,1
Data 2,2,100,100
Data 3,3,393,1
Data 3,4,498,276
Data 3,5,587,41
Data 3,6,483,41
Data 3,7,468,1
Data 3,8,648,1
Data 3,9,497,398
Data 3,10,420,191
Data 3,11,106,191
Data 3,12,85,152
Data 3,13,404,152
Data 3,14,391,116
Data 3,15,64,116
Data 3,16,42,76
Data 3,17,376,76
Data 3,18,363,41
Data 3,19,23,41
Data 4,20,1,1
' H:
Data 1,21,837,1
Data 2,22,900,20
Data 3,23,1237,1
Data 3,24,1215,41
Data 3,25,867,41
Data 3,26,854,76
Data 3,27,1195,76
Data 3,28,1173,116
Data 3,29,838,116
Data 3,30,826,151
Data 3,31,1153,151
Data 3,32,1131,191
Data 3,33,810,191
Data 3,34,614,707
Data 3,35,592,649
Data 3,36,732,277
Data 3,37,633,277
Data 3,38,542,515
Data 3,39,519,458
Data 3,40,693,1
Data 3,41,772,1
Data 3,42,757,41
Data 3,43,722,41
Data 3,44,649,237
Data 3,45,748,237
Data 4,46,837,1
' End
Data 5,45,-1,-1
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END VECTOR COORDINATE DATA @DATA
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' /////////////////////////////////////////////////////////////////////////////
Function InitVars$
Dim sError As String: sError = ""
' Init other global vars
dot& = _NewImage(1, 1, 32) ' ALL rotoline routines all need this defiend as so
AddSpectrumColors m_SpectrumColorArray() ' PALETTE FOR GENERAL GRAYSCALE COLORS
' Initialize global vars to default values from constants
iScreenWidth = cScreenWidth
iScreenHeight = cScreenHeight
iScaleToPercent = GetDefaultScale%
bEnableAnimation = cEnableAnimation
iDelayMS = cDelayMS
bMiniMenuIsVisible = cMiniMenuIsVisible
sFilenameTemplate = cFilenameTemplate
bEnableSaveResultsPopup = cEnableSaveResultsPopup
iCycleEverySeconds = cCycleEverySeconds
iRepaintEverySeconds = cRepaintEverySeconds
iColorSchemeIndex = cColorSchemeIndex
iBaseStripeCount = cBaseStripeCount
iStripeVariance = cStripeVariance
bEnableFlyingVH = cEnableFlyingVH
iNumVectors = cNumVectors
iVectorEveryMS = cVectorEveryMS
iMinDX = cMinDX
iMaxDX = cMaxDX
iMaxScale = cMaxScale
iScaleIncrement = cScaleIncrement
' LOAD SETTINGS FROM CONFING FILE
sError = LoadConfig$
' RETURN RESULT
InitVars$ = sError
End Function ' InitVars$
' /////////////////////////////////////////////////////////////////////////////
Sub VanHalenizer
' Local vars
Dim RoutineName As String:: RoutineName = "VanHalenizer"
ReDim arrColorScheme(-1) As String
ReDim arrMoreInfo(-1) As String
Dim arrWeight(1 To 4) As Single ' cStripe_1_8 = 1/8", cStripe_1_4 = 1/4", cStripe_1_2 = 1/2" and cStripe_3_4 = 3/4" (cStripe_1_16 = 1/16" and cStripe_1_0 = 1" is defined but not yet used)
ReDim arrLayer(-1) As LayerType
ReDim arrStripe(-1) As StripeType
ReDim arrLines(-1) As String
Dim in$
Dim message As String
Dim fg As _Unsigned Long
Dim t1 As Single
Dim t2 As Single
Dim n As Long
Dim c As Integer
Dim iValue1 As Integer
Dim iValue2 As Integer
Dim iScreenSize As Integer ' screen height or width whichever is smaller
Dim x As Long
Dim y As Long
Dim bRefresh As _Byte
Dim iOldColor As Integer
Dim bgColor As _Unsigned Long
Dim sngScale As Single ' always set to iScaleToPercent * .01
Dim iPixelsPerInch As Integer
Dim iTapeSize As Integer
Dim index As Long
Dim bSavedJPG As _Byte
Dim bSavedPNG As _Byte
Dim sPrompt As String
Dim fgPromptColor As _Unsigned Long
Dim bgPromptColor As _Unsigned Long
Dim sIndent As String
Dim bTurn As _Byte
Dim iLayer As Integer
Dim r, g, b As Integer
Dim iMaxColorSchemeNameLen As Integer
Dim x1, y1, x2, y2 As Single
Dim iLoop As Integer
Dim iLen As Integer
Dim iMaxLen As Integer
Dim sLine As String
Dim NextTime As _Float ' used by ExtendedTimer
Dim bMove As _Byte
Dim NextColor As _Float ' used by ExtendedTimer
Dim bCycleColor As _Byte
Dim NextRepaint As _Float ' used by ExtendedTimer
Dim bRepaint As _Byte
Dim sNextError As String
Dim iMin As Integer
Dim iMax As Integer
Dim iNumStripes As Integer ' calculated from iBaseStripeCount and percentage depending on the color scheme
Dim sngNumStripes As Single
Dim sngStripeDensity As Single
' IMAGES / LAYERS
Dim image1 As Long ' the cumulative layer
Dim image2 As Long ' copied over image1 (with transparency)
Dim VectorImage As Long ' for vh logo
Dim NextImage As Long ' for vh logo
' For vector graphics
Dim iShapeCount As Integer
Dim iPointCount As Integer
Dim id As Long
Dim iType As Long
Dim iPoint As Long
' Store the vector data
ReDim arrID(-1) As Long
ReDim arrType(-1) As Long
ReDim arrScreenX1(-1) As Long
ReDim arrScreenY1(-1) As Long
ReDim arrScreenX2(-1) As Long
ReDim arrScreenY2(-1) As Long
' Store the fill point for each shape
ReDim arrFillX(-1) As Long
ReDim arrFillY(-1) As Long
' For scaling to screen
'Dim sngScalingFactor As Single ' NOW HELD IN arrScalingFactor
Dim xMax As Long ' rightmost point in vector logo
Dim yMax As Long ' bottommost point in vector logo
' For autoscaling screen size to shape
Dim xDiff As Single
Dim yDiff As Single
' Variables to track the current absolute position
Dim nextX As Long
Dim nextY As Long
Dim startX As Long
Dim startY As Long
Dim iX1 As Long
Dim iY1 As Long
Dim iX2 As Long
Dim iY2 As Long
' Variables for multiple vectors
Dim arrScalingFactor(0 To iNumVectors) As Single
Dim arrScaleIncrement(0 To iNumVectors) As Single
Dim arrOffsetX(0 To iNumVectors) As Long
Dim arrOffsetY(0 To iNumVectors) As Long
Dim arrOffsetDX(0 To iNumVectors) As Long
Dim arrOffsetDY(0 To iNumVectors) As Long
'Dim arrVectorWeight(0 To iNumVectors) As Single ' used when shapes were just outlines drawn with RotoLine
Dim arrColor(0 To iNumVectors) As _Unsigned Long
Dim arrZOrder(0 To iNumVectors) As Integer ' for displaying closer shapes in front of farther shapes
Dim arrShapeSort(0 To iNumVectors) As Integer ' shape IDs in order of zOrder
Dim bSpawn As _Byte
' Variables for displaying vector shapes
Dim iWhichVector As Integer
Dim iWhichColor As Integer
Dim CurrentColor As _Unsigned Long
Dim NextVector As _Float ' used by ExtendedTimer
Dim VectorX As Long
Dim VectorY As Long
Dim VectorDX As Long
Dim VectorDY As Long
Dim xFill As Long ' calculate from arrFillX
Dim yFill As Long ' calculate from arrFillY
' Variables derived from shared variables loaded from configL
Dim sngMaxScale As Single ' = derived from: iMaxScale / 100
Dim sngScaleIncrement As Single ' = derived from: iScaleIncrement / 1000000
' Variables used to sort zOrder of shapes (flying vh symbols)
Dim BiggestShapeScale As Single
Dim BiggestShapeIndex As Integer
Dim iOrder As Integer
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN Initialize
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' CONVERT SOME VALUES FROM CONFIG SETTINGS
sngMaxScale = iMaxScale / 100
sngScaleIncrement = iScaleIncrement / 1000000
'' BEGIN DEBUG
'message = _tostr$(sngScaleIncrement) + " = " + _tostr$(iScaleIncrement) + " / 1000000"
'in$ = _InputBox$(m_ProgramName, "sngScaleIncrement = iScaleIncrement / 1000000", message)
'' END DEBUG
' ADJUST SCREEN SIZE BASED ON SETTINGS
If iScreenWidth <= 0 Then CurrentWidth = _DesktopWidth Else CurrentWidth = iScreenWidth
If iScreenHeight <= 0 Then CurrentHeight = _DesktopHeight Else CurrentHeight = iScreenHeight
iScreenSize = _Min(CurrentWidth, CurrentHeight)
' SETUP SCREEN
Screen _NewImage(CurrentWidth, CurrentHeight, 32)
'_ScreenMove 0, 0 ' USING THIS COMMAND BREAKS _FullScreen IF DONE RIGHT BEFORE _FullScreen
_FullScreen _SquarePixels
' CALCULATE AVAILABLE TEXT ROWS/COLUMNS
MaxRow = _Height / _FontHeight
MaxCol = _Width / _FontWidth
' INIT IMAGES
InitImage image1, CurrentWidth, CurrentHeight, _RGBA(0, 0, 0, 0)
InitImage image2, CurrentWidth, CurrentHeight, _RGBA(0, 0, 0, 0)
InitImage VectorImage, CurrentWidth, CurrentHeight, _RGBA(0, 0, 0, 0)
InitImage NextImage, CurrentWidth, CurrentHeight, _RGBA(0, 0, 0, 0)
' SET RANDOM SEED
Randomize Timer
' ================================================================================================================================================================
' OTHER INITIALIZATION
' ================================================================================================================================================================
bgColor = _RGB32(3, 20, 72)
fgPromptColor = _RGB32(0, 0, 0)
bgPromptColor = _RGB32(0, 255, 0)
iPixelsPerInch = 64
sngScale = iScaleToPercent * 0.01
'NOW IN arrScalingFactor: sngScalingFactor = 1 ' Scales the logo up (166 * 2.2 ~= 365 px high)
For index = LBound(arrScalingFactor) To UBound(arrScalingFactor): arrScalingFactor(index) = 0: Next index
bSpawn = _TRUE
iWhichColor = LBound(arrColor) - 1
'AddColor _rgb32(255, 255, 255), arrIgnoreColors()
' LINE WEIGHTS = STRIPE SIZES (DIFFERENT SIZES OF TAPE)
'arrWeight(cStripe_1_16) = 1 / 16
arrWeight(cStripe_1_8) = 1 / 8
arrWeight(cStripe_1_4) = 1 / 4
arrWeight(cStripe_1_2) = 1 / 2
arrWeight(cStripe_3_4) = 3 / 4
'arrWeight(cStripe_1_0) = 1
' RESET KEY STATES
For index = LBound(arrKeyState) To UBound(arrKeyState): arrKeyState(index) = _FALSE: Next index
' -----------------------------------------------------------------------------
' <COLOR SCHEME DEFINITONS>
' TODO: MOVE THESE INTO CONFIG FILE
' TODO: MOVE THE ReDim _Preserve + UBOUND INTO AN "AppendOption" SUB
' -----------------------------------------------------------------------------
ReDim _Preserve arrColorScheme(0 To UBound(arrColorScheme) + 1) As String
ReDim _Preserve arrMoreInfo(0 To UBound(arrMoreInfo) + 1) As String
index = UBound(arrColorScheme): arrColorScheme(index) = "Frankenstrat (Black/White on Red) "
index = UBound(arrMoreInfo): arrMoreInfo(index) = "The 'Frankenstrat' guitar repainted with the iconic red, black, and white stripes, the full-sized pickguard removed and a mysterious electical doodad in the middle pickup hole. Ed added the red paint on top of the existing black and white stripes by mid 1979."
ReDim _Preserve arrColorScheme(0 To UBound(arrColorScheme) + 1) As String
ReDim _Preserve arrMoreInfo(0 To UBound(arrMoreInfo) + 1) As String
index = UBound(arrColorScheme): arrColorScheme(index) = "78 Eruption (Black on White) "
index = UBound(arrMoreInfo): arrMoreInfo(index) = "The original 'Frankenstrat' guitar that Edward Van Halen built, as it looked in 1978 with a black and white striped pattern and black pickguard, used on the first album and tour."
ReDim _Preserve arrColorScheme(0 To UBound(arrColorScheme) + 1) As String
ReDim _Preserve arrMoreInfo(0 To UBound(arrMoreInfo) + 1) As String
index = UBound(arrColorScheme): arrColorScheme(index) = "79 Bumblebee (Yellow on Black) "
index = UBound(arrMoreInfo): arrMoreInfo(index) = "The guitar pictured on the Van Halen II album, with a black body with yellow stripes, used on the 1979 tour, and now lies buried with Pantera guitarist Dimebag Darrell (RIP)."
ReDim _Preserve arrColorScheme(0 To UBound(arrColorScheme) + 1) As String
ReDim _Preserve arrMoreInfo(0 To UBound(arrMoreInfo) + 1) As String
index = UBound(arrColorScheme): arrColorScheme(index) = "blue Frankenstrat (Black/White on Blue)"
index = UBound(arrMoreInfo): arrMoreInfo(index) = "(Frankenstrat blue)"
ReDim _Preserve arrColorScheme(0 To UBound(arrColorScheme) + 1) As String
ReDim _Preserve arrMoreInfo(0 To UBound(arrMoreInfo) + 1) As String
index = UBound(arrColorScheme): arrColorScheme(index) = "inverse 78 Eruption (White on Black) "
index = UBound(arrMoreInfo): arrMoreInfo(index) = "('78 guitar reversed colors)"
ReDim _Preserve arrColorScheme(0 To UBound(arrColorScheme) + 1) As String
ReDim _Preserve arrMoreInfo(0 To UBound(arrMoreInfo) + 1) As String
index = UBound(arrColorScheme): arrColorScheme(index) = "inverse 79 Bumblebee (Yellow on Black) "
index = UBound(arrMoreInfo): arrMoreInfo(index) = "(Bumblebee reversed colors)"
ReDim _Preserve arrColorScheme(0 To UBound(arrColorScheme) + 1) As String
ReDim _Preserve arrMoreInfo(0 To UBound(arrMoreInfo) + 1) As String
index = UBound(arrColorScheme): arrColorScheme(index) = "attempt #1 at Rasta guitar " ' black, white, red, green, yellow
index = UBound(arrMoreInfo): arrMoreInfo(index) = "(Sort of 'the rasta guitar' that Ed gave to Dweezil)"
ReDim _Preserve arrColorScheme(0 To UBound(arrColorScheme) + 1) As String
ReDim _Preserve arrMoreInfo(0 To UBound(arrMoreInfo) + 1) As String
index = UBound(arrColorScheme): arrColorScheme(index) = "attempt #2 at Rasta guitar " ' black, white, red, green, yellow
index = UBound(arrMoreInfo): arrMoreInfo(index) = "(Sort of 'the rasta guitar' that Ed gave to Dweezil)"
' Set index
If iColorSchemeIndex < LBound(arrColorScheme) Then
iColorSchemeIndex = LBound(arrColorScheme)
ElseIf iColorSchemeIndex > UBound(arrColorScheme) Then
iColorSchemeIndex = UBound(arrColorScheme)
End If
iOldColor = iColorSchemeIndex - 1 ' set value to something different to trigger initial refresh
' Get length of longest color scheme name
iMaxColorSchemeNameLen = Len(arrColorScheme(LBound(arrColorScheme)))
For index = LBound(arrColorScheme) + 1 To UBound(arrColorScheme)
If Len(arrColorScheme(index)) > iMaxColorSchemeNameLen Then
iMaxColorSchemeNameLen = Len(arrColorScheme(index))
End If
Next index
' -----------------------------------------------------------------------------
' </COLOR SCHEME DEFINITONS>
' -----------------------------------------------------------------------------
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN READ VECTOR DATA
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' Init vars
xMax = 0
yMax = 0
' Read vector data into array
Restore DataStart
iShapeCount = LBound(arrFillX) - 1
iPointCount = 0
Do
sNextError = ""
' READ NEXT DATA ROW
If Len(sNextError) = 0 Then
Read iType
Read id
Read nextX
Read nextY
End If
' IS NEXT DATA TYPE VALID?
If Len(sNextError) = 0 Then
If iType < 1 Then
sNextError = "DELETED"
End If
End If
' PROCESS NEXT DATA ROW
' first value in each line is type:
' 1 = cDrawStart = first point, don't draw line
' 2 = cDrawLine = draw line from last point
' NOT USED: 3 = cRelativeStart
' NOT USED: 4 = cBacktoStart
' 5 = cLastLine = draw line like cDrawLine
' 6 = cEndAll = draw line like cDrawLine; this is the final data, quit after this
If Len(sNextError) = 0 Then
If iType = cDrawStart Then
' New shape
iShapeCount = iShapeCount + 1
iPointCount = 0
' Increment arrays for each new shape
ReDim _Preserve arrFillX(0 To UBound(arrFillX) + 1)
ReDim _Preserve arrFillY(0 To UBound(arrFillY) + 1)
' Start point
startX = nextX
startY = nextY
iX1 = nextX
iY1 = nextY
iX2 = -1
iY2 = -1
If iX1 > xMax Then xMax = iX1
If iY1 > yMax Then yMax = iY1
ElseIf iType = cFillPoint Then
' Save fill point coords for this shape
arrFillX(iShapeCount) = nextX
arrFillY(iShapeCount) = nextY
ElseIf iType = cDrawLine Then
' For drawing line
iX2 = iX1
iY2 = iY1
iX1 = nextX
iY1 = nextY
If iX1 > xMax Then xMax = iX1
If iY1 > yMax Then yMax = iY1
ElseIf iType = cLastLine Then
' For drawing line
iX2 = iX1
iY2 = iY1
iX1 = nextX
iY1 = nextY
If iX1 > xMax Then xMax = iX1
If iY1 > yMax Then yMax = iY1
ElseIf iType = cEndAll Then
Exit Do
Else
sNextError = "TYPE UNKNOWN: " + _ToStr$(iType)
End If
End If
' SAVE VALUES TO ARRAY TO RENDER + EDIT LATER
If Len(sNextError) = 0 Then
' SAVE NEXT POINT
ReDim _Preserve arrID(0 To UBound(arrID) + 1): arrID(UBound(arrID)) = id
ReDim _Preserve arrType(0 To UBound(arrType) + 1): arrType(UBound(arrType)) = iType
ReDim _Preserve arrScreenX1(0 To UBound(arrScreenX1) + 1): arrScreenX1(UBound(arrScreenX1)) = iX1
ReDim _Preserve arrScreenY1(0 To UBound(arrScreenY1) + 1): arrScreenY1(UBound(arrScreenY1)) = iY1
ReDim _Preserve arrScreenX2(0 To UBound(arrScreenX2) + 1): arrScreenX2(UBound(arrScreenX2)) = iX2
ReDim _Preserve arrScreenY2(0 To UBound(arrScreenY2) + 1): arrScreenY2(UBound(arrScreenY2)) = iY2
End If
Loop
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END READ VECTOR DATA
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'' ================================================================================================================================================================
'' SET SCALE TO FIT SCREEN
'' ================================================================================================================================================================
'' Figure out the math:
'' xMax = 720, _width = 640, xDiff = 500 / 400 = 1.125
'' yMax = 800, _height = 480, yDiff = 600 / 300 = 1.666
'' If Y1 = 720, fit to screen height 480
''
'' 1.666 Y1=720
'' ----- = ------
'' 1 Y
''
'' 1.666 * Y = 1 * 720
''
'' Y * 1.666 = 720
'' Y = 720 / 1.666 = 432
'
'' so
''
'' If Y1 = 1, fit to screen 480
''
'' 1.666 = Y1=1
'' ----- ---
'' 1 Y=1
''
'' 1.666 * Y = 1 * Y1
''
'' Y * 1.666 = Y1
'' Y = Y1 / 1.666
'
'If xMax > _Width _OrElse yMax > _Height Then
' xDiff = xMax / _Width
' yDiff = yMax / _Height
' If xDiff > yDiff Then
' sngScalingFactor = 1 / xDiff
' Else
' sngScalingFactor = 1 / yDiff
' End If
'End If
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END Initialize
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN MAIN LOOP
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Do
' Clear screen
_Dest 0
Cls , bgColor
x = 0: y = 0
PrintLogo x, y ' PrintLogo returns x, y position byref to below logo
bRefresh = _TRUE
' ================================================================================================================================================================
' BEGIN CHOOSE SETTINGS
' ================================================================================================================================================================
Do
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' BEGIN REDRAW MENU
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
If bRefresh = _TRUE Then
_KeyClear: '_Delay .5
_Title "Van Halenizer v2.02"
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' Did color scheme change?
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ChangeColorScheme:
If iColorSchemeIndex <> iOldColor Then
' Select appropriate optimal default values
iOldColor = iColorSchemeIndex
Select Case iColorSchemeIndex
Case cFrankenstrat:
' red=190,2,13 white=248,247,242, black=16,20,20
fgPromptColor = _RGB32(0, 0, 0)
bgPromptColor = _RGB32(0, 255, 0)
sngStripeDensity = 1
ReDim arrLayer(0 To 1) As LayerType
' black:
'arrLayer(0).fg = _RGB32(0, 0, 0)
arrLayer(0).fg = _RGB32(0, 0, 0)
' white:
'arrLayer(0).bg = _RGB32(255, 255, 255)
arrLayer(0).bg = _RGB32(248, 247, 242)
' transparent
arrLayer(1).fg = _RGBA32(0, 0, 0, 0)
' red:
'arrLayer(1).bg = _RGB32(255, 0, 0)
arrLayer(1).bg = _RGB32(190, 2, 13)
Case cBlueFrankenstrat:
'blue=13,118,184 white=233,232,238 black=16,18,17
'blue=62,118,193 white=252,250,237 black=38,37,42
fgPromptColor = _RGB32(0, 0, 0)
bgPromptColor = _RGB32(255, 255, 255)
sngStripeDensity = 1
ReDim arrLayer(0 To 1) As LayerType
' black:
'arrLayer(0).fg = _RGB32(0, 0, 0)
arrLayer(0).fg = _RGB32(16, 18, 17)
' white:
'arrLayer(0).bg = _RGB32(255, 255, 255)
arrLayer(0).bg = _RGB32(233, 232, 238)
' transparent
arrLayer(1).fg = _RGBA32(0, 0, 0, 0)
' blue:
'arrLayer(1).bg = _RGB32(0, 0, 255)
arrLayer(1).bg = _RGB32(13, 118, 184)
Case c78:
fgPromptColor = _RGB32(0, 0, 0)
bgPromptColor = _RGB32(0, 255, 0)
sngStripeDensity = .75
ReDim arrLayer(0 To 0) As LayerType
'black:
arrLayer(0).fg = _RGB32(0, 0, 0)
'white:
'arrLayer(0).bg = _RGB32(255, 255, 255)
arrLayer(0).bg = _RGB32(246, 244, 240)
Case cInverse78:
fgPromptColor = _RGB32(0, 0, 0)
bgPromptColor = _RGB32(0, 255, 0)
sngStripeDensity = .75
ReDim arrLayer(0 To 0) As LayerType
'white:
arrLayer(0).fg = _RGB32(255, 255, 255)
'black:
arrLayer(0).bg = _RGB32(0, 0, 0)
Case cBumbleebee:
'yellow = 236,196,0
fgPromptColor = _RGB32(255, 255, 255)
bgPromptColor = _RGB32(0, 0, 255)
sngStripeDensity = .65
ReDim arrLayer(0 To 0) As LayerType
'yellow:
arrLayer(0).fg = _RGB32(255, 255, 0)
'black:
arrLayer(0).bg = _RGB32(0, 0, 0)
Case cInverseBumbleebee:
fgPromptColor = _RGB32(255, 255, 255)
bgPromptColor = _RGB32(0, 0, 255)
sngStripeDensity = .65
ReDim arrLayer(0 To 0) As LayerType
'black:
arrLayer(0).fg = _RGB32(0, 0, 0)
'yellow:
arrLayer(0).bg = _RGB32(255, 255, 0)
Case cRastaGuitar1:
' This version tapes the red/white/black, sprays green, removes paint, adds yellow stripes on top
' Not that great a recreation, needs more work
' but demonstrates that >2 layers work!
'black=17,17,18, white=232,239,241, red=197,0,24, green=13,126,58, yellow = 250,209,84
fgPromptColor = _RGB32(0, 0, 0)
bgPromptColor = _RGB32(255, 255, 255)
sngStripeDensity = 2.5
ReDim arrLayer(0 To 3) As LayerType
'black:
arrLayer(0).fg = _RGB32(17, 17, 18)
'white:
arrLayer(0).bg = _RGB32(232, 239, 241)
'red
arrLayer(1).bg = _RGB32(197, 0, 24)
arrLayer(1).fg = _RGBA32(0, 0, 0, 0) ' transparent bg
'green:
arrLayer(2).bg = _RGB32(13, 126, 58)
arrLayer(2).fg = _RGBA32(0, 0, 0, 0) ' transparent bg
'yellow:
arrLayer(3).fg = _RGB32(250, 209, 84)
arrLayer(3).bg = _RGBA32(0, 0, 0, 0) ' transparent bg
Case cRastaGuitar2:
' This version tapes the red/white/black, then adds green stripes on top, then yellow stripes on top (layer 2 fg/bg are swapped)
' Not that great a recreation, needs more work
' but demonstrates that >2 layers work!
'black=17,17,18, white=232,239,241, red=197,0,24, green=13,126,58, yellow = 250,209,84
fgPromptColor = _RGB32(0, 0, 0)
bgPromptColor = _RGB32(255, 255, 255)
sngStripeDensity = 2
ReDim arrLayer(0 To 3) As LayerType
'black:
arrLayer(0).fg = _RGB32(17, 17, 18)
'white:
arrLayer(0).bg = _RGB32(232, 239, 241)
'red
arrLayer(1).bg = _RGB32(197, 0, 24)
arrLayer(1).fg = _RGBA32(0, 0, 0, 0) ' transparent bg
'green:
arrLayer(2).fg = _RGB32(13, 126, 58)
arrLayer(2).bg = _RGBA32(0, 0, 0, 0) ' transparent bg
'yellow:
arrLayer(3).fg = _RGB32(250, 209, 84)
arrLayer(3).bg = _RGBA32(0, 0, 0, 0) ' transparent bg
End Select
If bCycleColor = _TRUE Then bCycleColor = _FALSE: GoTo PaintGuitar
If bRepaint = _TRUE Then bRepaint = _FALSE: GoTo PaintGuitar
End If
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' SHOW OPTIONS BELOW PrintLogo
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' Build the menu text with the current choices
in$ = ""
If Len(sNextError) > 0 Then
in$ = in$ + "*****************************************************************************" + Chr$(13)
in$ = in$ + "*** " + sNextError + Chr$(13)
in$ = in$ + "*****************************************************************************" + Chr$(13)
sNextError = ""
End If
If iScreenHeight >= 768 Then in$ = in$ + Chr$(13)
in$ = in$ + "Page Up/Down..........Base stripe count : " + PadLeft$(_ToStr$(iBaseStripeCount), 4) + " " + Chr$(13)
in$ = in$ + "Crsr Up/Down..........Scale size : " + PadLeft$(_ToStr$(iScaleToPercent), 4) + "% " + Chr$(13)
in$ = in$ + "Crsr Left/Right.......Change color scheme: " + arrColorScheme(iColorSchemeIndex) + Space$(iMaxColorSchemeNameLen) + Chr$(13)
in$ = in$ + "S: +1 X: -1..........Cycle scheme every: " + PadLeft$(_ToStr$(iCycleEverySeconds), 5) + " seconds (0 = stay put)" + Chr$(13)
in$ = in$ + "D: +1 C: -1..........Repaint every: " + PadLeft$(_ToStr$(iRepaintEverySeconds), 5) + " seconds (0 = stay put)" + Chr$(13)
in$ = in$ + "A: enable Z:disable...Toggle animation : " + "animation " + _IIf(bEnableAnimation, "enabled ", "disabled") + Chr$(13)
in$ = in$ + "F: enable V:disable...Toggle flying VH : " + "flying VH " + _IIf(bEnableFlyingVH, "enabled ", "disabled") + Chr$(13)
in$ = in$ + "M: enable N:disable...Toggle mini menu : " + "menu " + _IIf(bMiniMenuIsVisible, "enabled ", "disabled") + Chr$(13)
in$ = in$ + "Enter.................Van Halenize!" + Chr$(13)
in$ = in$ + "Esc...................Quit <- get off the computer and go play guitar!" + Chr$(13)
' We need to center it, but how?
' Let's think about a concrete example
' to sort out the math:
'
' 11111111112
'12345678901234567890
'abba
'dabba
'doo
'12345678901234567890
' abba
' dabba
' doo
'MaxCol=20
'iLen = 5
'(MaxCol-iLen) / 2 = ?
'(20 - 5 ) / 2 = 8
' Find the average line length
split in$, Chr$(13), arrLines()
iLen = 0: iMaxLen = 0
For iLoop = LBound(arrLines) To UBound(arrLines)
iLen = iLen + Len(arrLines(iLoop))
If Len(arrLines(iLoop)) > iMaxLen Then iMaxLen = Len(arrLines(iLoop))
Next iLoop
If iMaxLen <= MaxCol Then
' Calculate the indent
iLen = iLen / ((UBound(arrLines) - LBound(arrLines)) + 1)
iLen = (MaxCol - iLen) / 2
sIndent = Space$(iLen)
Else
' Not enough room for indent
sIndent = ""
End If
' Start beneath PrintLogo
If (y <= MaxRow) Then
Locate y + 1, 1
Else
Cls , bgColor
Print "The Van Halenizer by Softintheheadware"
End If
' 32-bit basic colors = Black, Blue, Cyan / Aqua, Lime, Magenta, Red, White
Color White, bgColor
' Print menu roughly centered
For iLoop = LBound(arrLines) To UBound(arrLines)
If Left$(arrLines(iLoop), 1) <> "*" Then
If IsOdd%(iLoop) Then Color White, bgColor Else Color Cyan, bgColor
Else
Color White, Red
End If
sLine = sIndent + arrLines(iLoop)
If Len(sLine) <= MaxCol Then
Print sLine
Else
Print Left$(sLine, MaxCol - 1)
End If
Next iLoop
'Print "iMaxLen=" + _ToStr$(iMaxLen)
'Print "iLen =" + _ToStr$(iLen)
'Print "sIndent=" + Chr$(34) + sIndent + Chr$(34)
'_PrintString (0, MaxRow * _FontHeight), "THIS IS THE LAST ROW"
_Display: bRefresh = _FALSE
End If
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' END REDRAW MENU
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' BEGIN PROCESS INPUT <---- *** TODO: MOVE THIS INTO ITS OWN ROUTINE ***
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' PAGE DOWN = STRIPE COUNT -1 PAGE UP = STRIPE COUNT +1
If _KeyDown(cPageDown) Then
iBaseStripeCount = iBaseStripeCount - 1
If iBaseStripeCount <= 1 Then iBaseStripeCount = 1
bRefresh = _TRUE
ElseIf _KeyDown(cPageUp) Then
iBaseStripeCount = iBaseStripeCount + 1
If iBaseStripeCount > 500 Then iBaseStripeCount = 500
bRefresh = _TRUE
End If
' DOWN = SCALE -1 UP = SCALE +1
If _KeyDown(cDownKD) Then
iScaleToPercent = iScaleToPercent - 1
If iScaleToPercent < 1 Then iScaleToPercent = 1
sngScale = iScaleToPercent * 0.01
bRefresh = _TRUE
ElseIf _KeyDown(cUpKD) Then
iScaleToPercent = iScaleToPercent + 1
If iScaleToPercent > 1000 Then iScaleToPercent = 1000
sngScale = iScaleToPercent * 0.01
bRefresh = _TRUE
End If
' RIGHT = COLOR SCHEME -1
If _KeyDown(cLeftKD) Then
If arrKeyState(KeyCode_Left) = _FALSE Then
arrKeyState(KeyCode_Left) = _TRUE
iColorSchemeIndex = iColorSchemeIndex - 1
If iColorSchemeIndex < LBound(arrColorScheme) Then iColorSchemeIndex = LBound(arrColorScheme)
bRefresh = _TRUE
End If
Else
arrKeyState(KeyCode_Left) = _FALSE
End If
' RIGHT = COLOR SCHEME +1
If _KeyDown(cRightKD) Then
If arrKeyState(KeyCode_Right) = _FALSE Then
arrKeyState(KeyCode_Right) = _TRUE
iColorSchemeIndex = iColorSchemeIndex + 1
If iColorSchemeIndex > UBound(arrColorScheme) Then iColorSchemeIndex = UBound(arrColorScheme)
bRefresh = _TRUE
End If
Else
arrKeyState(KeyCode_Right) = _FALSE
End If
' S = INCREASE TIME, X = DECREASE TIME
If _KeyDown(cUpperS) Or _KeyDown(cLowerS) Then
iCycleEverySeconds = iCycleEverySeconds + 1
If iCycleEverySeconds > 86400 Then iCycleEverySeconds = 86400 ' Max time = 1 day
bRefresh = _TRUE
ElseIf _KeyDown(cUpperX) Or _KeyDown(cLowerX) Then
iCycleEverySeconds = iCycleEverySeconds - 1
If iCycleEverySeconds < 0 Then iCycleEverySeconds = 0 ' 0 means color scheme doesn't cycle
bRefresh = _TRUE
End If
' D = INCREASE TIME, C = DECREASE TIME
If _KeyDown(cUpperD) Or _KeyDown(cLowerD) Then
iRepaintEverySeconds = iRepaintEverySeconds + 1
If iRepaintEverySeconds > 3600 Then iRepaintEverySeconds = 3600 ' Max time = 1 hour
bRefresh = _TRUE
ElseIf _KeyDown(cUpperC) Or _KeyDown(cLowerC) Then
iRepaintEverySeconds = iRepaintEverySeconds - 1
If iRepaintEverySeconds < 0 Then iRepaintEverySeconds = 0 ' 0 means picture doesn't repaint automatically (user must press Enter)
bRefresh = _TRUE
End If
' A = ENABLE, Z=DISABLE ANIMATE
If _KeyDown(cUpperA) Or _KeyDown(cLowerA) Then
bEnableAnimation = _TRUE
bRefresh = _TRUE
ElseIf _KeyDown(cUpperZ) Or _KeyDown(cLowerZ) Then
bEnableAnimation = _FALSE
bRefresh = _TRUE
End If
' F = ENABLE, V=DISABLE FLYING VH
If _KeyDown(cUpperF) Or _KeyDown(cLowerF) Then
bEnableFlyingVH = _TRUE
bRefresh = _TRUE
ElseIf _KeyDown(cUpperV) Or _KeyDown(cLowerV) Then
bEnableFlyingVH = _FALSE
bRefresh = _TRUE
End If
' M = ENABLE, N=DISABLE MENU
If _KeyDown(cUpperM) Or _KeyDown(cLowerM) Then
bMiniMenuIsVisible = _TRUE
bRefresh = _TRUE
ElseIf _KeyDown(cUpperN) Or _KeyDown(cLowerN) Then
bMiniMenuIsVisible = _FALSE
bRefresh = _TRUE
End If
' ENTER = START PAINTING!
If _KeyDown(cEnter) Then
Exit Do
End If
' ESC = EXIT
If _KeyDown(cEsc) Then
GoTo CleanupAndExit
End If
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' END PROCESS INPUT
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
_Limit 60
Loop
' Initialize vector spawn point
VectorX = _Width / 2
VectorY = _Height / 2
'VectorX = RandomNumber%(_Width/4, _Width - (_Width/4) )
'VectorY = RandomNumber%(_Height/4, _Height - (_Height/4) )
VectorDX = RandomNumber%(iMinDX, iMaxDX)
If RandomNumber%(0, 1) = 0 Then VectorDX = 0 - VectorDX
VectorDY = RandomNumber%(iMinDX, iMaxDX)
If RandomNumber%(0, 1) = 0 Then VectorDY = 0 - VectorDY
For iWhichVector = LBound(arrScalingFactor) To UBound(arrScalingFactor): arrScalingFactor(iWhichVector) = 0: Next iWhichVector
ResetTimer:
' Set timer to cycle color scheme
If iCycleEverySeconds > 0 Then
NextColor = ExtendedTimer + iCycleEverySeconds ' SCHEDULE COLOR SCHEME TO CHANGE IN iCycleEverySeconds SECONDS
End If
' Set timer to cycle repaint
If iRepaintEverySeconds > 0 Then
NextRepaint = ExtendedTimer + iRepaintEverySeconds ' SCHEDULE COLOR SCHEME TO CHANGE IN iCycleEverySeconds SECONDS
End If
' Set timer to spawn new vector
If iVectorEveryMS > 0 Then
NextVector = ExtendedTimer + iVectorEveryMS * 0.001 ' SCHEDULE NEW VECTOR SPAWNED IN iVectorEveryMS MILLISECONDS
End If
' ================================================================================================================================================================
' END CHOOSE SETTINGS
' ================================================================================================================================================================
' ================================================================================================================================================================
' BEGIN INITIALIZE STRIPES
' ================================================================================================================================================================
PaintGuitar:
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' PREPARE TO PAINT
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
'' Time it
't1 = Timer
' Reset stripes
ReDim arrStripe(-1) As StripeType
' How many stripes?
' Adjust depending on the pattern and add a little randomness
sngNumStripes = sngStripeDensity * iBaseStripeCount
iMin = _Cast(Integer, sngNumStripes) - iStripeVariance
If iMin < 1 Then iMin = 1
iMax = _Cast(Integer, sngNumStripes) + iStripeVariance
If iMax > 500 Then iMax = 500
iNumStripes = RandomNumber%(iMin, iMax)
' For now evenly divide them among layers
iValue1 = UBound(arrLayer) + 1
For index = LBound(arrLayer) To UBound(arrLayer)
arrLayer(index).Count = iNumStripes / iValue1
Next index
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' BEGIN CREATE STRIPES
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
For iLayer = LBound(arrLayer) To UBound(arrLayer)
For n = 1 To arrLayer(iLayer).Count
' Add stripe
ReDim _Preserve arrStripe(0 To UBound(arrStripe) + 1) As StripeType
' Get stripe's index
index = UBound(arrStripe)
' Save layer #
arrStripe(index).layer = iLayer
' Random stripe width
iTapeSize = RandomNumber%(LBound(arrWeight), UBound(arrWeight))
arrStripe(index).weight = iPixelsPerInch * arrWeight(iTapeSize) * sngScale
' Stripe color
arrStripe(index).fg = arrLayer(iLayer).fg
' Pick random start/end points
arrStripe(index).x1 = RandomNumber%(0, _Width)
arrStripe(index).y1 = RandomNumber%(0, _Height)
arrStripe(index).x2 = RandomNumber%(0, _Width)
arrStripe(index).y2 = RandomNumber%(0, _Height)
' Pick random movement for each end (clockwise or counter-clockwise)
arrStripe(index).wise1 = _IIf(RandomNumber%(0, 1), 1, -1)
arrStripe(index).wise2 = _IIf(RandomNumber%(0, 1), 1, -1)
'arrStripe(index).wise1 = 1
'arrStripe(index).wise2 = 1
' Pick which side of the screen the stripe begins at
iValue1 = RandomNumber%(1, 4) ' (1=left, 2=right, 3=top, 4=bottom)
' Pick which side of the screen the stripe ends at (depends on where it starts)
iValue2 = RandomNumber%(1, 3)
' Adjust begin & end points and movement direction of stripe depending on which side of screen
If iValue1 = 1 Then
' start off screen from left
arrStripe(index).x1 = 0 - arrStripe(index).x1
arrStripe(index).mx1 = 0
arrStripe(index).my1 = -1
If iValue2 = 1 Then
' To right
arrStripe(index).x2 = arrStripe(index).x2 + _Width
arrStripe(index).mx2 = 0
arrStripe(index).my2 = 1
ElseIf iValue2 = 2 Then
' To top
arrStripe(index).y2 = 0 - arrStripe(index).y2
arrStripe(index).mx2 = 1
arrStripe(index).my2 = 0
Else
' To bottom
arrStripe(index).y2 = arrStripe(index).y2 + _Height
arrStripe(index).mx2 = -1
arrStripe(index).my2 = 0
End If
ElseIf iValue1 = 2 Then
' start off screen from right
arrStripe(index).x1 = arrStripe(index).x1 + _Width
arrStripe(index).mx1 = 0
arrStripe(index).my1 = 1
If iValue2 = 1 Then
' To left
arrStripe(index).x2 = 0 - arrStripe(index).x2
arrStripe(index).mx2 = 0
arrStripe(index).my2 = -1
ElseIf iValue2 = 2 Then
' To top
arrStripe(index).y2 = 0 - arrStripe(index).y2
arrStripe(index).mx2 = 1
arrStripe(index).my2 = 0
Else
' To bottom
arrStripe(index).y2 = arrStripe(index).y2 + _Height
arrStripe(index).mx2 = -1
arrStripe(index).my2 = 0
End If
ElseIf iValue1 = 3 Then
' start off screen from top
arrStripe(index).y1 = 0 - arrStripe(index).y1
arrStripe(index).mx1 = 1
arrStripe(index).my1 = 0
If iValue2 = 1 Then
' To bottom
arrStripe(index).y2 = arrStripe(index).y2 + _Height
arrStripe(index).mx2 = -1
arrStripe(index).my2 = 0
ElseIf iValue2 = 2 Then
' To left
arrStripe(index).x2 = 0 - arrStripe(index).x2
arrStripe(index).mx2 = 0
arrStripe(index).my2 = -1
Else
' To right
arrStripe(index).x2 = arrStripe(index).x2 + _Width
arrStripe(index).mx2 = 0
arrStripe(index).my2 = 1
End If
Else
' start off screen from bottom
arrStripe(index).y1 = arrStripe(index).y1 + _Height
arrStripe(index).mx1 = -1
arrStripe(index).my1 = 0
If iValue2 = 1 Then
' To top
arrStripe(index).y2 = 0 - arrStripe(index).y2
arrStripe(index).mx2 = 1
arrStripe(index).my2 = 0
ElseIf iValue2 = 2 Then
' To left
arrStripe(index).x2 = 0 - arrStripe(index).x2
arrStripe(index).mx2 = 0
arrStripe(index).my2 = -1
Else
' To right
arrStripe(index).x2 = arrStripe(index).x2 + _Width
arrStripe(index).mx2 = 0
arrStripe(index).my2 = 1
End If
End If
' SAVE INITIAL MOTION
arrStripe(index).speed1 = 1 ' RandomNumber%(1, 5)
arrStripe(index).dx1 = arrStripe(index).mx1 * arrStripe(index).speed1 * arrStripe(index).wise1
arrStripe(index).dy1 = arrStripe(index).my1 * arrStripe(index).speed1 * arrStripe(index).wise1
arrStripe(index).speed2 = arrStripe(index).speed1 ' RandomNumber%(1, 15)
arrStripe(index).dx2 = arrStripe(index).mx2 * arrStripe(index).speed2 * arrStripe(index).wise2
arrStripe(index).dy2 = arrStripe(index).my2 * arrStripe(index).speed2 * arrStripe(index).wise2
Next n
Next iLayer
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' END CREATE STRIPES
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' ================================================================================================================================================================
' END INITIALIZE STRIPES
' ================================================================================================================================================================
' ================================================================================================================================================================
' BEGIN DRAW
' ================================================================================================================================================================
' CLEAR FLAGS FOR TIMED EVENTS
bCycleColor = _FALSE
bRepaint = _FALSE
bMove = _TRUE
' CLEAR THE MASTER IMAGE
Do
' $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
' TIMED EVENTS
' $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
If iDelayMS > 0 Then
If ExtendedTimer > NextTime Then
bMove = _TRUE
NextTime = ExtendedTimer + (iDelayMS * .001) ' SCHEDULE IT AGAIN IN 5 SECONDS
End If
End If
If bMove = _TRUE Then
_Dest image1
Cls , _RGBA32(0, 0, 0, 0)
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' BEGIN PAINT LAYERS
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' START AT BOTTOM LAYER MOVING UP TO THE TOP
For iLayer = LBound(arrLayer) To UBound(arrLayer)
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' BEGIN DRAW LAYER
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' CLEAR THE NEXT LAYER'S IMAGE
_Dest image2
Cls , arrLayer(iLayer).bg ' Lay down next layer's bg paint (or none if transparent)
' Set next layer's stripe color (handle differently for transparent)
If arrLayer(iLayer).fg <> _RGBA32(0, 0, 0, 0) Then
' Not transparent: just use the layer's fg color
fg = arrLayer(iLayer).fg
Else
' Stripe color is transparent, use inverse color of layer's bg color
r = _Red32(arrLayer(iLayer).bg): g = _Green32(arrLayer(iLayer).bg): b = _Blue32(arrLayer(iLayer).bg)
fg = _RGB32(255 - r, 255 - g, 255 - b)
End If
' DRAW NEXT LAYER'S STRIPES
'For index = LBound(arrStripe) To LBound(arrStripe)
For index = LBound(arrStripe) To UBound(arrStripe)
' Ignore stripes from other layers
If arrStripe(index).layer = iLayer Then
' FOR ANIMATION DON'T DO DIFFERENT COLOR STRIPES ON A LAYER
' TODO: IF NOT ANIMATING ENABLE THIS
'' If transparent, use inverse color of bg
'if arrStripe(index).fg = _RGBA32(0, 0, 0, 0) then
' r = _Red32(arrLayer(iLayer).bg): g = _Green32(arrLayer(iLayer).bg): b = _Blue32(arrLayer(iLayer).bg)
' fg = _RGB32(255-r, 255-g, 255-b)
'end if
' Draw the stripe
If arrStripe(index).x1 <> arrStripe(index).x2 And arrStripe(index).y1 <> arrStripe(index).y2 Then
RotoLine arrStripe(index).x1, arrStripe(index).y1, arrStripe(index).x2, arrStripe(index).y2, arrStripe(index).weight, fg
'ThickLine arrStripe(index).x1, arrStripe(index).y1, arrStripe(index).x2, arrStripe(index).y2, arrStripe(index).weight, fg
End If
' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
' BEGIN MOVE IT!
' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
' Move starting point
arrStripe(index).x1 = arrStripe(index).x1 + arrStripe(index).dx1
arrStripe(index).y1 = arrStripe(index).y1 + arrStripe(index).dy1
' Check boundaries and if reached a corner then turn
bTurn = _FALSE
If arrStripe(index).x1 > _Width Then
arrStripe(index).x1 = _Width
arrStripe(index).mx1 = 0
arrStripe(index).my1 = 1
bTurn = _TRUE
End If
If arrStripe(index).y1 > _Height Then
arrStripe(index).y1 = _Height
arrStripe(index).mx1 = -1
arrStripe(index).my1 = 0
bTurn = _TRUE
End If
If arrStripe(index).x1 < 0 Then
arrStripe(index).x1 = 0
arrStripe(index).mx1 = 0
arrStripe(index).my1 = -1
bTurn = _TRUE
End If
If arrStripe(index).y1 < 0 Then
arrStripe(index).y1 = 0
arrStripe(index).mx1 = 1
arrStripe(index).my1 = 0
bTurn = _TRUE
End If
If arrStripe(index).x1 > _Width Then arrStripe(index).x1 = _Width
If arrStripe(index).x1 < 0 Then arrStripe(index).x1 = 0
If arrStripe(index).y1 > _Height Then arrStripe(index).y1 = _Height
If arrStripe(index).y1 < 0 Then arrStripe(index).y1 = 0
If bTurn = _TRUE Then
arrStripe(index).dx1 = arrStripe(index).mx1 * arrStripe(index).speed1 * arrStripe(index).wise1
arrStripe(index).dy1 = arrStripe(index).my1 * arrStripe(index).speed1 * arrStripe(index).wise1
End If
' Move end point
arrStripe(index).x2 = arrStripe(index).x2 + arrStripe(index).dx2
arrStripe(index).y2 = arrStripe(index).y2 + arrStripe(index).dy2
' Check boundaries and if reached a corner then turn
bTurn = _FALSE
If arrStripe(index).x2 > _Width Then
arrStripe(index).x2 = _Width
arrStripe(index).mx2 = 0
arrStripe(index).my2 = 1
bTurn = _TRUE
End If
If arrStripe(index).y2 > _Height Then
arrStripe(index).y2 = _Height
arrStripe(index).mx2 = -1
arrStripe(index).my2 = 0
bTurn = _TRUE
End If
If arrStripe(index).x2 < 0 Then
arrStripe(index).x2 = 0
arrStripe(index).mx2 = 0
arrStripe(index).my2 = -1
bTurn = _TRUE
End If
If arrStripe(index).y2 < 0 Then
arrStripe(index).y2 = 0
arrStripe(index).mx2 = 1
arrStripe(index).my2 = 0
bTurn = _TRUE
End If
If arrStripe(index).x2 > _Width Then arrStripe(index).x2 = _Width
If arrStripe(index).x2 < 0 Then arrStripe(index).x2 = 0
If arrStripe(index).y2 > _Height Then arrStripe(index).y2 = _Height
If arrStripe(index).y2 < 0 Then arrStripe(index).y2 = 0
If bTurn = _TRUE Then
arrStripe(index).dx2 = arrStripe(index).mx2 * arrStripe(index).speed2 * arrStripe(index).wise2
arrStripe(index).dy2 = arrStripe(index).my2 * arrStripe(index).speed2 * arrStripe(index).wise2
End If
' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
' END MOVE IT!
' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
End If
Next index
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' END DRAW LAYER
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' ADD LAYER TO FINAL
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
_Dest image1
' If transparent, use inverse color of bg
If arrLayer(iLayer).fg = _RGBA32(0, 0, 0, 0) Then
'_CLEARCOLOR {color&|_NONE}[, Dest_Handle&]
_ClearColor fg, image2
Else
_ClearColor _None, image2
End If
' OVERLAY LAYER #2 OVER LAYER #1
_Dest image1
_PutImage (0, 0), image2, image1
Next iLayer
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' END PAINT LAYERS
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' ================================================================================================================================================================
' BEGIN DRAW + MOVE VECTOR
' ================================================================================================================================================================
' INIT IMAGE ALL LOGOS WILL GET STACKED ON
'TODO: TRACK Z-ORDER AND STACK IN ORDER OF FARTHEST TO NEAREST
_Dest VectorImage: Cls , _RGBA32(0, 0, 0, 0)
' ADD EACH LOGO IN ORDER OF Z ORDER
For index = iNumVectors To 0 Step -1
iWhichVector = arrShapeSort(index)
If iWhichVector > -1 Then
If arrScalingFactor(iWhichVector) > 0 Then
_Dest NextImage: Cls , _RGBA32(0, 0, 0, 0)
' GET NEXT LOGO'S COLOR
CurrentColor = arrColor(iWhichVector)
' DRAW IT
iShapeCount = LBound(arrFillX) - 1
For iPoint = LBound(arrID) To UBound(arrID)
id = arrID(iPoint)
iType = arrType(iPoint)
x1 = (arrScreenX1(iPoint) * arrScalingFactor(iWhichVector)) '+ arrOffsetX(iWhichVector)
y1 = (arrScreenY1(iPoint) * arrScalingFactor(iWhichVector)) '+ arrOffsetY(iWhichVector)
x2 = (arrScreenX2(iPoint) * arrScalingFactor(iWhichVector)) '+ arrOffsetX(iWhichVector)
y2 = (arrScreenY2(iPoint) * arrScalingFactor(iWhichVector)) '+ arrOffsetY(iWhichVector)
Select Case iType
Case cDrawStart:
'PSet (x1, y1), CurrentColor
iShapeCount = iShapeCount + 1
Case cDrawLine:
Line (x1, y1)-(x2, y2), CurrentColor
'RotoLine x1, y1, x2, y2, arrVectorWeight(iWhichVector), CurrentColor
Case cLastLine:
Line (x1, y1)-(x2, y2), CurrentColor
'RotoLine x1, y1, x2, y2, arrVectorWeight(iWhichVector), CurrentColor
Case cEndAll:
' EXIT LOOP
Exit For
Case Else:
' {DO NOTHING)
End Select
Next iPoint
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' NOW THAT THE SHAPE OUTLINE IS DRAWN,
' USE FLOOD FILL (e.g., Paint) TO MAKE IT SOLID IN COLOR CurrentColor
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
For iShapeCount = LBound(arrFillX) To UBound(arrFillX)
' Get coords for fill point
xFill = arrFillX(iShapeCount) * arrScalingFactor(iWhichVector)
yFill = arrFillY(iShapeCount) * arrScalingFactor(iWhichVector)
'PAINT [STEP] (column%, row%), fillColor[, borderColor%]
Paint (xFill, yFill), CurrentColor, CurrentColor
' OTHER FILL METHODS WHICH WEREN'T AS FAST:
'Paint2 xFill, yFill, CurrentColor
'PaintMask2 xFill, yFill, CurrentColor, _RGB32(255, 255, 255)
Next iShapeCount
' COPY SHAPE TO VECTOR LAYER
_PutImage (arrOffsetX(iWhichVector), arrOffsetY(iWhichVector)), NextImage, VectorImage
' TODO: instead of a solid color, use logo as a mask for the inverse color of the background
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' NOW MOVE THE SHAPE AND INCREASE THE SIZE
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' MOVE IT X / Y (UP / DOWN / RIGHT / LEFT)
arrOffsetX(iWhichVector) = arrOffsetX(iWhichVector) + arrOffsetDX(iWhichVector)
arrOffsetY(iWhichVector) = arrOffsetY(iWhichVector) + arrOffsetDY(iWhichVector)
'' ACCELERATE THE X / Y MOVEMENT AS THE SHAPE GETS CLOSER
'arrOffsetDX(iWhichVector) = arrOffsetDX(iWhichVector) * 2
'arrOffsetDY(iWhichVector) = arrOffsetDY(iWhichVector) * 2
' MOVE IT ALONG Z AXIS (FORWARD / BACK)
'arrScalingFactor(iWhichVector) = arrScalingFactor(iWhichVector) + 0.05
arrScalingFactor(iWhichVector) = arrScalingFactor(iWhichVector) + arrScaleIncrement(iWhichVector)
'This was when we used the RotoLine method:
'' LINE GETS THICKER AS IT GETS CLOSER
''arrVectorWeight(iWhichVector) = iPixelsPerInch * (1/8) * sngScale
'arrVectorWeight(iWhichVector) = arrVectorWeight(iWhichVector) * 1.01
' ACCELERATE SCALING FACTOR INCREMENT
arrScaleIncrement(iWhichVector) = arrScaleIncrement(iWhichVector) * 1.01
'arrScaleIncrement(iWhichVector) = arrScaleIncrement(iWhichVector) * 1.1
' HAS IT MOVED PAST US & TIME TO CREATE A NEW ONE?
'if arrScalingFactor(iWhichVector) >= sngMaxScale _orelse arrOffsetX(iWhichVector) > _width _orelse arrOffsetY(iWhichVector) > _height _orelse arrOffsetX(iWhichVector) < 0 _orelse arrOffsetY(iWhichVector) < 0 then
If arrScalingFactor(iWhichVector) >= sngMaxScale Then
' KILL IT, MAKE AVAILABLE FOR RESPAWN
arrScalingFactor(iWhichVector) = 0
End If
End If
End If
Next index
' ================================================================================================================================================================
' END DRAW + MOVE VECTOR
' ================================================================================================================================================================
' ================================================================================================================================================================
' BEGIN SPAWN VECTOR
' ================================================================================================================================================================
If bSpawn = _TRUE And bEnableFlyingVH = _TRUE Then
' FIND AN UNUSED ONE
iWhichVector = LBound(arrScalingFactor) - 1
For index = LBound(arrScalingFactor) To UBound(arrScalingFactor)
If arrScalingFactor(index) = 0 Then
iWhichVector = index
Exit For
End If
Next index
' IF ONE IS AVAIALBLE THEN INITIALIZE
If iWhichVector >= LBound(arrScalingFactor) Then
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' MOVE SPAWN POINT
VectorX = VectorX + VectorDX
If VectorX > _Width Then VectorX = 0 Else If VectorX < 0 Then VectorX = _Width
VectorY = VectorY + VectorDY
If VectorY > _Height Then VectorY = 0 Else If VectorY < 0 Then VectorY = _Height
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' GET NEXT COLOR
iWhichColor = iWhichColor + 1
If iWhichColor > UBound(m_SpectrumColorArray) Then iWhichColor = LBound(m_SpectrumColorArray)
arrColor(iWhichVector) = m_SpectrumColorArray(iWhichColor)
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' START LOGO SMALL
arrScalingFactor(iWhichVector) = .01
'sngScalingFactor = .01
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' SCALE INCREMENT = how fast it moves closer
' halfway = 500, to get to 0.05, multiply by what? 500x = .05, x = .05/500 = .0001
arrScaleIncrement(iWhichVector) = sngScaleIncrement
'' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
'' START LINE WEIGHT THIN
''arrVectorWeight(iWhichVector) = (iPixelsPerInch * (1/8) * sngScale) * .25
'arrVectorWeight(iWhichVector) = 1
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' X POSITION
arrOffsetX(iWhichVector) = VectorX
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' X MOVEMENT
'if RandomNumber%(0, 1) = 0 then
If VectorDX < 0 Then
arrOffsetDX(iWhichVector) = 1
Else
arrOffsetDX(iWhichVector) = -1
End If
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' Y POSITION
arrOffsetY(iWhichVector) = VectorY
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' Y MOVEMENT
'if RandomNumber%(0, 1) = 0 then
If VectorDY < 0 Then
arrOffsetDY(iWhichVector) = 1
Else
arrOffsetDY(iWhichVector) = -1
End If
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' RE-CALCULATE Z-ORDER FOR SHAPES
For iWhichVector = 0 To iNumVectors
arrZOrder(iWhichVector) = 0
arrShapeSort(iWhichVector) = -1
Next iWhichVector
iOrder = 0
Do
BiggestShapeScale = 0
BiggestShapeIndex = -1
For iWhichVector = 0 To iNumVectors
' Only enabled shapes
If arrScalingFactor(iWhichVector) > 0 Then
' Only unsorted shapes
If arrZOrder(iWhichVector) = 0 Then
If arrScalingFactor(iWhichVector) > BiggestShapeScale Then
BiggestShapeScale = arrScalingFactor(iWhichVector)
BiggestShapeIndex = iWhichVector
End If
End If
End If
Next iWhichVector
If BiggestShapeIndex >= 0 Then
iOrder = iOrder + 1
arrZOrder(BiggestShapeIndex) = iOrder
arrShapeSort(iOrder - 1) = BiggestShapeIndex
Else
Exit Do
End If
Loop
' ****************************************************************************************************************************************************************
' BEGIN DEBUG
' ****************************************************************************************************************************************************************
'PrintDebugFile "--------------------------------------------------------------------------------"
'PrintDebugFile _
' PadLeft$( "Z-Order" + " " + _
' PadLeft$( "Index") + " " + _
' PadLeft$( "ScalingFactor" + " " + _
' ""
'For iWhichVector = 0 To iNumVectors
' PrintDebugFile _
' PadLeft$( _ToStr$(arrZOrder(iWhichVector)), 7) + " " + _
' PadLeft$( _ToStr$(iWhichVector) , 5) + " " + _
' PadLeft$( SngRoundedToStr$(arrScalingFactor(iWhichVector), 3), 13) + " " + _
' ""
'Next iWhichVector
' ****************************************************************************************************************************************************************
' END DEBUG
' ****************************************************************************************************************************************************************
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' UNTIL WE MEET AGAIN!
bSpawn = _FALSE
End If
End If
' ================================================================================================================================================================
' END SPAWN VECTOR
' ================================================================================================================================================================
' COPY FINAL TO SCREEN
_Dest 0
_PutImage (0, 0), image1, 0
_PutImage (0, 0), VectorImage, 0
' ****************************************************************************************************************************************************************
' BEGIN DEBUGGING CODE
' ****************************************************************************************************************************************************************
'_Dest 0
'Color White, Blue
'For iShapeCount = LBound(arrFillX) To UBound(arrFillX)
' in$ = in$ + "arrFillX(" + _ToStr$(iShapeCount) + ")=" + _ToStr$(arrFillX(iShapeCount)) + " "
' in$ = in$ + "arrFillY(" + _ToStr$(iShapeCount) + ")=" + _ToStr$(arrFillY(iShapeCount)) + " "
'Next iShapeCount
'in$ = "LBound(arrFillX=" + _ToStr$(LBound(arrFillX)) + " UBound(arrFillX)=" + _ToStr$(UBound(arrFillX))
''in$ = "VectorX=" + _ToStr$(VectorX) + " VectorY=" + _ToStr$(VectorY)
'_PrintString (100, 100), "HELLO: " + in$
' ****************************************************************************************************************************************************************
' END DEBUGGING CODE
' ****************************************************************************************************************************************************************
' ****************************************************************************************************************************************************************
' BEGIN DEBUGGING CODE
' ****************************************************************************************************************************************************************
'' SEE LINE POSITION:
'Color fgPromptColor, bgPromptColor
'index = 0
'Locate 10, 1
'Print "x1=" + _ToStr$(arrStripe(index).x1)
'Print "y1=" + _ToStr$(arrStripe(index).y1)
'Print "x2=" + _ToStr$(arrStripe(index).x2)
'Print "y2=" + _ToStr$(arrStripe(index).y2)
'Locate 15, 1
'Print "dx1=" + _ToStr$(arrStripe(index).dx1)
'Print "dy1=" + _ToStr$(arrStripe(index).dy1)
'Print "dx2=" + _ToStr$(arrStripe(index).dx2)
'Print "dy2=" + _ToStr$(arrStripe(index).dy2)
'
'' SEE SPEED DELAY VALUE + ANIMATION FLAGS
'Color fgPromptColor, bgPromptColor
'Locate 20, 1
'Print "iDelayMS=" + _ToStr$(iDelayMS)
'Print "bMove =" + TrueFalse$(bMove)
'Print "bEnableAnimation=" + TrueFalse$(bEnableAnimation)
' ****************************************************************************************************************************************************************
' END DEBUGGING CODE
' ****************************************************************************************************************************************************************
' REFRESH DISPLAY
_Display
' WAIT FOR NEXT TIMER EVENT
If iDelayMS > 0 Then bMove = _FALSE
End If
' ================================================================================================================================================================
' END DRAW
' ================================================================================================================================================================
' ================================================================================================================================================================
' BEGIN WHAT NEXT
' ================================================================================================================================================================
' =============================================================================
' SHOW RESULTS + WAIT FOR USER
' =============================================================================
If bMiniMenuIsVisible = _TRUE Then
't2 = Timer
'Locate MaxRow - 2, 1: Print _ToStr$(t2 - t1) + " seconds to draw " + _ToStr$(iStripeCount) + " randomly generated lines.";
bRefresh = _TRUE
bSavedJPG = _FALSE
bSavedPNG = _FALSE
sPrompt = "PRESS " + _
_IIF(bSavedJPG=_FALSE, "J TO SAVE JPG, ", Space$(15)) + _
_IIF(bSavedPNG=_FALSE, "P TO SAVE PNG, ", Space$(15)) + _
"N/M TO HIDE/SHOW THIS MENU, ENTER TO REPAINT, SPACE FOR OPTIONS, ESC TO QUIT" + _
""
Color fgPromptColor, bgPromptColor
Locate MaxRow - 2, (MaxCol - Len(sPrompt)) / 2: Print sPrompt;
Color _RGBA32(0, 0, 0, 0), _RGBA32(0, 0, 0, 0)
_Display
Else
' SHOW KEYS TO EXIT IN TITLE BAR
_Title "Van Halenizer v2.02 - SPACE=MAIN MENU, UP/DOWN=SPEED, HOME/END=TOGGLE FULLSCREEN, ESC=QUIT"
End If
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' BEGIN GET USER INPUT
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
If bEnableAnimation = _TRUE Then
' WHILE ANIMATION IS ENABLED
' CHECK FOR INPUT SO USER CAN RETURN TO MAIN MENU, ETC.
' M = ENABLE, N=DISABLE MENU
If _KeyDown(cUpperM) Or _KeyDown(cLowerM) Then
bMiniMenuIsVisible = _TRUE
bRefresh = _TRUE
ElseIf _KeyDown(cUpperN) Or _KeyDown(cLowerN) Then
bMiniMenuIsVisible = _FALSE
bRefresh = _TRUE
End If
' UP/DOWN = SLOW DOWN/SPEED UP
If _KeyDown(cDownKD) Then
iDelayMS = iDelayMS + 1
If iDelayMS > 60000 Then iDelayMS = 60000
'bMove = _TRUE
NextTime = ExtendedTimer + (iDelayMS * .001) ' SCHEDULE IT AGAIN IN 5 SECONDS
ElseIf _KeyDown(cUpKD) Then
iDelayMS = iDelayMS - 1
If iDelayMS < 0 Then iDelayMS = 0
bMove = _TRUE
NextTime = ExtendedTimer + (iDelayMS * .001) ' SCHEDULE IT AGAIN IN 5 SECONDS
End If
' HOME = DECREASE TIME, END = INCREASE TIME
If _KeyDown(cHome) Then
iCycleEverySeconds = iCycleEverySeconds + 1
If iCycleEverySeconds > 86400 Then iCycleEverySeconds = 86400 ' Max time = 1 day
bRefresh = _TRUE
ElseIf _KeyDown(cEnd) Then
iCycleEverySeconds = iCycleEverySeconds - 1
If iCycleEverySeconds < 0 Then iCycleEverySeconds = 0 ' 0 means color scheme doesn't cycle
bRefresh = _TRUE
End If
' for some reason enable/disable animation while graphics are displayed doesn't work right
' * if we disable animate, it doesn't display the Save menu, have to press space to go back to the main menu
' * if we enable animate, everything freezes and won't unfreeze unless we goto PaintGuitar
'' A/Z = ENABLE / DISABLE ANIMATE
'If _KeyDown(cUpperA) Or _KeyDown(cLowerA) Then
' bEnableAnimation = _TRUE
' bRefresh = _TRUE : sPrompt = ""
' GoTo PaintGuitar
'ElseIf _KeyDown(cUpperZ) Or _KeyDown(cLowerZ) Then
' bEnableAnimation = _FALSE
' bRefresh = _TRUE : sPrompt = "" : _Title "Van Halenizer v2.02"
' GoTo PaintGuitar
'End If
' ENTER = REPAINT
' Did they press Enter (makes sure Enter key was released first)
If _KeyDown(cEnter) Then
If arrKeyState(KeyCode_Enter) = _FALSE Then
arrKeyState(KeyCode_Enter) = _TRUE
GoTo ResetTimer
End If
Else
arrKeyState(KeyCode_Enter) = _FALSE
End If
' SPACE = RETURN TO MENU
If _KeyDown(cSpace) Then GoTo LoopBackToMainMenu ' Exit Do
' ESC = QUIT
If _KeyDown(cEsc) Then GoTo CleanupAndExit
' $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
' TIMED EVENT
' $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
If iCycleEverySeconds > 0 Then
If ExtendedTimer > NextColor Then
' CYCLE COLOR SCHEME
iColorSchemeIndex = iColorSchemeIndex + 1
If iColorSchemeIndex > UBound(arrColorScheme) Then iColorSchemeIndex = LBound(arrColorScheme)
NextColor = ExtendedTimer + iCycleEverySeconds ' SCHEDULE COLOR SCHEME TO CHANGE IN iCycleEverySeconds SECONDS
NextRepaint = ExtendedTimer + iRepaintEverySeconds ' SCHEDULE REPAINT IN iRepaintEverySeconds SECONDS
bCycleColor = _TRUE
GoTo ChangeColorScheme
End If
End If
If iRepaintEverySeconds > 0 Then
If ExtendedTimer > NextRepaint Then
' PAINT A NEW ONE
NextRepaint = ExtendedTimer + iRepaintEverySeconds ' SCHEDULE REPAINT IN iRepaintEverySeconds SECONDS
bRepaint = _TRUE
GoTo PaintGuitar
'GoTo ChangeColorScheme
End If
End If
If iVectorEveryMS > 0 Then
If ExtendedTimer > NextVector Then
' SPAWN A NEW VECTOR
NextVector = ExtendedTimer + iVectorEveryMS * 0.001 ' SCHEDULE NEW VECTOR SPAWNED IN iVectorEveryMS MILLISECONDS
bSpawn = _TRUE
End If
End If
Else
Do
' M = ENABLE, N=DISABLE MENU
If _KeyDown(cUpperM) Or _KeyDown(cLowerM) Then
bMiniMenuIsVisible = _TRUE
bRefresh = _TRUE
ElseIf _KeyDown(cUpperN) Or _KeyDown(cLowerN) Then
bMiniMenuIsVisible = _FALSE
bRefresh = _TRUE
End If
' J = SAVE TO JPEG (IF NOT ALREADY SAVED TO JPEG)
If _KeyDown(cUpperJ) Or _KeyDown(cLowerJ) Then
If bSavedJPG = _FALSE Then
bSavedJPG = SaveImage%%(image1, "JPG")
If bSavedJPG Then sPrompt = "" : beep
End If
End If
' P = SAVE TO PNG (IF NOT ALREADY SAVED TO PNG)
If _KeyDown(cUpperP) Or _KeyDown(cLowerP) Then
If bSavedPNG = _FALSE Then
bSavedPNG = SaveImage%%(image1, "PNG")
If bSavedPNG Then sPrompt = "" : beep
End If
End If
' HOME = DECREASE TIME, END = INCREASE TIME
If _KeyDown(cHome) Then
iCycleEverySeconds = iCycleEverySeconds + 1
If iCycleEverySeconds > 86400 Then iCycleEverySeconds = 86400 ' Max time = 1 day
bRefresh = _TRUE
ElseIf _KeyDown(cEnd) Then
iCycleEverySeconds = iCycleEverySeconds - 1
If iCycleEverySeconds < 0 Then iCycleEverySeconds = 0 ' 0 means color scheme doesn't cycle
bRefresh = _TRUE
End If
'' for some reason if we disable animate, it doesn't display the Save menu
'' A = (RE)ENABLE ANIMATE
'If _KeyDown(cUpperA) Or _KeyDown(cLowerA) Then
' 'Sound 800, .15 ' iPitch% = 800
' bEnableAnimation = _TRUE
' bRefresh = _TRUE : sPrompt = "" : _Title "Van Halenizer v2.02"
' 'NextTime = ExtendedTimer + 1 ' SCHEDULE IT AGAIN IN 1 SECOND
' 'iDelayMS = 0 ' reset delay
' 'sPrompt = ""
' ' for some reason everything freezes and won't unfreeze unless we goto PaintGuitar
' GoTo PaintGuitar
'End If
' ENTER = REPAINT
If _KeyDown(cEnter) Then
If arrKeyState(KeyCode_Enter) = _FALSE Then
arrKeyState(KeyCode_Enter) = _TRUE
bSavedJPG = _FALSE
bSavedPNG = _FALSE
GoTo ResetTimer
End If
Else
arrKeyState(KeyCode_Enter) = _FALSE
End If
' SPACE = RETURN TO MENU
If _KeyDown(cSpace) Then GoTo LoopBackToMainMenu ' Exit Do
' ESC = QUIT
If _KeyDown(cEsc) Then GoTo CleanupAndExit
' Redraw prompt?
If Len(sPrompt) = 0 Then
sPrompt = "PRESS " + _
_IIF(bSavedJPG=_FALSE, "J TO SAVE JPG, ", Space$(15)) + _
_IIF(bSavedPNG=_FALSE, "P TO SAVE PNG, ", Space$(15)) + _
"ENTER TO REPAINT, SPACE FOR OPTIONS, ESC TO QUIT" + _
""
Color fgPromptColor, bgPromptColor
Locate MaxRow - 2, (MaxCol - Len(sPrompt)) / 2: Print sPrompt
End If
' $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
' TIMED EVENT
' $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
If iCycleEverySeconds > 0 Then
If ExtendedTimer > NextColor Then
' CYCLE COLOR SCHEME
iColorSchemeIndex = iColorSchemeIndex + 1
If iColorSchemeIndex > UBound(arrColorScheme) Then iColorSchemeIndex = LBound(arrColorScheme)
NextColor = ExtendedTimer + iCycleEverySeconds ' SCHEDULE COLOR SCHEME TO CHANGE IN iCycleEverySeconds SECONDS
NextRepaint = ExtendedTimer + iRepaintEverySeconds ' SCHEDULE REPAINT IN iRepaintEverySeconds SECONDS
bCycleColor = _TRUE
GoTo ChangeColorScheme
End If
End If
If iRepaintEverySeconds > 0 Then
If ExtendedTimer > NextRepaint Then
' PAINT A NEW ONE
NextRepaint = ExtendedTimer + iRepaintEverySeconds ' SCHEDULE REPAINT IN iRepaintEverySeconds SECONDS
bRepaint = _TRUE
GoTo PaintGuitar
'GoTo ChangeColorScheme
End If
End If
Loop
End If
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' END GET USER INPUT
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
' UPDATE SCREEN
_Display
_Limit 60
Loop
' ================================================================================================================================================================
' END WHAT NEXT
' ================================================================================================================================================================
' START OVER AT MAIN MENU
LoopBackToMainMenu:
Loop
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END MAIN LOOP
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CleanupAndExit:
' SAVE SETTINGS TO CONFIG FILE
sNextError = SaveConfig$
If Len(sNextError) > 0 Then
Cls , Black
Color White, Red
Print sNextError
End If
' RESET DISPLAY AND CLEAR IMAGES
_AutoDisplay
FreeImage image1
FreeImage image2
FreeImage VectorImage
FreeImage NextImage
If _FullScreen Then _FullScreen _Off
' BEGIN DEBUG
'in$ = _InputBox$(m_ProgramName, "debug file", m_ProgramPath$ + m_ProgramName$ + ".txt")
' END DEBUG
End Sub ' VanHalenizer
' /////////////////////////////////////////////////////////////////////////////
' based on
'
' bplus: The Gold Standard is even better than THE QB64 CIRCLE sub in this respect!
' https://forum.qb64.org/index.php?topic=1044.135
' from Steve Gold standard
' Renamed fcirc to DrawCircleSolid
' Not as fast as DrawCircleTopLeft but pretty fast.
' Example:
' Screen _NewImage(800, 600, 32)
' _ScreenMove 250, 60
' For r = 250 To 0 Step -60
' DrawCircleSolid 400, 300, r, _RGBA(255, 255, 255, 100)
' Next r
'DrawSolidCircle 0, iX, iY, iRadius, fgColor
Sub DrawSolidCircle (TargetImage As Long, iX As Long, iY As Long, iRadius As Integer, fgColor As _Unsigned Long)
Dim iNextRadius As Integer
Dim iRadiusError As Integer
Dim iNextX As Integer
Dim iNextY As Integer
'If TargetImage < -1 _orelse TargetImage > 0 then
If (TargetImage <= 0) Then
' Select target image
_Dest TargetImage ': Cls , cEmpty
' Draw circle fill
iNextRadius = Abs(iRadius)
iRadiusError = -iNextRadius
iNextX = iNextRadius
iNextY = 0
If iNextRadius = 0 Then
PSet (iX, iY), fgColor
Else
' Draw the middle span here so we don't draw it twice in the main loop,
' which would be a problem with blending turned on.
Line (iX - iNextX, iY)-(iX + iNextX, iY), fgColor, BF
While iNextX > iNextY
iRadiusError = iRadiusError + iNextY * 2 + 1
If iRadiusError >= 0 Then
If iNextX <> iNextY + 1 Then
Line (iX - iNextY, iY - iNextX)-(iX + iNextY, iY - iNextX), fgColor, BF
Line (iX - iNextY, iY + iNextX)-(iX + iNextY, iY + iNextX), fgColor, BF
End If
iNextX = iNextX - 1
iRadiusError = iRadiusError - iNextX * 2
End If
iNextY = iNextY + 1
Line (iX - iNextX, iY - iNextY)-(iX + iNextX, iY - iNextY), fgColor, BF
Line (iX - iNextX, iY + iNextY)-(iX + iNextX, iY + iNextY), fgColor, BF
Wend
End If
End If
End Sub ' DrawSolidCircle
' /////////////////////////////////////////////////////////////////////////////
Function DataTypeToString$ (MyValue As Integer)
Dim MyString As String
Select Case MyValue
Case cDrawStart:
MyString = "cDrawStart"
Case cDrawLine:
MyString = "cDrawLine"
Case cLastLine:
MyString = "cLastLine"
Case cEndAll:
MyString = "cEndAll"
Case Else:
MyString = _ToStr$(MyValue)
End Select
DataTypeToString$ = MyString
End Function ' DataTypeToString$
' /////////////////////////////////////////////////////////////////////////////
Function GetDefaultScale%
'iScaleToPercent = cScaleToPercent
If _DesktopWidth >= 3840 Then
GetDefaultScale% = 125
ElseIf _DesktopWidth >= 1920 Then
GetDefaultScale% = 110
ElseIf _DesktopWidth >= 1280 Then
GetDefaultScale% = 100
ElseIf _DesktopWidth >= 1024 Then
GetDefaultScale% = 80
ElseIf _DesktopWidth >= 800 Then
GetDefaultScale% = 60
Else
GetDefaultScale% = 50
End If
End Function ' GetDefaultScale%
' /////////////////////////////////////////////////////////////////////////////
Function LoadConfig$
Dim sError As String
Dim sNextError As String
Dim iLoop1 As Integer
Dim iLoop2 As Integer
ReDim NameArray$(-1 To -1)
ReDim ValuArray$(-1 To -1)
Dim sCompareName As String
Dim sCompareValu As String
Dim MyInteger As Integer
Dim MyLong As Long
Dim MyByte As _Byte
' READ IN NAMES + VALUES AS TEXT FROM CONFIG FILE
sError = ReadConfig$(NameArray$(), ValuArray$())
' DID VALUES LOAD?
If Len(sError) = 0 Then
' POPULATE VARIABLES WITH CONVERTED VALUES
' NAME VARIABLE VALUE RANGE TYPE
' ----------------------- --------------- ------------ -------
' ScreenWidth iScreenWidth 0 or 640 - _DesktopWidth Long
' ScreenHeight iScreenHeight 0 or 480 - _DesktopHeight Long
' ScaleToPercent iScaleToPercent 1-1000 (percent) Integer
' EnableAnimation bEnableAnimation True / False _Byte
' DelayMS iDelayMS 0-60000 (ms) Long
' MiniMenuIsVisible bMiniMenuIsVisible True / False _Byte
' FilenameTemplate sFilenameTemplate (any valid filename) String
' EnableSaveResultsPopup bEnableSaveResultsPopup True / False _Byte
' CycleEverySeconds iCycleEverySeconds 0-86400 (seconds) Long
' RepaintEverySeconds iRepaintEverySeconds 0-3600 (seconds) Long
' ColorSchemeIndex iColorSchemeIndex 0-7 Integer
' BaseStripeCount iBaseStripeCount 1-500 Integer
' StripeVariance iStripeVariance 1-250 Integer
' ----------------------- --------------- ------------ -------
' EnableFlyingVH bEnableFlyingVH True / False _Byte
' NumVectors iNumVectors 1-100 Integer
' VectorEveryMS iVectorEveryMS 50-9999 (ms) Integer
' MinDX iMinDX 1-8192 (px) Integer
' MaxDX iMaxDX 1-8192 (px) Integer
' MaxScale iMaxScale 1-1000 (percent) Integer
' ScaleIncrement iScaleIncrement 1000-5000 (micro %) Long
' TODO: turn all this validation into a reusable function(sCompareValu, bStripMinus, iMinLen, iMaxLen, iMinValue, iMaxValue)
For iLoop1 = LBound(NameArray$) To UBound(NameArray$)
sCompareName = LCase$(NameArray$(iLoop1))
sCompareValu = LCase$(_Trim$(ValuArray$(iLoop1)))
sCompareValu = Replace$(sCompareValu, "-", "")
sCompareValu = Replace$(sCompareValu, " ", "")
Select Case sCompareName
Case LCase$("ScreenWidth"):
If IsNumber%(sCompareValu) Then
If Len(sCompareValu) <= 4 Then
iScreenWidth = _Cast(Long, Val(sCompareValu))
If iScreenWidth < 640 Then iScreenWidth = _DesktopWidth Else If iScreenWidth > _DesktopWidth Then iScreenWidth = _DesktopWidth
Else
iScreenWidth = _DesktopWidth
End If
Else
iScreenWidth = _DesktopWidth
End If
Case LCase$("ScreenHeight"):
If IsNumber%(sCompareValu) Then
If Len(sCompareValu) <= 4 Then
iScreenHeight = _Cast(Long, Val(sCompareValu))
If iScreenHeight < 480 Then iScreenHeight = _DesktopHeight Else If iScreenHeight > _DesktopHeight Then iScreenHeight = _DesktopHeight
Else
iScreenHeight = _DesktopHeight
End If
Else
iScreenHeight = _DesktopHeight
End If
Case LCase$("ScaleToPercent"):
If IsNumber%(sCompareValu) Then
If Len(sCompareValu) <= 4 Then
iScaleToPercent = _Cast(Integer, Val(sCompareValu))
If iScaleToPercent < 1 Then iScaleToPercent = GetDefaultScale% Else If iScaleToPercent > 1000 Then iScaleToPercent = GetDefaultScale%
Else
iScaleToPercent = GetDefaultScale%
End If
Else
iScaleToPercent = GetDefaultScale%
End If
Case LCase$("EnableAnimation"):
bEnableAnimation = (sCompareValu = "true")
Case LCase$("DelayMS"):
If IsNumber%(sCompareValu) Then
If Len(sCompareValu) <= 5 Then
iDelayMS = _Cast(Long, Val(sCompareValu))
If iDelayMS < 0 Then iDelayMS = cDelayMS Else If iDelayMS > 86400 Then iDelayMS = cDelayMS
Else
iDelayMS = cDelayMS
End If
Else
iDelayMS = cDelayMS
End If
Case LCase$("MiniMenuIsVisible"):
bMiniMenuIsVisible = (sCompareValu = "true")
Case LCase$("FilenameTemplate"):
sFilenameTemplate = _IIf(Len(sCompareValu) > 0, sCompareValu, cFilenameTemplate)
Case LCase$("EnableSaveResultsPopup"):
bEnableSaveResultsPopup = (sCompareValu = "true")
Case LCase$("CycleEverySeconds"):
If IsNumber%(sCompareValu) Then
If Len(sCompareValu) <= 5 Then
iCycleEverySeconds = _Cast(Long, Val(sCompareValu))
If iCycleEverySeconds < 0 Then iCycleEverySeconds = cCycleEverySeconds Else If iCycleEverySeconds > 86400 Then iCycleEverySeconds = cCycleEverySeconds
Else
iCycleEverySeconds = cCycleEverySeconds
End If
Else
iCycleEverySeconds = cCycleEverySeconds
End If
Case LCase$("RepaintEverySeconds"):
If IsNumber%(sCompareValu) Then
If Len(sCompareValu) <= 5 Then
iRepaintEverySeconds = _Cast(Integer, Val(sCompareValu))
If iRepaintEverySeconds < 0 Then iRepaintEverySeconds = cRepaintEverySeconds Else If iRepaintEverySeconds > 3000 Then iRepaintEverySeconds = cRepaintEverySeconds
Else
iRepaintEverySeconds = cRepaintEverySeconds
End If
Else
iRepaintEverySeconds = cRepaintEverySeconds
End If
Case LCase$("ColorSchemeIndex"):
If IsNumber%(sCompareValu) Then
If Len(sCompareValu) <= 4 Then
iColorSchemeIndex = _Cast(Integer, Val(sCompareValu))
'TODO: test iColorSchemeIndex against boundaries of array
Else
iColorSchemeIndex = cColorSchemeIndex
End If
Else
iColorSchemeIndex = cColorSchemeIndex
End If
Case LCase$("BaseStripeCount"):
If IsNumber%(sCompareValu) Then
If Len(sCompareValu) <= 4 Then
iBaseStripeCount = _Cast(Long, Val(sCompareValu))
If iBaseStripeCount < 1 Then iBaseStripeCount = cBaseStripeCount Else If iBaseStripeCount > 500 Then iBaseStripeCount = cBaseStripeCount
Else
iBaseStripeCount = cBaseStripeCount
End If
Else
iBaseStripeCount = cBaseStripeCount
End If
Case LCase$("StripeVariance"):
If IsNumber%(sCompareValu) Then
If Len(sCompareValu) <= 4 Then
iStripeVariance = _Cast(Long, Val(sCompareValu))
If iStripeVariance < 1 Then iStripeVariance = cStripeVariance Else If iStripeVariance > 250 Then iStripeVariance = cStripeVariance
Else
iStripeVariance = cStripeVariance
End If
Else
iStripeVariance = cStripeVariance
End If
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
Case LCase$("EnableFlyingVH"):
bEnableFlyingVH = (sCompareValu = "true")
Case LCase$("NumVectors"):
If IsNumber%(sCompareValu) Then
If Len(sCompareValu) <= 4 Then
iNumVectors = _Cast(Integer, Val(sCompareValu))
Else
iNumVectors = cNumVectors
End If
Else
iNumVectors = cNumVectors
End If
Case LCase$("VectorEveryMS"):
If IsNumber%(sCompareValu) Then
If Len(sCompareValu) <= 4 Then
iVectorEveryMS = _Cast(Integer, Val(sCompareValu))
Else
iVectorEveryMS = cVectorEveryMS
End If
Else
iVectorEveryMS = cVectorEveryMS
End If
Case LCase$("MinDX"):
If IsNumber%(sCompareValu) Then
If Len(sCompareValu) <= 4 Then
iMinDX = _Cast(Integer, Val(sCompareValu))
Else
iMinDX = cMinDX
End If
Else
iMinDX = cMinDX
End If
Case LCase$("MaxDX"):
If IsNumber%(sCompareValu) Then
If Len(sCompareValu) <= 4 Then
iMaxDX = _Cast(Integer, Val(sCompareValu))
Else
iMaxDX = cMaxDX
End If
Else
iMaxDX = cMaxDX
End If
Case LCase$("MaxScale"):
If IsNumber%(sCompareValu) Then
If Len(sCompareValu) <= 4 Then
iMaxScale = _Cast(Integer, Val(sCompareValu))
Else
iMaxScale = cMaxScale
End If
Else
iMaxScale = cMaxScale
End If
Case LCase$("ScaleIncrement"):
If IsNumber%(sCompareValu) Then
If Len(sCompareValu) <= 4 Then
iScaleIncrement = _Cast(Long, Val(sCompareValu))
Else
iScaleIncrement = cScaleIncrement
End If
Else
iScaleIncrement = cScaleIncrement
End If
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
End Select
Next iLoop1
Else
' VALUES DIDN'T LOAD - WRITE A NEW CONFIG FILE
sNextError = SaveConfig$
If Len(sNextError) = 0 Then
'sError = "ReadConfig$ failed: " + sError + chr$(13) + "Saved settings to new config file."
sError = ""
Else
sError = "ReadConfig$ failed: " + sError + Chr$(13) + "SaveConfig$ failed: " + sNextError
End If
End If
LoadConfig$ = sError
End Function ' LoadConfig$
' /////////////////////////////////////////////////////////////////////////////
' NameValueArray$ must be declared:
' ReDim NameValueArray$(-1, 0 To 1)
Function ReadConfig$ (NameArray$(), ValuArray$())
Dim RoutineName As String:: RoutineName = "ReadConfig$"
Dim sError As String: sError = ""
Dim sFName As String
Dim sFile As String
Dim sLine As String
Dim sName As String
Dim sValue As String
'Dim iLineNum As Integer
' Get file name
If Len(sError) = 0 Then
sFName = Left$(m_ProgramName$, _InStrRev(m_ProgramName$, ".")) + "cfg"
sFile = m_ProgramPath + sFName
End If
' Make sure file exists
If Len(sError) = 0 Then
If _FileExists(sFile) = _FALSE Then
sError = "File not found: " + Chr$(34) + sFile + Chr$(34)
End If
End If
' Read data from file
If Len(sError) = 0 Then
Open sFile For Input As #1
'iLineNum = 0
While Not EOF(1)
Line Input #1, sLine ' read entire text file line
'iLineNum = iLineNum + 1
sLine = Replace$(sLine, Chr$(160), Chr$(32))
GetPair sLine, sName, sValue
If Len(sName) > 0 Then
ReDim _Preserve NameArray$(0 To UBound(NameArray$) + 1)
NameArray$(UBound(NameArray$)) = sName
ReDim _Preserve ValuArray$(0 To UBound(ValuArray$) + 1)
ValuArray$(UBound(ValuArray$)) = sValue
End If
Wend
Close #1
If LBound(NameArray$) <> LBound(ValuArray$) Then
sError = sError + _IIf(Len(sError) = 0, "", "; ") + "lbounds do not match"
End If
If UBound(NameArray$) <> UBound(ValuArray$) Then
sError = sError + _IIf(Len(sError) = 0, "", "; ") + "ubounds do not match"
End If
End If
' Return any error messages (blank string means no errors)
ReadConfig$ = sError
End Function ' ReadConfig$
' /////////////////////////////////////////////////////////////////////////////
Sub GetPair (MyString As String, MyName As String, MyValue As String)
Dim sLine As String
Dim iPos As Long
sLine = LTrim$(MyString)
If Len(sLine) > 0 _AndAlso Left$(sLine, 1) <> "#" _AndAlso Left$(sLine, 1) <> "[" Then
iPos = InStr(1, sLine, "=")
If iPos > 0 Then
MyName = _Trim$(Left$(sLine, iPos - 1))
MyValue = LTrim$(Right$(sLine, Len(sLine) - iPos))
Else
MyName = _Trim$(sLine)
End If
Else
MyName = "": MyValue = ""
End If
End Sub ' GetPair
'Sub GetPairTest
' GetPairTest1 "# A comment"
' GetPairTest1 ""
' GetPairTest1 "[My Section]"
' GetPairTest1 "name1 = value1 "
' GetPairTest1 " name2 = value2"
' GetPairTest1 "#name3 = value3"
' GetPairTest1 " # name4 = value4"
' GetPairTest1 "# name5 =# value5 "
' GetPairTest1 "name6"
' GetPairTest1 "name7="
'End Sub ' GetPairTest
'Sub GetPairTest1 (MyString As String)
' Static iCount As Integer
' Dim n$, v$
' iCount = iCount + 1
' GetPair MyString, n$, v$
' Print _ToStr$(iCount) + ". " + Chr$(34) + MyString + Chr$(34) + " returns " + _IIf(Len(n$) > 0, "MyName=" + Chr$(34) + n$ + Chr$(34) + " Myvalue=" + Chr$(34) + v$ + Chr$(34), "(Blank)")
'End Sub ' GetPairTest1
' /////////////////////////////////////////////////////////////////////////////
Function SaveConfig$
Dim RoutineName As String:: RoutineName = "SaveConfig$"
Dim sError As String: sError = ""
Dim sFName As String
Dim sFile As String
Dim sText As String
Dim sValue As String
' Get file name
If Len(sError) = 0 Then
sFName = Left$(m_ProgramName$, _InStrRev(m_ProgramName$, ".")) + "cfg"
sFile = m_ProgramPath + sFName
End If
' Populate template
If Len(sError) = 0 Then
sText = ""
sText = sText + "# Van Halenizer saved settings" + Chr$(13)
sText = sText + "" + Chr$(13)
sText = sText + "# =====================================================================================================================================================================" + Chr$(13)
sText = sText + "# SETTING VARIABLE VALID VALUES DESCRIPTION " + Chr$(13)
sText = sText + "# ------------------------- ----------------------- -------------------- -----------------------------------------------------------------------------------" + Chr$(13)
sText = sText + "# ScreenWidth iScreenWidth 0 or 640 - _DesktopWidth Horizontal screen resolution to use (0 = autodetect). " + Chr$(13)
sText = sText + "# ScreenHeight iScreenHeight 0 or 480 - _DesktopHeight Vertical screen resolution to use (0 = autodetect). " + Chr$(13)
sText = sText + "# ScaleToPercent iScaleToPercent 1-1000 (percent) Percent to scale stripe sizes up or down (100 = 100%). " + Chr$(13)
sText = sText + "# Resolution Recommended Value " + Chr$(13)
sText = sText + "# 640 x 480 45-55 " + Chr$(13)
sText = sText + "# 800 x 600 55-65 " + Chr$(13)
sText = sText + "# 1024 x 768 65-75 " + Chr$(13)
sText = sText + "# 1280 x 1024 95-105 " + Chr$(13)
sText = sText + "# 1920 x 1200 105-115 " + Chr$(13)
sText = sText + "# 3840 x 2160 125+ " + Chr$(13)
sText = sText + "# EnableAnimation bEnableAnimation True / False If True, stripes appear animated. " + Chr$(13)
sText = sText + "# DelayMS iDelayMS 0-60000 (ms) # milliseconds additional time delay to optionally slow down animation. " + Chr$(13)
sText = sText + "# MiniMenuIsVisible bMiniMenuIsVisible True / False If True, 1-line mini menu is displayed over images. " + Chr$(13)
sText = sText + "# FilenameTemplate sFilenameTemplate (any valid filename) Filename template for image save. Supports the following tags: " + Chr$(13)
sText = sText + "# ` ` ` Timestamp tags: {yyyy}{mm}{dd}{hh}{nn}{ss} " + Chr$(13)
sText = sText + "# ` ` ` Filename tags: {ext} " + Chr$(13)
sText = sText + "# EnableSaveResultsPopup bEnableSaveResultsPopup False If True, when image saved, inputbox opens with file path for copying to clipboard. " + Chr$(13)
sText = sText + "# CycleEverySeconds iCycleEverySeconds 0-86400 (seconds) # seconds before cycling to the next color scheme (0 = don't cycle color schemes). " + Chr$(13)
sText = sText + "# RepaintEverySeconds iRepaintEverySeconds 0-3600 (seconds) # seconds before generating a new set of stripes (0 = don't regenerate). " + Chr$(13)
sText = sText + "# ColorSchemeIndex iColorSchemeIndex 0-7 Index of the color scheme to start with (0 = the first one). " + Chr$(13)
sText = sText + "# BaseStripeCount iBaseStripeCount 1-500 (count) Base value to calculate # stripes to generate (percentage depends on color scheme)." + Chr$(13)
sText = sText + "# StripeVariance iStripeVariance 1-250 (count) For determining # of stripes, controls how random / wide a range # stripes can be. " + Chr$(13)
sText = sText + "# ------------------------- ----------------------- -------------------- -----------------------------------------------------------------------------------" + Chr$(13)
sText = sText + "# EnableFlyingVH bEnableFlyingVH True / False If True, flying VH logos adorn the screen " + Chr$(13)
sText = sText + "# NumVectors iNumVectors 1-100 (count) Max # of flying VH symbols on screen at a time " + Chr$(13)
sText = sText + "# VectorEveryMS iVectorEveryMS 50-9999 (ms) # milliseconds between spawning a new flying VH symbol " + Chr$(13)
sText = sText + "# MinDX iMinDX 0-8192 (px) Minimum speed spawn point can move (pixels) " + Chr$(13)
sText = sText + "# MaxDX iMaxDX 0-8192 (px) Maximum speed spawn point can move (pixels) " + Chr$(13)
sText = sText + "# MaxScale iMaxScale 1-1000 (percent) Maximum size (%) flying VH symbols reach before they disappear off the screen " + Chr$(13)
sText = sText + "# ScaleIncrement iScaleIncrement 1000-5000 (micro %) How fast (micro %) flying VH symbols grow (move toward you) " + Chr$(13)
sText = sText + "# =====================================================================================================================================================================" + Chr$(13)
sText = sText + "# For more 'psychedelic' effects try NumVectors=50 or 75, VectorEveryMS=50 or 75, MinDX=1, MaxDX=5 or 10, it can get slow with too many VHs but looks really cool " + Chr$(13)
sText = sText + "# =====================================================================================================================================================================" + Chr$(13)
sText = sText + "[Settings]" + Chr$(13)
sText = sText + "ScreenWidth = {ScreenWidth}" + Chr$(13)
sText = sText + "ScreenHeight = {ScreenHeight}" + Chr$(13)
sText = sText + "ScaleToPercent = {ScaleToPercent}" + Chr$(13)
sText = sText + "EnableAnimation = {EnableAnimation}" + Chr$(13)
sText = sText + "DelayMS = {DelayMS}" + Chr$(13)
sText = sText + "MiniMenuIsVisible = {MiniMenuIsVisible}" + Chr$(13)
sText = sText + "FilenameTemplate = {FilenameTemplate}" + Chr$(13)
sText = sText + "EnableSaveResultsPopup = {EnableSaveResultsPopup}" + Chr$(13)
sText = sText + "CycleEverySeconds = {CycleEverySeconds}" + Chr$(13)
sText = sText + "RepaintEverySeconds = {RepaintEverySeconds}" + Chr$(13)
sText = sText + "ColorSchemeIndex = {ColorSchemeIndex}" + Chr$(13)
sText = sText + "BaseStripeCount = {BaseStripeCount}" + Chr$(13)
sText = sText + "StripeVariance = {StripeVariance}" + Chr$(13)
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
sText = sText + "EnableFlyingVH = {EnableFlyingVH}" + Chr$(13)
sText = sText + "NumVectors = {NumVectors}" + Chr$(13)
sText = sText + "VectorEveryMS = {VectorEveryMS}" + Chr$(13)
sText = sText + "MinDX = {MinDX}" + Chr$(13)
sText = sText + "MaxDX = {MaxDX}" + Chr$(13)
sText = sText + "MaxScale = {MaxScale}" + Chr$(13)
sText = sText + "ScaleIncrement = {ScaleIncrement}" + Chr$(13)
sText = Replace$(sText, "`", Chr$(34))
If iScreenWidth = _DesktopWidth Then
sText = Replace$(sText, "{ScreenWidth}", "0")
Else
sText = Replace$(sText, "{ScreenWidth}", _ToStr$(iScreenWidth))
End If
If iScreenHeight = _DesktopHeight Then
sText = Replace$(sText, "{ScreenHeight}", "0")
Else
sText = Replace$(sText, "{ScreenHeight}", _ToStr$(iScreenHeight))
End If
sText = Replace$(sText, "{ScaleToPercent}", _ToStr$(iScaleToPercent))
sText = Replace$(sText, "{EnableAnimation}", _IIf(bEnableAnimation = _TRUE, "True", "False"))
sText = Replace$(sText, "{DelayMS}", _ToStr$(iDelayMS))
sText = Replace$(sText, "{MiniMenuIsVisible}", _IIf(bMiniMenuIsVisible = _TRUE, "True", "False"))
sText = Replace$(sText, "{FilenameTemplate}", sFilenameTemplate)
sText = Replace$(sText, "{EnableSaveResultsPopup}", _IIf(bEnableSaveResultsPopup = _TRUE, "True", "False"))
sText = Replace$(sText, "{CycleEverySeconds}", _ToStr$(iCycleEverySeconds))
sText = Replace$(sText, "{RepaintEverySeconds}", _ToStr$(iRepaintEverySeconds))
sText = Replace$(sText, "{ColorSchemeIndex}", _ToStr$(iColorSchemeIndex))
sText = Replace$(sText, "{BaseStripeCount}", _ToStr$(iBaseStripeCount))
sText = Replace$(sText, "{StripeVariance}", _ToStr$(iStripeVariance))
' ----------------------------------------------------------------------------------------------------------------------------------------------------------------
sText = Replace$(sText, "{EnableFlyingVH}", _IIf(bEnableFlyingVH = _TRUE, "True", "False"))
sText = Replace$(sText, "{NumVectors}", _ToStr$(iNumVectors))
sText = Replace$(sText, "{VectorEveryMS}", _ToStr$(iVectorEveryMS))
sText = Replace$(sText, "{MinDX}", _ToStr$(iMinDX))
sText = Replace$(sText, "{MaxDX}", _ToStr$(iMaxDX))
sText = Replace$(sText, "{MaxScale}", _ToStr$(iMaxScale))
sText = Replace$(sText, "{ScaleIncrement}", _ToStr$(iScaleIncrement))
End If
' Write file
If Len(sError) = 0 Then
sError = PrintFile$(sFile, sText, _FALSE)
End If
' Return results
SaveConfig$ = sError
End Function ' SaveConfig$
' /////////////////////////////////////////////////////////////////////////////
' Save the image image1 as PNG and JPG (format specified in sSaveFileFormat)
' Returns _TRUE if file was saved or _FALSE if not.
' _SAVEIMAGE saves the contents of an image or screen page to an image file.
' https://qb64phoenix.com/qb64wiki/index.php/SAVEIMAGE
' Syntax: _SAVEIMAGE fileName$[, ImageHandleArray&][, requirements$]
' Parameters
' fileName$ is literal or variable STRING file name value.
' Optional ImageHandleArray& is a LONG image handle or a valid screen page number.
' Optional requirements$ STRING values can be:
' BMP: Saves the image as Windows Bitmap if no file extension is specified.
' GIF: Saves the image as Graphics Interchange Format if no file extension is specified.
' HDR: Saves the image as Radiance HDR if no file extension is specified.
' ICO: Saves the image as Windows Icon if no file extension is specified.
' JPG: Saves the image as Joint Photographic Experts Group if no file extension is specified.
' PNG: Saves the image as Portable Network Graphics if no file extension is specified.
' QOI: Saves the image as Quite OK Image if no file extension is specified.
' TGA: Saves the image as Truevision TARGA if no file extension is specified.
Function SaveImage%% (image1 As Long, sSaveFileFormat As String)
Dim bResult As _Byte
Dim sName As String
Dim sTimestamp As String
Dim arrDateTime As String
Dim sFileName As String
Dim in$
' TODO: Prompt user to select a folder
'Dim SelectedPath$
''SelectedPath$ = _HOPEN$
'SelectedPath$ = _SelectFolderDialog$("Select folder to save image to", m_ProgramPath$)
'sFileName = SelectedPath$ + m_ProgramName + "_" + CurrentTimeStamp$ + "." + sSaveFileFormat
'_SaveImage sFileName, GridImage&, "JPG"
'OLD Construct filename: sFileName = m_ProgramPath + m_ProgramName + "_" + CurrentTimeStamp$ + "." + sSaveFileFormat
' Construct filename
sName = sFilenameTemplate ' "VanHalen_{yyyy}{mm}{dd}_{hh}{nn}{ss}.{ext}"
sTimestamp = CurrentDateTime$ ' returns in format "2025-10-23 18:46:51"
' Insert date/time parts, grab from positions in sTimestamp:
' 1111111111
' 1234567890123456789
' 2025-10-23 18:46:51
sName = Replace$(sName, "{yyyy}", Left$(sTimestamp, 4))
sName = Replace$(sName, "{yy}", Mid$(sTimestamp, 3, 2))
sName = Replace$(sName, "{mm}", Mid$(sTimestamp, 6, 2))
sName = Replace$(sName, "{dd}", Mid$(sTimestamp, 9, 2))
sName = Replace$(sName, "{hh}", Mid$(sTimestamp, 12, 2))
sName = Replace$(sName, "{nn}", Mid$(sTimestamp, 15, 2))
sName = Replace$(sName, "{ss}", Mid$(sTimestamp, 18, 2))
sName = Replace$(sName, "{ext}", LCase$(sSaveFileFormat))
sFileName = m_ProgramPath + sName
' Try to save file
'Locate MaxRow - 2, 1: Print "Saving image..."
_SaveImage sFileName, image1, sSaveFileFormat
' Make sure file exists
If _FileExists(sFileName) = _TRUE Then
bResult = _TRUE
' Show file name in popup inputbox they can copy to clipboard
If bEnableSaveResultsPopup = _TRUE Then
in$ = _InputBox$(m_ProgramName, "Saved image", sFileName)
End If
Else
bResult = _FALSE
' Show error in popup
If bEnableSaveResultsPopup = _TRUE Then
in$ = _InputBox$(m_ProgramName, "Error, not saved", sFileName)
End If
End If
SaveImage%% = bResult
End Function ' SaveImage%%
' /////////////////////////////////////////////////////////////////////////////
Function StripeName$ (iStripeNum%)
Dim MyString$: MyString$ = ""
Select Case iStripeNum%
Case cStripe_1_8:
MyString$ = "1/8" + Chr$(34)
Case cStripe_1_4:
MyString$ = "1/4" + Chr$(34)
Case cStripe_1_2:
MyString$ = "1/2" + Chr$(34)
Case cStripe_3_4:
MyString$ = "3/4" + Chr$(34)
End Select
StripeName$ = MyString$
End Function ' StripeName$
' /////////////////////////////////////////////////////////////////////////////
Function VHLogo$
Dim vh$
vh$ = ""
If CurrentWidth >= 1024 And CurrentHeight >= 768 Then
' 12345678901234567890123456789012345678901234567890123456789012345678901234567890123
vh$ = vh$ + "0 " + Chr$(13)
vh$ = vh$ + "0 = The Van Halenizer = " + Chr$(13)
vh$ = vh$ + "0 " + Chr$(13)
vh$ = vh$ + "0 by Softintheheadware " + Chr$(13)
vh$ = vh$ + "0 " + Chr$(13)
vh$ = vh$ + "1_____________________ ___________________ ______ ______________________" + Chr$(13)
vh$ = vh$ + "1\888888888888888888888\ \88888888888888888/\ /888888/\ /888888888888888888888//" + Chr$(13)
vh$ = vh$ + "1 \888888888888888888888\ \888888888888888/ /888888/ / /888888888888888888888// " + Chr$(13)
vh$ = vh$ + "1 \888\ \________/888/ /888/\__\/ /888/ " + Chr$(13)
vh$ = vh$ + "1 \8888888888888888888888\ /888/ /888/ / /888888888888888888888// " + Chr$(13)
vh$ = vh$ + "1 \8888888888888888888888\ /888/ /888/ / /888888888888888888888// " + Chr$(13)
vh$ = vh$ + "1 \888\ /888/ /888/ / /888/ " + Chr$(13)
vh$ = vh$ + "1 \8888888888888888888888\ /888/ /888/ / /8888888888888888888888// " + Chr$(13)
vh$ = vh$ + "1 \8888888888888888888888\ /888/ /8888888888888888888888888888888888/ " + Chr$(13)
vh$ = vh$ + "1 \_________________\888\ /888/ /888888888888888/\ _______________/ " + Chr$(13)
vh$ = vh$ + "1 \888.888/ /888/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 \88888/ /888/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 \888/ /888/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 \8/ /888/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 \ /888/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 /888/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 \88/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 \/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 \/ /888/ / " + Chr$(13)
vh$ = vh$ + "1 /888/ / " + Chr$(13)
vh$ = vh$ + "1 /888/ / " + Chr$(13)
vh$ = vh$ + "1 \88/ / " + Chr$(13)
vh$ = vh$ + "1 \/ / " + Chr$(13)
vh$ = vh$ + "1 \/ " + Chr$(13)
vh$ = vh$ + "1 " + Chr$(13)
ElseIf CurrentWidth >= 800 And CurrentHeight >= 600 Then
vh$ = vh$ + "0 = The Van Halenizer by Softintheheadware = " + Chr$(13)
vh$ = vh$ + "1_____________________ ___________________ ______ ______________________" + Chr$(13)
vh$ = vh$ + "1\888888888888888888888\ \88888888888888888/\ /888888/\ /888888888888888888888//" + Chr$(13)
vh$ = vh$ + "1 \888888888888888888888\ \888888888888888/ /888888/ / /888888888888888888888// " + Chr$(13)
vh$ = vh$ + "1 \888\ \________/888/ /888/\__\/ /888/ " + Chr$(13)
vh$ = vh$ + "1 \8888888888888888888888\ /888/ /888/ / /888888888888888888888// " + Chr$(13)
vh$ = vh$ + "1 \8888888888888888888888\ /888/ /888/ / /888888888888888888888// " + Chr$(13)
vh$ = vh$ + "1 \888\ /888/ /888/ / /888/ " + Chr$(13)
vh$ = vh$ + "1 \8888888888888888888888\ /888/ /888/ / /8888888888888888888888// " + Chr$(13)
vh$ = vh$ + "1 \8888888888888888888888\ /888/ /8888888888888888888888888888888888/ " + Chr$(13)
vh$ = vh$ + "1 \_________________\888\ /888/ /888888888888888/\ _______________/ " + Chr$(13)
vh$ = vh$ + "1 \888.888/ /888/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 \88888/ /888/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 \888/ /888/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 \8/ /888/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 \ /888/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 /888/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 \88/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 \/ / /888/ / " + Chr$(13)
vh$ = vh$ + "1 \/ /888/ / " + Chr$(13)
vh$ = vh$ + "1 /888/ / " + Chr$(13)
vh$ = vh$ + "1 /888/ / " + Chr$(13)
vh$ = vh$ + "1 \88/ / " + Chr$(13)
vh$ = vh$ + "1 \/ / " + Chr$(13)
vh$ = vh$ + "1 \/ " + Chr$(13)
Else
vh$ = vh$ + "0 = The Van Halenizer = " + Chr$(13)
vh$ = vh$ + "0 by Softintheheadware " + Chr$(13)
vh$ = vh$ + "1______ __ __ ______ " + Chr$(13)
vh$ = vh$ + "1 ___\ / / /___ " + Chr$(13)
vh$ = vh$ + "1 ___\ / /___ /___ " + Chr$(13)
vh$ = vh$ + "1 \ / / / " + Chr$(13)
vh$ = vh$ + "1 \/ / / " + Chr$(13)
vh$ = vh$ + "1 / / " + Chr$(13)
vh$ = vh$ + "1 / " + Chr$(13)
vh$ = vh$ + "1 / " + Chr$(13)
End If
VHLogo$ = vh$
End Function ' VHLogo$
' /////////////////////////////////////////////////////////////////////////////
Sub PrintLogo (x1 As Long, y1 As Long)
Dim bg0 As _Unsigned Long
Dim fg0 As _Unsigned Long
Dim bg1 As _Unsigned Long
Dim fg1 As _Unsigned Long
Dim bg2 As _Unsigned Long
Dim fg2 As _Unsigned Long
Dim vh$
Dim LineArray(-1) As String
Dim iLine As Integer
Dim sLine As String
Dim sMode As String
Dim iChar As Integer
Dim sChar As String
Dim x As Long
Dim y As Long
Dim OffsetX As Long
Dim r, g, b As Integer
Dim r1, g1, b1 As Single
Dim r2, g2, b2 As Single
Dim dr, dg, db As Single
Dim iSteps As Integer
Dim iLen As Integer
Dim sIndent As String
Dim bgNone As _Unsigned Long
Dim fgNone As _Unsigned Long
MaxRow = _Height / _FontHeight
MaxCol = _Width / _FontWidth
x = x1
y = y1
bgNone = _RGBA32(0, 0, 0, 0)
fgNone = bgNone
fg0 = _RGB32(255, 255, 255)
bg0 = _RGBA32(0, 0, 0, 0)
fg1 = _RGB32(0, 128, 255)
bg1 = _RGBA32(0, 0, 0, 0)
'bg1 = _RGB32(0, 0, 128)
fg2 = _RGB32(96, 96, 96)
bg2 = _RGBA32(0, 0, 0, 0)
vh$ = VHLogo$
split vh$, Chr$(13), LineArray()
' Calculate gradient:
' steps = UBound(LineArray) + 1 = 25
' start = 220, 220, 220
' end = 169, 50, 45
' r start = 220, end = 255
' r journey = end - start = 255 - 220 = 35
' r increment = journey / steps = 35 / 25 = 1.4
' g start = 220, end = 0
iSteps = 0
'
' Also, find the average line length
iLen = 0
For iLine = LBound(LineArray) To UBound(LineArray)
iLen = iLen + (Len(LineArray(iLine)) - 1)
If Left$(LineArray(iLine), 1) = "1" Then iSteps = iSteps + 1
Next iLine
' Find average width
iLen = iLen / ((UBound(LineArray) - LBound(LineArray)) - 1)
' Calculate the indent
iLen = (MaxCol - iLen) / 2
sIndent = Space$(iLen)
' Calculate gradient
r1 = 220: g1 = 220: b1 = 220 ' start color (at top)
r2 = 255: g2 = 50: b2 = 45 ' end color (at bottom)
dr = (r2 - r1) / iSteps: dg = (g2 - g1) / iSteps: db = (b2 - b1) / iSteps
For iLine = LBound(LineArray) To UBound(LineArray)
sLine = LineArray(iLine)
sMode = Left$(sLine, 1)
sLine = Right$(sLine, Len(sLine) - 1)
'OffsetX = (MaxCol - Len(sLine)) / 2
'sLine = String$(OffsetX, " ") + sLine
sLine = sIndent + sLine
If sMode = "1" Then
r = _Cast(Integer, r1)
g = _Cast(Integer, g1)
b = _Cast(Integer, b1)
fg1 = _RGB32(r, g, b)
r1 = r1 + dr: g1 = g1 + dg: b1 = b1 + db
End If
For iChar = 1 To Len(sLine)
sChar = Mid$(sLine, iChar, 1)
If sMode = "0" Then
If sChar = " " Then
Color fg0, bg0
Else
Color fg1, bg1
End If
ElseIf sMode = "1" Then
If sChar = " " Then
Color fgNone, bgNone
Else
Color fg1, bg1
End If
ElseIf sMode = "2" Then
Color fg2, bg2
End If
x = iChar - 1
_PrintString (x * _FontWidth, y * _FontHeight), sChar
Next iChar
y = y + 1: x = x1
Next iLine
' Return current row, column
y1 = y
x1 = x
End Sub ' PrintLogo
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN GENERAL PURPOSE UTILITY ROUTINES #GEN
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' /////////////////////////////////////////////////////////////////////////////
' Simple timestamp function
Function CurrentDateTime$
CurrentDateTime$ = Mid$(Date$, 7, 4) + "-" + _
Mid$(Date$, 1, 5) + " " + _
Time$
End Function ' CurrentDateTime$
' /////////////////////////////////////////////////////////////////////////////
Function CurrentTimeStamp$
Dim MyDate$
MyDate$ = CurrentDateTime$
MyDate$ = Replace$(MyDate$, " ", "_")
MyDate$ = Replace$(MyDate$, "-", "")
MyDate$ = Replace$(MyDate$, ":", "")
CurrentTimeStamp$ = MyDate$
End Function ' CurrentTimeStamp$
' /////////////////////////////////////////////////////////////////////////////
Function ExtendedTimer##
'Simplified version of the TimeStamp routine, streamlined to only give positive values based on the current timer.
'Note: Only good until the year 2100, as we don't do all the fancy calculations for leap years.
'A timer should work quickly and efficiently in the background; and the less we do, the less lag we might insert
'into a program.
Dim m As Integer, d As Integer, y As Integer
Dim s As _Float, day As String
day = Date$
m = Val(Left$(day, 2))
d = Val(Mid$(day, 4, 2))
y = Val(Right$(day, 4)) - 1970
Select Case m 'Add the number of days for each previous month passed
Case 2: d = d + 31
Case 3: d = d + 59
Case 4: d = d + 90
Case 5: d = d + 120
Case 6: d = d + 151
Case 7: d = d + 181
Case 8: d = d + 212
Case 9: d = d + 243
Case 10: d = d + 273
Case 11: d = d + 304
Case 12: d = d + 334
End Select
If (y Mod 4) = 2 And m > 2 Then d = d + 1 'add a day if this is leap year and we're past february
d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
d = d + (y + 2) \ 4 'add in days for leap years passed
s = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
ExtendedTimer## = (s + Timer)
End Function ' ExtendedTimer##
' /////////////////////////////////////////////////////////////////////////////
Sub FreeImage (ThisImage&)
If ThisImage& < -1 Or ThisImage& > 0 Then _FreeImage ThisImage&
End Sub ' FreeImage
' /////////////////////////////////////////////////////////////////////////////
Sub InitImage (ThisImage&, iWidth&, iHeight&, bgColor~&)
FreeImage ThisImage&
ThisImage& = _NewImage(iWidth&, iHeight&, 32)
_Dest ThisImage&: Cls , bgColor~&
End Sub ' InitImage
' /////////////////////////////////////////////////////////////////////////////
' Returns _TRUE if number n is even
' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
' see also: IsOdd%
Function IsEven% (n)
If n Mod 2 = 0 Then
IsEven% = _TRUE
Else
IsEven% = _FALSE
End If
End Function ' IsEven%
' /////////////////////////////////////////////////////////////////////////////
' Returns _TRUE if value OriginalString$ is numeric.
' Re: Does a Is Number function exist in QB64?
' https://www.qb64.org/forum/index.php?topic=896.15
' Version 2 by madscijr
' Returns _TRUE (-1) if string is an integer, _FALSE (0) if not
' Version 1 by MWheatley
' Reply #18 on: January 01, 2019, 11:24:30 AM
' returns 1 if string is an integer, 0 if not
Function IsNumber% (OriginalString$)
Dim bResult%: bResult% = _FALSE
Dim iLoop%
Dim TestString$
'Dim bNegative%
Dim iDecimalCount%
Dim sNextChar$
'THEY SHOULD TRIM OUTSIDE THE FUNCTION!
'TestString$ = _TRIM$(OriginalString$)
If Len(OriginalString$) > 0 Then
TestString$ = ""
If Left$(OriginalString$, 1) = "+" Then
TestString$ = Right$(OriginalString$, Len(OriginalString$) - 1)
'bNegative% = _FALSE
ElseIf Left$(OriginalString$, 1) = "-" Then
TestString$ = Right$(OriginalString$, Len(OriginalString$) - 1)
'bNegative% = _TRUE
Else
TestString$ = OriginalString$
'bNegative% = _FALSE
End If
If Len(TestString$) > 0 Then
bResult% = _TRUE
iDecimalCount% = 0
For iLoop% = 1 To Len(TestString$)
sNextChar$ = Mid$(TestString$, iLoop%, 1)
If sNextChar$ = "." Then
iDecimalCount% = iDecimalCount% + 1
If iDecimalCount% > 1 Then
' TOO MANY DECIMAL POINTS, INVALID!
bResult% = _FALSE
Exit For
End If
ElseIf Asc(sNextChar$) < 48 Or Asc(sNextChar$) > 57 Then
' NOT A NUMERAL OR A DECIMAL, INVALID!
bResult% = _FALSE
Exit For
End If
Next iLoop%
End If
End If
IsNumber% = bResult%
End Function ' IsNumber%
' /////////////////////////////////////////////////////////////////////////////
' Returns _TRUE if number n is odd
' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
' see also: IsEven%
Function IsOdd% (n)
If n Mod 2 = 1 Then
IsOdd% = _TRUE
Else
IsOdd% = _FALSE
End If
End Function ' IsOdd%
' /////////////////////////////////////////////////////////////////////////////
Function PadLeft$ (sValue As String, iWidth As Integer)
PadLeft$ = Right$(String$(iWidth, " ") + sValue, iWidth)
End Function ' PadLeft$
' /////////////////////////////////////////////////////////////////////////////
Function PadRight$ (sValue As String, iWidth As Integer)
PadRight$ = Left$(sValue + String$(iWidth, " "), iWidth)
End Function ' PadRight$
' /////////////////////////////////////////////////////////////////////////////
' Writes sText to a debug file in the EXE folder.
' Debug file is named the same thing as the program EXE name with ".txt" at the end.
' For example the program "C:\QB64\MyProgram.BAS" running as
' "C:\QB64\MyProgram.EXE" would have an output file "C:\QB64\MyProgram.EXE.txt".
' If the file doesn't exist, it is created, otherwise it is appended to.
Sub PrintDebugFile (sText As String)
Dim sFileName As String
Dim sError As String
Dim sOut As String
sFileName = m_ProgramPath$ + m_ProgramName$ + ".txt"
sError = ""
If _FileExists(sFileName) = _FALSE Then
sOut = ""
sOut = sOut + "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" + Chr$(13) + Chr$(10)
sOut = sOut + "PROGRAM : " + m_ProgramName$ + Chr$(13) + Chr$(10)
sOut = sOut + "RUN DATE: " + CurrentDateTime$ + Chr$(13) + Chr$(10)
sOut = sOut + "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" + Chr$(13) + Chr$(10)
sError = PrintFile$(sFileName, sOut, _FALSE)
End If
If Len(sError) = 0 Then
sError = PrintFile$(sFileName, sText, _TRUE)
End If
If Len(sError) <> 0 Then
Print CurrentDateTime$ + " PrintDebugFile FAILED: " + sError
End If
End Sub ' PrintDebugFile
' /////////////////////////////////////////////////////////////////////////////
' Writes sText to file sFileName.
' If bAppend=_TRUE appends to file, else overwrites it.
' Returns blank if successful else returns error message.
' Example:
' ProgramPath$ = Left$(Command$(0), _InStrRev(Command$(0), "\"))
' ProgramName$: m_ProgramName$ = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1)
' sFileName = ProgramPath$ + ProgramName$ + ".OUT.txt"
' sText = "This is a test." + chr$(13) + "Here is line 2." + chr$(13) + "End."
' sError = PrintFile$(sFileName, sText, _FALSE)
Function PrintFile$ (sFileName As String, sText As String, bAppend As Integer)
Dim sError As String: sError = ""
If (bAppend = _TRUE) Then
If _FileExists(sFileName) Then
Open sFileName For Append As #1 ' opens an existing file for appending
Else
sError = "Error in PrintFile$ : File not found. Cannot append."
End If
Else
Open sFileName For Output As #1 ' opens and clears an existing file or creates new empty file
End If
If Len(sError) = 0 Then
' NOTE: WRITE places text in quotes in the file
'WRITE #1, x, y, z$
'WRITE #1, sText
' PRINT does not put text inside quotes
Print #1, sText
Close #1
End If
PrintFile$ = sError
End Function ' PrintFile$
' /////////////////////////////////////////////////////////////////////////////
' Generate random value between Min and Max inclusive.
Function RandomNumber% (Min%, Max%)
Dim NumSpread%
' SET RANDOM SEED
Randomize Timer
NumSpread% = (Max% - Min%) + 1
RandomNumber% = Int(Rnd * NumSpread%) + Min% ' GET RANDOM # BETWEEN Max% AND Min%
End Function ' RandomNumber%
' /////////////////////////////////////////////////////////////////////////////
' 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$
' /////////////////////////////////////////////////////////////////////////////
' https://www.qb64.org/forum/index.php?topic=3605.0
' Quote from: SMcNeill on Today at 03:53:48 PM
'
' Sometimes, you guys make things entirely too complicated.
' There ya go! Three functions to either round naturally,
' always round down, or always round up, to whatever number of digits you desire.
' EDIT: Modified to add another option to round scientific,
' since you had it's description included in your example.
' Receives + returns _FLOAT myVar## (-1.18E-4932 to +1.18E+4932)
' =============================================================================
' ROUNDING FUNCTIONS FOR TYPE _FLOAT
' old name: RoundNatural##
Function Round## (num##, digits%)
Round## = Int(num## * 10 ^ digits% + .5) / 10 ^ digits%
End Function
Function RoundUp## (num##, digits%)
RoundUp## = _Ceil(num## * 10 ^ digits%) / 10 ^ digits%
End Function
Function RoundDown## (num##, digits%)
RoundDown## = Int(num## * 10 ^ digits%) / 10 ^ digits%
End Function
' old name: Round_Scientific##
Function RoundScientific## (num##, digits%)
RoundScientific## = _Round(num## * 10 ^ digits%) / 10 ^ digits%
End Function
' =============================================================================
' ROUNDING FUNCTIONS FOR TYPE DOUBLE
Function RoundDouble# (num#, digits%)
RoundDouble# = Int(num# * 10 ^ digits% + .5) / 10 ^ digits%
End Function
Function RoundUpDouble# (num#, digits%)
RoundUpDouble# = _Ceil(num# * 10 ^ digits%) / 10 ^ digits%
End Function
Function RoundDownDouble# (num#, digits%)
RoundDownDouble# = Int(num# * 10 ^ digits%) / 10 ^ digits%
End Function
Function RoundScientificDouble# (num#, digits%)
RoundScientificDouble# = _Round(num# * 10 ^ digits%) / 10 ^ digits%
End Function
' =============================================================================
' ROUNDING FUNCTIONS FOR TYPE SINGLE
Function RoundSingle! (num!, digits%)
RoundSingle! = Int(num! * 10 ^ digits% + .5) / 10 ^ digits%
End Function
' NOTE: not sure this one works: when digits%=3, it rounds .31 to .32
Function RoundUpSingle! (num!, digits%)
RoundUpSingle! = _Ceil(num! * 10 ^ digits%) / 10 ^ digits%
End Function
Function RoundDownSingle! (num!, digits%)
RoundDownSingle! = Int(num! * 10 ^ digits%) / 10 ^ digits%
End Function
Function RoundScientificSingle! (num!, digits%)
RoundScientificSingle! = _Round(num! * 10 ^ digits%) / 10 ^ digits%
End Function
' /////////////////////////////////////////////////////////////////////////////
' 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
' /////////////////////////////////////////////////////////////////////////////
Function TrueFalse$ (MyValue%)
TrueFalse$ = _IIf(MyValue% = _TRUE, "_TRUE", "_FALSE")
End Function ' TrueFalse$
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END GENERAL PURPOSE UTILITY ROUTINES @GEN
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN LINE DRAWING ROUTINES
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' /////////////////////////////////////////////////////////////////////////////
Function DegTo! (x1, y1, x2, y2)
' returns an angle in degrees from point x1,y1 to point x2,y2
DegTo! = _Atan2((y2 - y1), (x2 - x1)) / 0.01745329
End Function ' DegTo!
' /////////////////////////////////////////////////////////////////////////////
' RotoLine Demo by James D, Jarvis October 11,2023
' a program that demonstrates how to use rotozoom and related commands to draw lines thicker than one pixel
' https://qb64phoenix.com/forum/showthread.php?tid=2081&pid=20561#pid20561
' RotoLine x1 As Single, y1 As Single, x2 As Single, y2 As Single, thk As Single, klr As _Unsigned Long
Sub RotoLine (x1 As Single, y1 As Single, x2 As Single, y2 As Single, thk As Single, klr As _Unsigned Long)
Dim cx As Single
Dim cy As Single
Dim o&
Dim rtn As Single
Dim lnth As Single
'use rotozoom to draw a line of thickness thk of color klr from x1,y1 to x2,y2
cx = (x1 + x2) / 2
cy = (y1 + y2) / 2
o& = _Dest
_Dest dot&
PSet (0, 0), klr
_Dest o&
rtn = DegTo!(x1, y1, x2, y2)
lnth = Sqr(Abs(x2 - x1) * Abs(x2 - x1) + Abs(y2 - y1) * Abs(y2 - y1))
RotoZoom23d cx, cy, dot&, lnth, thk, rtn
End Sub ' RotoLine
' /////////////////////////////////////////////////////////////////////////////
' This sub gives really nice control over displaying an Image.
' by BPlus
' Scale rotate font text strings by B+
' https://qb64phoenix.com/forum/showthread.php?tid=414&highlight=rotate+text
Sub RotoZoom23d (centerX As Single, centerY As Single, Image As Long, xScale As Single, yScale As Single, Rotation As Single)
'rotate an image with Rotation defined in units of degrees, 0 is along x axis to the right gogin clockwise
Dim px(3) As Single
Dim py(3) As Single
Dim Wi&
Dim Hi&
Dim W&
Dim H&
Dim sinr!
Dim cosr!
Dim i&
Dim x2&
Dim y2&
Wi& = _Width(Image&)
Hi& = _Height(Image&)
W& = Wi& / 2 * xScale
H& = Hi& / 2 * yScale
px(0) = -W&: py(0) = -H&: px(1) = -W&: py(1) = H&
px(2) = W&: py(2) = H&: px(3) = W&: py(3) = -H&
sinr! = Sin(-0.01745329 * Rotation)
cosr! = Cos(-0.01745329 * Rotation)
For i& = 0 To 3
x2& = (px(i&) * cosr! + sinr! * py(i&)) + centerX
y2& = (py(i&) * cosr! - px(i&) * sinr!) + centerY
px(i&) = x2&: py(i&) = y2&
Next
_MapTriangle (0, 0)-(0, Hi& - 1)-(Wi& - 1, Hi& - 1), Image& To(px(0), py(0))-(px(1), py(1))-(px(2), py(2))
_MapTriangle (0, 0)-(Wi& - 1, 0)-(Wi& - 1, Hi& - 1), Image& To(px(0), py(0))-(px(3), py(3))-(px(2), py(2))
End Sub ' RotoZoom23d
' /////////////////////////////////////////////////////////////////////////////
Function SngRoundedToStr$ (sngValue As Single, intNumPlaces As Integer)
Dim sngNew As Single
sngNew = RoundSingle!(sngValue, intNumPlaces)
SngRoundedToStr$ = SngToStr$(sngNew)
End Function ' SngRoundedToStr$
' /////////////////////////////////////////////////////////////////////////////
' Scientific notation - QB64 Wiki
' https://www.qb64.org/wiki/Scientific_notation
' Example: A string function that displays extremely small or large exponential decimal values.
Function SngToStr$ (n!)
Dim result$: result$ = ""
Dim value$
Dim Xpos%
Dim expo%
Dim sign$
Dim valu$
Dim dot%
Dim L%
Dim add$
Dim min$
Dim DP$
Dim n%
Dim num$
value$ = UCase$(LTrim$(Str$(n!)))
Xpos% = InStr(value$, "D") + InStr(value$, "E") ' only D or E can be present
If Xpos% Then
expo% = Val(Mid$(value$, Xpos% + 1))
If Val(value$) < 0 Then
sign$ = "-"
valu$ = Mid$(value$, 2, Xpos% - 2)
Else
valu$ = Mid$(value$, 1, Xpos% - 1)
End If
dot% = InStr(valu$, ".")
L% = Len(valu$)
If expo% > 0 Then
add$ = String$(expo% - (L% - dot%), "0")
End If
If expo% < 0 Then
min$ = String$(Abs(expo%) - (dot% - 1), "0")
DP$ = "."
End If
For n% = 1 To L%
If Mid$(valu$, n%, 1) <> "." Then
num$ = num$ + Mid$(valu$, n%, 1)
End If
Next n%
result$ = _Trim$(sign$ + DP$ + min$ + num$ + add$)
Else
result$ = value$
End If
SngToStr$ = result$
End Function ' SngToStr$
' /////////////////////////////////////////////////////////////////////////////
' From: SMcNeill
' Date: 01-02-2024, 08:19 AM
' https://qb64phoenix.com/forum/showthread.php?tid=2372&pid=22425#pid22425
' ThickLine x1, y1, x2, y2, thk, kolor AS _UNSIGNED LONG
Sub ThickLine (x1, y1, x2, y2, thk, kolor As _Unsigned Long)
'draw a line of thickness thk on color klr from x1,y1 to x2,y2
'orientation of line is set in the middle of line thickness
Static tempimage As Long
Static m As _MEM
Dim cang As Single
Dim ta As Single
Dim tb As Single
Dim v As Single
Dim tax1 As Single
Dim tay1 As Single
Dim tax4 As Single
Dim tay4 As Single
Dim tax2 As Single
Dim tay2 As Single
Dim tax3 As Single
Dim tay3 As Single
If tempimage = 0 Then tempimage = _NewImage(1, 1, 32): m = _MemImage(tempimage)
$Checking:Off
_MemPut m, m.OFFSET, kolor
$Checking:On
cang = _Atan2((y2 - y1), (x2 - x1)) 'get the angle from x1,y1 to x2,y2
ta = cang + _Pi(.5)
tb = ta + _Pi
tax1 = x1 + (thk / 2) * Cos(ta)
tay1 = y1 + (thk / 2) * Sin(ta)
tax4 = x1 + (thk / 2) * Cos(tb)
tay4 = y1 + (thk / 2) * Sin(tb)
tax2 = x2 + (thk / 2) * Cos(ta)
tay2 = y2 + (thk / 2) * Sin(ta)
tax3 = x2 + (thk / 2) * Cos(tb)
tay3 = y2 + (thk / 2) * Sin(tb)
_MapTriangle (0, 0)-(0, 0)-(0, 0), tempimage To(tax1, tay1)-(tax2, tay2)-(tax4, tay4)
_MapTriangle (0, 0)-(0, 0)-(0, 0), tempimage To(tax2, tay2)-(tax3, tay3)-(tax4, tay4)
End Sub ' ThickLine
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END LINE DRAWING ROUTINES
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' 0.824 seconds Paint
' 2.692 seconds Fill enableBlend%=_FALSE
' 5.494 seconds Fill enableBlend%=_TRUE
' 1.759 seconds Paint2
' 813.184 seconds Paint3
' 5.000 seconds PaintMask
' ################################################################################################################################################################
' # BEGIN Steve's fill code
' ################################################################################################################################################################
' /////////////////////////////////////////////////////////////////////////////
Sub Fill (x, y, Kolor As _Unsigned Long, EnableBlend%)
Dim As _Unsigned Long OC, BC
OC = Point(x, y) 'original color
If EnableBlend% = _TRUE Then
' blend is enabled
If _Alpha32(Kolor) <> 255 Or _Alpha32(OC) <> 255 Then ' we're going to blend
PSet (x, y), Kolor
BC = Point(x, y) ' blended color
End If
BlendFiller x, y, Kolor, OC, BC
Else
Filler x, y, Kolor, OC
End If
End Sub ' Fill
' /////////////////////////////////////////////////////////////////////////////
' Paintbucket fill (opaque)
Sub Filler (x, y, Kolor As _Unsigned Long, OC As _Unsigned Long)
Dim l, r, i
If Kolor = OC Then Exit Sub
l = x: r = x 'find left/right to fill
Do Until l = 0
If Point(l - 1, y) = OC Then l = l - 1 Else Exit Do
Loop 'find the left boundry
Do Until r = _Width - 1
If Point(r + 1, y) = OC Then r = r + 1 Else Exit Do
Loop 'find the right boundry
Line (l, y)-(r, y), Kolor, BF
For i = l To r
If Point(i, y + 1) = OC Then Filler i, y + 1, Kolor, OC
Next
For i = l To r
If Point(i, y - 1) = OC Then Filler i, y - 1, Kolor, OC
Next
End Sub ' Filler
' /////////////////////////////////////////////////////////////////////////////
' Paintbucket fill with blending colors w/alpha < 255
Sub BlendFiller (x, y, Kolor As _Unsigned Long, OC As _Unsigned Long, BC As _Unsigned Long)
Dim l, r, i
If Kolor = OC Or Kolor = BC Then Exit Sub
l = x: r = x 'find left/right to fill
Do Until l = 0
If Point(l - 1, y) = BC Then Exit Do
If Point(l - 1, y) = OC Then l = l - 1 Else Exit Do
Loop 'find the left boundry
Do Until r = _Width - 1
If Point(r + 1, y) = BC Then Exit Do
If Point(r + 1, y) = OC Then r = r + 1 Else Exit Do
Loop 'find the right boundry
Line (l, y)-(r, y), Kolor, BF
For i = l To r
If Point(i, y + 1) = BC Then _Continue
If Point(i, y + 1) = OC Then BlendFiller i, y + 1, Kolor, OC, BC
Next
For i = l To r
If Point(i, y - 1) = BC Then _Continue
If Point(i, y - 1) = OC Or Point(l - 1, y) = BC Then BlendFiller i, y - 1, Kolor, OC, BC
Next
End Sub ' BlendFiller
' ################################################################################################################################################################
' # END Steve's fill code
' ################################################################################################################################################################
' ################################################################################################################################################################
' # BEGIN Petr's fill code
' ################################################################################################################################################################
' /////////////////////////////////////////////////////////////////////////////
' Petr, Mini-Mod
' 4/24/2025 9:42 AM
' https://qb64phoenix.com/forum/showthread.php?tid=1507
Sub Paint2 (x, y, c~&)
Dim W
Dim H
Dim Virtual As Long
Dim position&
Dim Clr2~&
Dim D&
Dim CLR~&
W = _Width: H = _Height
Virtual = _NewImage(W, H, 32)
Dim m As _MEM, n As _MEM, Bck As _Unsigned Long
m = _MemImage(_Source)
n = _MemImage(Virtual)
'create mask (2 color image)
position& = (y * W + x) * 4
_MemGet m, m.OFFSET + position&, Bck
Clr2~& = _RGB32(_Red32(Bck) - 1, _Green32(Bck) - 1, _Blue32(Bck) - 1, _Alpha32(Bck) - 1)
D& = 0
Do Until D& = n.SIZE
CLR~& = _MemGet(m, m.OFFSET + D&, _Unsigned Long)
If CLR~& = Bck~& Then _MemPut n, n.OFFSET + D&, CLR~& Else _MemPut n, n.OFFSET + D&, Clr2~&
D& = D& + 4
Loop
D& = _Dest
_Dest Virtual
Paint (x, y), c~&, Clr2~&
_Dest D&
_ClearColor Clr2~&, Virtual
_PutImage , Virtual, D&
_MemFree m
_MemFree n
_FreeImage Virtual
End Sub ' Paint2
' ################################################################################################################################################################
' # END Petr's fill code
' ################################################################################################################################################################
' ################################################################################################################################################################
' # BEGIN madscijr's fill code
' ################################################################################################################################################################
' /////////////////////////////////////////////////////////////////////////////
' Does a paintbucket fill with paint
' using _CLEARCOLOR to protect unwanted colors
' from being painted over.
' Receives arrIgnoreColors() an array of "protected" colors
' which are removed from temp image with _CLEARCOLOR,
' First we look at point x0, y0 to get the target color,
' then _CLEARCOLOR all the colors in arrIgnoreColors()
' then _PUTIMAGE to a temp image, paint does fill on that,
' then _PUTIMAGE that back to the original.
' * v2 eliminates a temp image we didn't need.
' Prequisites:
' _SOURCE & _DEST must be set to the target image.
' -----------------------------------------------------------------------------
' NOTES:
' The _CLEARCOLOR statement sets a specific color to be treated as
' transparent when an image is later put (via _PUTIMAGE) onto another image.
' Syntax: _CLEARCOLOR {color&|_NONE}[, Dest_Handle&]
' The _SETALPHA statement sets the alpha channel transparency level of some
' or all of the pixels of an image.
' Syntax: _SETALPHA alpha&[, color1&][ TO colour2&] [, imageHandle&]
' -----------------------------------------------------------------------------
' Example usage:
' PaintMask2 x0, y0, FillColor, IgnoreColor
Sub PaintMask2 (x0, y0, FillColor~&, IgnoreColor~&)
Dim imgSource&
Dim imgFill&
Dim index%
Dim bgColor~&
' Reference original image
imgSource& = _Dest
' Get target color
bgColor~& = Point(x0, y0)
If bgColor~& <> FillColor~& Then
' Clear any colors not the target color or fill color
'For index% = LBound(arrIgnoreColors) To UBound(arrIgnoreColors)
If IgnoreColor~& <> FillColor~& Then
'If arrIgnoreColors(index%) <> FillColor~& Then
'If arrIgnoreColors(index%) <> bgColor~& Then
If IgnoreColor~& <> bgColor~& Then
_ClearColor IgnoreColor~&, imgSource&
End If
End If
'Next index%
' Create fill target
InitImage imgFill&, _Width(imgSource&), _Height(imgSource&), _RGB32(0, 0, 0, 0)
'_PUTIMAGE , sourceHandle&, destHandle& 'size full source to fit full destination area
_PutImage , imgSource&, imgFill&
' Fill in fill target
_Dest imgFill&
'PAINT [STEP] (column%, row%), fillColor[, borderColor%]
Paint (x0, y0), FillColor~&, _RGB32(0, 0, 0, 0)
' Copy fill target onto main image
'_PUTIMAGE , sourceHandle&, destHandle& 'size full source to fit full destination area
_PutImage , imgFill&, imgSource& 'size full source to fit full destination area
' Point back at main image
_Source imgSource&
_Dest imgSource&
' Undo _CLEARCOLOR
_ClearColor _None, imgSource&
'_ClearColor _RGB32(0, 0, 0, 0), imgSource& ' re-add the color we use for transparent?
' Cleanup
FreeImage imgFill&
End If
End Sub ' PaintMask2
' ################################################################################################################################################################
' # END madscijr's fill code
' ################################################################################################################################################################
' ################################################################################################################################################################
' BEGIN COLOR ARRAY FUNCTIONS #COLR
' ################################################################################################################################################################
' /////////////////////////////////////////////////////////////////////////////
Sub AddColor (ColorValue As _Unsigned Long, arrColor() As _Unsigned Long)
ReDim _Preserve arrColor(0 To UBound(arrColor) + 1) As _Unsigned Long
arrColor(UBound(arrColor)) = ColorValue
End Sub ' AddColor
' /////////////////////////////////////////////////////////////////////////////
Sub AddColors (ColorValue As _Unsigned Long, arrColor() As _Unsigned Long, HowMany As Long)
Dim iLoop As Integer
For iLoop = 1 To HowMany
AddColor ColorValue, arrColor()
Next iLoop
End Sub ' AddColors
' /////////////////////////////////////////////////////////////////////////////
Sub AddSpectrumColors (arrColor() As _Unsigned Long)
Dim iNum As Integer
iNum = 1
AddColors cRed, arrColor(), iNum
AddColors cOrangeRed, arrColor(), iNum
AddColors cDarkOrange, arrColor(), iNum
AddColors cOrange, arrColor(), iNum
AddColors cGold, arrColor(), iNum
AddColors cYellow, arrColor(), iNum
AddColors cChartreuse, arrColor(), iNum
AddColors cOliveDrab1, arrColor(), iNum
AddColors cLime, arrColor(), iNum
AddColors cMediumSpringGreen, arrColor(), iNum
AddColors cSpringGreen, arrColor(), iNum
AddColors cCyan, arrColor(), iNum
AddColors cDeepSkyBlue, arrColor(), iNum
AddColors cDodgerBlue, arrColor(), iNum
AddColors cSeaBlue, arrColor(), iNum
AddColors cBlue, arrColor(), iNum
AddColors cBluePurple, arrColor(), iNum
AddColors cDeepPurple, arrColor(), iNum
AddColors cPurple, arrColor(), iNum
AddColors cPurpleRed, arrColor(), iNum
End Sub ' AddSpectrumColors
' ################################################################################################################################################################
' END COLOR ARRAY FUNCTIONS @COLR
' ################################################################################################################################################################
' ################################################################################################################################################################
' BEGIN COLOR FUNCTIONS #COLOR
' ################################################################################################################################################################
Function cRed~& ()
cRed = _RGB32(255, 0, 0)
End Function
Function cOrangeRed~& ()
cOrangeRed = _RGB32(255, 69, 0)
End Function ' cOrangeRed~&
Function cDarkOrange~& ()
cDarkOrange = _RGB32(255, 140, 0)
End Function ' cDarkOrange~&
Function cOrange~& ()
cOrange = _RGB32(255, 165, 0)
End Function ' cOrange~&
Function cGold~& ()
cGold = _RGB32(255, 215, 0)
End Function ' cGold~&
Function cYellow~& ()
cYellow = _RGB32(255, 255, 0)
End Function ' cYellow~&
' LONG-HAIRED FRIENDS OF JESUS OR NOT,
' THIS IS NOT YELLOW ENOUGH (TOO CLOSE TO LIME)
' TO USE FOR OUR COMPLEX RAINBOW SEQUENCE:
Function cChartreuse~& ()
cChartreuse = _RGB32(127, 255, 0)
End Function ' cChartreuse~&
' WE SUBSTITUTE THIS CSS3 COLOR FOR INBETWEEN LIME AND YELLOW:
Function cOliveDrab1~& ()
cOliveDrab1 = _RGB32(192, 255, 62)
End Function ' cOliveDrab1~&
Function cLime~& ()
cLime = _RGB32(0, 255, 0)
End Function ' cLime~&
Function cMediumSpringGreen~& ()
cMediumSpringGreen = _RGB32(0, 250, 154)
End Function ' cMediumSpringGreen~&
' ADDED THIS FOR THE GAUGE COLOR:
Function cSpringGreen~& ()
cSpringGreen = _RGB32(0, 255, 160)
End Function ' cSpringGreen~&
Function cCyan~& ()
cCyan = _RGB32(0, 255, 255)
End Function ' cCyan~&
Function cDeepSkyBlue~& ()
cDeepSkyBlue = _RGB32(0, 191, 255)
End Function ' cDeepSkyBlue~&
Function cDodgerBlue~& ()
cDodgerBlue = _RGB32(30, 144, 255)
End Function ' cDodgerBlue~&
Function cSeaBlue~& ()
cSeaBlue = _RGB32(0, 64, 255)
End Function ' cSeaBlue~&
Function cBlue~& ()
cBlue = _RGB32(0, 0, 255)
End Function ' cBlue~&
Function cBluePurple~& ()
cBluePurple = _RGB32(64, 0, 255)
End Function ' cBluePurple~&
Function cDeepPurple~& ()
cDeepPurple = _RGB32(96, 0, 255)
End Function ' cDeepPurple~&
Function cPurple~& ()
cPurple = _RGB32(128, 0, 255)
End Function ' cPurple~&
Function cPurpleRed~& ()
cPurpleRed = _RGB32(128, 0, 192)
End Function ' cPurpleRed~&
Function cDarkRed~& ()
cDarkRed = _RGB32(160, 0, 64)
End Function ' cDarkRed~&
Function cBrickRed~& ()
cBrickRed = _RGB32(192, 0, 32)
End Function ' cBrickRed~&
Function cDarkGreen~& ()
cDarkGreen = _RGB32(0, 100, 0)
End Function ' cDarkGreen~&
Function cGreen~& ()
cGreen = _RGB32(0, 128, 0)
End Function ' cGreen~&
Function cOliveDrab~& ()
cOliveDrab = _RGB32(107, 142, 35)
End Function ' cOliveDrab~&
Function cLightPink~& ()
cLightPink = _RGB32(255, 182, 193)
End Function ' cLightPink~&
Function cHotPink~& ()
cHotPink = _RGB32(255, 105, 180)
End Function ' cHotPink~&
Function cDeepPink~& ()
cDeepPink = _RGB32(255, 20, 147)
End Function ' cDeepPink~&
Function cMagenta~& ()
cMagenta = _RGB32(255, 0, 255)
End Function ' cMagenta~&
Function cBlack~& ()
cBlack = _RGB32(0, 0, 0)
End Function ' cBlack~&
Function cDimGray~& ()
cDimGray = _RGB32(105, 105, 105)
End Function ' cDimGray~&
Function cGray~& ()
cGray = _RGB32(128, 128, 128)
End Function ' cGray~&
Function cDarkGray~& ()
cDarkGray = _RGB32(169, 169, 169)
End Function ' cDarkGray~&
Function cSilver~& ()
cSilver = _RGB32(192, 192, 192)
End Function ' cSilver~&
Function cLightGray~& ()
cLightGray = _RGB32(211, 211, 211)
End Function ' cLightGray~&
Function cGainsboro~& ()
cGainsboro = _RGB32(220, 220, 220)
End Function ' cGainsboro~&
Function cWhiteSmoke~& ()
cWhiteSmoke = _RGB32(245, 245, 245)
End Function ' cWhiteSmoke~&
Function cWhite~& ()
cWhite = _RGB32(255, 255, 255)
End Function ' cWhite~&
Function cDarkBrown~& ()
cDarkBrown = _RGB32(128, 64, 0)
End Function ' cDarkBrown~&
Function cLightBrown~& ()
cLightBrown = _RGB32(196, 96, 0)
End Function ' cLightBrown~&
Function cKhaki~& ()
cKhaki = _RGB32(240, 230, 140)
End Function ' cKhaki~&
Function cEmpty~& ()
cEmpty = _RGB32(0, 0, 0, 0)
End Function ' cEmpty~&
' ################################################################################################################################################################
' END COLOR FUNCTIONS @COLOR
' ################################################################################################################################################################
' ################################################################################################################################################################
' #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%
' _KEYDOWN Keyboard Values
'
' Esc F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 Sys ScL Pause
' 27 15104 15360 15616 15872 16128 16384 16640 16896 17152 17408 34048 34304 +316 +302 +019
' `~ 1! 2@ 3# 4$ 5% 6^ 7& 8* 9( 0) -_ =+ BkSp Ins Hme PUp NumL / * -
' 126 33 64 35 36 37 94 38 42 40 41 95 43 8 20992 18176 18688 +300 47 42 45
' 96 49 50 51 52 53 54 55 56 57 48 45 61
' Tab Q W E R T Y U I O P [{ ]} \| Del End PDn 7Hme 8/? 9PU +
' 9 81 87 69 82 84 89 85 73 79 80 123 125 124 21248 20224 20736 18176 18432 18688 43
' 113 119 101 114 116 121 117 105 111 112 91 93 92 55 56 57
' CapL A S D F G H J K L ;: '" Enter 4/?- 5 6/-?
' +301 65 83 68 70 71 72 74 75 76 58 34 13 19200 19456 19712 E
' 97 115 100 102 103 104 106 107 108 59 39 52 53 54 n
' Shift Z X C V B N M ,< .> /? Shift ? 1End 2/? 3PD t
' +304 90 88 67 86 66 78 77 60 62 63 +303 18432 20224 20480 20736 e
' 122 120 99 118 98 110 109 44 46 47 49 50 51 r
' Ctrl Win Alt Spacebar Alt Win Menu Ctrl ?- ? -? 0Ins .Del
' +306 +311 +308 32 +307 +312 +319 +305 19200 20480 19712 20992 21248 13
' Width Height Aspect Ratio Name Comments
' 320 240 4:3 Standard resolution Classic arcade games & console emulators
' 640 480 4:3 VGA really really old PCs
' 800 600 4:3 SVGA really old PCs
' 1024 768 4:3 XGA old PCs
' 1280 1024 5:4 SXGA old PCs
' 720 1600 5.33:1 HD+ budged phones
' 1080 2400 9:20 FHD+ mid-range premium phones
' 1280 720 16:9 WXGA HD budget laptops
' 1366 768 16:9 HD / 720p budget laptops
' 1440 3200 20:9 QHD+ (Quad HD+) high-end mobile
' 1900 1080 16:9 Full HD (FHD) / 1080p HD monitors
' 2560 1440 16:9 QHD (Quad HD) Lenovo, Thinkpad, Pixel XL
' 3840 2160 16:9 4k UHD 4k monitors
' 2208 1768 1.25:1 QXGA+ foldable display (Galaxy Z fold)
' 1344 2772 1:2.06 ? (some list as QHD) foldable display (Galaxy Z fold)
' @REFERENCE
' ################################################################################################################################################################
