Linear Gradient Fill example for MASM

This is an old example I've created for MASM, which was posted in MASM32 forum 2 years ago:
http://www.masm32.com/board/index.php?topic=5944.0

It has a simple approach of double buffering and working with MSIMG32 for the gradient fills.

If you're into drawing in windows (Win32), and you like to program in assembly language; this is example is for you.
Download the source from attachment, or copy the source codes below.


Cheers,

-chris

LinearGradient.asm


.386
.model flat, stdcall
option casemap:none
option proc:private

include windows.inc

include user32.inc
include kernel32.inc
include gdi32.inc
include msimg32.inc

includelib user32.lib
includelib kernel32.lib
includelib gdi32.lib
includelib msimg32.lib

include MsgCrack.inc

; ==========================================================
; Protos
; ==========================================================
WinMain proto :HINSTANCE, :HINSTANCE, :LPSTR, :dword
WndProc proto :HWND, :UINT, :WPARAM, :LPARAM
DrawFancyDivider proto :HDC, :ptr RECT

; ==========================================================
; MessageHandlers Protos
; ==========================================================
WmDestroy proto :HWND
WmCommand proto :HWND, :word, :HWND, :word
WmPaint proto :HWND

option dotname

; ==========================================================
; Local Macros
; ==========================================================
m2m    macro mem32A, mem32B
    push    mem32B
    pop        mem32A
endm

func macro functionName:req, functionParams:vararg
    invoke    functionName, functionParams
    exitm    <eax>
endm

; ==========================================================
; Data
; ==========================================================
.data?
    hInstance    dd ?
    hFont        HFONT ?
   
.data
    szClassName db "ChrisVega.WinLion", 0
    szWndText    db "Win32 Assembly ROCK!", 0
    lgFont        LOGFONT <-19, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, "Arial">
   
    szText        db "Linear GradientFill sample program by Chris Vega", 0
    szTextLen    dd $-szText-1

.const
    WND_WIDTH    = 540
    WND_HEIGHT    = 180
   
    mnuFileExit = 2001
    mnuHelpAbout= 3001

; ==========================================================
; Entry Point
; ==========================================================
.code
start:
    invoke    WinMain, func(GetModuleHandle, 0), NULL, NULL, SW_SHOW
    invoke    ExitProcess, 0
   
; ==========================================================
; WinMain
; ==========================================================
WinMain proc uses edi esi hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:dword

    local    hwnd:HWND   
    local    msg:MSG
    local    hMenu:HANDLE
    local    wc:WNDCLASSEX
   
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    ; Register the class
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    m2m        wc.hInstance, hInst
    mov        wc.lpszClassName, offset szClassName
    mov        wc.lpfnWndProc, offset WndProc
    mov        wc.style, CS_PARENTDC or CS_HREDRAW or CS_VREDRAW
    mov        wc.cbSize, sizeof WNDCLASSEX
    mov        wc.hIcon, func(LoadIcon, hInst, 100)
    mov        wc.hIconSm, eax
    mov        wc.hCursor, func(LoadCursor, NULL, IDC_ARROW)
    mov        wc.lpszMenuName, NULL
    mov        wc.cbClsExtra, 0
    mov        wc.cbWndExtra, 0
    mov        wc.hbrBackground, NULL
    .if        !func(RegisterClassEx, addr wc)
            ret
    .endif

    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    ; Create the window
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    mov        edi, func(GetSystemMetrics, SM_CXSCREEN)
    shr        edi, 1
    mov        eax, WND_WIDTH
    shr        eax, 1
    sub        edi, eax
   
    mov        esi, func(GetSystemMetrics, SM_CYSCREEN)
    shr        esi, 1
    mov        eax, WND_HEIGHT
    shr        eax, 1
    sub        esi, eax

    invoke    CreateWindowEx,\
                WS_EX_APPWINDOW or WS_EX_WINDOWEDGE, \
                addr szClassName,\
                addr szWndText,\
                   WS_OVERLAPPEDWINDOW,\
                   edi,\
                   esi,\
                   WND_WIDTH,\
                   WND_HEIGHT,\
                   NULL,\
                   func(LoadMenu, hInst, 1000),\
                   hInst,\
                   NULL
    mov        hwnd, eax
   
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    ; Set the window font
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    mov        hFont, func(CreateFontIndirect, addr lgFont)

    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    ; Make the window visible
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    invoke    SendMessage, hwnd, WM_SETICON, ICON_BIG or ICON_SMALL, func(LoadIcon, hInst, 1000)
    invoke    ShowWindow, hwnd, CmdShow
    invoke    UpdateWindow, hwnd
   
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    ; Messageloop (with IsDialogMessage)
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    .while TRUE
        invoke GetMessage, addr msg, hwnd, 0, 0
        .break .if eax!=TRUE
        .if !func(IsDialogMessage,hwnd,addr msg)
            invoke    TranslateMessage, addr msg
            invoke    DispatchMessage, addr msg
        .endif
    .endw
   
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    ; Exit WinMain
    ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    mov eax, msg.wParam
    ret
   
WinMain endp

; ==========================================================
; Window Procedure
; ==========================================================
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
   
    .handle_msg_begin
        .handle_msg WM_DESTROY, WmDestroy
        .handle_msg WM_COMMAND, WmCommand
        .handle_msg WM_PAINT, WmPaint
    .handle_msg_end
   
    invoke    DefWindowProc, hWnd, uMsg, wParam, lParam
    ret

WndProc endp

; ==========================================================
; DrawFancyDivider
; ==========================================================
DrawFancyDivider proc uses ebx edi hdc:HDC, lpRect:ptr RECT
    local    pen:HPEN
    local    pen2:HPEN
   
    mov        ebx, lpRect
    assume    ebx: ptr RECT
   
    invoke    CreatePen, PS_SOLID, 1, 00404040h
    mov        pen, eax
   
    invoke    CreatePen, PS_SOLID, 1, 00707070h
    mov        pen2, eax
   
    invoke    SelectObject, hdc, pen
    push    eax
   
    mov        edi, [ebx].top
    add        edi, 3
    invoke    MoveToEx, hdc, [ebx].left, edi, NULL
    invoke    LineTo, hdc, [ebx].right, edi
    dec        edi
    invoke    SelectObject, hdc, pen2
    invoke    MoveToEx, hdc, [ebx].left, edi, NULL
    invoke    LineTo, hdc, [ebx].right, edi
    sub        edi, 2
    invoke    SelectObject, hdc, pen2
    invoke    MoveToEx, hdc, [ebx].left, edi, NULL
    invoke    LineTo, hdc, [ebx].right, edi
    inc        edi
    invoke    SelectObject, hdc, func(GetStockObject, WHITE_PEN)
    invoke    MoveToEx, hdc, [ebx].left, edi, NULL
    invoke    LineTo, hdc, [ebx].right, edi
   
    invoke    DeleteObject, pen
    invoke    DeleteObject, pen2
   
    pop        eax
    invoke    SelectObject, hdc, eax

    ret
DrawFancyDivider endp

; ==========================================================
; WmDestroy : Handles WM_DESTROY message
; ==========================================================
WmDestroy proc hWnd:HWND
    invoke    PostQuitMessage, 0
    ret
WmDestroy endp

; ==========================================================
; WmCommand : Handles WM_COMMAND message
; ==========================================================
WmCommand proc hWnd:HWND, id:word, hwndCtl:HWND, codeNotify:word

    ; ----------------------------------------------
    .if id==mnuFileExit
   
    push    hWnd
    call    WmDestroy

    ; ----------------------------------------------
    .elseif id==mnuHelpAbout

    invoke    MessageBox, hWnd, addr szText, addr szWndText, MB_ICONINFORMATION

    ; ----------------------------------------------
    .endif
   
    ret
WmCommand endp

; ==========================================================
; WmPaint : Handles WM_PAINT message
; ==========================================================
WmPaint proc uses ebx hWnd:HWND

    local hdc:HDC
    local rect:RECT
    local sz:SIZEL
   
    local memDC:HDC
    local memBM:HBITMAP
   
    local mesh:GRADIENT_RECT
    local vertex[3]:TRIVERTEX
   
    ; ---------------------------------------------------------------------
    ; Get the handle to the device context
    ; ---------------------------------------------------------------------
    mov        hdc, func(GetDC, hWnd)
   
    ; ---------------------------------------------------------------------
    ; Get the client rectangle
    ; ---------------------------------------------------------------------
    invoke    GetClientRect, hWnd, addr rect
   
    ; ---------------------------------------------------------------------
    ; Create an off-screen device context (double buffering) [1]
    ; ---------------------------------------------------------------------
    mov        memDC, func(CreateCompatibleDC, hdc)
    mov        memBM, func(CreateCompatibleBitmap, hdc, rect.right, rect.bottom)
    invoke    SelectObject, memDC, memBM
   
    ; ---------------------------------------------------------------------
    ; Populate vertex 1 structure
    ; ---------------------------------------------------------------------
    lea        ebx, vertex
    assume    ebx: ptr TRIVERTEX
    m2m        [ebx].x, rect.left
    m2m        [ebx].y, rect.top
    mov        [ebx].Alpha, 0
    mov        [ebx].Red, 07d00h
    mov        [ebx].Green, 0aa00h
    mov        [ebx].Blue, 0c300h
   
    ; ---------------------------------------------------------------------
    ; Populate vertex 2 structure
    ; ---------------------------------------------------------------------
    add        ebx, sizeof TRIVERTEX
    m2m        [ebx].x, rect.right
    m2m        [ebx].y, rect.bottom
    mov        [ebx].Alpha, 0
    mov        [ebx].Red, 00100h
    mov        [ebx].Green, 02a00h
    mov        [ebx].Blue, 04400h
   
    ; ---------------------------------------------------------------------
    ; Set the mesh (gradient rectangle) point
    ; ---------------------------------------------------------------------
    mov        mesh.UpperLeft, 0
    mov        mesh.LowerRight, 1
   
    ; ---------------------------------------------------------------------
    ; Call GradientFill function
    ; ---------------------------------------------------------------------
    invoke    GradientFill, memDC, addr vertex, 2, addr mesh, 1, GRADIENT_FILL_RECT_V
   
    ; ---------------------------------------------------------------------
    ; Draw the text, centered to the window
    ; ---------------------------------------------------------------------
    invoke    SetBkMode, memDC, TRANSPARENT
    invoke    SelectObject, memDC, hFont
    invoke    GetTextExtentPoint32, memDC, addr szText, szTextLen, addr sz
    invoke    SetTextColor, memDC, 0
    mov        eax, sz.x
    shr        eax, 1
    mov        sz.x, eax
    mov        eax, sz.y
    shr        eax, 1
    mov        sz.y, eax
    mov        eax, rect.right
    sub        eax, rect.left
    shr        eax, 1
    sub        eax, sz.x
    mov        edx, rect.bottom
    sub        edx, rect.top
    shr        edx, 1
    sub        edx, sz.y
    push    eax
    push    edx
    invoke    TextOut, memDC, eax, edx, addr szText, szTextLen
    invoke    SetTextColor, memDC, 00f0f0f0h
    pop        edx
    pop        eax
    sub        edx, 2
    sub        eax, 2
    invoke    TextOut, memDC, eax, edx, addr szText, szTextLen
   
    ; ---------------------------------------------------------------------
    ; Draw some fancy divider
    ; ---------------------------------------------------------------------
    invoke    DrawFancyDivider, memDC, addr rect
   
    ; ---------------------------------------------------------------------
    ; Flush the result to the window
    ; ---------------------------------------------------------------------
    invoke    BitBlt, hdc, 0, 0, rect.right, rect.bottom, memDC, 0, 0, SRCCOPY
   
    ; ---------------------------------------------------------------------
    ; Release all the resources we've used
    ; ---------------------------------------------------------------------
    invoke    DeleteDC, memDC
    invoke    DeleteObject, memBM

    ; ---------------------------------------------------------------------
    ; Release the device context
    ; ---------------------------------------------------------------------
    invoke    ReleaseDC, hWnd, hdc
   
    ; Notes:
    ;    [1] We need to create an off-screen device context for this demo,
    ;        this is because filling a rectangle with GradientFill function
    ;        will take some time to complete, and shows a lot of flickering
    ;        if we let the function use the window's DC.
    ret
WmPaint endp


end start

Attachment: Gradient.zip
Published 02-26-2009 11:08 PM by cvega
Filed under: ,

Comments

# re: Linear Gradient Fill example for MASM

Thursday, March 19, 2009 9:59 PM by modchip

COOL!!!