Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Flaming Text (let's make it a challenge)
#2
My version. Inspired by the BPlus program - solution with mask is perfect.

Code: (Select All)

Option _Explicit
Randomize Timer

Type POINTAPI
    X As Long
    Y As Long
End Type

Declare Dynamic Library "user32" '                        transparent program window, clickable as in my DLL demos. Tested in 64bit IDE in Windows only.
    Function GetCursorPos& (lpPoint As POINTAPI)
    Function GetWindowLongPtrA%& (ByVal hwnd As _Offset, ByVal nIndex As Long)
    Function SetWindowLongPtrA%& (ByVal hwnd As _Offset, ByVal nIndex As Long, ByVal dwNewLong As _Offset)
    Function SetLayeredWindowAttributes& (ByVal hwnd As _Offset, ByVal crKey As Long, ByVal bAlpha As _Unsigned _Byte, ByVal dwFlags As Long)
    Function SetWindowPos& (ByVal hwnd As _Offset, ByVal Zorder As Long, ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal Flags As Long)
    Function GetAsyncKeyState% (ByVal vKey As Long)
End Declare

Const GWL_STYLE& = -16
Const GWL_EXSTYLE& = -20
Const VK_LBUTTON& = 1
Const WS_CAPTION%& = &HC00000
Const WS_THICKFRAME%& = &H40000
Const WS_SYSMENU%& = &H80000
Const WS_MINIMIZEBOX%& = &H20000
Const WS_MAXIMIZEBOX%& = &H10000
Const WS_EX_LAYERED%& = &H80000
Const LWA_COLORKEY& = 1
Const SWP_NOSIZE& = &H1
Const SWP_NOMOVE& = &H2
Const SWP_NOZORDER& = &H4
Const SWP_NOACTIVATE& = &H10
Const SWP_FRAMECHANGED& = &H20
Const SWP_SHOWWINDOW& = &H40
Const HWND_TOPMOST& = -1
Const HWND_NOTOPMOST& = -2


Dim Shared As Long W, H, N, Scrn, MaskImg, FontSize, FontH, DefaultFontH, Pad, FlameSpace, DragDX, DragDY, Fs
ReDim Shared As _Unsigned _Byte Heat(0), MaskAll(0), MaskTop(0)
ReDim Shared Wind(0) As Integer
Dim Shared As Integer PrevDown, DragOn 'program window mouse move
Dim Shared MemScr As _MEM
Dim Shared As String Txt, FontFile

Txt$ = "System's on fire! Hell yeah, Basic!"
FontFile$ = "impact.ttf" '
FontSize& = 96
Pad = 20

DefaultFontH& = _Font
FontH& = _LoadFont(FontFile$, FontSize&, "BOLD")
Fs = _NewImage(800, 600, 32)
Screen Fs
If FontH& > 0 Then
    _Font FontH&
Else
    _Font 16 ' fallback built-in
    FontH& = _Font
End If

W = _PrintWidth(Txt$) + Pad * 2
H = _FontHeight + Pad * 8 + FlameSpace
N = W * H
Scrn& = _NewImage(W, H, 256)
Screen Scrn&
If FontH& > 0 Then _Font FontH&

_FreeImage Fs
FlameSpace = _FontHeight / 3

Cls , 0

' Make screen memory handle once (fast rendering)
MemScr = _MemImage(0)

' Palette for fire (index 0 stays black = transparent key); palette solution is inspired with BPlus fire demo!
BuildFirePalette

' Build text masks
MaskImg& = _NewImage(W, H, 256)
BuildTextMasks

' Setup window: borderless + layered colorkey black + optionally topmost
SetupLayeredBorderless 1

' Center window (safe after screen exists)
Do: Loop Until _ScreenExists
_ScreenMove _Middle

ReDim Heat(N - 1) As _Unsigned _Byte
ReDim MaskAll(N - 1) As _Unsigned _Byte
ReDim MaskTop(N - 1) As _Unsigned _Byte
ReDim Wind(H - 1) As Integer

' Copy mask bytes into MaskAll/MaskTop (once)
CopyMasksFromImage


Do
    HandleDrag
    UpdateWind
    UpdateFire
    RenderFire

    _Display
    _Limit 60
Loop Until _KeyDown(27)

' Cleanup
Screen 0
_MemFree MemScr
If MaskImg& < -1 Then _FreeImage MaskImg&
If Scrn& < -1 Then _FreeImage Scrn&
End


Sub SetupLayeredBorderless (TopMost As Integer)
    Dim As _Offset hwnd, style, exstyle
    Dim As Long flags, z, N

    hwnd%& = _WindowHandle

    ' Remove borders/caption/system buttons
    style%& = GetWindowLongPtrA%&(hwnd%&, GWL_STYLE)
    style%& = style%& And Not (WS_CAPTION Or WS_THICKFRAME Or WS_SYSMENU Or WS_MINIMIZEBOX Or WS_MAXIMIZEBOX)
    N = SetWindowLongPtrA%&(hwnd%&, GWL_STYLE, style%&)

    ' Enable layered window
    exstyle%& = GetWindowLongPtrA%&(hwnd%&, GWL_EXSTYLE)
    exstyle%& = exstyle%& Or WS_EX_LAYERED
    N = SetWindowLongPtrA%&(hwnd%&, GWL_EXSTYLE, exstyle%&)

    ' Color key = black (COLORREF 0) => transparent + click-through on those pixels
    N = SetLayeredWindowAttributes&(hwnd%&, 0, 0, LWA_COLORKEY)

    ' Apply style changes
    flags = SWP_NOMOVE Or SWP_NOSIZE Or SWP_FRAMECHANGED Or SWP_SHOWWINDOW Or SWP_NOACTIVATE
    If TopMost Then z = HWND_TOPMOST Else z = HWND_NOTOPMOST
    N = SetWindowPos&(hwnd%&, z, 0, 0, 0, 0, flags)
End Sub

Sub BuildFirePalette
    Dim As Long i, r, g, b, t

    ' index 0 MUST be black (transparent key)
    _PaletteColor 0, _RGB32(0, 0, 0)

    For i = 1 To 255
        ' 0..255 => black->red->yellow->white
        If i < 86 Then
            r = i * 3
            g = 0
            b = 0
        ElseIf i < 171 Then
            r = 255
            g = (i - 85) * 3
            b = 0
        Else
            r = 255
            g = 255
            b = (i - 170) * 3
        End If

        If r > 255 Then r = 255
        If g > 255 Then g = 255
        If b > 255 Then b = 255

        _PaletteColor i, _RGB32(r, g, b)
    Next i
End Sub

Sub BuildTextMasks
    Dim tx As Long, ty As Long

    _Dest MaskImg&
    Cls , 0
    _Font FontH&
    Color 255, 0

    tx = Pad
    ty = FlameSpace + Pad

    _PrintString (tx, ty), Txt$
    _Dest 0
End Sub

Sub CopyMasksFromImage
    Dim m As _MEM
    Dim As Long i, x, y, idx
    Dim v As _Unsigned _Byte

    m = _MemImage(MaskImg&)

    ' Fill MaskAll from mask image bytes
    For i = 0 To N - 1
        v = _MemGet(m, m.OFFSET + i, _Unsigned _Byte)
        If v <> 0 Then
            MaskAll(i) = 1
        Else
            MaskAll(i) = 0
        End If
    Next i

    ' MaskTop = text pixel that has NO text pixel above it (top edge) => feeds flames
    For y = 0 To H - 1
        For x = 0 To W - 1
            idx = y * W + x
            If MaskAll(idx) Then
                If y = 0 Then
                    MaskTop(idx) = 1
                Else
                    If MaskAll(idx - W) = 0 Then
                        MaskTop(idx) = 1
                    Else
                        MaskTop(idx) = 0
                    End If
                End If
            Else
                MaskTop(idx) = 0
            End If
        Next x
    Next y

    _MemFree m
End Sub

Sub UpdateWind
    Dim As Long y, WindRichtung
    For y = 0 To H - 1
        If Rnd * 6 > 3 Then WindRichtung = -1 Else WindRichtung = 1
        Wind(y) = Int(Rnd * 5) * WindRichtung - 1 ' -1,0,1
    Next y
End Sub

Sub UpdateFire
    Dim As Long x, y, idx, sx, v, cool, fuel, zaklad 'to jsem na to zvedavej.

    ' Clear last 2 rows to prevent "fire from nowhere"
    zaklad = (H - 2) * W
    For idx = zaklad To N - 1
        Heat(idx) = 0
    Next idx

    ' Propagate upward (top-to-bottom in-place)
    For y = 0 To H - 3
        cool = (y * 40) \ H ' small cooling gradient

        For x = 1 To W - 2
            sx = x + Wind(y)
            If sx < 1 Then sx = 1
            If sx > W - 2 Then sx = W - 2

            idx = y * W + x

            v = Heat((y + 1) * W + sx)
            v = v + Heat((y + 1) * W + (sx - 1))
            v = v + Heat((y + 1) * W + (sx + 1))
            v = v + Heat((y + 2) * W + sx)
            v = v \ 4

            If v > cool Then v = v - cool Else v = 0
            Heat(idx) = v
        Next x

        ' edges
        Heat(y * W) = 0
        Heat(y * W + (W - 1)) = 0
    Next y

    ' Keep letters glowing + feed flames mainly from top edges
    For idx = 0 To N - 1
        If MaskAll(idx) Then
            If Heat(idx) < 110 Then Heat(idx) = 110
        End If

        If MaskTop(idx) Then
            fuel = 220 + Int(Rnd * 35) ' 220..254
            If Heat(idx) < fuel Then Heat(idx) = fuel
        End If
    Next idx
End Sub

Sub RenderFire
    Dim idx As Long
    Dim o As _Offset

    o = MemScr.OFFSET

    'make it faster
    $Checking:Off
    For idx = 0 To N - 1
        _MemPut MemScr, o + idx, Heat(idx) As _UNSIGNED _BYTE
    Next idx
    $Checking:On
End Sub

Sub HandleDrag
    Dim p As POINTAPI
    Dim As Long wndX, wndY, mx, my, N, idx
    Dim ks As Integer
    Dim down As Integer

    N = GetCursorPos&(p)

    ' Globální stav tlacitka
    ks = GetAsyncKeyState%(VK_LBUTTON)
    down = (ks And &H8000) <> 0

    wndX = _ScreenX
    wndY = _ScreenY

    mx = p.X - wndX
    my = p.Y - wndY

    ' Start drag jen na HRANE stisku (edge detect)
    If down And (PrevDown = 0) Then
        If mx >= 0 And mx < W And my >= 0 And my < H Then
            idx = my * W + mx

            ' Hit-test
            If Heat(idx) <> 0 Then
                DragDX = p.X - wndX
                DragDY = p.Y - wndY
                DragOn = -1
            End If
        End If
    End If

    ' Tah  move
    If DragOn Then
        If down Then
            _ScreenMove p.X - DragDX, p.Y - DragDY
        Else
            DragOn = 0
        End If
    End If

    PrevDown = down
End Sub


Reply


Messages In This Thread
RE: Flaming Text (let's make it a challenge) - by Petr - 01-30-2026, 11:13 PM

Possibly Related Threads…
Thread Author Replies Views Last Post
  3D Text SMcNeill 13 775 02-10-2026, 08:17 AM
Last Post: Unseen Machine
  CHALLENGE: Make a better drag and drop to a form. Pete 0 223 12-20-2025, 08:41 AM
Last Post: Pete
  Clouds? for 100 Lines or Less Challenge bplus 12 1,135 10-27-2025, 08:23 AM
Last Post: bplus
  Text Previewer (windows only) SMcNeill 14 2,463 03-25-2024, 02:34 PM
Last Post: SMcNeill
  using QB64 to make "end credits" to a movie MrCreemy 0 491 12-29-2022, 04:36 AM
Last Post: MrCreemy

Forum Jump:


Users browsing this thread: 2 Guest(s)