News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

FloodFill and ExtFloodFill

Started by zedd151, February 26, 2025, 03:08:52 PM

Previous topic - Next topic

zedd151

Quote from: raymond on February 27, 2025, 05:33:05 AMHave you ever considered using the CreatePolygonRgn and FillRgn functions with two regions, one for each the oblique parts of the X.

It would fill the center part of the X twice but who cares!

I had never used that, since I don't know how. I didn't fully understand the docs I read online about it. Simply using a thick pen seems to work sufficiently for my purposes. But thanks for the suggestion.
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

zedd151

#16
After making some pen size and positioning adjustments, I think it looks pretty good now.

I will proceed to replace that bitmap as well, with other gdi32 drawing functions.  :azn:
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

NoCforMe

If you want to play around with my homebrew flood-fill code, it's attached here.

It's not ready to roll: it was created for an app of mine that used a bitmap consisting of 1-byte pixels (actually a cursor bitmap), so you'd have to adapt it to your usage.

And it operates on a bitmap in memory, not on a GDI "object", so you'd have to adapt that as well.

However, it does show the technique of flood-filling, which is actually pretty simple:
When I figure out how to post a damn picture here properly I'll do that.

Assembly language programming should be fun. That's why I do it.

zedd151

[quote author=NoCforMe link=msg=136367 date=1740633471]
And it operates on a bitmap in memory, not on a GDI "object", so you'd have to adapt that as well.
A bitmap created with CreateCompatibleBitmap? but that is a gdi object. what else is there? Load a bitmap using LoadBitmap and draw on it? I don't get it. Just draw to a correctly sized array, then blit it somehow onto the device context?

QuoteWhen I figure out how to post a damn picture here properly I'll do that.
This might help.
If not, what issues are you having posting pix?
https://masm32.com/board/index.php?msg=136368
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

NoCforMe

OK, now that I've finally figured out how to properly post a pic:

Here's the flood-fill algo in nutshell:
You start at the starting pixel (x,y) passed in to the function.
For each pixel, you look at its four non-diagonal neighbors:



If any of those pixels are not the fill color (the color you want the shape to be flooded with), you change them to that color and then you recursively process each of those pixels, looking at its four neighbors, and so on.

Since you're recursively processing pixels, the routine will automatically expand to fill the entire interior space of the shape you want to fill.

You stop when you reach a pixel that is already the fill color, which will be either just a stray interior pixel or one of the boundary pixels. Therefore, the routine will stop when it hits the boundary. (You also need to handle the "edge" cases, literally, where you're on the edge of the bitmap. This happens when either x or y is equal to zero or is equal to the size (horizontal or vertical) of the bitmap minus one.)

Since it's recursive, you need to make sure you have enough stack space available. This usually won't be a problem unless you're processing very large bitmaps.
Assembly language programming should be fun. That's why I do it.

zedd151

That still doesn't tell me where and how to use this.  :undecided:
I just need a small code snippet, where your little function is called from.
And exactly what the flood fill will be applied to...
I barely grasp gdi32 stuff. This (what you posted) is unknown to me as well.

I'm all thumbs when working on unknown material.
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

NoCforMe

OK, I'll make a post about GDI, bitmaps, etc.
Warning: it's a bit complicated.
However, it's not rocket surgery. Can be understood by the average programmer.
Assembly language programming should be fun. That's why I do it.

zedd151

Quote from: NoCforMe on February 28, 2025, 08:31:11 AMOK, I'll make a post about GDI, bitmaps, etc.
Warning: it's a bit complicated.
However, it's not rocket surgery. Can be understood by the average programmer.
I think I could handle it.
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

satpro

Quote from: zedd151 on February 28, 2025, 07:30:22 AMThat still doesn't tell me where and how to use this.  :undecided:
I just need a small code snippet, where your little function is called from.
And exactly what the flood fill will be applied to...
I barely grasp gdi32 stuff. This (what you posted) is unknown to me as well.

I'm all thumbs when working on unknown material.
Would you like to try drawing a window with something like DirectDraw?  It's only a couple of lines of code (especially with DDraw) and then the screen is yours and Windows behaves.  You can even write to the primary surface if you like, yet it is still just a window, with nothing to be wary of.

I am saying that if you want to get into it without all those costly GDI calls, the program seems to be a couple of nice hires shapes and nine coordinates, a call to create a primary surface, and a surface lock.  In essence this is a bitmap but without ANY calls to make it a bitmap.  Even your Xs and 0s are literally two simple shapes you could draw out on paper first.

This would probably cut the size of the program AND your effort significantly. It's not scary.  I even have easy boilerplate code if you would like.  Nothing tricky.

Let's turn those thumbs into coding shears!

NoCforMe

DirectDraw? I guess I'm all ears.
This doesn't require COM or anything fancy like that, does it?
Is it a standard Windows API?
Yes, GDI is somewhat clunky and a pain in the ass.
Assembly language programming should be fun. That's why I do it.

satpro

NoC,

COM is a Windows call with your interface pointer as the #1 parameter.  Literally, that's it!  I studied DirectDraw for over a year to find what makes it tick.  Most of it (almost all, actually) is nearly useless, but the thing it has is that primary surface screen access.  With screen access I can SSE or AVX-blit a 4k screen 60x/sec without even stressing the machine.  That's a 32-meg screen.

Also, DirectDraw is the last DirectX to let you do that.  With it you can do what Windows does.

GDI is really convoluted at times.  The technique I am talking about is not at all.

zedd151

Quote from: satpro on February 28, 2025, 08:46:50 AMI even have easy boilerplate code if you would like.  Nothing tricky.
Okay, I'm game. Lets see your stuff.  :biggrin:
You must have been attaching that while I was posting.
; ==================================================================================================
;                                       DIRECTDRAW
; ==================================================================================================

align 16
EXPORT uhd_DDraw:       ; minimal DirectDraw startup to get at the primary surface

; -----

; create a stack frame
    sub rsp, 28h                        ; an aligned stack frame w/ pre-allocated param space

; -----  Enter  -----


    xor ecx, ecx                        ; p1: 0 (param1 for the DirectDrawCreateEx function)

; zero the DDraw interface pointers while there is a register = 0
    mov [pp_DD7], rcx                   ; + zero the top-level interface ptr
    mov [pp_Front], rcx                 ; + zero the front surface interface ptr

; create a DirectDraw7 COM instance 
    lea rdx, pp_DD7                     ; p2: address of the instance pptr
    lea r8, IID_DD7                     ; p3: address of the IDirectDraw7 interface GUID
    xor r9, r9                          ; p4: 0
    call DirectDrawCreateEx             ; creates the DDraw COM instance
        or eax, eax
        hint.nobranch jnz << Winc64Error

; set up to use as a windowed, borderless app with a system-memory Screenbuffer
    mov rcx, [pp_DD7]                   ; *this
    xor edx, edx                        ; p1: hWnd
    mov r8d, DDSCL_NORMAL               ; p2: dwFlags
   
    mov rax, [rcx]
    add eax, IDirectDraw7.SetCooperativeLevel
    call [rax]
        or eax, eax
        hint.nobranch jnz << Winc64Error
   
   
; --------------------
;   Frontbuffer only
; --------------------

; clear a DDSURFACEDESC2 structure for the front buffer
    lea rdx, ddsd
    xor eax, eax
    mov cl, sizeof(DDSURFACEDESC2 / 8)

:   mov [rdx], rax
    add edx, 8
    dec cl
    jnz <

; fill in a DDSURFACEDESC2 structure
  mov D[ddsd.dwSize], sizeof(DDSURFACEDESC2)  ; set the structure size field
  mov D[ddsd.dwFlags], DDSD_CAPS
  mov D[ddsd.ddsCaps.dwCaps], DDSCAPS_PRIMARYSURFACE

; create the front buffer surface
    mov rcx, [pp_DD7]                   ; *this
    lea rdx, ddsd                       ; p1:
    lea r8, pp_Front                    ; p2:
    xor r9d, r9d                        ; p3:

    mov rax, [rcx]
    add eax, IDirectDraw7.CreateSurface
    call [rax]
        or eax, eax
        hint.nobranch jnz << Winc64Error

; -----

; get the monitor frequency in Hz (frames per second)
    mov rcx, [pp_DD7]                   ; *this
    lea rdx, MonitorHz                  ; p1:

    mov rax, [rcx]
    add eax, IDirectDraw7.GetMonitorFrequency
    call [rax]
        or eax, eax
        hint.nobranch jnz << Winc64Error


; -----  Exit  -----

; destroy the stack frame
    add rsp, 28h

    ret

; ==================================================================================================
Okay.. bbbut I am working with 32 bit code. And some details are missing. Remember I am new to this stuff.  :smiley:
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

satpro

I will create a 32-bit program to get you there.  It will be GoAsm, but not to worry; it is a very straight-forward assembler and will be easy to understand.  I will need a minute...

zedd151

Quote from: satpro on February 28, 2025, 09:51:17 AMI will need a minute...
Thanks, Bert. NoCforme might even be interested in it, too. (as well as others, I'd imagine.)
¯\_(ツ)_/¯   :azn:

'As we don't do "requests", show us your code first.'  -  hutch—

satpro

Okay, here is what I could quickly convert to 32-bit.  I had to think a bit!

It is because I program exclusively in 64 bits these days and this old mind, well, you know.  The freedom and extra registers are wonderful, though.  Hope I got the stack right (converting back to 32-bit) and it might not be precise as I did it real fast.  I'm guessing an error or two somewhere...  :biggrin:

1.  Params can be entered in the natural order.
2.  COM is the same as Win32, except for the first param, which is the interface ptr (e.g. ppDD7).
3.  At the end of a program you do not need to clean anything.  Call ExitProcess and that's it.

It's long.  All told, over a meg of GoAsm source.  I could not upload this as 'code' because it is too much.  Attached is the video-creation part, some memory movers, part of WndProc, creating the main window, and a 1x & 2x blit to screen (still 64-bit) and there is much more if this does not make enough sense.  I didn't want to get too carried away.  lol

*****

This is from an emulator I am almost finished with.  If no one minds, the program is my attempt at a 32-bit version of the 65c02 in a program called WinC64.  WinC64 is an HD version of a very modern C64, one that has a 32-bit cpu and 32-bit graphics, and MANY x86 instructions (made into 32-bit 65c02) that run it.  I think it's cool, and if I count right has been a mere 12 years in the making.  :eusa_boohoo: