BITMAP3B.ASM - WIN32NASM bitmap fader
From: Al (opcodeac_at_hotmail.com)
Date: 12/15/03
- Next message: Bx. C: "Re: Xtevens MagicSquare"
- Previous message: Ross Simpson: "Re: A Parable of Two Carpenters"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Mon, 15 Dec 2003 21:03:20 GMT
This piece of code was extracted from a derelect win32 screensaver
project of mine that I worked on in early 2000. This code is designed to
fade the image in and out in a nonstop loop. Be advised though that the
speed of this is highly dependent on the speed of the machine and the
sort of image you use. Some images go faster than others.
As far as specifying the image, it's hardcoded in the asm. There's a
variable (BitmapPath) in the data section that holds the filename. Enjoy
ppl.
EXTERN GetMessageA
IMPORT GetMessageA user32.dll
EXTERN DispatchMessageA
IMPORT DispatchMessageA user32.dll
EXTERN TranslateMessage
IMPORT TranslateMessage user32.dll
EXTERN SendMessageA
IMPORT SendMessageA user32.dll
EXTERN PostQuitMessage
IMPORT PostQuitMessage user32.dll
EXTERN CreateWindowExA
IMPORT CreateWindowExA user32.dll
EXTERN ShowWindow
IMPORT ShowWindow user32.dll
EXTERN UpdateWindow
IMPORT UpdateWindow user32.dll
EXTERN ExitProcess
IMPORT ExitProcess kernel32.dll
EXTERN RegisterClassA
IMPORT RegisterClassA user32.dll
EXTERN DefWindowProcA
IMPORT DefWindowProcA user32.dll
EXTERN LoadIconA
IMPORT LoadIconA user32.dll
EXTERN LoadCursorA
IMPORT LoadCursorA user32.dll
EXTERN MessageBoxA
IMPORT MessageBoxA user32.dll
EXTERN GetModuleHandleA
IMPORT GetModuleHandleA kernel32.dll
EXTERN DestroyWindow
IMPORT DestroyWindow user32.dll
EXTERN BeginPaint
IMPORT BeginPaint user32.dll
EXTERN TextOutA
IMPORT TextOutA gdi32.dll
EXTERN EndPaint
IMPORT EndPaint user32.dll
EXTERN LoadImageA
IMPORT LoadImageA user32.dll
EXTERN GetDC
IMPORT GetDC user32.dll
EXTERN CreateCompatibleDC
IMPORT CreateCompatibleDC gdi32.dll
EXTERN SelectObject
IMPORT SelectObject gdi32.dll
EXTERN BitBlt
IMPORT BitBlt gdi32.dll
EXTERN StretchBlt
IMPORT StretchBlt gdi32.dll
EXTERN InvalidateRect
IMPORT InvalidateRect user32.dll
EXTERN DeleteObject
IMPORT DeleteObject gdi32.dll
EXTERN DeleteDC
IMPORT DeleteDC gdi32.dll
EXTERN ReleaseDC
IMPORT ReleaseDC user32.dll
EXTERN CreateFileA
IMPORT CreateFileA kernel32.dll
EXTERN GetFileSize
IMPORT GetFileSize kernel32.dll
EXTERN ReadFile
IMPORT ReadFile kernel32.dll
EXTERN StretchDIBits
IMPORT StretchDIBits gdi32.dll
EXTERN GlobalAlloc
IMPORT GlobalAlloc kernel32.dll
EXTERN GlobalLock
IMPORT GlobalLock kernel32.dll
EXTERN GlobalUnlock
IMPORT GlobalUnlock kernel32.dll
EXTERN GlobalFree
IMPORT GlobalFree kernel32.dll
EXTERN CloseHandle
IMPORT CloseHandle kernel32.dll
EXTERN CreateDIBitmap
IMPORT CreateDIBitmap gdi32.dll
EXTERN CreateDIBSection
IMPORT CreateDIBSection gdi32.dll
EXTERN GetBitmapDimensionEx
IMPORT GetBitmapDimensionEx gdi32.dll
EXTERN SetFilePointer
IMPORT SetFilePointer kernel32.dll
EXTERN SetTimer
IMPORT SetTimer user32.dll
EXTERN BeginPaint
IMPORT BeginPaint user32.dll
EXTERN EndPaint
IMPORT EndPaint user32.dll
[BITS 32]
SECTION CODE USE32 CLASS=CODE
..start:
;-----------------------------------------------------------------------------------
; |
; The window creation routines |
; |
; This code will generate a window that will be used for all graphics |
; operations. |
; |
; Program flow: |
; 1. Get the current module's handle |
; 2. Load system default icon for usage in this program |
; 3. Load system default cursor for usage in this program |
; 4. Register my window class |
; 5. Get module handle once again |
; 6. Generate the desired window, using information I pushed onto |
; da stack and data I placed within the WNDCLASS structure. |
; 7. Make the window show up |
; 8. Update the window (UpdateWindow API call will send a WM_PAINT |
; message to this program's window procedure |
; 9. Get da DC (Device Context) for this window |
; 10. Create a timer to send WM_TIMER message to our window procedure |
; 11. Send WM_CREATE message to window |
; |
; Registers/usage: |
; EAX = Holds return values from each API call. Also used for |
; loading with data which needs to be pushed X times. |
; Saves bytes |
; EBX = Zeroed. PUSHed instead of an immediate 0 to save bytes |
; |
; |
; |
;-----------------------------------------------------------------------------------
xor ebx, ebx ; Make EBX register 0
; Save bytes on PUSHes
push LPCTSTR ebx ; Pass NULL value
call [GetModuleHandleA] ; Get da module handle
mov [WCS+WNDCLASS.hInstance], eax ; Place returned module handle
; into hInstance member of
; WNDCLASS structure
push LPCTSTR IDI_APPLICATION ; Request default icon
push HINSTANCE ebx ; Pass NULL value
call [LoadIconA] ; Get da icon handle
mov [WCS+WNDCLASS.hIcon], eax ; Place returned icon handle
; into hIcon member of WNDCLASS
; structure
push LPCTSTR IDC_ARROW ; Request default cursor
push HINSTANCE ebx ; Pass NULL value
call [LoadCursorA] ; Get da cursor handle
mov [WCS+WNDCLASS.hCursor], eax ; Place returned cursor handle
; into hCursor member of WNDCLASS
; structure
push DWORD WCS ; Pass pointer to WCS instance
; of WNDCLASS structure
call [RegisterClassA] ; Register da class!
push LPCTSTR ebx ; Pass a NULL value
call [GetModuleHandleA] ; Yep, we're gettin da module
; handle
push LPVOID ebx ; Pass NULL since we don't use
; the CREATESTRUCT or an MDI
push HINSTANCE eax ; Pass the module handle
push HMENU ebx ; Pass NULL since we have no menu
push HWND ebx ; This window is no child window,
; so NULL is passed
mov eax, CW_USEDEFAULT ; Place CW_USEDEFAULT into EAX
push INTEGER eax ; Window height will be default
push INTEGER eax ; Window width will be default
push INTEGER eax ; Vertical position is default
push INTEGER eax ; Horizontal position is default
push DWORD WS_OVERLAPPEDWINDOW ; Combines WS_EX_CLIENTEDGE and
; WS_EX_WINDOWEDGE styles
push LPCTSTR WindowName ; Caption of window
push LPCTSTR WindowClass ; Registered window class
push DWORD ebx ; No extended window style
call [CreateWindowExA] ; Generate the darn window!
mov [WindowHwnd], eax ; Save returned window value in
; WindowHwnd variable
push INTEGER SW_SHOWNORMAL ; Specify that window will
; appear at normal size
push HWND eax ; Pass window handle
call [ShowWindow] ; Make da window appear!
push HWND [WindowHwnd] ; Handle of window
call [UpdateWindow] ; Send WM_PAINT message to da
; window procedure
push HWND [WindowHwnd] ; Handle of window
call [GetDC] ; Get da Device Context
mov [MyDC], eax ; Save it!
push DWORD NULL ; No timer procedure
push UINT 1 ; 1 millisecond
push UINT NULL ; Let system decide timer
; identifier
push HWND [WindowHwnd] ; Da window handle!
call [SetTimer] ; Make the timer!
push LPARAM NULL ; No low word parameter
push WPARAM NULL ; No high word parameter
push UINT WM_CREATE ; WM_CREATE message
push UINT [WindowHwnd] ; Window handle!
call [SendMessageA] ; Do it!
;---------------------------------------------------------------------------
; |
; Message fetch and dispatch loop |
; |
; This loop is the heart of all activity in this program. It basically |
; fetches messages and dispatches the message to the window procedure. |
; |
; Program flow: |
; 1. Get da message |
; 2. Dispatch it |
; 3. Repeat da loop |
; |
; Registers/usage: |
; EAX = Holds return values for each API call. Also used to pass |
; NULL X times. |
; |
;----------------------------------------------------------------------------
Message_Loop:
mov LPMSG ebx, Msg ; Place pointer to Msg instance for MSG struct
; into EBX
xor eax, eax ; Zero EAX
push UINT eax ; No message filtering
push UINT eax ; No message filtering
push HWND eax ; Get messages for any window belonging to
; this program
push LPMSG ebx ; Pass EBX
call [GetMessageA] ; Get da message!
test eax, eax ; Did we get WM_QUIT?
je Quit ; If so, then go to my program termination
; routine
push LPMSG ebx ; Pass that instance
call [DispatchMessageA] ; Dispatch da message!
jmp Message_Loop ; Keep the loop goin!
Quit:
push UINT NULL ; Return a NULL exit code
call [ExitProcess] ; Kill da program!
WindowProc:
%define hwnd ebp+8
%define uMsg ebp+12
%define wParam ebp+16
%define lParam ebp+20
enter 0, 0 ; Allocate da stack frame for my program. This
; line o code simply reserves enough space for
; the message info on the stack
cmp UINT [uMsg], WM_PAINT ; Did we get WM_PAINT?
je NEAR PaintBitmap ; paint da bitmap
; Hopefully the rest is rather
; straightforward :)
cmp UINT [uMsg], WM_CREATE
je NEAR LoadShowBitmap
cmp UINT [uMsg], WM_TIMER
je NEAR FadeBitmap
cmp UINT [uMsg], WM_DESTROY
je NEAR PostQMSG
push LPARAM [lParam] ; Pass low word paramter
push WPARAM [wParam] ; Pass high word
push UINT [uMsg] ; Pass window message
push HWND [hwnd] ; Pass da window handle
call [DefWindowProcA] ; Let default window procedure handle
; messages we'd rather ignore :)
jmp unhandled ; Go to our routine that serves as
; an end point to all the others
PaintBitmap:
push BOOL FALSE ; Don't erase window client area
push DWORD Rct ; Update area that contains picture
push HWND [hwnd] ; Pass da handle
call [InvalidateRect] ; Mark the area for repainting
mov ebx, [hwnd]
push DWORD PaintSt ; Pass instance to PAINTSTRUCT
push DWORD ebx ; pass da handle
call [BeginPaint] ; Update area set by previous API call
push DWORD SRCCOPY ; Copy source to destination as is
xor eax, eax ; The byte saving technique!
push INTEGER 384 ; 384 pixels vertical source
push INTEGER 384 ; 384 pixels horizontal source
push INTEGER eax ; 0 horizontal axis source
push INTEGER eax ; 0 vertical axis source
push HDC [mDC] ; Source device context containing pic
push INTEGER 384 ; 384 pixels vertical destination
push INTEGER 384 ; 384 pixels horizontal destination
push INTEGER eax ; 0 horizontal axis destination
push INTEGER eax ; 0 vertical axis destination
push HDC [MyDC] ; The window client area
call [StretchBlt] ; Blit the pic!
push DWORD PaintSt ; PAINTSTRUCT
push DWORD ebx ; Window handle
call [EndPaint] ; End the paint operation
jmp unhandled ; Go to the end point
FadeBitmap:
IsFadeInDone:
cmp DWORD [FFlag], 1 ; Has the image already faded out?
jne InitFadeRoutine ; If not, go to initialization code
; for fade in
InitFadeInRoutine:
mov eax, [MemPointer2] ; Get pointer to allocated
; memory holding original
; image into EAX
mov eax, [eax+000ah] ; Retrieve offset to bitmap
; data from entry in bitmap
; header
add eax, [MemPointer2] ; Add this offset to the
; memory pointer
mov [BitmapData2], eax ; Place pointer to bitmap data
; in memory into BitmapData2
; variable
mov edi, eax ; EDI will now contain the
; bitmap data pointer
mov edx, [BitmapData] ; Get pointer to bitmap data
; in first allocated chunk of
; memory holding the fading
; image
mov ecx, [BitmapSize] ; Get the total number of
; bitmap data bytes into ECX
push ecx ; Save registers onto stack :)
push edx
push edi
DoFadeInLoop:
mov eax, DWORD [edi] ; Grab pixel in second chunk
; pointed to by EDI
mov ebx, DWORD [edx] ; Grab pixel in first chunk
; pointed to by EDX
cmp bl, al ; Is the pixel in both images
; the same value?
je SkipInFade ; If so, skip to next pixel
inc ebx ; Increment pixel value
mov [edx], ebx ; Overwrite current pixel value
; in first chunk
SkipInFade:
test ecx, ecx ; Have all the pixels been
; incremented?
je CheckIfInAllDone ; If so, check to make sure
; the pic has been fully
; restored
dec ecx ; Another byte to go!
inc edx ; Point to next pixel in fading img
inc edi ; Point to next pixel in original img
jmp DoFadeInLoop ; Repeat the loop
CheckIfInAllDone:
pop edi ; Restore da registers
pop edx
pop ecx
DoCheckInLoop:
mov eax, DWORD [edi] ; Load EAX with pixel pointed to in original img
mov ebx, DWORD [edx] ; Load EBX with pixel pointed to in fading img
cmp bl, al ; Are both pixels the same?
jne DeleteHandles ; Display the newly faded image
inc edx ; Point to next byte in fading image
inc edi ; Point to next byte in original image
test ecx, ecx ; Has all the bytes been checked?
je CheckInDone ; Yep, signify that the fade in has complete
dec ecx ; Another byte to go!
jmp DoCheckInLoop ; Check next byte :)
CheckInDone:
xor ebx, ebx ; Obvious
mov [FFlag], ebx ; Make FFlag variable contain 0
jmp unhandled ; End the routine!
InitFadeRoutine:
mov ebx, [FileSize]
mov ecx, [MemPointer]
mov ecx, [ecx+000ah]
sub ebx, ecx
xchg ebx, ecx
mov [BitmapSize], ecx
mov edx, [BitmapData]
push ecx
push edx
DoFadeLoop:
FadeDDSubloopInit:
mov ebx, DWORD [edx]
cmp bl, 0
je SkipFade
dec ebx
mov [edx], ebx
SkipFade:
test ecx, ecx
je CheckIfAllDone
dec ecx
inc edx
jmp DoFadeLoop
CheckIfAllDone:
pop edx
pop ecx
DoCheckLoop:
mov ebx, DWORD [edx]
cmp bl, 0
jne DeleteHandles
inc edx
test ecx, ecx
je CheckDone
dec ecx
jmp DoCheckLoop
CheckDone:
xor ebx, ebx
inc ebx
mov [FFlag], ebx
jmp unhandled
DeleteHandles:
push HDC [mDC]
call [DeleteDC]
push HDC [BmpHandle]
call [DeleteObject]
jmp DispBitmap
PostQMSG:
push HDC [mDC]
call [DeleteDC]
push HDC [BmpHandle]
call [DeleteObject]
push DWORD [MemObject]
call [GlobalUnlock]
push DWORD [MemObject]
call [GlobalFree]
push DWORD [FileHwnd]
call [CloseHandle]
push INTEGER NULL
call [PostQuitMessage]
break:
xor eax, eax
unhandled:
leave
ret
DispBitmap:
; mov eax, [MemPointer]
; mov eax, [eax+000ah]
; mov ebx, eax
mov eax, [MemPointer]
mov eax, [eax+000ah]
add eax, [MemPointer]
mov [BitmapData], eax
mov eax, [MemPointer]
mov ebx, [eax+0012h]
mov [Rct+RECT.right], ebx
mov ebx, [eax+0016h]
mov [Rct+RECT.bottom], ebx
xor ebx, ebx
push UINT DIB_RGB_COLORS
lea eax, [eax+000eh]
push DWORD eax
push DWORD [BitmapData]
push DWORD CBM_INIT
push DWORD eax
push HDC [MyDC]
call [CreateDIBitmap]
mov [BmpHandle], eax
push HDC [MyDC]
call [CreateCompatibleDC]
mov [mDC], eax
push DWORD [BmpHandle]
push DWORD eax
call [SelectObject]
mov ecx, [MemPointer]
mov edx, [ecx+0016h]
mov esi, [ecx+0012h]
push DWORD SRCCOPY
xor eax, eax
push INTEGER edx
push INTEGER esi
push INTEGER eax
push INTEGER eax
push HDC [mDC]
push INTEGER edx
push INTEGER esi
push INTEGER eax
push INTEGER eax
push HDC [MyDC]
call [StretchBlt]
jmp break
LoadShowBitmap:
xor ebx, ebx
push DWORD ebx
push DWORD FILE_ATTRIBUTE_NORMAL
push DWORD OPEN_EXISTING
push DWORD ebx
push DWORD FILE_SHARE_READ
push DWORD GENERIC_READ
push DWORD BitmapPath
call [CreateFileA]
mov [FileHwnd], eax
push DWORD ebx
push DWORD [FileHwnd]
call [GetFileSize]
mov [FileSize], eax
add eax, 4
push DWORD eax
push UINT GMEM_MOVEABLE | GMEM_ZEROINIT
call [GlobalAlloc]
mov [MemObject], eax
push DWORD eax
call [GlobalLock]
mov [MemPointer], eax
push DWORD ebx
push LPDWORD NumBytesRead
push DWORD [FileSize]
push DWORD [MemPointer]
push HANDLE [FileHwnd]
call [ReadFile]
MakeSecondCopyInMem:
mov eax, [FileSize]
add eax, 4
push DWORD eax
push UINT GMEM_MOVEABLE | GMEM_ZEROINIT
call [GlobalAlloc]
mov [MemObject2], eax
push DWORD eax
call [GlobalLock]
mov [MemPointer2], eax
push DWORD FILE_BEGIN
push DWORD NULL
push DWORD NULL
push HWND [FileHwnd]
call [SetFilePointer]
push DWORD ebx
push LPDWORD NumBytesRead
push DWORD [FileSize]
push DWORD [MemPointer2]
push HANDLE [FileHwnd]
call [ReadFile]
push DWORD [FileHwnd]
call [CloseHandle]
jmp DispBitmap
SECTION DATA USE32 CLASS=DATA
BitmapData resd 1
BitmapData2 resd 1
BitmapSize resd 1
WCS:
ISTRUC WNDCLASS
at WNDCLASS.style, DD CS_HREDRAW | CS_VREDRAW
at WNDCLASS.lpfnWndProc, DD WindowProc
at WNDCLASS.cbClsExtra, DD 0
at WNDCLASS.cbWndExtra, DD 0
at WNDCLASS.hInstance, DD 0
at WNDCLASS.hIcon, DD 0
at WNDCLASS.hCursor, DD 0
at WNDCLASS.hbrBackground, DD COLOR_WINDOW + 1
at WNDCLASS.lpszMenuName, DD 0
at WNDCLASS.lpszClassName, DD WindowClass
IEND
Msg:
ISTRUC MSG
IEND
FileHwnd resd 1
FileSize resd 1
MemObject resd 1
MemPointer resd 1
MemObject2 resd 1
MemPointer2 resd 1
NumBytesRead resd 1
WindowClass db "MyClass", 0
WindowName db "Al's Window", 0
WindowHwnd resd 1
MyDC resd 1
mDC resd 1
BmpHandle resd 1
BitmapPath db "red.bmp", 0
FFlag dd 0
PaintSt:
ISTRUC PAINTSTRUCT
IEND
Rct:
ISTRUC RECT
at RECT.left, DD NULL
at RECT.top, DD NULL
at RECT.right, DD NULL
at RECT.bottom, DD NULL
IEND
- Next message: Bx. C: "Re: Xtevens MagicSquare"
- Previous message: Ross Simpson: "Re: A Parable of Two Carpenters"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]