Procedural Fire and GDI+ Cont'd

(FBSL v3 Dynamic Assembler Code)

Moderator: Mike Lobanovsky

Procedural Fire and GDI+ Cont'd

Unread postby Mike Lobanovsky » Thu Jun 07, 2012 1:41 am

Hello everybody,

In continuation of the thread here , here's an FBSL script that implements the same procedural fire generation algorithm, this time using FBSL's Dynamic Assembler.

As always, the assembly language removes the viewport size restrictions imposed by relative slowliness of the interpreted nested loops. As you will see, the fire can be rendered into screen-wide windows without any visible loss of speed. In fact, the rendering speed is even restricted by the timer to approx. 30FPS to make the flame look more natural. Higher FPS rates and/or larger window sizes are possible though they may stress the CPU unnecessarily.

The script uses a transparent layered window onto which a 32-bpp alpha-channeled DIB is rendered using GDI+ APIs. The DIB (device-independent bitmap) is generated on the fly based on the flame pixel data created programmatically. Flicker is eliminated using double back-buffering in the memory DCs. Special care is taken to release GDI and GDI+ resources in each render call to eliminate possible memory and resource leaks.

Provided the GDI+ DLL is available on the PC (normally it is), the script runs on any configuration of Win XP and it also runs as intended under Basic and Classic themes of Win Vista and Win 7. Composited Aero modes are not fully supported though they don't break program execution. The currently available version of Win 8 CP doesn't provide any non-composited themes at all so the rendering portion of the application wouldn't yield the intended transparency effects there either.

Click on the fire or press "Escape" to exit.

Code: Select all
' =====================================
' " ... Heaven's on Fire! ... " (©1984 "KISS")
' http://www.youtube.com/watch?v=EZjevnnkA20
' =====================================
' ©2012 Mike LOBANOVSKY -= Public Domain =-
' Heck, that was exactly half of my life ago! ;)
' =====================================

#Uses "@|WIN32"
#Option Strict

#DllDeclare User32("SetLayeredWindowAttributes", "SystemParametersInfo", "GetDesktopWindow")
#DllDeclare Gdiplus("GdiplusStartup", "GdiplusShutdown", "GdipCreateBitmapFromScan0", _
"GdipCreateFromHDC", "GdipDrawImageRectI", "GdipDisposeImage", "GdipDeleteGraphics")

#Define WS_EX_LAYERED &H80000
#Define LWA_COLORKEY &H1
#Define LWA_ALPHA &H2
#Define SRCCOPY &HCC0020 ' blit mode
#Define SPI_GETWORKAREA 48 ' unobscured by taskbar

Type BYTE
   Default %b * 8
End Type

Type RECT
   %Left
   %Top
   %Right
   %Bottom
End Type

Type GDIPLUSSTARTUPINPUT
   GdiplusVersion As Integer
   DebugEventCallback As Integer
   SuppressBackgroundThread As Integer
   SuppressExternalCodecs As Integer
End Type

Dim %token ' just another one of Windows' atrocities, for some unknown reason required to run GDI+
Dim sui As GDIPLUSSTARTUPINPUT ' GDI+ startup UDT
Dim %hImg, %hGrfx ' these can't be reduced to volatiles

Dim %X, %Y, %Fire[255], RC As RECT

For X = 0 To 255 ' alpha + rgb ==> RGBA format, little-endian style
   Fire[X] = ((%IIf((X << 2) < 255, X << 2, 255)) << 24) BOr Rgb(0, %IIf((X << 1) < 255, X << 1, 255), %IIf((X << 1) < 255, %IIf((X << 2) < 255, X * 3, 255), 255))
Next

Style_Remove(ME, WS_OVERLAPPEDWINDOW)
SystemParametersInfo(SPI_GETWORKAREA, 0, @RC, 0)

Dim %W = rc.Right - rc.Left, %H = 165, %L = rc.Left, %T = rc.Bottom - H
Resize(ME, L, T, W, H)

Dim %Heavens[W - 1, H - 1], Hell[W - 1, H - 1] As BYTE ' 4 times less memory
Dim %hDeskDC = GetDC(GetDesktopWindow())

sui.GdiplusVersion = 1 ' initialize GDI+ startup structure (this is the only GDI+ version to date)
GdiplusStartup(@token, @sui, 0) ' launch GDI+

ExStyle_Add(ME, WS_EX_LAYERED)
Fbsl_SetFormColor(ME, 0) ' else it flickers on launching
SetLayeredWindowAttributes(ME, 0, 255, LWA_ALPHA BOr LWA_COLORKEY) ' black transparent color

Fbsl_SetText(ME, "Heaven's on Fire!")
SetTimer(ME, &HDEADBEEF, 35)
Show(ME)

Begin Events
   Select Case CBMSG
      Case WM_COMMAND
         ' That's VK_ESCAPE pressed
         If CBWPARAM = 2 Then PostMessage(ME, WM_LBUTTONDOWN, 0, 0)
      Case WM_TIMER
         If CBWPARAM = &HDEADBEEF Then
            Burn()
            Return 0
         End If
      Case WM_LBUTTONDOWN
         Destroy(ME)
         Return 0
      Case WM_DESTROY
         If token Then GdiplusShutdown(token) ' unload GDI+
         ReleaseDC(GetDesktopWindow, hDeskDC)
         KillTimer(ME, &HDEADBEEF)
   End Select
End Events

Sub Burn()
   For X = 0 To W - 1
      Hell[X, H - 1] = RandInt(0, 255)
   Next
   
   Ignite()
   GdipCreateBitmapFromScan0(W, H, W * 4, &H26200A, @Heavens[0, 0], @hImg) ' create GDI+ image from raw pixel data (PixelFormat32bppARGB)
   
   CreateCompatibleDC(GetDC(ME))
   CreateCompatibleBitmap(GetDC, W, H)
   SelectObject(CreateCompatibleDC, CreateCompatibleBitmap)
   BitBlt(CreateCompatibleDC, 0, 0, W, H, hDeskDC, L, T, SRCCOPY) ' blit desktop into memory DC first
   
   GdipCreateFromHDC(CreateCompatibleDC, @hGrfx) ' create GDI+ graphics object from device context where user can draw things interactively
   GdipDrawImageRectI(hGrfx, hImg, 0, 0, W, H) ' overlay transparent GDI+ image onto GDI+ graphics object using integer metrics (width, height)
   BitBlt(GetDC, 0, 0, W, H, CreateCompatibleDC, 0, 0, SRCCOPY) ' blit everything to layered window
   
   ReleaseDC(ME, GetDC) ' clean up GDI objects
   DeleteObject(SelectObject(CreateCompatibleDC, SelectObject))
   DeleteDC(CreateCompatibleDC)
   
   GdipDeleteGraphics(hGrfx) ' delete GDI+ graphics object
   GdipDisposeImage(hImg) ' delete GDI+ image object
End Sub

Asm Ignite(%b = w, %t = h, %hellptr = @Hell[0, 0], %pixptr = @Heavens[0, 0], %palptr = @Fire[0]) As Integer
push ebp
mov ebp, esp
push ebx
push esi
push edi

Xor ebx, ebx ' y
@foryhell

Xor ecx, ecx ' x
@forxhell

Xor edx, edx
mov eax, ecx ' x
dec eax
add eax,[ebp + 8] ' w
div WORD PTR[ebp + 8] ' w
mov[esp - 4], edx ' (x-1+w) Mod w

Xor edx, edx
mov eax, ebx ' y
inc eax
div WORD PTR[ebp + 12] ' h
imul edx,[ebp + 8] ' w
mov esi,[ebp + 16] ' hellptr
add esi, edx ' esi=@Hell[0,0]+((y+1) Mod h)*w

mov eax,[esp - 4]
movzx eax, BYTE PTR[esi + eax]
mov[esp - 4], eax ' Hell[(x-1+w) Mod w, (y+1) Mod h]

Xor edx, edx
mov eax, ecx ' x
inc eax
div WORD PTR[ebp + 8] ' w
movzx eax, BYTE PTR[esi + edx]
mov[esp - 8], eax ' Hell[(x+1) Mod w, (y+1) Mod h]

Xor edx, edx
mov eax, ecx ' x
div WORD PTR[ebp + 8] ' w
mov[esp - 16], edx ' x Mod w
movzx eax, BYTE PTR[esi + edx]
mov[esp - 12], eax ' Hell[x Mod w, (y+1) Mod h]

Xor edx, edx
mov eax, ebx ' y
add eax, 2
div WORD PTR[ebp + 12] ' h
imul edx,[ebp + 8] ' w
mov esi,[ebp + 16] ' hellptr
add esi, edx ' esi=@Hell[0,0]+((y+2) Mod h)*w

mov eax,[esp - 16]
movzx eax, BYTE PTR[esi + eax] ' Hell[x Mod w, (y + 2) Mod h]

add eax,[esp - 12] ' Hell[x Mod w, (y+1) Mod h]
add eax,[esp - 8] ' Hell[(x+1) Mod w, (y+1) Mod h]
add eax,[esp - 4] ' Hell[(x-1+w) Mod w, (y+1) Mod h]

Xor edx, edx
shl eax, 5
mov DWORD PTR[esp - 4], 129
div WORD PTR[esp - 4]

mov edx, ebx ' y
imul edx,[ebp + 8] ' w
add edx,[ebp + 16] ' hellptr
mov[edx + ecx], al

inc ecx
cmp ecx,[ebp + 8] ' w
jl forxhell

inc ebx
cmp ebx,[ebp + 12] ' h
jl foryhell

mov edi,[ebp + 20] ' pixptr

Xor ebx, ebx ' y
@forypal

Xor ecx, ecx ' x
@forxpal
mov eax,[ebp + 8] ' w
imul eax, ebx ' y
mov[esp - 4], eax ' y*w

mov esi,[ebp + 16] ' hellptr
add esi, eax
movzx eax, BYTE PTR[esi + ecx]

mov esi,[ebp + 24] ' palptr
mov eax,[esi + 4 * eax] ' color

mov edx,[esp - 4] ' y*w
add edx, ecx
mov[edi + 4 * edx], eax

inc ecx
cmp ecx,[ebp + 8] ' w
jl forxpal

inc ebx
cmp ebx,[ebp + 12] ' h
jl forypal

pop edi
pop esi
pop ebx
pop ebp
ret
End Asm
Mike
"Я старый солдат, мадам, и не знаю слов любви."
"I am an old soldier, ma'am, and I don't know the words of love."
"Je suis un vieux soldat, madame, et je ne connais pas les mots d'amour."

__________________________________________________________________________________________________________________________________________
(2.2GHz Core2 Duo, 4GB RAM / 2 x GeForce 8600 GTS SLI-bridged, 1GB VRAM)
(x86 Win XP Pro Russian Sp3/x86 Win Vista Ultimate SP1/x64 Win 7 Ultimate Sp1/x64 Win 8 Consumer Preview)
User avatar
Mike Lobanovsky
FBSL Administrator
FBSL Administrator
 
Posts: 1486
Joined: Tue Apr 19, 2005 8:22 am
Location: Republic of Belarus

Re: Procedural Fire and GDI+ Cont'd

Unread postby Gerome » Thu Jun 07, 2012 2:40 am

Mike Lobanovsky wrote:Hello everybody,


Fire onto my screen !!!
Wow excellent and impressive sample Mike !!
Yours,

(¯`·._.·[Gerome GUILLEMIN]·._.·´¯)
:: Full SETUP w. HELP 05th of December 2011 ::
http://gedd123.free.fr/FBSLv3.exe [3.4.0.10]
http://gedd123.free.fr/FBSLv3bin.zip [minimal]
Laissons les jolies femmes aux hommes sans imagination. / Let us leave pretty women to men without imagination.(M.Proust)
The success is a defeat for the one who does not want to dance any more! (H.F. Thiefaine)
User avatar
Gerome
FBSL Administrator
FBSL Administrator
 
Posts: 3065
Joined: Sat Mar 12, 2005 9:06 pm
Location: Paris -- France

Re: Procedural Fire and GDI+ Cont'd

Unread postby Mike Lobanovsky » Sat Jun 09, 2012 3:44 am

Thanks for the appreciation Gerome,

And you can have yet some more fun here . :D
Mike
"Я старый солдат, мадам, и не знаю слов любви."
"I am an old soldier, ma'am, and I don't know the words of love."
"Je suis un vieux soldat, madame, et je ne connais pas les mots d'amour."

__________________________________________________________________________________________________________________________________________
(2.2GHz Core2 Duo, 4GB RAM / 2 x GeForce 8600 GTS SLI-bridged, 1GB VRAM)
(x86 Win XP Pro Russian Sp3/x86 Win Vista Ultimate SP1/x64 Win 7 Ultimate Sp1/x64 Win 8 Consumer Preview)
User avatar
Mike Lobanovsky
FBSL Administrator
FBSL Administrator
 
Posts: 1486
Joined: Tue Apr 19, 2005 8:22 am
Location: Republic of Belarus


Return to Assembly Code

Who is online

Users browsing this forum: No registered users and 1 guest