News:

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

Main Menu

Using BITMAPS to create borderless window

Started by GoneFishing, September 22, 2013, 01:36:21 AM

Previous topic - Next topic

GoneFishing

#15
I must say it's the best  MASM example I've ever seen!
I never thought the source code may be so artistically formatted  :t

Now I looked at your source and saw that you used your own random number generator
It would be interesting to test the default MASM  nrandom routine in such a way

MichaelW

Quote from: dedndave on September 22, 2013, 06:26:18 AM
when i first got it up and running, i saw a flaw in my random generator code

It's easy to make a mistake when rolling your own RNG. I did a scatter-plot test of your code using the same method I used to find the problem in the original nrandom, and problems in multiple other generators, and in the 10 minutes or so I spent trying various resolutions I could see no non-random patterns.

;==============================================================================
    include \masm32\include\masm32rt.inc
    .686
;==============================================================================
    .data
      qwRnd64         QWORD    ?
      dwAsCnt         dd     1

      hInstance dd    0
      hDlg      dd    0
      hdc       dd    0
      msg       MSG   <>
      rc        RECT  <>
      sz        db 30 dup(0)
      ctr       dd 0
    .code
;==============================================================================

ASeed   PROC base:DWORD

;Auto-Seeding Unscaled Random QWORD Generator - DednDave
;version 1, 11-2010
;version 2, 5-2013
;version 3, 6-2013

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

    mov     ecx,dwAsCnt
    mov     edx,dword ptr qwRnd64+4
    dec     ecx
    .if ZERO?
        rdtsc
        mov     cl,al
        mov dword ptr qwRnd64,eax
        mov     ch,1
        xor     edx,eax
    .endif
    mov     eax,1517746329
    mov     dwAsCnt,ecx
    mul     edx
    add     eax,dword ptr qwRnd64
    adc     edx,0
    xor     edx,eax
    mov dword ptr qwRnd64+4,eax
    mov dword ptr qwRnd64,edx

    ; mov eax, edx ; uncomment this to test low-order dword
    xor edx, edx
    div base
    mov eax, edx

    ret

ASeed   ENDP
;==============================================================================

DialogProc proc hwndDlg:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD

    SWITCH uMsg

        CASE WM_CTLCOLORDLG

            invoke GetStockObject, WHITE_BRUSH
            ret

        CASE WM_SIZE

            invoke InvalidateRgn, hwndDlg, NULL, TRUE

        CASE WM_COMMAND

            SWITCH wParam
                CASE IDCANCEL
                    invoke DestroyWindow, hwndDlg
            ENDSW

        CASE WM_CLOSE

            invoke DestroyWindow, hwndDlg

        CASE WM_DESTROY

            invoke PostQuitMessage, NULL

    ENDSW

    xor eax, eax
    ret

DialogProc endp

;==============================================================================
start:
;==============================================================================

    invoke GetModuleHandle, NULL
    mov hInstance, eax

    Dialog "Test", \
           "FixedSys", 11, \
            WS_VISIBLE or WS_OVERLAPPEDWINDOW or \
            DS_CENTER, \
            0, \
            0,0,100,75, \
            1024

    CallModelessDialog hInstance, 0, DialogProc, NULL
    mov hDlg, eax

    invoke GetDC, hDlg
    mov hdc, eax

    invoke Sleep, 1000

  msgLoop:

    invoke PeekMessage, ADDR msg, NULL, 0, 0, PM_REMOVE
    .IF msg.message != WM_QUIT
        .IF eax != 0
            invoke IsDialogMessage, hDlg, ADDR msg
        .ELSE
            invoke GetClientRect, hDlg, ADDR rc

            inc ctr
            cmp ctr, 1000
            jb  @f

            invoke szappend, addr sz, chr$("  "), 0
            mov esi, eax
            invoke szappend, addr sz, str$(rc.right), esi
            mov esi, eax
            invoke szappend, addr sz, chr$(" x "), esi
            mov esi, eax
            invoke szappend, addr sz, str$(rc.bottom), esi
            invoke SetWindowText, hDlg, addr sz
            mov ctr, 0

          @@:
            invoke ASeed, rc.right
            mov ebx, eax
            invoke ASeed, rc.bottom
            mov esi, eax
            invoke ASeed, 1 SHL 24
            mov edi, eax
            invoke SetPixel, hdc, ebx, esi, edi
        .ENDIF
        jmp msgLoop
    .ENDIF

    invoke ExitProcess, eax

;==============================================================================
end start

Well Microsoft, here's another nice mess you've gotten us into.

dedndave

#17
if you comment out the XOR EDX,EAX from my ASeed routine, you will see the flaw it had   :P

as for it being a good example - well, i could have added a lot more comments, but thanks   :redface:

i found a small error in the RC file...
#define  IDI_ICON               501
was supposed to be
#define  IDI_ICON               101

i updated the attachment, above

MichaelW

My test showed no problem without the XOR EDX,EAX even after I converted the colors to monochrome.

Well Microsoft, here's another nice mess you've gotten us into.

GoneFishing

 commented out the XOR EDX,EAX  in ASeed proc -  really there was a flaw (see the screenshot below)

Quote from: MichaelW on September 22, 2013, 12:04:55 PM
My test showed no problem without the XOR EDX,EAX even after I converted the colors to monochrome.
the ASeed proc code in the Dave's attachment slightly differs from that in your post

changed RC file to:
#define  IDI_ICON               101
and rebuild the program . Now you can see your icon on the screenshot 
about comments ... maybe one day you will add them to complete this example ?  ;)

dedndave

yup - that's the flaw - lol
it's only the 3rd byte in each qword, but the easy fix was to alter the entire lower dword

Michael - not sure which program you are running, but this is already monochrome
the ASeed routine has evolved a little bit - with the XOR, it's the 4th version, now

i may add some comments - some of the graphics stuff is probably a little tricky for beginners

GoneFishing

I also tested nrandom routine with Michael's code (see screenshot below)  :

msgLoop:
...
  @@:
           ; invoke ASeed, rc.right
            invoke nrandom,0ffffffffh
            invoke nseed,eax
            invoke nrandom,rc.right
            mov ebx, eax
           ; invoke ASeed, rc.bottom
            invoke nrandom,0ffffffffh
            invoke nseed,eax
            invoke nrandom,rc.bottom
            mov esi, eax
           ; invoke ASeed, 1 SHL 24
           ; mov edi, eax
            invoke nrandom,0ffffffffh
            invoke nseed,eax
            invoke nrandom,256
            mov ah,al
            shl eax,8
            mov al,ah
            mov edi,eax
           
            invoke SetPixel, hdc, ebx, esi, edi
...


Michael:  your code is very nice for testing various RNGs !

One minor problem that I could not solve is to set client area to 256x256 pixels (the height can be either 255 or 257 but not 256) :
Quote
Dialog "Test", \
           "FixedSys", 11, \
            WS_VISIBLE or WS_OVERLAPPEDWINDOW or \
            DS_CENTER, \
            0, \
            0,0,128,136, \  ; original size : 100,75
            1024

dedndave

when you create a dialog in resource, it is sized by "dialog base units"
dialog base units are based on the system font size   ::)

if you set the size with MoveWindow or SetWindowPos, you can specify the size in pixels
of course, you have to add the border and title bar widths
nothing is ever easy - lol

GoneFishing

Well , I made the window 256x256:
invoke MoveWindow, hDlg, 10,10, 272,295,1

dedndave

you could do something like this.....

SetClientSize PROTO :HWND,:DWORD,:DWORD

    .CODE

    INVOKE  SetClientSize,hWindow,256,256
;
;
SetClientSize PROC USES EDI hWnd:HWND,dwClientWidth:DWORD,dwClientHeight:DWORD

    LOCAL   _rcClient       :RECT
    LOCAL   _rcWindow       :RECT

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

    INVOKE  GetClientRect,hWnd,addr _rcClient
    INVOKE  GetWindowRect,hWnd,addr _rcWindow

    mov     ecx,dwClientWidth
    mov     edx,dwClientHeight
    mov     eax,_rcWindow.left
    mov     edi,_rcWindow.top

    add     ecx,_rcWindow.right
    add     edx,_rcWindow.bottom
    add     ecx,_rcClient.left
    add     edx,_rcClient.top
    sub     ecx,_rcClient.right
    sub     edx,_rcClient.bottom
    sub     ecx,eax
    sub     edx,edi

    INVOKE  MoveWindow,hWnd,eax,edi,ecx,edx,TRUE
    ret

SetClientSize ENDP


it gets the current window and client sizes, and adjusts the window size to match the desired client size

GoneFishing

Thank you, Dave
very useful routine

Just tested nrandom,2 i.e. only Black  and White (see screenshot):

       @@:
           ; invoke ASeed, rc.right
            invoke nrandom,0ffffffffh
            invoke nseed,eax
            invoke nrandom,rc.right
            mov ebx, eax
           ; invoke ASeed, rc.bottom
            invoke nrandom,0ffffffffh
            invoke nseed,eax
            invoke nrandom,rc.bottom
            mov esi, eax
           ; invoke ASeed, 1 SHL 24
           ; mov edi, eax
            invoke nrandom,0ffffffffh
            invoke nseed,eax
;             invoke nrandom,256
;             mov ah,al
;             shl eax,8
;             mov al,ah
;             mov edi,eax

           invoke nrandom,2
             .if eax == 0
                 mov edi,0
             .elseif
                 mov edi, 0ffffffh
             .endif           
           
            invoke SetPixel, hdc, ebx, esi, edi


Now I 'm thinking of drawing a grid (let's say 64x64) of small rectangles ( 8x8 pixels or so) which will be randomly filled only with black and white brushes.
Client area background is meant to be gray.

MichaelW

Dave,

I was trying to use a modification of my code to see the problem with your generator when the:
xor     edx,eax
is commented out. I could not see the problem using random colors, so I changed the code to use random monochrome colors, but still could not see the problem. AFAICT the problem in your code sets the color for every eighth pixel to zero. If I change the code in FillDIBRandGray to use the low-order dword of qwRnd64 in both statements, then every fourth pixel has the color set to zero. If I change the code to use the high-order dword of qwRnd64 in both statements, then there are no vertical bands, but I can see a large number of small-scale repetitive patterns.

Well Microsoft, here's another nice mess you've gotten us into.

GoneFishing

Here it is , based on \MASM32\examples\exampl06\barchart demo (requires barchart.inc)
Thank you Dave for your  SetClientSize  routine , I used it in this demo:

      .486                      ; create 32 bit code
      .model flat, stdcall      ; 32 bit memory model
      option casemap :none      ; case sensitive

      include barchart.inc      ; local includes for this file

      DrawRect PROTO :DWORD,:DWORD,:DWORD,:DWORD
      SetClientSize PROTO :HWND,:DWORD,:DWORD

   .code

start:

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    ; ------------------
    ; set global values
    ; ------------------
      mov hInstance,   FUNC(GetModuleHandle, NULL)
      mov CommandLine, FUNC(GetCommandLine)
      mov hIcon,       FUNC(LoadIcon,hInstance,500)
      mov hCursor,     FUNC(LoadCursor,NULL,IDC_ARROW)
      mov sWid,        FUNC(GetSystemMetrics,SM_CXSCREEN)
      mov sHgt,        FUNC(GetSystemMetrics,SM_CYSCREEN)

      call Main

      invoke ExitProcess,eax

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

Main proc

    LOCAL Wwd:DWORD,Wht:DWORD,Wtx:DWORD,Wty:DWORD

    STRING szClassName,"BlacknWhite_class"

  ; --------------------------------------------
  ; register class name for CreateWindowEx call
  ; --------------------------------------------
    invoke RegisterWinClass,ADDR WndProc,ADDR szClassName,
                       hIcon,hCursor,COLOR_BTNSHADOW+1;COLOR_APPWORKSPACE ;COLOR_BTNFACE+10

    mov Wwd, 512
    mov Wht, 512
    invoke TopXY,Wwd,sWid
    mov Wtx, eax
    invoke TopXY,Wht,sHgt
    mov Wty, eax

    invoke CreateWindowEx,WS_EX_LEFT,
                          ADDR szClassName,
                          ADDR szDisplayName,
                          WS_OVERLAPPED or WS_SYSMENU,
                          Wtx,Wty,Wwd,Wht,
                          NULL,NULL,
                          hInstance,NULL
    mov hWnd,eax

INVOKE  SetClientSize,hWnd,512,512

  ; ---------------------------
  ; macros for unchanging code
  ; ---------------------------
    DisplayWindow hWnd,SW_SHOWNORMAL

    call MsgLoop
    ret

Main endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

RegisterWinClass proc lpWndProc:DWORD, lpClassName:DWORD,
                      Icon:DWORD, Cursor:DWORD, bColor:DWORD

    LOCAL wc:WNDCLASSEX

    mov wc.cbSize,         sizeof WNDCLASSEX
    mov wc.style,          CS_BYTEALIGNCLIENT or \
                           CS_BYTEALIGNWINDOW
    m2m wc.lpfnWndProc,    lpWndProc
    mov wc.cbClsExtra,     NULL
    mov wc.cbWndExtra,     NULL
    m2m wc.hInstance,      hInstance
    m2m wc.hbrBackground,  bColor
    mov wc.lpszMenuName,   NULL
    m2m wc.lpszClassName,  lpClassName
    m2m wc.hIcon,          Icon
    m2m wc.hCursor,        Cursor
    m2m wc.hIconSm,        Icon

    invoke RegisterClassEx, ADDR wc

    ret

RegisterWinClass endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

MsgLoop proc

    LOCAL msg:MSG

    push esi
    push edi
    xor edi, edi                        ; clear EDI
    lea esi, msg                        ; Structure address in ESI
    jmp jumpin

    StartLoop:
      invoke TranslateMessage, esi
      invoke DispatchMessage,  esi
    jumpin:
      invoke GetMessage,esi,edi,edi,edi
      test eax, eax
      jnz StartLoop

    mov eax, msg.wParam
    pop edi
    pop esi

    ret

MsgLoop endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

WndProc proc hWin:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD

    Switch uMsg
      Case WM_PAINT
        invoke Paint_Proc,hWin
        return 0
      Case WM_DESTROY
        invoke PostQuitMessage,NULL
        return 0
    Endsw

    invoke DefWindowProc,hWin,uMsg,wParam,lParam

    ret

WndProc endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

TopXY proc wDim:DWORD, sDim:DWORD

    mov eax, [esp+8]
    sub eax, [esp+4]
    shr eax, 1

    ret 8

TopXY endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

Paint_Proc proc hWin:DWORD

    LOCAL hDC      :DWORD
    LOCAL Rct      :RECT
    LOCAL Ps       :PAINTSTRUCT
    LOCAL x        :DWORD
    LOCAL y        :DWORD
    LOCAL recX     :DWORD
    LOCAL recY     :DWORD
   
    mov hDC, rv(BeginPaint,hWin,ADDR Ps)
   
mov x,0
mov recY,40
mov y,0
nextY:
      .WHILE x<24
          mov ebx,40
          mov eax,18
          mul x     
          add ebx,eax
          invoke nrandom,0ffffffffh
          invoke nseed,eax
          invoke nrandom,2
             .if eax == 0
                  invoke DrawRect,hDC,ebx,recY, 000000h
             .elseif
                  invoke DrawRect,hDC,ebx,recY, 0ffffffh
             .endif           

          xor ebx,ebx
          inc x
      .ENDW   

mov x,0
inc y

      .WHILE y<24
            mov recY,40
            mov eax,18
            mul y
            add recY,eax
            jmp nextY
      .ENDW     

    invoke FrameWindow,hWnd,4,1,1
    invoke FrameWindow,hWnd,7,1,0

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

    invoke EndPaint,hWin,ADDR Ps

    ret

Paint_Proc endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

DrawRect proc hDC:DWORD,tx:DWORD,ty:DWORD,bruchcol:DWORD

    LOCAL rct   :RECT

    m2m rct.left, tx                                ; set top X and Y to structure members
    m2m rct.top, ty
    m2m rct.right, tx
    m2m rct.bottom, ty
    mov eax, 16                               
    add rct.right, eax                           
    add rct.bottom, 16                           
    invoke FillRect, hDC,ADDR rct,                  ; fill rect with fill colour
                     rv(CreateSolidBrush,bruchcol)
 
    ret

DrawRect endp


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

SetClientSize PROC USES EDI hwnd:HWND,dwClientWidth:DWORD,dwClientHeight:DWORD

    LOCAL   _rcClient       :RECT
    LOCAL   _rcWindow       :RECT

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

    INVOKE  GetClientRect,hWnd,addr _rcClient
    INVOKE  GetWindowRect,hWnd,addr _rcWindow

    mov     ecx,dwClientWidth
    mov     edx,dwClientHeight
    mov     eax,_rcWindow.left
    mov     edi,_rcWindow.top

    add     ecx,_rcWindow.right
    add     edx,_rcWindow.bottom
    add     ecx,_rcClient.left
    add     edx,_rcClient.top
    sub     ecx,_rcClient.right
    sub     edx,_rcClient.bottom
    sub     ecx,eax
    sub     edx,edi

    INVOKE  MoveWindow,hwnd,eax,edi,ecx,edx,TRUE
    ret

SetClientSize ENDP

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start


Now I'm planning to add some interaction with the user but don't know how to do it yet ...

MichaelW

Here is a version that can optionally center the window on the screen:

;---------------------------------------------------------------------
; This procedure sizes the specified window so the client area is the
; specified width and height and optionally centers the window on the
; the screen.
;
; Note that AdjustWindowRect cannot be used to calculate the required
; window rectangle here because it does not support windows with the
; WS_OVERLAPPED style.
;
; Not tested in combination with a status bar, menu bar, etc.
;---------------------------------------------------------------------

SetClientSize proc hwnd:HWND, pixelWidth:DWORD, pixelHeight:DWORD, fCenter:DWORD

    LOCAL _x:DWORD, _y:DWORD, nWidth:DWORD, nHeight:DWORD
    LOCAL rcc:RECT, rcw:RECT

    invoke GetClientRect, hwnd, ADDR rcc
    invoke GetWindowRect, hwnd, ADDR rcw

    mov ecx, rcw.right
    sub ecx, rcw.left       ; ecx = window width - 1

    mov eax, pixelWidth
    dec eax                 ; eax = pixelWidth - 1
    mov edx, rcc.right      ; edx = client width - 1
    sub edx, eax            ; edx = difference
    sub ecx, edx            ; adjust width
    mov nWidth, ecx

    mov ecx, rcw.bottom
    sub ecx, rcw.top        ; ecx = window height - 1

    mov eax, pixelHeight
    dec eax                 ; eax = pixelHeight - 1
    mov edx, rcc.bottom     ; edx = client height - 1
    sub edx, eax            ; edx = difference
    sub ecx, edx            ; adjust height
    mov nHeight, ecx

    .IF fCenter
        invoke GetSystemMetrics, SM_CXSCREEN
        shr eax, 1
        mov edx, nWidth
        shr edx, 1
        sub eax, edx
        mov _x, eax
        invoke GetSystemMetrics, SM_CYSCREEN
        shr eax, 1
        mov edx, nHeight
        shr edx, 1
        sub eax, edx
        mov _y, eax
    .ELSE
        m2m _x, rcw.left
        m2m _y, rcw.top
    .ENDIF

    invoke MoveWindow, hwnd, _x, _y, nWidth, nHeight, TRUE

    ret

SetClientSize endp


And just in case it might be useful here, the attachment contains the most recent test of some code for a Minesweeper clone that uses a bitmap button grid. It's barely functional, and has multiple unsolved problems, but it might provide some useful information or ideas.
Well Microsoft, here's another nice mess you've gotten us into.

GoneFishing

Michael,
I've just tested your routine. It works fine .One detail though:
if I specify 512 as width/height your window's title becomes 511x511,  and 512x512 if I pass 513,513 as parameters