09-03-2024, 12:58 PM (This post was last modified: 09-03-2024, 01:00 PM by bplus.)
Code: (Select All)
'vince's circle fill this one does not bother with types good almost identical to Steve's
Sub fcirc1 (x, y, r, c As _Unsigned Long)
x0 = r
y0 = 0
e = -r
Do While y0 < x0
If e <= 0 Then
y0 = y0 + 1
Line (x - x0, y + y0)-(x + x0, y + y0), c, BF
Line (x - x0, y - y0)-(x + x0, y - y0), c, BF
e = e + 2 * y0
Else
Line (x - y0, y - x0)-(x + y0, y - x0), c, BF
Line (x - y0, y + x0)-(x + y0, y + x0), c, BF
x0 = x0 - 1
e = e - 2 * x0
End If
Loop
Line (x - r, y)-(x + r, y), c, BF
End Sub
Read the thread, I used this in Speed tests and Samuel saw it and used it in his version.
09-03-2024, 04:15 PM (This post was last modified: 09-03-2024, 04:45 PM by bplus.)
I suspect I know what this is doing:
Code: (Select All)
e = e + 2 * y0
else
e = e - 2 * x0
Can you put it into words so maybe I can confirm my suspicions.
BTW what we are calling Steve's is a version of Bresenham
from StackOverFlow void circle(Point p, int r) {
int x = 0;
int y = r;
int f = 1-r;
// plot vert/horiz points indepedently
while (x<y) {
x++;
if (f<0) {
f += 2*x+1;
} else {
y--;
f += 2*(x-y+1);
}
glRecti(p.x+x, p.y+y, p.x+x+1, p.y+y+1);
// plot other points using 8 way symmetry
// attempt to fill the circle - didn't go well
plotLine(Point(p.x, p.y+x), Point(p.x+x, p.y+x));
}
}
Update: that code is wrong! "didn't go well" indeed!
which looks more like vince version!
No creators here just copiers LOL we stand on shoulders of other great copiers.
BTW I was just watching argument of Creationist against evolution because I got into discussion about man not evolving from ape but BOTH evolving from a common ancestor species down the tree of Life.
yeah the "meta" algorithm is called Bresenham's and it's only a matter of from who each of us stole it from. I attached the couple of PDFs from where i learned it, then just typed it out in QB64, nothing original
the superficial way to draw a circle is to use square root, ie r = sqr(x^2 + y^2) and go from there, and likely on modern processors a simple square root might be as fast as addition, depending on how and where -- bresenham's just optimizes it away into sheer addition. the next consideration for filled circles is transparency support, avoiding overlapping lines, and assuming LINE BF is super fast as it should be
09-03-2024, 04:51 PM (This post was last modified: 09-03-2024, 05:09 PM by bplus.)
Thankyou vince for PDF's because I was considering doing a Circle, one to replace our faulty Circle built-in, ie you can NOT do transparent circles without lighter pixels on the x, y axis. It might come in handy for someone needing Transparent Circle edges.
Update: yeah these
Code: (Select All)
e = e + 2 * y0
else
e = e - 2 * x0
are what's getting around the need for SQR. Something about using the derivative of Square function for X^2 = 2x plus some fooling around
Well, it looks like this thread is finally winding down. Thanks for all the fun action, everyone! I'll will post my final FC SUB and last ball demo here using it. This had to be the most fun and challenging ball demo I've worked on. Bouncing balls inside a big ball, moving on the screen. It was a great learning experience, and I tried to fully comment the code. Hope you like it. FC SUB is posted at the bottom.
- Dav
Code: (Select All)
'===============
'BIGBALLDEMO.BAS
'===============
'Bouncing balls demo using vector reflection.
'By Dav, SEP 3rd/2024, for QB64 Phoenix Edition.
'===============
'About this demo
'===============
'This demo shows balls bouncing inside a bigger ball, and other balls
'bouncing on the outside. It uses my FC SUB to draw all the balls.
'Use the mouse to move the big ball. Press Any key to exit the demo.
'============================
'More details about this demo
'============================
'This demo was a challenge and a great learning experience for me.
'Instead of just reversing velocity direction when a ball hits an object,
'this demo uses 'vector reflection' to make them bounce realistically.
'When two balls collide, their velocity vector changes direction based on
'angle of impact, and the normal vector at the contact point. Their
'reflection velocities are computed based on their sizes, and their x/y
'positions are adjusted to prevent overlapping after collision.
Randomize Timer
Screen _NewImage(1000, 700, 32)
'=== defaults for the bigball ===
bigballsize = 200
bigballx = _Width / 2
bigbally = _Height / 2
'=== arrays for inside balls ===
insidenum = 50 'num of inside balls
Dim insidex(insidenum) 'x positions of inside balls
Dim insidey(insidenum) 'ypositions of inside balls
Dim insidexv(insidenum) 'x velocities of inside balls
Dim insideyv(insidenum) 'y velocities of inside balls
Dim insidesize(insidenum) 'sizes of inside balls
Dim insideclr~&(insidenum) 'colors of inside balls
'=== arrays for outside balls ===
outsidenum = 150 'num of outside balls
Dim outsidex(outsidenum) 'x positions of outside balls
Dim outsidey(outsidenum) 'y positions of outside balls
Dim outsidexv(outsidenum) 'x velocities of outside balls
Dim outsideyv(outsidenum) 'y velocities of outside balls
Dim outsidesizes(outsidenum) 'sizes of outside balls
Dim outsideclr~&(outsidenum) 'colors of outside balls
'=== initialize inside balls ===
For i = 0 To insidenum - 1
insidesize(i) = 5 + (Rnd * 15) 'random size
insideclr~&(i) = _RGBA(Rnd * 255, Rnd * 255, Rnd * 255, 200) 'color
insidexv(i) = (Rnd * 2 + 1) * (2 * Rnd - 1) 'x velocity between -3 and 3
insideyv(i) = (Rnd * 2 + 1) * (2 * Rnd - 1) 'y velocity between -3 and 3
Next
'=== initialize outside Balls ===
For j = 0 To outsidenum - 1
outsidesizes(j) = Int(Rnd * 26) + 5 'random size
outsideclr~&(j) = _RGBA(Rnd * 225, Rnd * 225, Rnd * 225, 125) 'color
outsidex(j) = Int(Rnd * _Width) 'x position
outsidey(j) = Int(Rnd * _Height) 'y position
outsidexv(j) = (Rnd * 2 + 1) * (2 * Rnd - 1) 'x velocity between -3 and 3
outsideyv(j) = (Rnd * 2 + 1) * (2 * Rnd - 1) 'y velocity between -3 and 3
Next
'=== draw a background image ===
For i = 1 To 1000
fc Rnd * _Width, Rnd * _Height, 20, _RGBA(55 + (Rnd * 100), 55 + (Rnd * 150), 55 + (Rnd * 200), 30), 0
Next: back& = _CopyImage(_Display)
'=== put mouse in middle of screen ===
_MouseMove _Width / 2, _Height / 2
'=========
'MAIN LOOP
'=========
Do
'=== put down background image ===
Cls: _PutImage (0, 0), back&
'=== handle inside balls ===
For i = 0 To insidenum - 1
'== move inside balls ==
insidex(i) = insidex(i) + insidexv(i)
insidey(i) = insidey(i) + insideyv(i)
'=== check if they collide with bigball edge ===
'calculate distance from the center x/y of bigball
dis = Sqr((insidex(i) - bigballx) ^ 2 + (insidey(i) - bigbally) ^ 2)
'check if distance + insideball size exceeds bigball size
If dis + insidesize(i) > bigballsize Then
'calculate normal vector for reflection
x = (insidex(i) - bigballx) / dis
y = (insidey(i) - bigbally) / dis
'calculate the reflection of velocity based impact angle
vr = insidexv(i) * x + insideyv(i) * y
'update velocity of insideball based on the normal
insidexv(i) = insidexv(i) - 2 * vr * x
insideyv(i) = insideyv(i) - 2 * vr * y
'below prevents overlapping by pushing insideball back
over = (dis + insidesize(i)) - bigballsize
insidex(i) = insidex(i) - x * over
insidey(i) = insidey(i) - y * over
End If
'=== finally draw insideball ===
fc insidex(i), insidey(i), insidesize(i), insideclr~&(i), 1
Next
'=== handle collisions of insideballs ===
For i = 0 To insidenum - 1
For j = i + 1 To insidenum - 1
If i <> j Then
'calculate distance between the two insideballs
dx = insidex(j) - insidex(i)
dy = insidey(j) - insidey(i)
dis = Sqr(dx * dx + dy * dy)
'check for collision, if so...
If dis < (insidesize(i) + insidesize(j)) Then
'calculate normal vector and overlapping distance
x = dx / dis: y = dy / dis 'normal
over = (insidesize(i) + insidesize(j)) - dis 'overlap distance
'move balls apart based on overlap amount
insidex(i) = insidex(i) - x * (over / 2)
insidey(i) = insidey(i) - y * (over / 2)
insidex(j) = insidex(j) + x * (over / 2)
insidey(j) = insidey(j) + y * (over / 2)
'reflect velocities based on collision
vr = (insidexv(j) - insidexv(i)) * x + (insideyv(j) - insideyv(i)) * y
'update ball velocities based on collision
insidexv(i) = insidexv(i) + vr * x: insideyv(i) = insideyv(i) + vr * y
insidexv(j) = insidexv(j) - vr * x: insideyv(j) = insideyv(j) - vr * y
End If
End If
Next
Next
'=== handle Outside balls ===
For j = 0 To outsidenum - 1
'draw outside ball
fc outsidex(j), outsidey(j), outsidesizes(j), outsideclr~&(j), 1
outsidex(j) = outsidex(j) + outsidexv(j)
outsidey(j) = outsidey(j) + outsideyv(j)
'these bounce the ball off the edges of screen.
'if outsideballs hits the edge, reverse directions.
If outsidex(j) < outsidesizes(j) Then
outsidex(j) = outsidesizes(j): outsidexv(j) = -outsidexv(j)
End If
If outsidex(j) > _Width - outsidesizes(j) Then
outsidex(j) = _Width - outsidesizes(j): outsidexv(j) = -outsidexv(j)
End If
If outsidey(j) < outsidesizes(j) Then
outsidey(j) = outsidesizes(j): outsideyv(j) = -outsideyv(j)
End If
If outsidey(j) > _Height - outsidesizes(j) Then
outsidey(j) = _Height - outsidesizes(j): outsideyv(j) = -outsideyv(j)
End If
'==== check for otsideball collision with bigball ===
'calculate distance from center
dis = Sqr((outsidex(j) - bigballx) ^ 2 + (outsidey(j) - bigbally) ^ 2)
If dis < (bigballsize + outsidesizes(j)) Then
'calculate the normal vector
x = (outsidex(j) - bigballx) / dis
y = (outsidey(j) - bigbally) / dis
'reflect the velocity off the normal vector
vr = outsidexv(j) * x + outsideyv(j) * y
outsidexv(j) = outsidexv(j) - 2 * vr * x
outsideyv(j) = outsideyv(j) - 2 * vr * y
'move outside ball back
'calculate how much it's overlapping...
over = (bigballsize + outsidesizes(j)) - dis
'move it away from the bigball
outsidex(j) = outsidex(j) + x * over
outsidey(j) = outsidey(j) + y * over
End If
Next
'=== handle collisions between the outsideballs ===
For i = 0 To outsidenum - 1
For j = i + 1 To outsidenum - 1
If i <> j Then
'get distance between the two outside balls
dx = outsidex(j) - outsidex(i)
dy = outsidey(j) - outsidey(i)
dis = Sqr(dx * dx + dy * dy)
'check for collision, if so...
If dis < (outsidesizes(i) + outsidesizes(j)) Then
'calculate normal vector and overlapping distance
x = dx / dis: y = dy / dis
'total overlap distance
over = (outsidesizes(i) + outsidesizes(j)) - dis
'move balls apart based on overlap
outsidex(i) = outsidex(i) - x * (over / 2)
outsidey(i) = outsidey(i) - y * (over / 2)
outsidex(j) = outsidex(j) + x * (over / 2)
outsidey(j) = outsidey(j) + y * (over / 2)
'reflect velocities between balls
vr = (outsidexv(j) - outsidexv(i)) * x + (outsideyv(j) - outsideyv(i)) * y
'update velocities based on collision
outsidexv(i) = outsidexv(i) + vr * x
outsideyv(i) = outsideyv(i) + vr * y
outsidexv(j) = outsidexv(j) - vr * x
outsideyv(j) = outsideyv(j) - vr * y
End If
End If
Next
Next
'=== draw the bigball ===
fc bigballx, bigbally, bigballsize, _RGBA(100, 200, 255, 75), 0
'draw an edge around it
Circle (bigballx, bigbally), bigballsize, _RGBA(255, 255, 255, 75)
_Display
_Limit 60
Loop Until InKey$ <> ""
Sub fc (cx, cy, radius, clr~&, grad)
'FC SUB by Dav
'Draws filled circle at cx/cy with given radius and color.
'If grad=1 it will create a gradient effect, otherwise it's a solid color.
If radius = 0 Then Exit Sub 'a safety bail (thanks bplus!)
If grad = 1 Then
red = _Red32(clr~&)
grn = _Green32(clr~&)
blu = _Blue32(clr~&)
alpha = _Alpha32(clr~&)
End If
r2 = radius * radius
For y = -radius To radius
x = Sqr(r2 - y * y)
' If doing gradient
If grad = 1 Then
For i = -x To x
dis = Sqr(i * i + y * y) / radius
red2 = red * (1 - dis) + (red / 2) * dis
grn2 = grn * (1 - dis) + (grn / 2) * dis
blu2 = blu * (1 - dis) + (blu / 2) * dis
clr2~& = _RGBA(red2, grn2, blu2, alpha)
Line (cx + i, cy + y)-(cx + i, cy + y), clr2~&, BF
Next
Else
Line (cx - x, cy + y)-(cx + x, cy + y), clr~&, BF
End If
Next
End Sub
Code: (Select All)
Sub fc (cx, cy, radius, clr~&, grad)
'FC SUB by Dav
'Draws filled circle at cx/cy with given radius and color.
'If grad=1 it will create a gradient effect, otherwise it's a solid color.
If radius = 0 Then Exit Sub 'a safety bail (thanks bplus!)
If grad = 1 Then
red = _Red32(clr~&)
grn = _Green32(clr~&)
blu = _Blue32(clr~&)
alpha = _Alpha32(clr~&)
End If
r2 = radius * radius
For y = -radius To radius
x = Sqr(r2 - y * y)
' If doing gradient
If grad = 1 Then
For i = -x To x
dis = Sqr(i * i + y * y) / radius
red2 = red * (1 - dis) + (red / 2) * dis
grn2 = grn * (1 - dis) + (grn / 2) * dis
blu2 = blu * (1 - dis) + (blu / 2) * dis
clr2~& = _RGBA(red2, grn2, blu2, alpha)
Line (cx + i, cy + y)-(cx + i, cy + y), clr2~&, BF
Next
Else
Line (cx - x, cy + y)-(cx + x, cy + y), clr~&, BF
End If
Next
End Sub