News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

How to create a Transparent Pen in MASM?

Started by Airam, April 17, 2009, 07:32:03 PM

Previous topic - Next topic

Airam

Hi assemblers!!

I'm trying to paint some lines horizontally an vertically in order to make a grid.

This is the code that i'm using to make the horizontal lines:
      Invoke CreatePen, PS_SOLID, 1, 00101010H ;
      Mov GridPen, Eax
                .
                .
                .

                drawGrid proc private hWnd:HWND, uMsg:ULONG
                Invoke BeginPaint, hWnd, Addr ps
      Mov StaticHDC, Eax
      Invoke GetClientRect, hWnd, Addr StaticRect
      Invoke FillRect, StaticHDC, Addr StaticRect, BoardPen
                Invoke SelectObject, StaticHDC, GridPen
      Xor Ebx, Ebx
      .While (Ebx < heightWindow)
         Invoke MoveToEx, StaticHDC, 0, Ebx, NULL   
         Invoke LineTo, StaticHDC, widthWindow, Ebx
         Add Ebx, 30 ; Line separation
      .EndW
                dataGrid endp
where
heightWindow = is the heigth of the window
StaticHDC is the handle of a static (or label) which I use to paint.
widthWindow = is the width of the Window.

So, the question is how to print transparent lines. What I really what is to define al alpha channel of transparency. No all transparent but for example 50% transparent.

MichaelW

#1
The first method that occurs to me is to use GDI+. This example is based on an in-memory dialog created with the MASM32 macros. Note that it depends on the gdiplus include file and import library that are included with MASM32 version 10 only. And it also depends on gdiplus.dll, which AFAIK is included only for Windows XP and later. For Windows 2000 the redistributable is available here. And there is a useful GDI+ reference (code examples in PB)
here.

Edit: This code has a problem with not fully redrawing the client area under all conditions, and I don't have time right now to fix it.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
    include \masm32\include\gdiplus.inc
    includelib \masm32\lib\gdiplus.lib

    ARGB MACRO alpha, red, green, blue
        IFNDEF __a_r_g_b__
          .data
            __a_r_g_b__ dd 0
          .code
        ENDIF
        push eax
        mov al, alpha
        shl eax, 8
        mov al, red
        shl eax, 8
        mov al, green
        shl eax, 8
        mov al, blue
        mov __a_r_g_b__, eax
        pop eax
        EXITM <__a_r_g_b__>
    ENDM

    GdiplusStartupInput STRUCT
      GdiplusVersion           DWORD ?
      DebugEventCallback       DWORD ?
      SuppressBackgroundThread DWORD ?
      SuppressExternalCodecs   DWORD ?
    GdiplusStartupInput ENDS

    UNITPIXEL equ 2

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
      hInstance dd 0
      token     dd 0
      pbmp      dd 0
      gdipsi    GdiplusStartupInput <1>  ; version must be 1
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

;--------------------------------------------------
; This procedure sizes the specified window so the
; client area is the specified width and height.
;--------------------------------------------------

SetClientSize proc uses ebx hwnd:HWND, pixelWidth:DWORD, pixelHeight: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 ebx, rcc.right      ; ebx = client width - 1
    sub ebx, eax            ; ebx = difference
    sub ecx, ebx            ; adjust width

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

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

    invoke MoveWindow, hwnd, rcw.left, rcw.top, ecx, edx, TRUE

    ret

SetClientSize endp

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

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

    LOCAL ps        :PAINTSTRUCT
    LOCAL graphics  :DWORD
    LOCAL pen       :DWORD

    SWITCH uMsg

      CASE WM_INITDIALOG

        invoke SetClientSize, hwndDlg, 200, 200

        invoke GdiplusStartup, ADDR token, ADDR gdipsi, NULL

      CASE WM_PAINT

        invoke BeginPaint, hwndDlg, ADDR ps

        invoke GdipCreateFromHDC, ps.hdc, ADDR graphics

        invoke GdipCreatePen1, ARGB(127, 255, 0, 0),
                               FP4(10.0), UNITPIXEL, ADDR pen

        invoke GdipDrawLineI, graphics, pen, 0, 20, 199, 20
        invoke GdipDrawLineI, graphics, pen, 0, 60, 199, 60
        invoke GdipDrawLineI, graphics, pen, 0, 100, 199, 100
        invoke GdipDrawLineI, graphics, pen, 0, 140, 199, 140
        invoke GdipDrawLineI, graphics, pen, 0, 180, 199, 180

        invoke GdipCreatePen1, ARGB(127, 0, 255, 0),
                               FP4(10.0), UNITPIXEL, ADDR pen

        invoke GdipDrawLineI, graphics, pen, 20, 0, 20, 199
        invoke GdipDrawLineI, graphics, pen, 60, 0, 60, 199
        invoke GdipDrawLineI, graphics, pen, 100, 0, 100, 199
        invoke GdipDrawLineI, graphics, pen, 140, 0, 140, 199
        invoke GdipDrawLineI, graphics, pen, 180, 0, 180, 199

        invoke GdipCreatePen1, ARGB(64, 0, 0, 255),
                               FP4(10.0), UNITPIXEL, ADDR pen

        invoke GdipDrawLineI, graphics, pen, 0, 0, 199, 199
        invoke GdipDrawLineI, graphics, pen, 0, 199, 199, 0

        invoke GdipDeletePen, pen

        invoke GdipDeleteGraphics, graphics

        invoke EndPaint, hwndDlg, ADDR ps

      CASE WM_CLOSE

        invoke GdiplusShutdown, token

        invoke EndDialog,hwndDlg,0

    ENDSW
    xor eax, eax
    ret
DlgProc endp

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    invoke GetModuleHandle, NULL
    mov hInstance, eax
    Dialog "Test", \
           "MS Sans Serif",10, \
           WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \
           0,0,0,150,100,1024
    CallModalDialog hInstance,0,DlgProc,NULL
    exit

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start


eschew obfuscation

Airam

Thanks MichaelW it really works fine!!!

Thank you very very much!!!

MichaelW

This is an improved version that, among other things, corrects the redraw problem on my system.

; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
    include \masm32\include\gdiplus.inc
    includelib \masm32\lib\gdiplus.lib
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    GdiplusStartupInput STRUCT
      GdiplusVersion           DWORD ?
      DebugEventCallback       DWORD ?
      SuppressBackgroundThread DWORD ?
      SuppressExternalCodecs   DWORD ?
    GdiplusStartupInput ENDS

    UNITPIXEL equ 2

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

    ;---------------------------------------------------------------------
    ; This macro function returns a 32-bit value calculated at assembly
    ; time from the specified components, each of which must be expressed
    ; as a constant in the range 0-255. Note that the returned value is
    ; of the hexadecimal form AARRGGBB as expected by the GDI+ functions,
    ; with the color component order reversed relative to a GDI COLORREF
    ; value as returned by the RGB macro (00BBGGRR).
    ;---------------------------------------------------------------------

    ARGB MACRO alpha, red, green, blue
      EXITM % alpha SHL 24 OR red SHL 16 OR green SHL 8 OR blue
    ENDM

; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data

      hInst HMODULE 0

      hdcBM HDC     0
      hbmp  HBITMAP 0

      gdipsi GdiplusStartupInput <1>        ; version must be 1

    .code
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

;---------------------------------------------------------------------
; This procedure sizes the specified window so the client area is the
; specified width and height, without changing the window position.
;---------------------------------------------------------------------

SetClientSize proc hwnd:HWND, pixelWidth:DWORD, pixelHeight: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                ; ecx = adjusted width

    push ecx                    ; preserve adjusted width

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

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

    pop ecx                     ; recover adjusted width

    invoke MoveWindow, hwnd, rcw.left, rcw.top, ecx, edx, TRUE

    ret

SetClientSize endp

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

;------------------------------------------------------------
; This procedure centers the specified window on the screen,
; without changing the window size or Z order.
;------------------------------------------------------------

CenterWindow proc hwnd:HWND

    LOCAL rc:RECT

    invoke GetWindowRect, hwnd, ADDR rc

    invoke GetSystemMetrics, SM_CXSCREEN

                                ; eax = screen width
    mov ecx, rc.right
    sub ecx, rc.left
    inc ecx                     ; ecx = window width

    shr eax, 1                  ; eax = screen width / 2
    shr ecx, 1                  ; ecx = windows width / 2
    sub eax, ecx                ; eax = new X coordinate

    push eax                    ; preserve new X coordinate

    invoke GetSystemMetrics, SM_CYSCREEN

    mov edx, eax                ; edx = screen height
    mov eax, rc.bottom
    sub eax, rc.top
    inc eax                     ; eax = window height

    shr edx, 1                  ; edx = screen height / 2
    shr eax, 1                  ; eax = window height / 2
    sub edx, eax                ; edx = new Y coordinate

    pop ecx                     ; recover new X coordinate

    invoke SetWindowPos, hwnd, 0, ecx, edx, 0, 0,
                         SWP_NOZORDER or SWP_NOSIZE

    ret

CenterWindow endp

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

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

    LOCAL hdcClient :HDC
    LOCAL token     :DWORD
    LOCAL graphics  :DWORD
    LOCAL pen       :DWORD
    LOCAL ps        :PAINTSTRUCT
    LOCAL rc        :RECT

    SWITCH uMsg

      CASE WM_INITDIALOG

        invoke SetClientSize, hwndDlg, 200, 200
        invoke CenterWindow, hwndDlg

        ;----------------------------------------------------
        ; Get a DC for the client area of the dialog window,
        ; create a compatible memory DC and a compatible
        ; bitmap to use as a drawing surface.
        ;----------------------------------------------------

        invoke GetDC, hwndDlg
        mov hdcClient, eax
        invoke CreateCompatibleDC, hdcClient
        mov hdcBM, eax
        invoke CreateCompatibleBitmap, hdcClient, 200, 200
        mov hbmp, eax

        ;---------------------------------------
        ; Select the bitmap into the memory DC.
        ;---------------------------------------

        invoke SelectObject, hdcBM, hbmp

        ;-----------------------------
        ; Fill the bitmap with white.
        ;-----------------------------

        invoke SetRect, ADDR rc, 0, 0, 200, 200
        invoke GetStockObject, WHITE_BRUSH
        invoke FillRect, hdcBM, ADDR rc, eax

        ;------------------------------------------------------
        ; Draw the grid on the bitmap using a transparent pen.
        ;------------------------------------------------------

        invoke GdiplusStartup, ADDR token, ADDR gdipsi, NULL

        invoke GdipCreateFromHDC, hdcBM, ADDR graphics

        invoke GdipCreatePen1, ARGB(32, 0, 0, 255),
                               FP4(2.0), UNITPIXEL, ADDR pen

        invoke GdipDrawLineI, graphics, pen, 0, 0, 199, 0
        invoke GdipDrawLineI, graphics, pen, 0, 40, 199, 40
        invoke GdipDrawLineI, graphics, pen, 0, 80, 199, 80
        invoke GdipDrawLineI, graphics, pen, 0, 120, 199, 120
        invoke GdipDrawLineI, graphics, pen, 0, 160, 199, 160
        invoke GdipDrawLineI, graphics, pen, 0, 199, 199, 199

        invoke GdipDrawLineI, graphics, pen, 0, 0, 0, 199
        invoke GdipDrawLineI, graphics, pen, 40, 0, 40, 199
        invoke GdipDrawLineI, graphics, pen, 80, 0, 80, 199
        invoke GdipDrawLineI, graphics, pen, 120, 0, 120, 199
        invoke GdipDrawLineI, graphics, pen, 160, 0, 160, 199
        invoke GdipDrawLineI, graphics, pen, 199, 0, 199, 199

        ;-----------
        ; Clean up.
        ;-----------

        invoke GdipDeletePen, pen
        invoke GdipDeleteGraphics, graphics
        invoke GdiplusShutdown, token

      CASE WM_CTLCOLORDLG

        ;------------------------------------------
        ; Set the client area background to white.
        ;------------------------------------------

        invoke GetStockObject, WHITE_BRUSH
        ret

      CASE WM_PAINT

        ;---------------------------------------------------
        ; Display the bitmap by copying it to the paint DC.
        ;---------------------------------------------------

        invoke BeginPaint, hwndDlg, ADDR ps

        invoke CreateCompatibleBitmap, ps.hdc, 200, 200
        push eax
        invoke SelectObject, ps.hdc, eax
        push eax

        invoke BitBlt, ps.hdc, 0, 0, 200, 200, hdcBM, 0, 0, SRCCOPY

        pop eax
        invoke SelectObject, ps.hdc, eax
        pop eax
        invoke DeleteObject, eax

        invoke EndPaint, hwndDlg, ADDR ps

      CASE WM_COMMAND

        mov eax, wParam
        .IF ax == IDCANCEL

          ;-----------
          ; Clean up.
          ;-----------

          invoke DeleteObject, hbmp
          invoke DeleteDC, hdcBM

          invoke EndDialog, hwndDlg, NULL

        .ENDIF

      CASE WM_CLOSE

        ;-----------
        ; Clean up.
        ;-----------

        invoke DeleteObject, hbmp
        invoke DeleteDC, hdcBM

        invoke EndDialog, hwndDlg, 0

    ENDSW
    xor eax, eax
    ret
DlgProc endp

; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

    invoke GetModuleHandle, NULL
    mov hInst, eax

    ;------------------------------------------------------------------------
    ; The dialog size and position coordinates can be specified as zero here
    ; because the size and position will be set in the WM_INITDIALOG handler
    ; before the dialog is displayed.
    ;------------------------------------------------------------------------

    Dialog "Test", \                          ; caption
           "MS Sans Serif",10, \              ; font,pointsize
           WS_OVERLAPPED or WS_SYSMENU, \     ; dialog window styles
           0, \                               ; number of controls
           0,0,0,0, \                         ; x, y, width, height
           1024                               ; template buffer size
    CallModalDialog hInst,0,DlgProc,NULL
    exit

; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
eschew obfuscation

Airam