I have been working on using gdi32 drawing functions to use instead of bitmaps for my tic tac toe game.
I now have all of the bimaps removed from the game. All of the drawing issues have been resolved.
(https://i.postimg.cc/QxHTDF17/untitled.png)
No Title bar, no movable borders. You close the program with the ESC key. :wink2: Plain and simple.
I might add an ini file, for the user to select their own color for X and O. This image shows another variation of contrasting colors for X and O.
Can't you just draw a line using a wide pen? For the X.
Quote from: sinsi on February 26, 2025, 03:31:30 PMCan't you just draw a line using a wide pen? For the X.
I have not. :sad: I was spending way too much time trying to figure the FloodFill problems out.
What would the 'points' of the X look like, I hope not rounded.
I'll try that when I get back inside, to see how it looks.
Quote from: zedd151 on February 26, 2025, 03:39:36 PMWhat would the 'points' of the X look like
Think of a thick texta (sharpie?)
Quote from: sinsi on February 26, 2025, 03:41:02 PMQuote from: zedd151 on February 26, 2025, 03:39:36 PMWhat would the 'points' of the X look like
Think of a thick texta (sharpie?)
Okay. If needed I could always put in a coupla lines to make the points less round and more square like the bitmap.
I'll post my progress in a little while. :smiley:
It never dawned on me to try it. I did think about using extra large fonts though.
Speaking of fonts, I used to have a bootleg copy of Font Creator. You could design your own fonts, even from a bitmap. :biggrin: I might just explore that possibility, if this doesn't look very good using wide pen..
Dunno if it'll help, but I have my own flood-fill routine I could post that you could try. Works for me.
Quote from: zedd151 on February 26, 2025, 03:44:54 PMIt never dawned on me to try it.
First thing I thought of :biggrin:
Flashbacks to drawing on a 320x200x256 VGA screen on a 386sx. Everything.
None of this fancy Windows drawing stuff.
It needs a little tweaking, but I can live with that.
Thanks, sinsi. That
works much better, it will
look even better after a few adjustments.
Quote from: sinsi on February 26, 2025, 04:25:57 PMQuote from: zedd151 on February 26, 2025, 03:44:54 PMIt never dawned on me to try it.
First thing I thought of :biggrin:
Flashbacks to drawing on a 320x200x256 VGA screen on a 386sx. Everything.
None of this fancy Windows drawing stuff.
I never had to suffer such Phun.
The new X looks friendlier :badgrin:
Quote from: NoCforMe on February 26, 2025, 04:03:38 PMDunno if it'll help, but I have my own flood-fill routine I could post that you could try. Works for me.
I totally missed your post earlier. Sorry.
Sure, you only need to post the essential bits. I won't need a full blown example. At least I don't think I will.
Quote from: sinsi on February 26, 2025, 04:49:59 PMThe new X looks friendlier :badgrin:
Why do you fear the old style? :greensml:
I still need to tweak it so it looks 'right' next to the O's.
I just had another overnight epiphany while I slept, sinsi. :biggrin:
Why the hell don't I now use the thick pen to also draw the "O", so it will look much better when side by side with the new and improved "X".
Last night, I was thinking about making the X (created with a thick pen), look better and match it to the O, which was created using filled ellipses.
Kinda like making an apple look like an orange. :joking:
Amazing what a little sleep can do, to restore common sense, or at least better thought processes. :biggrin:
Quote from: zedd151 on February 26, 2025, 03:44:54 PMQuote from: sinsi on February 26, 2025, 03:41:02 PMQuote from: zedd151 on February 26, 2025, 03:39:36 PMWhat would the 'points' of the X look like
Think of a thick texta (sharpie?)
Okay. If needed I could always put in a coupla lines to make the points less round and more square like the bitmap.
I'll post my progress in a little while. :smiley:
It never dawned on me to try it. I did think about using extra large fonts though.
Speaking of fonts, I used to have a bootleg copy of Font Creator. You could design your own fonts, even from a bitmap. :biggrin: I might just explore that possibility, if this doesn't look very good using wide pen..
I am using code that changes font to bigger size in my unicode chess,so big 'X' and 'O' could be used
Quote from: daydreamer on February 27, 2025, 02:18:01 AMI am using code that changes font to bigger size in my unicode chess,so big 'X' and 'O' could be used
I have considered that possibilty as well. I am currently working on a different approach, though. :biggrin:
YaY! I got 'er done.Thanks again sinsi for a simple solution. I like simplicity. But I still wonder why I had issues with FloodFill and ExtFloodFill.
DrawX proc hDC:dword, color:dword, x:dword, y:dword
local hPen:dword, hPenOld:dword
invoke CreatePen, PS_SOLID, 20, red
mov hPen, eax
invoke SelectObject, hDC, hPen
mov hPenOld, eax
mov ecx, x
mov edx, y
add ecx, 26
add edx, 26
invoke MoveToEx, hDC, ecx, edx, 0
mov ecx, x
add ecx, 112
mov edx, y
add edx, 112
invoke LineTo, hDC, ecx, edx
mov ecx, x
add ecx, 112
mov edx, y
add edx, 26
invoke MoveToEx, hDC, ecx, edx, 0
mov ecx, x
mov edx, y
add ecx, 26
add edx, 112
invoke LineTo, hDC, ecx, edx
invoke SelectObject, hDC, hPenOld
invoke DeleteObject, hPen
ret
DrawX endp
DrawO proc hDC:dword, hback:dword, hfill:dword, x:dword, y:dword
local hPen:dword
invoke SelectObject, hDC, hback
invoke CreatePen, PS_SOLID, 18, blue
mov hPen, eax
invoke SelectObject, hDC, hPen
add x, 32
mov eax, x
add eax, 96
add y, 32
mov ecx, y
add ecx, 96
invoke Ellipse, hDC, x, y, eax, ecx
ret
DrawO endp
So that issue is still unresolved. I must have spent the better part of half a day messing around trying to get either of those to behave.
Have 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!
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.
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:
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.
[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 (https://masm32.com/board/index.php?msg=136368)
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:
(https://i.postimg.cc/wvL6h5Fm/4-neighbors.gif)
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.
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.
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.
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.
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!
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.
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.
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:
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...
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.)
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:
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
; ==================================================================================================
Thanks satpro, I will take a look at this later this evening. :smiley:
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.
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!
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...
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:
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:
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.
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....
@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:
: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 (https://masm32.com/board/index.php?msg=135599)... 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
(https://i.postimg.cc/jdnVj9nj/untitled.png)
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.
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.)
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.
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:
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.
Quote from: NoCforMe on March 01, 2025, 08:43:05 AMSo 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.
I will be happy to, and thank you. In my opinion DirectDraw is a gem from another time. Nothing really works, but it does let you access screen ram like in the old days. And that's big. Microsoft (obviously) does not want us tinkering with the primary surface.
What I will do is write something separate and explain some things that are not necessarily in all of the docs. In fact, the farther back you go in time, the more MS was willing to share. Objects, how to call COM, video sync, what works and what doesn't -- all of it will be covered.
I will show you how to draw there -- it is liberating and so much faster than using the graphics card. For example, you can fill a box or draw any line before equivalent DirectX COM code executes that does the same, exact thing! I'll explain this more, but one thing I have found is that once I bypassed the card (I'm talking doing it
all in system memory and then SSE-copying directly to video ram) cpu usage goes way down, and the program itself runs faster and smoother -- the exact opposite of what you might expect.
Again, thank you for wishing to give this a second look. I'll get on that "write" away.
Quote from: satpro on March 01, 2025, 10:08:36 AMcpu usage goes way down, and the program itself runs faster and smoother -- the exact opposite of what you might expect
That is indeed interesting, as we are always taught that graphics cards are so much faster than ordinary x86 cpus :cool:
Quote from: satpro on March 01, 2025, 10:08:36 AMAgain, thank you for wishing to give this a second look. I'll get on that "write" away.
Well, thank you (in advance).
If you could, would you include at least a couple of drawing operations like lines, ellipses, maybe filled shapes?
Don't care about the programming style here, so don't worry about that. Just want to see how it works "under the hood".
I have made several ddraw program and posted in forum before
But coding style more kinda dos style with library or own proc 's for draw different shapes
Fast speed write directly to vram,but the way graphics port worked oneway before 100 * slower reading vram
Isn't it replaced with newer interface ,alternative to GDI it draws hardware accelerated shapes ?
But don't forget d3d9 isn't only Poly's,you also have linelist, pointlist
Not so fun ?
Introduction to DirectWrite (http://www.nuonsoft.com/blog/2009/05/27/introduction-to-directwrite/)
Only two functions to import, D2D1CreateFactory() and DWriteCreateFactory()
so perhaps using dynamic way, so don't need those import libraries.
Direct2D Tutorial Part 2: Basic Shapes (https://www.codeproject.com/Articles/5277136/Direct2D-Tutorial-Part-2-Basic-Shapes#round_rect)
Suggestion:
Maybe someone can start a new topic dedicated to these Direct Draw discussions?
Perhaps not relevant in a thread where the topic was gdi32 FloodFill and ExtFloodFill. And the issue with those gdi32 functions has been resolved, several posts ago. (https://masm32.com/board/index.php?msg=136444)
Quote from: zedd151 on March 01, 2025, 03:50:05 AM:rolleyes: um.... I found the problem with FloodFill.
Which worked fine in the example Here (https://masm32.com/board/index.php?msg=136444).
However, after adding several drawing function then add the funtion that uses FloodFill, the drawing is not bothered by moving the window below the task bar anymore... but now when the window is minimized using the window borders similar issues with it:
(https://i.postimg.cc/wjg69Psm/untitled.png)
I had even tried breaking up the outline of the X into 5 pieces to FloodFill smaller sections but that did not help.
The only way I found to resolve this is to call InvalidateRect in WM_SIZE, which restores everything being painted, if the window gets resized using the window border.
Maybe it is better to stick with bitmap images?
Unless there is a way to create the X (using FloodFill) only once. And keep a memory bitmap of it, to be blitted when needed. I confess though, that I have no clue how to do that. :sad:
Most likely I will revert to using bitmaps...
Quote from: zedd151 on March 02, 2025, 01:40:56 AMSuggestion:
Maybe someone can start a new topic dedicated to these Direct Draw discussions?
Your wish is my command.
I started a new thread (https://masm32.com/board/index.php?topic=12575.0). It's just a placeholder for now, to be fleshed out as more info comes in.
Speaking of which, @satpro, anytime you have some example code for us you can post it there.
Quote from: zedd151 on March 02, 2025, 10:47:36 AMThe only way I found to resolve this is to call InvalidateRect in WM_SIZE, which restores everything being painted, if the window gets resized using the window border.
Well, that's exactly what you should be doing. Does that solve the redrawing problem? If so, then, as they say, Bob's your uncle.
Quote from: NoCforMe on March 02, 2025, 11:00:37 AMQuote from: zedd151 on March 02, 2025, 01:40:56 AMSuggestion:
Maybe someone can start a new topic dedicated to these Direct Draw discussions?
Your wish is my command.
...
Siekmanski will be around shortly to help you guys out... a little bird told me.
Quote from: NoCforMe on March 02, 2025, 11:02:30 AMWell, that's exactly what you should be doing. Does that solve the redrawing problem? If so, then, as they say, Bob's your uncle.
Just when I thought I had that problem knackered. Is that a legit way to handle it? And yes, it does resolve the drawing irregularities. Under normal circumstances it was drawing fine otherwise, and no gdi leaks.
Much experimenting on my part to figure all of this out.
Quote from: zedd151 on March 02, 2025, 11:16:32 AMQuote from: NoCforMe on March 02, 2025, 11:02:30 AMWell, that's exactly what you should be doing. Does that solve the redrawing problem? If so, then, as they say, Bob's your uncle.
Just when I thought I had that problem knackered. Is that a legit way to handle it? And yes, it does resolving the drawing irregularities. Under normal circumstances it was drawing fine otherwise, and no gdi leaks.
Yes; the overall point is that you, the programmer, are responsible for making sure things are redrawn when certain events occur, like the window being resized. Not all of this is done automagically by Windows, as you discovered.
And it really has nothing to do with GDI leaks, which happen when you create objects and then forget to delete them. That's a separate issue.
Quote from: NoCforMe on March 02, 2025, 12:12:34 PMQuote from: zedd151 on March 02, 2025, 11:16:32 AMQuote from: NoCforMe on March 02, 2025, 11:02:30 AMWell, that's exactly what you should be doing. Does that solve the redrawing problem? If so, then, as they say, Bob's your uncle.
Just when I thought I had that problem knackered. Is that a legit way to handle it? And yes, it does resolving the drawing irregularities. Under normal circumstances it was drawing fine otherwise, and no gdi leaks.
Yes; the overall point is that you, the programmer, are responsible for making sure things are redrawn when certain events occur, like the window being resized. Not all of this is done automagically by Windows, as you discovered.
okay.
QuoteAnd it really has nothing to do with GDI leaks, which happen when you create objects and then forget to delete them. That's a separate issue.
yes, I know is a separate issue. But it does happens a lot more than you would think it does. And not just to me. :badgrin:
Quote from: zedd151 on March 02, 2025, 12:19:08 PMQuote from: NoCforMe on March 02, 2025, 12:12:34 PMAnd it really has nothing to do with GDI leaks, which happen when you create objects and then forget to delete them. That's a separate issue.
yes, I know is a separate issue. But it does happens a lot more than you would think it does. And not just to me. :badgrin:
Oh, yeah, I know all about GDI leaks. (Don't ask me how I know.)
That's why Task Manager is your friend.
Re: GDI leaks...
:toothy: Don't you hate it when that happens. :biggrin:
Anyway I have updated the image in post #1. It closely resembles the original game graphics. Maybe not pixel for pixel in the "tic - tac - toe" banner, but most of the other graphics are a match. The O's might be a little off, though. :smiley:
I am going to now integrate the drawing functions and WM_PAINT (in its entirety) into the original code.
Hopefully I can package it all up, and never need to look at its code again! :greensml:
Quote from: zedd151 on March 02, 2025, 01:51:28 PMI am going to now integrate the drawing functions and WM_PAINT (in its entirety) into the original code.
Nope. That had some issues. It appears that the window DC was getting corrupted somewhere, and I could not locate exactly where...
Sooooo..... I am rewriting it from scratch, except for the new graphics stuff. I have updated the current code and attachment for tic-tac-toe Here (https://masm32.com/board/index.php?msg=136249)
The tic-tac-toe rewrite is about as close to finished as it needs to be... it wasn't all that hard to rewrite it.
Btw,
no other issues found regarding FloodFill and/or ExtFloodFill. That issue is now fully resolved.