Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Neon Lights
#1
I came across this neat little Haiku screensaver and couldn't resist porting it to QB64‑PE.

Enjoy!

[Image: Screenshot-2026-03-04-163128.png]

Code: (Select All)
' =========================================================================
' Neon Lights
' Ported from a Haiku C++ screensaver to QB64-PE by a740g
' Original Author: Adrien Destugues (MIT License)
' https://github.com/pulkomandy/neonlights
' =========================================================================

_DEFINE A-Z AS LONG
OPTION _EXPLICIT

$COLOR:32

CONST SCREEN_WIDTH = 1024
CONST SCREEN_HEIGHT = 768
CONST PARTICLES = 3000
CONST CITIES = 64
CONST SPOTS = 22 ' must be <= CITIES

TYPE City
    x AS SINGLE
    y AS SINGLE
    oldX AS SINGLE
    oldY AS SINGLE
    vx AS SINGLE
    vy AS SINGLE
    other AS LONG
    r AS LONG
    g AS LONG
    b AS LONG
END TYPE

DIM SHARED cities(0 TO CITIES - 1) AS City
DIM SHARED goodColor(0 TO 5) AS _UNSIGNED LONG
goodColor(0) = Blue
goodColor(1) = Cyan
goodColor(2) = Magenta
goodColor(3) = Green
goodColor(4) = Red
goodColor(5) = Yellow

SCREEN _NEWIMAGE(SCREEN_WIDTH, SCREEN_HEIGHT, 32)
_TITLE "Neon Lights"

RANDOMIZE TIMER

DIM frame AS LONG

DO
    IF (frame AND 1023) = 0 THEN
        Restart
    END IF

    DIM a AS LONG, b AS LONG, tr AS LONG
    DIM t AS SINGLE, dx AS SINGLE, dy AS SINGLE

    DIM n AS LONG
    WHILE n < PARTICLES
        a = INT(RND * SPOTS)
        tr = 0
        DO
            b = INT(RND * SPOTS)
            tr = tr + 1
        LOOP WHILE tr < 100 _ANDALSO CityDistance(a, b) < (SCREEN_WIDTH * SCREEN_HEIGHT) / (10 * (SCREEN_WIDTH + SCREEN_HEIGHT))

        IF tr < 100 THEN
            t = _PI(RND)

            dx = SIN(t) * (cities(b).x - cities(a).x) + cities(a).x
            dy = SIN(t) * (cities(b).y - cities(a).y) + cities(a).y

            dx = dx + (RND * 3!) - 1.5!
            dy = dy + (RND * 3!) - 1.5!

            DIM mixedR AS LONG: mixedR = (cities(a).r + cities(b).r) \ 2
            DIM mixedG AS LONG: mixedG = (cities(a).g + cities(b).g) \ 2
            DIM mixedB AS LONG: mixedB = (cities(a).b + cities(b).b) \ 2

            PSET (dx, dy), _RGB32(mixedR, mixedG, mixedB, 32)
        END IF

        n = n + 1
    WEND
    n = 0

    DIM c AS LONG
    WHILE c < SPOTS
        cities(c).vx = cities(c).vx + (cities(cities(c).other).x - cities(c).x) / SCREEN_WIDTH
        cities(c).vy = cities(c).vy + (cities(cities(c).other).y - cities(c).y) / SCREEN_HEIGHT

        cities(c).vx = cities(c).vx * 0.986!
        cities(c).vy = cities(c).vy * 0.979!

        IF RND < 0.01! THEN
            cities(c).other = INT(RND * SPOTS)
        END IF

        cities(c).x = cities(c).x + cities(c).vx
        cities(c).y = cities(c).y + cities(c).vy

        LINE (cities(c).oldX, cities(c).oldY)-(cities(c).x, cities(c).y), White

        cities(c).oldX = cities(c).x
        cities(c).oldY = cities(c).y

        c = c + 1
    WEND
    c = 0

    _DISPLAY
    _LIMIT 60

    frame = frame + 1
LOOP UNTIL _KEYHIT = _KEY_ESC

SYSTEM

SUB Restart
    CLS

    DIM tinc AS SINGLE: tinc = _PI(2! / SPOTS)

    DIM i AS LONG
    WHILE i < SPOTS
        cities(i).x = SCREEN_WIDTH \ 2
        cities(i).y = SCREEN_HEIGHT \ 2
        cities(i).oldX = cities(i).x
        cities(i).oldY = cities(i).y

        cities(i).vx = (1! + INT(RND * 11!)) * SIN(tinc * i)
        cities(i).vy = (1! + INT(RND * 11!)) * COS(tinc * i)

        DIM cIdx AS LONG: cIdx = INT(RND * 6!)
        cities(i).r = _RED32(goodColor(cIdx))
        cities(i).g = _GREEN32(goodColor(cIdx))
        cities(i).b = _BLUE32(goodColor(cIdx))

        DO
            cities(i).other = INT(RND * SPOTS)
        LOOP WHILE cities(i).other = i

        i = i + 1
    WEND
END SUB

FUNCTION CityDistance! (a AS LONG, b AS LONG)
    IF a <> b THEN
        DIM dx AS SINGLE: dx = cities(b).x - cities(a).x
        DIM dy AS SINGLE: dy = cities(b).y - cities(a).y
        CityDistance = SQR(dx * dx + dy * dy)
    END IF
END FUNCTION
Reply
#2
+1 and it's nice without the white line:

   
  724  855  599  923  575  468  400  206  147  564  878  823  652  556 bxor cross forever
Reply
#3
This reminds me of Guts only going in several directions at once!

Here is my mod from cities to stars!
Code: (Select All)
' =========================================================================
' Neon Lights mod b+ 2026-03-04 of a740g port
' Ported from a Haiku C++ screensaver to QB64-PE by a740g
' Original Author: Adrien Destugues (MIT License)
' https://github.com/pulkomandy/neonlights
' =========================================================================

_Define A-Z As LONG
Option _Explicit

$Color:32

Const SCREEN_WIDTH = 1024
Const SCREEN_HEIGHT = 720
Const PARTICLES = 3000
Const STARS = 64
Const SPOTS = 22 ' must be <= STARS

Type Star
    x As Single
    y As Single
    oldX As Single
    oldY As Single
    vx As Single
    vy As Single
    other As Long
    r As Long
    g As Long
    b As Long
End Type

Dim Shared stars(0 To STARS - 1) As Star
Dim Shared goodColor(0 To 5) As _Unsigned Long
goodColor(0) = Blue
goodColor(1) = Cyan
goodColor(2) = Magenta
goodColor(3) = Green
goodColor(4) = Red
goodColor(5) = Yellow

Screen _NewImage(SCREEN_WIDTH, SCREEN_HEIGHT, 32)
_ScreenMove 0, 0
_Title "Neon Stars press any for new Star System, esc to quit"

Randomize Timer

Dim frame As Long
Restart
Do
    If InKey$ <> "" Then
        Restart
    End If

    Dim a As Long, b As Long, tr As Long, r
    Dim t As Single, dx As Single, dy As Single

    Dim n As Long
    While n < PARTICLES
        a = Int(Rnd * SPOTS)
        tr = 0
        Do
            b = Int(Rnd * SPOTS)
            tr = tr + 1
        Loop While tr < 100 _AndAlso StarDistance(a, b) < (SCREEN_WIDTH * SCREEN_HEIGHT) / (10 * (SCREEN_WIDTH + SCREEN_HEIGHT))

        If tr < 100 Then
            t = _Pi(Rnd)

            dx = Sin(t) * (stars(b).x - stars(a).x) + stars(a).x
            dy = Sin(t) * (stars(b).y - stars(a).y) + stars(a).y

            dx = dx + (Rnd * 3!) - 1.5!
            dy = dy + (Rnd * 3!) - 1.5!

            Dim mixedR As Long: mixedR = (stars(a).r + stars(b).r) \ 2
            Dim mixedG As Long: mixedG = (stars(a).g + stars(b).g) \ 2
            Dim mixedB As Long: mixedB = (stars(a).b + stars(b).b) \ 2

            PSet (dx, dy), _RGB32(mixedR, mixedG, mixedB, 32)
        End If

        n = n + 1
    Wend
    n = 0

    Dim c As Long
    While c < SPOTS
        stars(c).vx = stars(c).vx + (stars(stars(c).other).x - stars(c).x) / SCREEN_WIDTH
        stars(c).vy = stars(c).vy + (stars(stars(c).other).y - stars(c).y) / SCREEN_HEIGHT

        stars(c).vx = stars(c).vx * 0.986!
        stars(c).vy = stars(c).vy * 0.979!

        If Rnd < 0.01! Then
            stars(c).other = Int(Rnd * SPOTS)
        End If

        stars(c).x = stars(c).x + stars(c).vx
        stars(c).y = stars(c).y + stars(c).vy

        'Line (stars(c).oldX, stars(c).oldY)-(stars(c).x, stars(c).y), White
        For r = 7 To 0 Step -1
            Circle (stars(c).x, stars(c).y), r, _RGB32(Rnd * 250, 80 + Rnd * 80, 160, 60 * (8 - r) / 8)
            Circle (stars(c).x, stars(c).y), 0, &HFFFFFFFF '_RGB32(Rnd * 250, 80 + Rnd * 80, 160, 255)
        Next

        stars(c).oldX = stars(c).x
        stars(c).oldY = stars(c).y

        c = c + 1
    Wend
    c = 0

    _Display
    _Limit 60

    frame = frame + 1
Loop Until _KeyHit = _KEY_ESC

System

Sub Restart
    Cls

    Dim tinc As Single: tinc = _Pi(2! / SPOTS)

    Dim i As Long
    While i < SPOTS
        stars(i).x = SCREEN_WIDTH \ 2
        stars(i).y = SCREEN_HEIGHT \ 2
        stars(i).oldX = stars(i).x
        stars(i).oldY = stars(i).y

        stars(i).vx = (1! + Int(Rnd * 15!)) * Sin(tinc * i)
        stars(i).vy = (1! + Int(Rnd * 15!)) * Cos(tinc * i)

        Dim cIdx As Long: cIdx = Int(Rnd * 6!)
        stars(i).r = _Red32(goodColor(cIdx))
        stars(i).g = _Green32(goodColor(cIdx))
        stars(i).b = _Blue32(goodColor(cIdx))

        Do
            stars(i).other = Int(Rnd * SPOTS)
        Loop While stars(i).other = i

        i = i + 1
    Wend
End Sub

Function StarDistance! (a As Long, b As Long)
    If a <> b Then
        Dim dx As Single: dx = stars(b).x - stars(a).x
        Dim dy As Single: dy = stars(b).y - stars(a).y
        StarDistance = Sqr(dx * dx + dy * dy)
    End If
End Function


Attached Files Thumbnail(s)
   
  724  855  599  923  575  468  400  206  147  564  878  823  652  556 bxor cross forever
Reply
#4
Cool program, @a740g. I was sniffing at the code and noticed your use of _KEY_ESC. What is this mysterious unicorn? Why have I never seen anyone use this before? Are there other key codes like this for _KEYHIT, a list somewhere? Thnx
Reply
#5
(03-05-2026, 05:40 AM)NakedApe Wrote: Cool program, @a740g. I was sniffing at the code and noticed your use of _KEY_ESC. What is this mysterious unicorn? Why have I never seen anyone use this before? Are there other key codes like this for _KEYHIT, a list somewhere? Thnx

@NakedApe As of v4.0 QB64PE comes with a whole package of predefined CONST values like this.  You can get a list of them from here: 

https://qb64phoenix.com/qb64wiki/index.php/Constants

I also developed a tool which makes browsing and finding them much simpler as well.  You can get it here:

https://qb64phoenix.com/forum/showthread.php?tid=4333
Reply
#6
@bplus @NakedApe Thanks!  Smile

If you want to quickly see what was added or changed in each version of QB64-PE, check out the change logs here: https://qb64phoenix.com/qb64wiki/index.p...d_Versions
Reply
#7
Thanks, Steve and Sam! That one slipped by me. I like those constants.  Smile
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Makes shift lights blink in a binary pattern eoredson 1 626 06-04-2024, 03:56 AM
Last Post: SMcNeill
  3D Disco Lights SierraKen 4 1,204 08-23-2022, 05:44 PM
Last Post: SierraKen

Forum Jump:


Users browsing this thread: