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

satpro

Forgot this bit:

; ==================================================================================================
;                                       MESSAGE LOOP
; ==================================================================================================

align 16
EXPORT MessageLoop:
    xor ecx, ecx
    mov [esp], addr msg                 ; p1: addr msg
    mov [esp+4], edx                    ; p2: 0
    mov [esp+8], edx                    ; p3: 0
    mov [esp+12], edx                   ; p4: 0
    call GetMessage                     ; retrieve messages from the queue

    or eax, eax                         ; if message = 0 (WM_QUIT),
    jz >                                ; it's time to quit, so branch to Exit

    mov [esp], addr msg                 ; p1: addr msg
    call TranslateMessage               ; translate virtual-key messages into character messages

    mov [esp], addr msg                 ; p1: addr msg
    call DispatchMessage                ; send the message to WndProc for processing

    jmp < MessageLoop                   ; return to the message loop

:

; -----  Exit the program  -----

; exit properly thru Windows
    mov ecx, TRUE                             ; retval = TRUE (OKAY)
    call ExitProcess                          ; ends the process, quits


; ==================================================================================================
;                                       WNDPROC
; ==================================================================================================

; ---------
; on entry:
; ---------
; rcx: hwnd
; rdx: uMsg
; r8:  wParam
; r9:  lParam

align 16
EXPORT WndProc:         ; hwnd,uMsg,wParam,lParam

; create a stack frame
    sub esp, 14h

; -----
  mov edx, [esp+4]  ; uMsg
 
    cmp edx, WM_KEYDOWN                 ; check if a KEYDOWN message has arrived
    je >> .doKEYDOWN

    cmp edx, WM_PAINT                   ; check if a PAINT message has arrived
    je >> .doPAINT

    cmp edx, WM_DESTROY                 ; check if a DESTROY message has arrived
    je > .doDESTROY

    cmp edx, WM_CREATE                  ; check if a CREATE message has arrived
    je >> .doCREATE

    cmp edx, WM_NCCREATE                ; check if a NCCREATE message has arrived
    je >> .doNCCREATE                   ; CreateWindowExA fails if this is not here

    cmp edx, WM_CLOSE                   ; check if a CLOSE message has arrived
    je >> .doCLOSE

; go default for anything else, then fall thru & exit
    call DefWindowProcA

; -----
   
align 16
.GetOutRight
    add esp, 14h                            ; restore the stack

    xor eax, eax
    ret

; ==================================================================================================
; WM_DESTROY message handler

align 16
.doDESTROY
; exit via the message loop by posting WM_QUIT to queue
    mov [esp], 0                        ; p1: 0
    call PostQuitMessage
 
    jmp << .GetOutRight

; ==================================================================================================
; WM_PAINT message handler

align 16
.doPAINT
    mov ecx, [WindowHandle]
    mov [esp], ecx                      ; p1: hwnd
    mov [esp+4], addr ps                   
    call BeginPaint                     ; p2: addr ps

; -----
; -----

    mov ecx, [WindowHandle]
    mov [esp], ecx                      ; p1: hwnd
    mov [esp+4], addr ps                   
    call EndPaint                       ; p2: addr ps

    jmp << .GetOutRight


; ==================================================================================================
; WM_KEYDOWN message handler

align 16
.doKEYDOWN      ; respond to a keypress

;    cmp r8, VK_ESCAPE                   ; compare keypress to: "ESC KEY = Show/Hide fkey Menu"
;    je >> .doMENU                       ; go to MENU handler for this

;    cmp r8, VK_DOWN                     ; compare keypress to: "CURSOR DOWN KEY = Menu Go Down"
;    je >> .doMENUDOWN                   ; go to MENUDOWN handler for this

;    cmp r8, VK_UP                       ; compare keypress to: "CURSOR UP KEY = Menu Go Up"
;    je >> .doMENUUP                     ; go to MENUUP handler for this

    cmp r8, VK_F1                       ; compare keypress to: "F1 KEY = Go - Stop"
    je >> .doPAUSE                      ; go to PAUSE handler for this

    cmp r8, VK_F4                       ; compare keypress to: "F8 KEY = Exit"
    je >> .doCLOSE                      ; go to WM_CLOSE handler for this

    jmp << .GetOutRight                 ; any other key returns to WinC64


; ==================================================================================================
; WM_CREATE message handler

align 16
.doCREATE

    jmp << .GetOutRight

; ==================================================================================================
; WM_NCCREATE message handler

align 16
.doNCCREATE

    add esp, 14h                            ; restore the stack

    mov eax, 1
    ret

; ==================================================================================================
; WM_CLOSE message handler (alt-F4)

align 16
.doCLOSE

; disable the cpu thread
;    mov B[IsPowerOn], 0

; stop the timer for the cpu thread
;    xor ecx, ecx                        ; p1: HWND hWnd, handle of window that installed timer
;    mov edx, [hTimer1]                  ; p2: UINT uIDEvent, timer identifier
;    call KillTimer

; release front buffer interface
    mov ecx, [pp_Front]
    mov eax, [ecx]
    add eax, IDirectDrawSurface7.Release
    call [eax]
    or eax, eax
    jnz << Winc64Error

; release DirectDraw interface
    mov ecx, [pp_DD7]
    mov eax, [ecx]
    add eax, IDirectDraw7.Release
    call [eax]
    or eax, eax
    jnz << Winc64Error

; zero the interface ptrs
    xor eax, eax
    mov [pp_Front], eax
    mov [pp_DD7], eax

; destroy the window, send WM_DESTROY message to queue
    mov ecx, [WindowHandle]
    mov [esp], ecx
    call DestroyWindow                  ; destroy window, send WM_DESTROY msg


    jmp << .GetOutRight


; ==================================================================================================

zedd151

Thanks satpro, I will take a look at this later this evening.  :smiley:
¯\_(ツ)_/¯   :azn:

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

satpro

Great!  Watch out for uncorrected 64-bit.  I noticed something later in WndProc that still has r8 instead of a stack MOV [esp].
But you already have your WndProc, so that's not a big deal.  I am sorry I left those mem movers at 64-bit.  It would take some more work to make those x86-32, but even still in 32-bit, they work quick.

Please PM me if you need clarity.

NoCforMe

Sorry, I don't use GoAsm and have no intention of doing so.
I don't have any of those include files (7 of 'em!) and don't want to have to acquire them.
Any chance of making this a plain old MASM (32 bit) program?

Just so you know, you don't need to do any of that stack "setup" stuff you're doing for a 32-bit program: it's already all set up for you by the loader. No need for the "align 16" and that other stack-manipulation code you have in there.

One thing I really really HATE is the use of addressing like mov [esp+n], eax, where[esp+n] points to a local variable. There's absolutely no justification at this late stage of the game (2025!) to use primitive, cryptic addressing like this. This is like the kind of programming that was used for the Apollo missions back in the 1970s.

Use named variables, man!
Assembly language programming should be fun. That's why I do it.

zedd151

Quote from: satpro on February 28, 2025, 12:10:07 PMGreat!  Watch out for uncorrected 64-bit.  I noticed something later in WndProc that still has r8 instead of a stack MOV [esp].
But you already have your WndProc, so that's not a big deal.  I am sorry I left those mem movers at 64-bit.  It would take some more work to make those x86-32, but even still in 32-bit, they work quick.

Please PM me if you need clarity.
No worries, satpro. It might take me some time, but I think I can handle a bit of housekeeping there in regards to 64 bit leftovers.
But we will see...
¯\_(ツ)_/¯   :azn:

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

sinsi

Is this bit of code right?
EXPORT MessageLoop:
    xor ecx, ecx
    mov [esp], addr msg                 ; p1: addr msg
    mov [esp+4], edx                    ; p2: 0
    mov [esp+8], edx                    ; p3: 0
    mov [esp+12], edx                   ; p4: 0
    call GetMessage                     ; retrieve messages from the queue
You zero ecx but then store edx, which could be anything.
Typo I assume?  :biggrin:

zedd151

Quote from: sinsi on February 28, 2025, 01:42:42 PMIs this bit of code right?
EXPORT MessageLoop:
    xor ecx, ecx
    mov [esp], addr msg                 ; p1: addr msg
    mov [esp+4], edx                    ; p2: 0
    mov [esp+8], edx                    ; p3: 0
    mov [esp+12], edx                   ; p4: 0
    call GetMessage                     ; retrieve messages from the queue
You zero ecx but then store edx, which could be anything.
Typo I assume?  :biggrin:
@ satpro: Upon a cursory inspection of the code, aside from what sinsi posted above, it leaves a lot to be desired. I'll probably postpone any attempted efforts on this piece of work.  I have many other things to do, but so little time. When I have a full free weekend, I might continue down this path.  :undecided:
¯\_(ツ)_/¯   :azn:

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

satpro

Quote from: sinsi on February 28, 2025, 01:42:42 PMIs this bit of code right?
EXPORT MessageLoop:
    xor ecx, ecx
    mov [esp], addr msg                 ; p1: addr msg
    mov [esp+4], edx                    ; p2: 0
    mov [esp+8], edx                    ; p3: 0
    mov [esp+12], edx                   ; p4: 0
    call GetMessage                     ; retrieve messages from the queue
You zero ecx but then store edx, which could be anything.
Typo I assume?  :biggrin:
Yes, a typo!.  I'm sorry.  This was all written as 64-bit.  I wasn't thinking 32-bit when I wrote the original and also, did the conversion fast.  When you program in 64-bit the four params generally form an automatic "flow" between subroutine calls.  In other words, the Windows API is set up so that you can let params and registers float from one call to the next.  x86 does not do this at all.  In an actual program this winds up making your calls to memory almost nil (what you want).  Once I started looking through and converting this code I realized what a job it would really be, especially in WndProc.  There you can let the registers do ALL the work with no stack involvement, but not in x86.

sinsi, if you want the original code, I can zip it up and send it to you.

zedd, NoC:  I am sorry this isn't what you guys were looking for.  From my perspective you two are killing your own programming effort by not moving "up" to 64 bits!  Pessimism and negativity are the two emotions that kill productivity and learning.  Granted, who wants to try to figure out how to convert from anything to anything???  I know I didn't like doing it here.  

As for GoAsm, I love it like a brother and always will.  Do you have ANY idea how much fun it is to program without LIB files???

If you want real help, you may wish to embrace what I am saying.  The alternative is that you may be arguing about the merits of macros forever.  The rest of the world has moved on from 32-bit programing and so have I.

So, if you need me, I'm here and WILL help you, but not for an argument about GoAsm or 32-bit.  

satpro

Quote from: NoCforMe on February 28, 2025, 12:43:27 PMSorry, I don't use GoAsm and have no intention of doing so.
I don't have any of those include files (7 of 'em!) and don't want to have to acquire them.
Any chance of making this a plain old MASM (32 bit) program?

Just so you know, you don't need to do any of that stack "setup" stuff you're doing for a 32-bit program: it's already all set up for you by the loader. No need for the "align 16" and that other stack-manipulation code you have in there.

One thing I really really HATE is the use of addressing like mov [esp+n], eax, where[esp+n] points to a local variable. There's absolutely no justification at this late stage of the game (2025!) to use primitive, cryptic addressing like this. This is like the kind of programming that was used for the Apollo missions back in the 1970s.

Use named variables, man!

This is precisely why you don't understand it.  It seems to me you want this to be easy.  Well, it's not.  I had to read a lot of those 1500-page programming books and most of that 3800-page Intel manual to get it.  Fake NASA has nothing to do with it.

Yes, I hastily whipped up 32-bit code.  I would rather use stack pushes and pulls, but you don't need those at all in x64.  Do you want pretty names for your TEMPORARY stack variables, or would you rather have a complete understanding of why they are just known offsets?

Asking the question and then arguing with the answer....

zedd151

@satpro, I can and sometimes do write 64 bit masm code, even translate 32 bit -> 64 bit masm code. Your code doesn't look like masm that I am used to seeing. So, it will take me quite some time, to convert it to code more to my liking. :smiley:
¯\_(ツ)_/¯   :azn:

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

zedd151

#40
:rolleyes:  um.... I found the problem with FloodFill.
My implementation of using a double buffer in WM__PAINT was not quite double buffering. And for some of my testing, I was not using double buffering at all. Some of the gdi32 drawing functions work fine without double buffering, but it seems that FloodFill and ExtFloodFill are not in that category.

Now that I have properly implemented a double buffer, FloodFill is now working 100% as expected.
...
I had borrowed fearless' double buffering code from here ... I happened upon that thread while browsing the forum this morning, and noticed a slight difference in the implementation from mine.
I may have my own somewhere, but dozens of source I checked used the faulty painting scheme.  :rolleyes:

I guess I had never had any issues with it, until now, in the Tic Tac Toe game.  (Grumble, grumble)

      .elseif uMsg == WM_PAINT
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ;;
        ;;  WM_PAINT startup code
        ;;
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        invoke BeginPaint, hWin, addr ps
        mov hDC, eax
        invoke GetClientRect, hWin, addr rct
        invoke CreateCompatibleDC, hDC
        mov mDC, eax
        invoke CreateCompatibleBitmap, hDC, rct.right, rct.bottom
        mov hBmp, eax
        invoke SelectObject, mDC, hBmp
        mov hBmpOld, eax

        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ;;
        ;;  draw background color
        ;;
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
       
        invoke CreateSolidBrush, 00FF7F3Fh
        mov hBrush, eax
        invoke SelectObject, mDC, hBrush
        mov hBrushOld, eax
        invoke FillRect, mDC, addr rct, hBrush
        invoke SelectObject, mDC, hBrushOld
        invoke DeleteObject, hBrush

        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ;;
        ;;  drawing rectangle by drawing lines
        ;;  then use FloodFill to fill the rectangle
        ;;
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

       
        invoke CreatePen, 0, 6, 00000000h
        mov hPen, eax
        invoke SelectObject, mDC, hPen
        mov hPenOld, eax
        invoke CreateSolidBrush, 003F7FFFh
        mov hBrush, eax
        invoke SelectObject, mDC, hBrush
        mov hBrushOld, eax
        invoke MoveToEx, mDC, 100, 100, 0
        invoke LineTo,   mDC, 100, 200
        invoke LineTo,   mDC, 200, 200
        invoke LineTo,   mDC, 200, 100
        invoke LineTo,   mDC, 100, 100
        invoke FloodFill, mDC, 110, 110, 00000000h
        invoke SelectObject, mDC, hBrushOld
        invoke DeleteObject, hBrush
        invoke SelectObject, mDC, hPenOld
        invoke DeleteObject, hPen

        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ;;
        ;;  WM_PAINT ending code
        ;;
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        invoke BitBlt, hDC, 0, 0, rct.right, rct.bottom, mDC, 0, 0, SRCCOPY
        invoke SelectObject, mDC, hBmpOld
        invoke DeleteObject, hBmp
        invoke DeleteDC, mDC
        invoke EndPaint, hWin, addr ps
        mov eax, 0
        ret
      .elseif uMsg == WM_SIZE





Later:
I found the source (literally) of the erroneous code. In a couple (not 1) of my 'template' files, it was there in WM_PAINT. Time to make new Window Templates.  :tongue:  ... and find all the asm sources that use the bad code.
¯\_(ツ)_/¯   :azn:

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

NoCforMe

Quote from: satpro on February 28, 2025, 09:32:35 PMI would rather use stack pushes and pulls, but you don't need those at all in x64.
And neither do you need them in 32-bit code; that's why god invented invoke.

QuoteDo you want pretty names for your TEMPORARY stack variables, or would you rather have a complete understanding of why they are just known offsets?

The former, obviously; I don't need a constant lesson in stack addressing when I look at my code; what I do need is to know which goddamn variable I'm looking at without having to consult a lookup table. Those variables may be "temporary" (active only within the scope of the subroutine they're in), but they're variables nonetheless, therefore it would be nice to know exactly which one you're dealing with by name.

Or would you rather we all go back to using numeric offsets for addressing all of our variables? Remember, the whole idea of an assembler is to make so-called machine language more manageable to the poor programmer. Which is why we have such luxuries as named variables, subroutine names, jump targets, etc.

Otherwise we might as well just go back to front-panel programming. (I'm guessing you might be a bit too young to remember what that was.)
Assembly language programming should be fun. That's why I do it.

NoCforMe

Quote from: zedd151 on March 01, 2025, 03:50:05 AM:rolleyes:  um.... I found the problem with FloodFill.

I'm glad you found the problem. It would have taken a lot of re-jiggering to use my flood-fill routine.
Assembly language programming should be fun. That's why I do it.

zedd151

Quote from: NoCforMe on March 01, 2025, 07:44:07 AMI'm glad you found the problem.
Yeah, me too.

Quote from: NoCforMeIt would have taken a lot of re-jiggering to use my flood-fill routine.
I really didn't want to go that route, or any of the other work-arounds proposed here - unless as a last resort. I wanted the program to work as I intended, even if I had to beat it into submission.  :biggrin:

All I had to do was take a closer look at the rest of the WM_PAINT code.  :rolleyes:

Mission accomplished, problem solved, case closed, water under the bridge, etc., etc.  :tongue:
¯\_(ツ)_/¯   :azn:

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

NoCforMe

Quote from: satpro on February 28, 2025, 08:46:50 AMWould 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.

@satpro: I am curious about DirectDraw, as I'm well acquainted with the hassles of using GDI (and even GDI+).

But looking at the stuff on Micro$oft Learn, I'm still pretty much in the dark as to what DirectDraw actually does or how to use it. I see you can create DD "objects", but I don't know what exactly those objects are, what they do, and how to get them to draw what you want on the screen. I don't see any primitives like GDI has (lines, ellipses, etc.)

And another mystery is the stuff I see that apparently gives you access to things like the horizontal and vertical retrace periods, which seems to be quite CRT-specific.

So could you possibly give a very brief overview of what DD does and how to use it? It might be worthwhile learning it, despite the barriers of having to deal with COM and "interfaces" intended for C++.

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