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

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Recursive Fills (almost)
« on: November 03, 2021, 01:39:42 am »
I almost have it working, it has a little problem getting around circles, looks kind of interesting though. It's pretty fast! see random tests after first screen.
Code: QB64: [Select]
  1. _Title "Recursive Fill" 'b+ 2021-11-03
  2. Screen _NewImage(800, 600, 32)
  3. _Delay .25
  4.  
  5. Line (110, 200)-Step(580, 200), _RGB32(255, 0, 0), B
  6. Circle (400, 300), 280, _RGB32(255, 0, 0)
  7. 'Circle (400, 300), 200.5, _RGB32(255, 0, 0) ' some circle radius leak like radius = 200
  8. 'Circle (400, 300), 201, _RGB32(255, 0, 0)
  9. fill 400, 300, _RGB32(255, 0, 0)
  10. Line (300, 10)-Step(200, 580), _RGB32(255, 0, 0), B
  11. fill 400, 150, _RGB32(255, 0, 0)
  12. fill 400, 450, _RGB32(255, 0, 0)
  13. While _KeyDown(27) = 0
  14.     Cls
  15.     Line (0, 0)-(_Width - 1, _Height - 1), _RGB32(255, 0, 0), B
  16.     doBoxes = Int(Rnd * 2)
  17.     For i = 1 To 10
  18.         If doBoxes Then Line (Rnd * (_Width - 100) + 50, Rnd * (_Height - 100) + 50)-(Rnd * 100, Rnd * 100), _RGB32(255, 0, 0), B
  19.         x = Rnd * _Width: y = Rnd * _Height: r = Rnd * 50 + 10
  20.         Circle (x, y), r, _RGB32(255, 0, 0)
  21.         Circle (x, y), r + .5, _RGB32(255, 0, 0)
  22.         Circle (x, y), r + 1, _RGB32(255, 0, 0)
  23.     Next
  24.     fill 400, 300, _RGB32(255, 0, 0)
  25.     'Beep
  26.     Sleep
  27.  
  28. Function plus (x, y, c As _Unsigned Long)
  29.     If Point(x, y) <> c Then
  30.         For i = x - 1 To 0 Step -1
  31.             If Point(i, y) = c Then xl = i + 1: Exit For
  32.         Next
  33.         'if xl = 0 then xl = 0
  34.         For i = x + 1 To _Width - 1
  35.             If Point(i, y) = c Then xr = i - 1: Exit For
  36.         Next
  37.         If xr = 0 Then xr = _Width - 1
  38.         For i = y - 1 To 0 Step -1
  39.             If Point(x, i) = c Then yu = i + 1: Exit For
  40.         Next
  41.         'if yu = 0 then yu = 0
  42.         For i = y + 1 To _Height - 1
  43.             If Point(x, i) = c Then yd = i - 1: Exit For
  44.         Next
  45.         If yd = 0 Then yd = _Height - 1
  46.         Line (xl, y)-(xr, y), c
  47.         Line (x, yu)-(x, yd), c
  48.         plus = -1
  49.     End If
  50.  
  51. Sub fill (x, y, c As _Unsigned Long)
  52.     If plus(x, y, c) Then
  53.         fill x - 1, y - 1, c
  54.         fill x - 1, y + 1, c
  55.         fill x + 1, y - 1, c
  56.         fill x + 1, y + 1, c
  57.     End If
  58.  
  59.  

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Recursive Fills (almost)
« Reply #1 on: November 03, 2021, 03:40:21 am »
Cool... Very fast... :)
Logic is the beginning of wisdom.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Recursive Fills (almost)
« Reply #2 on: November 03, 2021, 02:39:15 pm »
Thanks @johnno56 got any ideas for use?

I am thinking a mod of this will get us through mazes.

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Recursive Fills (almost)
« Reply #3 on: November 04, 2021, 06:40:28 am »
Been "out of the loop" today. Figured I would re-install my OS. Nice and fresh; quick and uncluttered... That should be good for another week... My Desktop is a magnet for junk and clutter... Where was I? Ideas you say? As long as the areas that require flood filling aren't too big, I suppose anything really... Mazes? 2D or 3D? Simple 2D mazes probably won't need a fill... After all, the walls, are just filled squares and rectangles... "line()-()" could take care of that... Raycasting could use vertical rectangle segments... Odd 4-sided walls could use a flood fill instead of using textures... Or any of the programs on QB64 that use that fcirc() routine... Board games like checkers or chess. Flood filling "pieces" of those sizes should be quick enough without cause memory issues... perhaps a flight sim (not the MS ones) like Red Baron etc. Might push memory limits... or the old Battle Zone (tank game)... Simple sprite editor... Struggling because of low caffeine levels...
Logic is the beginning of wisdom.

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Recursive Fills (almost)
« Reply #4 on: November 04, 2021, 09:36:17 am »
Hi, BPlus

I tried your program and unfortunately I was able to replicate a known program crash error using recursion. The added program will crash after a while with the announcement that the program has stopped working and will therefore be terminated. By no means would I want to look for a similar problem in large source code. The same mistake can be made in other ways - by sound, but I'm not talking about it now.

So the question. Is there a way to avoid such a recursion-induced program crash? This silly meaningless message from Windows is as beneficial as coat for the corpse.

Thanks for sharing.


Code: QB64: [Select]
  1. _Title "Recursive Fill" 'b+ 2021-11-03
  2. Screen _NewImage(1920, 1080, 32)
  3. _Delay .25
  4.  
  5. Line (110, 200)-Step(580, 200), _RGB32(255, 0, 0), B
  6. Circle (400, 300), 280, _RGB32(255, 0, 0)
  7. 'Circle (400, 300), 200.5, _RGB32(255, 0, 0) ' some circle radius leak like radius = 200
  8. 'Circle (400, 300), 201, _RGB32(255, 0, 0)
  9. fill 400, 300, _RGB32(255, 0, 0)
  10. Line (300, 10)-Step(200, 580), _RGB32(255, 0, 0), B
  11. fill 400, 150, _RGB32(255, 0, 0)
  12. fill 400, 450, _RGB32(255, 0, 0)
  13. fill 5, 5, &HFFFFFF00
  14. While _KeyDown(27) = 0
  15.     Cls
  16.     Line (0, 0)-(_Width - 1, _Height - 1), _RGB32(255, 0, 0), B
  17.     doBoxes = Int(Rnd * 2)
  18.     For i = 1 To 10
  19.         If doBoxes Then Line (Rnd * (_Width - 100) + 50, Rnd * (_Height - 100) + 50)-(Rnd * 100, Rnd * 100), _RGB32(255, 0, 0), B
  20.         x = Rnd * _Width: y = Rnd * _Height: r = Rnd * 50 + 10
  21.         Circle (x, y), r, _RGB32(255, 0, 0)
  22.         Circle (x, y), r + .5, _RGB32(255, 0, 0)
  23.         Circle (x, y), r + 1, _RGB32(255, 0, 0)
  24.     Next
  25.     fill 400, 300, _RGB32(255, 0, 0)
  26.     'Beep
  27.     Sleep
  28.  
  29. Function plus (x, y, c As _Unsigned Long)
  30.     If Point(x, y) <> c Then
  31.         For i = x - 1 To 0 Step -1
  32.             If Point(i, y) = c Then xl = i + 1: Exit For
  33.         Next
  34.         'if xl = 0 then xl = 0
  35.         For i = x + 1 To _Width - 1
  36.             If Point(i, y) = c Then xr = i - 1: Exit For
  37.         Next
  38.         If xr = 0 Then xr = _Width - 1
  39.         For i = y - 1 To 0 Step -1
  40.             If Point(x, i) = c Then yu = i + 1: Exit For
  41.         Next
  42.         'if yu = 0 then yu = 0
  43.         For i = y + 1 To _Height - 1
  44.             If Point(x, i) = c Then yd = i - 1: Exit For
  45.         Next
  46.         If yd = 0 Then yd = _Height - 1
  47.         Line (xl, y)-(xr, y), c
  48.         Line (x, yu)-(x, yd), c
  49.         plus = -1
  50.     End If
  51.  
  52. Sub fill (x, y, c As _Unsigned Long)
  53.     If plus(x, y, c) Then
  54.         fill x - 1, y - 1, c
  55.         fill x - 1, y + 1, c
  56.         fill x + 1, y - 1, c
  57.         fill x + 1, y + 1, c
  58.     End If
  59.  
  60.  
  61.  
  62.  

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Recursive Fills (almost)
« Reply #5 on: November 04, 2021, 09:54:53 am »
@bplus
You don't have to answer, I found a recursion thread where Steve explains it. I'll try to find a way to reliably clean the memory tank (it will be a lot of beers and a lot of headaches) BUT I just have to try. When a reliable method is found, it opens up many possibilities. In this case, for example - how about dividing an image into images with a size of 100x100 pixels, doing coordinate conversions, then filling it in and finally reassembling? Damn, when I read it, I'm not feeling well...

Offline bplus

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

The trouble making line in your mod of my code was this one:
fill 5, 5, &HFFFFFF00 
There was nothing to stop the color from flooding the whole screen and beyond.
This is fixed by drawing a containment border first around the area to fill with the same color you are about to fill with eg,
Code: QB64: [Select]
  1. _Title "Recursive Fill" 'b+ 2021-11-03
  2. Screen _NewImage(1280, 740, 32)  ' <<<<<<<<<<<<<<<<<< biggest screen I can see on laptop
  3. _Delay .25
  4.  
  5. Line (0, 0)-(_Width - 1, _Height - 1), &HFFFFFF00, B ' you must contain the color you are filling with that color border
  6. fill 5, 5, &HFFFFFF00
  7.  
  8. Function plus (x, y, c As _Unsigned Long)
  9.     If Point(x, y) <> c Then
  10.         For i = x - 1 To 0 Step -1
  11.             If Point(i, y) = c Then xl = i + 1: Exit For
  12.         Next
  13.         'if xl = 0 then xl = 0
  14.         For i = x + 1 To _Width - 1
  15.             If Point(i, y) = c Then xr = i - 1: Exit For
  16.         Next
  17.         If xr = 0 Then xr = _Width - 1
  18.         For i = y - 1 To 0 Step -1
  19.             If Point(x, i) = c Then yu = i + 1: Exit For
  20.         Next
  21.         'if yu = 0 then yu = 0
  22.         For i = y + 1 To _Height - 1
  23.             If Point(x, i) = c Then yd = i - 1: Exit For
  24.         Next
  25.         If yd = 0 Then yd = _Height - 1
  26.         Line (xl, y)-(xr, y), c
  27.         Line (x, yu)-(x, yd), c
  28.         plus = -1
  29.     End If
  30.  
  31. Sub fill (x, y, c As _Unsigned Long)
  32.     If plus(x, y, c) Then
  33.         fill x - 1, y - 1, c
  34.         fill x - 1, y + 1, c
  35.         fill x + 1, y - 1, c
  36.         fill x + 1, y + 1, c
  37.     End If
  38.  

When you hear the beep you will know you didn't crash.
Notice I had to use _Width -1, _Height - 1 to keep the containment box on screen.

BTW The fill routine is not better than Paint to Border color but worse! It's just an experiment with Recursive Sub to attempt a Paint like fill.

If you need a Fill / Paint that changes a color until contained by any other color I have a beauty I call Paint3.
« Last Edit: November 04, 2021, 10:22:09 am by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Recursive Fills (almost)
« Reply #7 on: November 04, 2021, 10:29:13 am »
I suppose I could put checks on Fill to make sure x, y aren't off screen. Thus we won't need a containment box, yeah!

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

Fixed! Thanks @Petr

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Recursive Fills (almost)
« Reply #8 on: November 04, 2021, 12:11:59 pm »
Very good, BPlus :) I don't know why I still need to scratch with my right foot behind my left ear...

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Recursive Fills (almost)
« Reply #9 on: November 04, 2021, 01:19:18 pm »
@Petr you seem uncomfortable about something?

Well no worries this will replace Paint or Paint with Border. :) But might be useful pathfinding mod?

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Recursive Fills (almost)
« Reply #10 on: November 04, 2021, 03:20:46 pm »
This may not make much sense but please read on.

I had a problem with scrolling background images. Set the two images in the right place. Moved both images at the same speed. The first image moves off the screen; the second image is placed next; the second image moves off the screen and the first image... you get the point? What has this got to do with fill?  The problem I had with the moving images was a tiny gap between them. I forgot to account for the speed.

My theory, for the fill example is, you are testing the pixel directly beneath where you want to draw - If Point(x,y) <> c - instead of checking the pixel you want to move towards. eg: if you land on a line (or the edge of the screen) it could be too late because the fill routine is already placing pixels beyond the 'landing' point. I'm not sure if I am making sense. Perhaps, checking the pixel you intend to move to first - If Point(x+speed,y) or '1' in this case - will give the fill routine enough warning before going beyond the 'limits'? Just a thought... Similar system in platform games. When moving a character you don't check for collision when you are already in place. You always check 'ahead' to see if the character 'can' move in that direction. Would not the same system apply to the 'collision' of the fill pixels? Apologies for babbling...
Logic is the beginning of wisdom.

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Recursive Fills (almost)
« Reply #11 on: November 05, 2021, 07:29:46 am »
@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 solution for coloring. It's been a long time since I've dealt with this. Acceleration there would mean dropping PAINT and using MEM. But that's an old familiar thing. Here's what I use when I need to color something that doesn't have the same color areas. I see that it still stays with the first version. Well, I'm doing something else again...
My SLOW solution use not recursion, so its out of topic :)
Code: QB64: [Select]
  1. ' paint first pre - alternative. Program logic:
  2. '- User set coordinates and output color (border color is NOT NEED)
  3. '- Program find colors borders in easyest way. Create virtual screen and draw borders.
  4. '- Use QB64 statement PAINT in this virtual screen and then copy colored area back to visible screen
  5. '- Kill arrays and virtual screen and return back.
  6.  
  7. 'It is first version, extreme slow!
  8.  
  9. 'If is something "super", so has not big value. So this is named super.....slow.....wait........Sub :-D
  10. 'in true, i thing about - how do it many months. Because i have not enough time, i started this many times in different ways. First -   I wanted to do this by moving the X, Y pointer
  11. 'along the Y axis up to the border of the colors, and then copying the border of the color boundaries and reducing its radius at each turn. Unfortunately, when using a circle, the pointer
  12. 'has always run away. It was fun, but I did not to laugh ...
  13.  
  14. Screen _NewImage(800, 600, 32)
  15.  
  16.  
  17. Circle (400, 300), 250, _RGB32(100, 20, 33)
  18. Circle (400, 300), 450, _RGB32(10, 200, 133)
  19. Line (100, 100)-(400, 400), _RGB32(10, 200, 133), B
  20. Line (300, 300)-(500, 500), _RGB32(10, 20, 99), B
  21.  
  22. SuperPaint 338, 349, _RGB32(255, 0, 0)
  23.  
  24. SuperPaint 531, 219, _RGB32(10, 255, 0)
  25.  
  26. SuperPaint 436, 451, _RGB32(0, 10, 255)
  27.  
  28. SuperPaint 715, 242, _RGB32(255, 255, 0)
  29.  
  30.  
  31.  
  32.  
  33. Sub SuperPaint (x As Integer, y As Integer, clr As _Unsigned Long) '32 bit: ok   8 bit: ok
  34.     Background& = Point(x, y)
  35.     W = _Width(0)
  36.     H = _Height(0)
  37.     Dim O(W, H) As Integer, bclr As _Unsigned Long
  38.  
  39.     For Sy = 0 To H - 1
  40.         For sx = 1 To W - 2
  41.             If Point(sx, Sy) <> Point(sx + 1, Sy) Then
  42.                 oldsx = sx
  43.                 O(sx, Sy) = 1
  44.             End If
  45.     Next sx, Sy
  46.  
  47.     For sx = 0 To W - 1
  48.         For Sy = 0 To H - 1
  49.             If Point(sx, Sy) <> Point(sx, Sy + 1) Then
  50.                 oldsy = Sy
  51.                 O(sx, Sy) = 1
  52.             End If
  53.     Next Sy, sx
  54.     i = 0
  55.     bclr& = 255
  56.         Case 1: bclr = clr - 1: Depth = 256
  57.         Case 4: bclr = _RGB32(_Red32(clr) - 1, _Green32(clr) - 1, _Blue32(clr) - 1): Depth = 32
  58.     End Select
  59.     my& = _Dest
  60.     virtual& = _NewImage(W, H, Depth)
  61.     _Dest virtual&
  62.     For Sy = 0 To H
  63.         For sx = 0 To W
  64.             If O(sx, Sy) Then
  65.                 PSet (sx, Sy), bclr
  66.             End If
  67.     Next sx, Sy
  68.     _Dest virtual&
  69.     Paint (x, y), clr, bclr
  70.     Erase O
  71.     For sx = 0 To W
  72.         For Sy = 0 To H
  73.             _Source virtual&
  74.             _Dest my&
  75.             If Point(sx, Sy) = clr Then PSet (sx, Sy), clr
  76.             If Point(sx - 1, Sy) = clr Then PSet (sx, Sy), clr
  77.             If Point(sx, Sy - 1) = clr Then PSet (sx, Sy), clr
  78.     Next Sy, sx
  79.     _Dest my&
  80.     _FreeImage virtual&
  81.  

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Recursive Fills (almost)
« Reply #12 on: November 05, 2021, 08:09:56 am »
Here's the Fill I usually use, but it doesn't have any recursion going on with it.

Code: QB64: [Select]
  1. Screen _NewImage(1024, 720, 32)
  2.  
  3.  
  4. TestLimit = 100
  5. Radius = 350
  6.  
  7. t# = Timer
  8. For i = 1 To TestLimit
  9.     k& = &HFF000000 + Int(Rnd * &HFFFFFF)
  10.  
  11.     Circle (512, 360), Radius, k&
  12.     Fill 512, 360, k&
  13.  
  14. t1# = Timer
  15. For i = 1 To TestLimit
  16.     k& = &HFF000000 + Int(Rnd * &HFFFFFF)
  17.  
  18.     Circle (512, 360), Radius, k&
  19.     Paint (512, 360), k&
  20. t2# = Timer
  21.  
  22.  
  23. For i = 1 To TestLimit
  24.     k& = &HFF000000 + Int(Rnd * &HFFFFFF)
  25.  
  26.     CircleFill 512, 360, Radius, k&
  27.  
  28. t3# = Timer
  29.  
  30.  
  31. Print Using "###.#### seconds for Fill."; t1# - t#
  32. Print Using "###.#### seconds for Paint."; t2# - t1#
  33. Print Using "###.#### seconds for CircleFill."; t3# - t2#
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40.  
  41. Sub CircleFill (CX As Integer, CY As Integer, R As Integer, C As _Unsigned Long)
  42.     ' CX = center x coordinate
  43.     ' CY = center y coordinate
  44.     '  R = radius
  45.     '  C = fill color
  46.     Dim Radius As Integer, RadiusError As Integer
  47.     Dim X As Integer, Y As Integer
  48.     Radius = Abs(R)
  49.     RadiusError = -Radius
  50.     X = Radius
  51.     Y = 0
  52.     If Radius = 0 Then PSet (CX, CY), C: Exit Sub
  53.     Line (CX - X, CY)-(CX + X, CY), C, BF
  54.     While X > Y
  55.         RadiusError = RadiusError + Y * 2 + 1
  56.         If RadiusError >= 0 Then
  57.             If X <> Y + 1 Then
  58.                 Line (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  59.                 Line (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  60.             End If
  61.             X = X - 1
  62.             RadiusError = RadiusError - X * 2
  63.         End If
  64.         Y = Y + 1
  65.         Line (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  66.         Line (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  67.     Wend
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75.  
  76. Sub Fill (Passx, Passy, kolor As Long)
  77.     B = _Blend
  78.  
  79.     Dim TempGrid(_Width - 1, _Height - 1) As Long
  80.     Dim As _MEM m, m1: m = _Mem(TempGrid()): m1 = _MemImage(0)
  81.     Dim o As _Offset
  82.     _MemCopy m1, m1.OFFSET, m1.SIZE To m, m.OFFSET
  83.     o = 0
  84.     Do Until o >= m.SIZE
  85.         If _MemGet(m1, m1.OFFSET + o, _Unsigned Long) = kolor Then
  86.             _MemPut m, m.OFFSET + o, -1 As LONG
  87.             'Else
  88.             '_MemPut m, m.OFFSET + o, 0 As LONG
  89.         End If
  90.         o = o + 4
  91.     Loop
  92.  
  93.     TempGrid(Passx, Passy) = 1
  94.     startx = Passx - pass: finishx = Passx + pass
  95.     starty = Passy - pass: finishy = Passy + pass
  96.  
  97.     Do Until finished
  98.         pass = pass + 1
  99.         finished = -1
  100.         For x = startx To finishx
  101.             For y = starty To finishy
  102.                 If TempGrid(x, y) = pass Then
  103.                     tempx = x
  104.                     Do Until tempx = 0
  105.                         If TempGrid(tempx - 1, y) = 0 Then
  106.                             TempGrid(tempx - 1, y) = pass + 1
  107.                             tempx = tempx - 1
  108.                             If tempx < startx Then startx = tempx
  109.                             finished = 0
  110.                         Else
  111.                             tempx = 0
  112.                         End If
  113.                     Loop
  114.  
  115.                     tempx = x
  116.                     Do Until tempx = _Width - 1
  117.                         If TempGrid(tempx + 1, y) = 0 Then
  118.                             TempGrid(tempx + 1, y) = pass + 1
  119.                             tempx = tempx + 1
  120.                             If tempx > finishx Then finishx = tempx
  121.                             finished = 0
  122.                         Else
  123.                             tempx = _Width - 1
  124.                         End If
  125.                     Loop
  126.  
  127.                     tempy = y
  128.                     Do Until tempy = 0
  129.                         If TempGrid(x, tempy - 1) = 0 Then
  130.                             TempGrid(x, tempy - 1) = pass + 1
  131.                             tempy = tempy - 1
  132.                             If tempy < starty Then startx = tempy
  133.                             finished = 0
  134.                         Else
  135.                             tempy = 0
  136.                         End If
  137.                     Loop
  138.  
  139.                     tempy = y
  140.                     Do Until tempy = _Height - 1
  141.                         If TempGrid(x, tempy + 1) = 0 Then
  142.                             TempGrid(x, tempy + 1) = pass + 1
  143.                             tempy = tempy + 1
  144.                             If tempy > finishy Then finishy = tempy
  145.                             finished = 0
  146.                         Else
  147.                             tempy = _Height - 1
  148.                         End If
  149.                     Loop
  150.                 End If
  151.         Next y, x
  152.     Loop
  153.  
  154.     o = 0
  155.     Do Until o >= m.SIZE
  156.         If _MemGet(m, m.OFFSET + o, _Unsigned Long) <> 0 Then _MemPut m1, m1.OFFSET + o, kolor As _UNSIGNED LONG
  157.         o = o + 4
  158.     Loop
  159.     _MemFree m: _MemFree m1
  160.     If B Then _Blend

It's faster than PAINT, but still no where near the speeds of a decent CircleFIll routine.

 
SS.png


NOTE:  This is also the same thing which I do for my 2D games which require pathfinding, though it's just usually on a much smaller scale.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Recursive Fills (almost)
« Reply #13 on: November 05, 2021, 08:49:50 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.  

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Recursive Fills (almost)
« Reply #14 on: November 05, 2021, 09:21:33 am »
Quote
@bplus  Your program works badly:

And thus the title of the thread: Recursive Fills (almost)

Steve's "simple" little recursive fill that doesn't work got me on the hunt for a

Recursive Fill Routine

I already offered a non recursive Paint Routine that covers (no pun intended) what Paint doesn't. It looks allot like Steve's without the Mem stuff because we had worked it out here this forum probably at least a year ago. Oh I can check the date a quick search for where it is in my new list of bas files...

Code: QB64: [Select]
  1. _Title "PAINT3 test" 'b+ 2020-06-26
  2. Screen _NewImage(800, 600, 32)
  3. _Delay .25
  4. Dim i, mb, mx, my
  5. For i = 1 To 50
  6.     Line (Rnd * 800, Rnd * 600)-(Rnd * 800, Rnd * 600), _RGB32(Rnd * 255, Rnd * 255, Rnd * 255, 128 + Rnd * 128)
  7.     Circle (Rnd * 800, Rnd * 600), Rnd * 50 + 10, _RGB32(Rnd * 255, Rnd * 255, Rnd * 255, 128 + Rnd * 128)
  8.     mx = _MouseX: my = _MouseY: mb = _MouseButton(1)
  9.     If mb Then paint3 mx, my, &HFFFFFFFF
  10.     _Limit 200
  11.  
  12. Sub paint3 (x0, y0, fill As _Unsigned Long) ' needs max, min functions
  13.     Dim fillColor As _Unsigned Long, W, H, parentF, tick, ystart, ystop, xstart, xstop, x, y
  14.     fillColor = Point(x0, y0)
  15.     'PRINT fillColor
  16.     W = _Width - 1: H = _Height - 1
  17.     Dim temp(W, H)
  18.     temp(x0, y0) = 1: parentF = 1
  19.     PSet (x0, y0), fill
  20.     While parentF = 1
  21.         parentF = 0: tick = tick + 1
  22.         ystart = max(y0 - tick, 0): ystop = min(y0 + tick, H)
  23.         y = ystart
  24.         While y <= ystop
  25.             xstart = max(x0 - tick, 0): xstop = min(x0 + tick, W)
  26.             x = xstart
  27.             While x <= xstop
  28.                 If Point(x, y) = fillColor And temp(x, y) = 0 Then
  29.                     If temp(max(0, x - 1), y) Then
  30.                         temp(x, y) = 1: parentF = 1: PSet (x, y), fill
  31.                     ElseIf temp(min(x + 1, W), y) Then
  32.                         temp(x, y) = 1: parentF = 1: PSet (x, y), fill
  33.                     ElseIf temp(x, max(y - 1, 0)) Then
  34.                         temp(x, y) = 1: parentF = 1: PSet (x, y), fill
  35.                     ElseIf temp(x, min(y + 1, H)) Then
  36.                         temp(x, y) = 1: parentF = 1: PSet (x, y), fill
  37.                     End If
  38.                 End If
  39.                 x = x + 1
  40.             Wend
  41.             y = y + 1
  42.         Wend
  43.     Wend
  44.  
  45. Function min (n1, n2)
  46.     If n1 > n2 Then min = n2 Else min = n1
  47.  
  48. Function max (n1, n2)
  49.     If n1 < n2 Then max = n2 Else max = n1
  50.  
  51.  

But that's not recursive