11-06-2025, 08:06 PM (This post was last modified: 11-08-2025, 09:05 AM by madscijr.
Edit Reason: added psychedelic version
)
UPDATE: figured this out, the final program is here! But I'm tired... In the words of c3p0, "no more adventures!"
Hi everyone... over the weekend I did some work on the "van halen" screensaver, playing around with vector graphics, and added the band logo moving across the screen and getting bigger for a 3D effect.
It works good drawn as just an outline, even with 10 or 20 of them going at once (for that see attached "VanHalenizer2-05-17.multi vectors.bas").
(Hey @BPlus, check out "VanHalenizer2-05-17b.multi vectors.PSYCHEDELIC!.bas"! )
BUT then I wanted to make them solid (filled in), and that's where I ran into trouble.
At first I tried filling in the logo itself which is 2 closed shapes, but was having trouble determining a point inside each shape. That version runs pretty fast and looks good... when the flood fill is working (about half the time) - for that see attached "VanHalenizer2-05-17i.multi vectors.PAINT FILL.bas"). Maybe fixing this version is the ticket?
So I changed tactics to fill around the shape with black and then use _ClearColor to get rid of the black, and voila, solid shape. Which brings us to the last version ("VanHalenizer2-05-23.bas"). It reliably produces the solid shapes, but is SLOOOOW (search "USE FLOOD FILL" to go right to the problem section).
I tried a couple of different flood fill methods which haven't made a difference, which is surprising, because back around May we had a thread about fast ways to do flood fill, and came up with some pretty good ones (this program compares the various methods).
If anyone has any suggestions that don't involve completely rewriting the program & vector logic (which took a long time to get right!), a 2nd set of eyes would be much appreciated...
11-06-2025, 10:57 PM (This post was last modified: 11-06-2025, 11:07 PM by madscijr.)
Thanks, B! Your various eye candy programs have definitely been an inspiration!
The colors are not random - I actually put some effort into choosing each, then I just populated an array with the values in order of the spectrum. But no fancy math like in your proggies!
I got it working right - the solution I used was simply to store a "fill point" in the data for each shape. I think a more robust solution would be to come up with logic to find a point inside the shape, such a routine could come in handy for other projects, but I'm feeling too burnt out right now and it's not that important.
Quote:I think a more robust solution would be to come up with logic to find a point inside the shape,
What kind of shapes are we talking about? Assuming 2D there are shapes created by points connected by lines that enclose a space which can be described by linear equations for lines and there are closed curves which have far more exotic formula descriptions. I suspect you are talking of the first case of which a triangle is simplest case and finding some point inside not difficult. For that take the midpoint of 2 points and then find midpoint of that point and the third point. I would say:
for triangle {(x1, y1), (x2, y2), (x3, y3)}
pt ((x3 + (x1 + x2)/2)/2, (y3 + (y1 + y2)/2)/2) will be inside it.
11-08-2025, 03:29 PM (This post was last modified: 11-08-2025, 05:46 PM by madscijr.
Edit Reason: fixed typo
)
I tried doing the "centroid" of the triangle as you suggested, but that requires knowing 3 points whose middle lies enclosed in the shape. If you look at the V and H in the band logo here we see it may not be so easy if the starting point isn't the top left or top right. Once the point is found for the V and the H, it can be adjusted as the shapes change scale. So by robust I mean an algorithm that takes a set of points for one or more non-connected COMPLEX shapes and determines the "inside" point of each, WITHOUT a human having to tell it which points to use, where the start and end points can lie anywhere.
11-08-2025, 05:32 PM (This post was last modified: 11-08-2025, 05:38 PM by Petr.)
I don't know if I understood correctly, but is it just about coloring the logo? If so, here is a simpler and faster solution. You do need an image, but it can also be easily converted directly into the source code.
In this example, you don't calculate anything at all. You use the image as a mask, according to which you then change the pixel color value with the _Mem command. It's much faster than calculating something and then coloring it.
If is needed coloring those shapes that are created with the Line command as vectors, so you can't use transparency there (for POINT) but this could be solved with the _MapTriangle command, where you map one pixel with transparency to three points. That then works the same as if you were coloring it, but it's much faster. I haven't studied this part of the program... I've already chosen my vacation, sorry.
Code: (Select All)
logo$ = "VHLogo.png"
Dim logo As Long
logo = _LoadImage(logo$, 32)
Const TotalLogos = 50
Dim As _MEM m, n
Dim NewColor As _Unsigned Long, Black As _Unsigned Long
Black = _RGB32(0)
Type LogoPos
As Integer X, Y
Handle As Long
As Single Zoom, Xstep, Ystep
End Type
Dim ColoredLogo(1 To TotalLogos) As LogoPos
W = _Width(logo)
H = _Height(logo)
For EmptyImages = 1 To TotalLogos
ColoredLogo(EmptyImages).Handle = _NewImage(W, H, 32)
Next
Virtual = _NewImage(W, H, 32)
m = _MemImage(logo)
n = _MemImage(Virtual)
'fill start values and logo colors
For Logos = 1 To TotalLogos
NewColor = _RGBA32(255 * Rnd, 255 * Rnd, 255 * Rnd, 255 * Rnd)
Do Until i& = m.SIZE - 4
If _MemGet(m, m.OFFSET + i&, _Unsigned Long) = Black Then _MemPut n, n.OFFSET + i&, NewColor
i& = i& + 4
Loop
i& = 0
ColoredLogo(Logos).Handle = _CopyImage(Virtual, 32)
_MemFill n, n.OFFSET, n.SIZE, 0 As _UNSIGNED LONG
ColoredLogo(Logos).X = Rnd * 1024
ColoredLogo(Logos).Y = Rnd * -H
ColoredLogo(Logos).Zoom = (1 + Rnd * 10) / 15
If Rnd * 10 > 3 Then o = -1 Else o = 1
ColoredLogo(Logos).Xstep = (1 + Rnd * 3) / 2 * o
ColoredLogo(Logos).Ystep = (1 + Rnd * 10) / 1.5
If ColoredLogo(Logos).Y > -H * ColoredLogo(Logos).Zoom Then ColoredLogo(Logos).Y = -H * ColoredLogo(Logos).Zoom - 200
Next
Screen _NewImage(1024, 768, 32)
L = 0
Do Until _KeyHit
L = L + 1
If L > TotalLogos Then
L = 1
_Display
_Limit 20
Cls
End If
11-08-2025, 05:44 PM (This post was last modified: 11-08-2025, 05:47 PM by madscijr.
Edit Reason: whoops
)
Thanks for sharing - very interesting. In this case, the image changes size, starting very small then getting bigger, and can't be pixellated. Also, there can be 50 or more of them moving on the screen at the same time, all different colors and sizes. I'd prefer not to rely on additional files such as PNG. But I'll play with your code when I get a chance, I could learn a thing or two. Thanks again, @petr!
_PutImage , t& 'check our current image , OK
cc~& = Point(5, 5) ' back color to remove from image
Black~& = &HFF000000 ' black lines the color to change
While _KeyDown(27) = 0
resetPlasma
Cls
scale = .1: rot = 0
For x = 100 To 460 Step 2
newT& = swapColor&(t&, Black~&, Plasma~&)
_ClearColor cc~&, newT&
RotoZoom23d x * 1.05, x, newT&, scale, scale, rot
scale = scale + .008
rot = rot + 2
_FreeImage newT&
_Display
_Limit 30
Next
_Delay 1
Wend
' create new Image Handle for an image copy with a color changed from original image, returns new Handle&
'https://www.qb64.org/forum/index.php?topic=2451.0
' from Petr to Craz1000
Function swapColor& (oldHandle&, oldcolor~&, newcolor~&)
Dim m As _MEM, c As _Unsigned Long, h As Long
h = _CopyImage(oldHandle&, 32)
m = _MemImage(h)
Do Until a& = m.SIZE - 4
a& = a& + 4
c~& = _MemGet(m, m.OFFSET + a&, _Unsigned Long)
If c~& = oldcolor~& Then _MemPut m, m.OFFSET + a&, newcolor~&
Loop
_MemFree m
swapColor& = h
End Function
' tested in same rotozoom23d test code as original 2023-01-20
Sub RotoZoom23d (centerX As Long, centerY As Long, Image As Long, xScale As Single, yScale As Single, DRotation As Single)
Dim As Single px(3), py(3), sinr, cosr ' thanks to James D Jarvis who fixed this on 2023/01/18
Dim As Long IW, IH, i, x2, y2
IW& = _Width(Image&): IH& = _Height(Image&)
px(0) = -IW& / 2 * xScale: py(0) = -IH& / 2 * yScale: px(1) = -IW& / 2 * xScale: py(1) = IH& / 2 * yScale
px(2) = IW& / 2 * xScale: py(2) = IH& / 2 * yScale: px(3) = IW& / 2 * xScale: py(3) = -IH& / 2 * yScale
sinr! = Sin(-0.01745329 * DRotation): cosr! = Cos(-0.01745329 * DRotation)
For i& = 0 To 3
' x2& = (px(i&) * cosr! + sinr! * py(i&)) * xScale + centerX: y2& = (py(i&) * cosr! - px(i&) * sinr!) * yScale + centerY
x2& = (px(i&) * cosr! + sinr! * py(i&)) + centerX: y2& = (py(i&) * cosr! - px(i&) * sinr!) + centerY
px(i&) = x2&: py(i&) = y2&
Next
' might not need Seamless?
_MapTriangle _Seamless(0, 0)-(0, IH& - 1)-(IW& - 1, IH& - 1), Image& To(px(0), py(0))-(px(1), py(1))-(px(2), py(2))
_MapTriangle _Seamless(0, 0)-(IW& - 1, 0)-(IW& - 1, IH& - 1), Image& To(px(0), py(0))-(px(3), py(3))-(px(2), py(2))
End Sub
_PutImage , t& 'check our current image , OK
cc~& = Point(5, 5) ' back color to remove from image
Black~& = &HFF000000 ' black lines the color to change
While _KeyDown(27) = 0
resetPlasma
Cls
scale = .1: rot = 0
For x = 100 To 460 Step 10
newT& = swapColor&(t&, Black~&, Plasma~&)
_ClearColor cc~&, newT&
RotoZoom23d x * 1.05, x, newT&, scale, scale, rot
scale = scale + .02
rot = rot + 10
_FreeImage newT&
_Display
_Limit 30
Next
_Delay 1
Wend
' create new Image Handle for an image copy with a color changed from original image, returns new Handle&
'https://www.qb64.org/forum/index.php?topic=2451.0
' from Petr to Craz1000
Function swapColor& (oldHandle&, oldcolor~&, newcolor~&)
Dim m As _MEM, c As _Unsigned Long, h As Long
h = _CopyImage(oldHandle&, 32)
m = _MemImage(h)
Do Until a& = m.SIZE - 4
a& = a& + 4
c~& = _MemGet(m, m.OFFSET + a&, _Unsigned Long)
If c~& = oldcolor~& Then _MemPut m, m.OFFSET + a&, newcolor~&
Loop
_MemFree m
swapColor& = h
End Function
' tested in same rotozoom23d test code as original 2023-01-20
Sub RotoZoom23d (centerX As Long, centerY As Long, Image As Long, xScale As Single, yScale As Single, DRotation As Single)
Dim As Single px(3), py(3), sinr, cosr ' thanks to James D Jarvis who fixed this on 2023/01/18
Dim As Long IW, IH, i, x2, y2
IW& = _Width(Image&): IH& = _Height(Image&)
px(0) = -IW& / 2 * xScale: py(0) = -IH& / 2 * yScale: px(1) = -IW& / 2 * xScale: py(1) = IH& / 2 * yScale
px(2) = IW& / 2 * xScale: py(2) = IH& / 2 * yScale: px(3) = IW& / 2 * xScale: py(3) = -IH& / 2 * yScale
sinr! = Sin(-0.01745329 * DRotation): cosr! = Cos(-0.01745329 * DRotation)
For i& = 0 To 3
' x2& = (px(i&) * cosr! + sinr! * py(i&)) * xScale + centerX: y2& = (py(i&) * cosr! - px(i&) * sinr!) * yScale + centerY
x2& = (px(i&) * cosr! + sinr! * py(i&)) + centerX: y2& = (py(i&) * cosr! - px(i&) * sinr!) + centerY
px(i&) = x2&: py(i&) = y2&
Next
' might not need Seamless?
_MapTriangle _Seamless(0, 0)-(0, IH& - 1)-(IW& - 1, IH& - 1), Image& To(px(0), py(0))-(px(1), py(1))-(px(2), py(2))
_MapTriangle _Seamless(0, 0)-(IW& - 1, 0)-(IW& - 1, IH& - 1), Image& To(px(0), py(0))-(px(3), py(3))-(px(2), py(2))
End Sub