Author Topic: Recursive Fills (almost)  (Read 6986 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Recursive Fills (almost)
« Reply #15 on: November 05, 2021, 09:40:37 am »
The main thing mine is doing with _MEM is just copying our screen over into an array for us, so we can play with the values with the array, rather than having to use POINT each time, since POINT is slow.  I simply set my array to what elements need to be filled and then paint the screen based off those coordinates once I've gathered them all.

Weird enough however, I've ran into a real oddity that I can't explain at all in the process here: https://www.qb64.org/forum/index.php?topic=4361.0

The method that does the least mem duplication and copying of values is the one that runs the slowest for us -- by a 10 to 1 margin of speed!  Now, what the heck is up with that??
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Recursive Fills (almost)
« Reply #16 on: November 05, 2021, 09:55:44 am »
I sat down and now (since the last post here) I wrote something, that seems to work faster (as fast as paint). The solution is to create a two-color mask and then use the paint statement and finally insert the image over the original. It's not as fast as Steve's version, but it's definitely faster than what I created in 2018.

Code: QB64: [Select]
  1.  
  2. Screen _NewImage(1024, 768, 32)
  3.     Cls , Red
  4.     For c = 1 To 40
  5.         Circle (Rnd * 980, Rnd * 740), Rnd * 100 + 10, _RGB32(255 * Rnd)
  6.         X = Rnd * 1024
  7.         Y = Rnd * 768
  8.         Lwidth = Rnd * 100
  9.         Lheight = Rnd * 100
  10.         Line (X, Y)-(X + Lwidth, Y + Lheight), _RGB32(255 * Rnd, 255 * Rnd, 255 * Rnd), BF
  11.     Next
  12.     _Delay .3
  13.     _MouseMove 512, 384
  14.  
  15.  
  16.     sp 512, 384, White
  17.     _Delay .3
  18.  
  19. Sub sp (x, y, c~&)
  20.     W = _Width: H = _Height
  21.     Virtual = _NewImage(W, H, 32)
  22.  
  23.     Dim m As _MEM, n As _MEM, Bck As _Unsigned Long
  24.     m = _MemImage(_Source)
  25.     n = _MemImage(Virtual)
  26.  
  27.     'create mask (2 color image)
  28.     position& = (y * W + x) * 4
  29.     _MemGet m, m.OFFSET + position&, Bck
  30.     Clr2~& = _RGB32(_Red32(Bck) - 1, _Green32(Bck) - 1, _Blue32(Bck) - 1)
  31.     D& = 0
  32.     Do Until D& = n.SIZE
  33.         CLR~& = _MemGet(m, m.OFFSET + D&, _Unsigned Long)
  34.         If CLR~& = Bck~& Then _MemPut n, n.OFFSET + D&, CLR~& Else _MemPut n, n.OFFSET + D&, Clr2~&
  35.         D& = D& + 4
  36.     Loop
  37.  
  38.  
  39.     d = _Dest
  40.     _Dest Virtual
  41.     Paint (x, y), c~&, Clr2~&
  42.     _Dest d
  43.     _ClearColor Clr2~&, Virtual
  44.     _PutImage , Virtual, d
  45.     _MemFree m
  46.     _MemFree n
  47.     _FreeImage Virtual
  48.  
  49.  
  50. _MouseMove in program is used for us to show where is fill point.
  51.  

WTF @Petr this completely disables my mouse and I have to shut down computer!  :(
« Last Edit: November 05, 2021, 10:25:21 am by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Recursive Fills (almost)
« Reply #17 on: November 05, 2021, 10:06:41 am »
WTF @Petr this completely diables my mouse and I have to shut down computer!  :(

How does it disable the mouse?   It moves it into the center of the screen, but the mouse is still there.  All you have to do is Alt-F4 to close the program as it doesn't have any native QUIT built into it, but it doesn't require a PC reboot.  :P
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Recursive Fills (almost)
« Reply #18 on: November 05, 2021, 10:20:30 am »
How does it disable the mouse?   It moves it into the center of the screen, but the mouse is still there.  All you have to do is Alt-F4 to close the program as it doesn't have any native QUIT built into it, but it doesn't require a PC reboot.  :P

Alt+F4 didn't work, @SMcNeill so you've tried the code and works fine for you?

I'm using v2.0 does that make a difference?

What it does is take a screen shot of my IDE and everytime I move outside the screen shot with mouse it moves it back into screen.

BTW It was drawing (Drawing Screen) underneath the IDE Screen.

If I don't have control of mouse, I consider it disabling it, specially when I am pissed.
« Last Edit: November 05, 2021, 10:29:16 am by bplus »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Recursive Fills (almost)
« Reply #19 on: November 05, 2021, 10:29:45 am »
@bplus

BPlus, this is unexpected. I always test it before I release it to the world, I usually end it by pressing Ctrl + Pause and this is a reliable way to exit (unless it is disabled by the _EXIT command, which in this case is not). Via Ctrl + Pause it can always be terminated. If this program is not in focus, so switch to it with ALT + TAB and then also Alt+F4 works!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Recursive Fills (almost)
« Reply #20 on: November 05, 2021, 10:37:52 am »
@Petr

OK I have noted Ctrl + Pause as something else to try. Hmm... my Pause is 2nd listing on my right shift key, don't think I've ever used it for anything before.

Why not draw arrow and label as Paint/Fill Point after drawing random stuff?

EDIT OK additional notes (after your edit) duly noted, thanks Petr

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Recursive Fills (almost)
« Reply #21 on: November 05, 2021, 11:14:42 am »
@Petr with some mods I can safely demo that great, fast fill! very nice, it was a painful birth but what a baby!

Code: QB64: [Select]
  1. _Title "Fast Fill! by Petr, arrow points to fill point!" ' b+ mods for safer running/specailly exiting  2021-11-05
  2. ' Very Nice Petr!!!  ref: https://www.qb64.org/forum/index.php?topic=4357.msg137803#msg137803
  3. ' bplus changed screen size, centered it and is drawing arrow to paint point (3 additional subs for that!)
  4.  
  5. Screen _NewImage(1024, 700, 32) ' a little less height please, dang it sharnk again because bottom below screen bottom
  6. _ScreenMove 150, 40 'Sorry guys _Middle is not!! why is this not centered I have room above title bar but screen extends below sight????
  7.  
  8.     Cls , Red
  9.     For c = 1 To 40
  10.         Circle (Rnd * 980, Rnd * 740), Rnd * 100 + 10, _RGB32(255 * Rnd)
  11.         X = Rnd * 1024
  12.         Y = Rnd * _Height
  13.         Lwidth = Rnd * 100
  14.         Lheight = Rnd * 100
  15.         Line (X, Y)-(X + Lwidth, Y + Lheight), _RGB32(255 * Rnd, 255 * Rnd, 255 * Rnd), BF
  16.     Next
  17.     arrow 514, 384, _Pi(1.25), 200
  18.     _Delay .7
  19.     '_MouseMove 512, 384  ' <<<<<<<< trouble maker!!!
  20.     sp 512, 384, White
  21.     _Delay 3
  22. Loop Until _KeyDown(27) ' bug out if user wants
  23.  
  24. Sub sp (x, y, c~&)
  25.     W = _Width: H = _Height
  26.     Virtual = _NewImage(W, H, 32)
  27.  
  28.     Dim m As _MEM, n As _MEM, Bck As _Unsigned Long
  29.     m = _MemImage(_Source)
  30.     n = _MemImage(Virtual)
  31.  
  32.     'create mask (2 color image)
  33.     position& = (y * W + x) * 4
  34.     _MemGet m, m.OFFSET + position&, Bck
  35.     Clr2~& = _RGB32(_Red32(Bck) - 1, _Green32(Bck) - 1, _Blue32(Bck) - 1)
  36.     D& = 0
  37.     Do Until D& = n.SIZE
  38.         If _KeyDown(27) Then System '>>>>  bug out if user wants
  39.         CLR~& = _MemGet(m, m.OFFSET + D&, _Unsigned Long)
  40.         If CLR~& = Bck~& Then _MemPut n, n.OFFSET + D&, CLR~& Else _MemPut n, n.OFFSET + D&, Clr2~&
  41.         D& = D& + 4
  42.     Loop
  43.  
  44.     d = _Dest
  45.     _Dest Virtual
  46.     Paint (x, y), c~&, Clr2~&
  47.     _Dest d
  48.     _ClearColor Clr2~&, Virtual
  49.     _PutImage , Virtual, d
  50.     _MemFree m
  51.     _MemFree n
  52.     _FreeImage Virtual
  53.  
  54. Sub arrow (x0, y0, rAngle, lngth)
  55.     Dim x1, y1, x2, y2, pi, i As Integer
  56.     pi = 3.14159265
  57.     x2 = x0 - lngth * Cos(rAngle)
  58.     y2 = y0 - lngth * Sin(rAngle)
  59.     drawLink x0, y0, .001 * lngth, x2, y2, .01 * lngth, &HFF00BB00
  60.     Line (x0, y0)-(x2, y2), &HFF00BB00
  61.     x2 = x0 - .1 * lngth * Cos(rAngle - .2 * pi)
  62.     y2 = y0 - .1 * lngth * Sin(rAngle - .2 * pi)
  63.     x1 = x0 - .1 * lngth * Cos(rAngle + .2 * pi)
  64.     y1 = y0 - .1 * lngth * Sin(rAngle + .2 * pi)
  65.     ftri x0, y0, x1, y1, x2, y2, &HFFFF8800
  66.     For i = .8 * lngth To lngth Step 3
  67.         x1 = x0 - i * Cos(rAngle)
  68.         y1 = y0 - i * Sin(rAngle)
  69.         x2 = x1 - .1 * lngth * Cos(rAngle - .25 * pi)
  70.         y2 = y1 - .1 * lngth * Sin(rAngle - .25 * pi)
  71.         Line (x1, y1)-(x2, y2), &HFF0000FF
  72.         x2 = x1 - .1 * lngth * Cos(rAngle + .25 * pi)
  73.         y2 = y1 - .1 * lngth * Sin(rAngle + .25 * pi)
  74.         Line (x1, y1)-(x2, y2), &HFF0000FF
  75.     Next
  76.  
  77. Sub drawLink (x1, y1, r1, x2, y2, r2, c As _Unsigned Long)
  78.     Dim a, a1, a2, x3, x4, x5, x6, y3, y4, y5, y6
  79.     a = _Atan2(y2 - y1, x2 - x1)
  80.     a1 = a + _Pi(1 / 2)
  81.     a2 = a - _Pi(1 / 2)
  82.     x3 = x1 + r1 * Cos(a1): y3 = y1 + r1 * Sin(a1)
  83.     x4 = x1 + r1 * Cos(a2): y4 = y1 + r1 * Sin(a2)
  84.     x5 = x2 + r2 * Cos(a1): y5 = y2 + r2 * Sin(a1)
  85.     x6 = x2 + r2 * Cos(a2): y6 = y2 + r2 * Sin(a2)
  86.     fquad x3, y3, x4, y4, x5, y5, x6, y6, c
  87.  
  88. 'need 4 non linear points (not all on 1 line) list them clockwise so x2, y2 is opposite of x4, y4
  89. Sub fquad (x1 As Integer, y1 As Integer, x2 As Integer, y2 As Integer, x3 As Integer, y3 As Integer, x4 As Integer, y4 As Integer, c As _Unsigned Long)
  90.     ftri x1, y1, x2, y2, x4, y4, c
  91.     ftri x3, y3, x4, y4, x1, y1, c
  92.  
  93. Sub ftri (x1, y1, x2, y2, x3, y3, K As _Unsigned Long)
  94.     Dim a&
  95.     a& = _NewImage(1, 1, 32)
  96.     _Dest a&
  97.     PSet (0, 0), K
  98.     _Dest 0
  99.     _MapTriangle _Seamless(0, 0)-(0, 0)-(0, 0), a& To(x1, y1)-(x2, y2)-(x3, y3)
  100.     _FreeImage a& '<<< this is important!
  101.  
  102.  

Updated code to deal with my _ScreenMove issues, no _Middle means no need for delay.
1024 X 700 QB64screen: 1024 is best max width for speedy graphics and 700 is max height that fits under a potential taskbar running along top of screen. RND y's fixed for new Height.
« Last Edit: November 05, 2021, 12:30:03 pm by bplus »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Recursive Fills (almost)
« Reply #22 on: November 05, 2021, 11:38:50 am »
Nicely done, @bplus :)

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Recursive Fills (almost)
« Reply #23 on: November 05, 2021, 12:33:03 pm »
@Petr

I made some changes for my _ScreenMove _Middle issues. If you have taskbar along top edge of your screen you might like this better now. The _Height is maximum screen that fits my laptop screen assuming a 40 pixel high Taskbar.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Recursive Fills (almost)
« Reply #24 on: November 05, 2021, 03:25:37 pm »
@johnno56  You are right!
@bplus  Your program works badly:

Code: QB64: [Select]
  1. _Title "Recursive Fill" 'b+ 2021-11-03
  2. Screen _NewImage(1980, 1050, 32) ' <<<<<<<<<<<<<<<<<< biggest screen I can see on laptop
  3. _Delay .25
  4.  
  5. Circle (900, 555), 450, Gold
  6. fill 900, 555, Gold
  7. fill 5, 5, Red
  8.  
  9. Function plus (x, y, c As _Unsigned Long)
  10.     plus = 0
  11.     If Point(x, y) <> c Then
  12.         For i = x - 1 To 0 Step -1
  13.             If Point(i, y) = c Then xl = i + 1: Exit For
  14.         Next
  15.         'if xl = 0 then xl = 0
  16.         For i = x + 1 To _Width - 1
  17.             If Point(i, y) = c Then xr = i - 1: Exit For
  18.         Next
  19.         If xr = 0 Then xr = _Width - 1
  20.         For i = y - 1 To 0 Step -1
  21.             If Point(x, i) = c Then yu = i + 1: Exit For
  22.         Next
  23.         'if yu = 0 then yu = 0
  24.         For i = y + 1 To _Height - 1
  25.             If Point(x, i) = c Then yd = i - 1: Exit For
  26.         Next
  27.         If yd = 0 Then yd = _Height - 1
  28.         Line (xl, y)-(xr, y), c
  29.         Line (x, yu)-(x, yd), c
  30.         plus = -1
  31.     End If
  32.  
  33. Sub fill (x, y, c As _Unsigned Long)
  34.     If x >= 0 And x < _Width And y >= 0 And y < _Height Then
  35.         If plus(x, y, c) Then
  36.             fill x - 1, y - 1, c
  37.             fill x - 1, y + 1, c
  38.             fill x + 1, y - 1, c
  39.             fill x + 1, y + 1, c
  40.         End If
  41.     End If
  42.  

I found my old...

Not seeing a problem with this code that fits my screen:
Code: QB64: [Select]
  1. _Title "Recursive Fill" 'b+ 2021-11-03
  2. Screen _NewImage(1024, 700, 32) ' <<<<<<<<<<<<<<<<<< biggest screen I can see on laptop
  3. _ScreenMove 150, 40
  4.  
  5. Circle (_Width / 2, _Height / 2), _Height / 2 - 5, Gold
  6. fill _Width / 2, _Height / 2, Gold
  7. fill 5, 5, Red
  8.  
  9. Function plus (x, y, c As _Unsigned Long)
  10.     plus = 0
  11.     If Point(x, y) <> c Then
  12.         For i = x - 1 To 0 Step -1
  13.             If Point(i, y) = c Then xl = i + 1: Exit For
  14.         Next
  15.         'if xl = 0 then xl = 0
  16.         For i = x + 1 To _Width - 1
  17.             If Point(i, y) = c Then xr = i - 1: Exit For
  18.         Next
  19.         If xr = 0 Then xr = _Width - 1
  20.         For i = y - 1 To 0 Step -1
  21.             If Point(x, i) = c Then yu = i + 1: Exit For
  22.         Next
  23.         'if yu = 0 then yu = 0
  24.         For i = y + 1 To _Height - 1
  25.             If Point(x, i) = c Then yd = i - 1: Exit For
  26.         Next
  27.         If yd = 0 Then yd = _Height - 1
  28.         Line (xl, y)-(xr, y), c
  29.         Line (x, yu)-(x, yd), c
  30.         plus = -1
  31.     End If
  32.  
  33. Sub fill (x, y, c As _Unsigned Long)
  34.     If x >= 0 And x < _Width And y >= 0 And y < _Height Then
  35.         If plus(x, y, c) Then
  36.             fill x - 1, y - 1, c
  37.             fill x - 1, y + 1, c
  38.             fill x + 1, y - 1, c
  39.             fill x + 1, y + 1, c
  40.         End If
  41.     End If
  42.  
  43.  

It works as expected, this recursive fill only stops when it encounters the same color that it's filling, pretty useless actually, worse this fill wont go around circles but will around rectangles?

Anyway at least it's recursive.

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Recursive Fills (almost)
« Reply #25 on: November 05, 2021, 04:40:38 pm »
I remember this type of non-recursive flood fill. Back in '85, my old Amstrad, no paint or fill... Had to use a program similar to this one. Using a 4mhz CPU was 'painful' to watch... Compared to your 'thoroughbred' my old routine was a 'plough horse'... Nicely done... I have snaffled the min / max functions to store in my 'snippets' folder... bonus! ;) lol
Logic is the beginning of wisdom.