borderAndreaVB free resources for Visual Basic developersborder

borderAndreaVB Visual Basic and VB.NET source code resources - Copyright © 1999-2007 Andrea Tincaniborder

AndreaVB Home | News Home | Forum Home | Downloads | Register | Search | PM | Profile

Previous Topic (Testing and Debugging Windows Services and Web Services in .NET Framework)Next Topic (Ways of doing Image Processing) New Topic Post Reply
AndreaVB OnLine : Articles and tutorials : Animations using DIB Section
Poster Resource
Asim-GDI GURU
Level: Sage

Registered: 29-07-2005
Posts: 54
icon Animations using DIB Section

Random animations are always nothing more than a good procedure which must be able to run for always and must be able to calculate certain random values. In our case the randomely calculated values are the points (X,Y,Z). Its not my procedure, copied here from a book called Flash Math. The original procedure is by some other guy and he used it in Flash to create such marvellous animation that stunned me four years ago when I's used to be a geek of Flash. The procedure is great and does nothing but calculate x,y,z according to the settings the user give it.
I used this procedure in VB very easily. The first phase is to make a shape that must reside in memory (for better and fast calculations). This is not a problem to do. Lots of ways are there. First of all there is a possiblity of using Region which can be very easy to create, just one command and you are done, but the problem with my style is I always choose the difficult way. So I choosed creating a DIB Section. A DIB Section is obviously not required of any introduction now. Then the second phase was how to change the colours randomely. For that problem I used simple GetDIBits and SetDIBits, and when it comes to random colours Rnd() * 255 is the best way to do it. Many of you may think whether GetDIBits and SetDIBits will prove to be that fast as we're talking in terms of a trail which is timed with the precission of only 40 milliseconds. So I've the answer, the SetDIBits methode is enough fast to edit an image of arround 500x500 in not more than 31 milliseconds and we used a DIB Section of 200x200 pixels which cuts the time to its half.
I inserted another good feature in this animation that it uses a user-defined BMP(32-bit) as the shape container. It makes quite easy for the program to just change the BMP and see great results. I think its enough talking lets start coding..

' Types Declaration
Private Type BITMAP
        bmType As Long
        bmWidth As Long
        bmHeight As Long
        bmWidthBytes As Long
        bmPlanes As Integer
        bmBitsPixel As Integer
        bmBits As Long
End Type
Private Type BITMAPINFOHEADER
    biSize As Long
    biWidth As Long
    biHeight As Long
    biPlanes As Integer
    biBitCount As Integer
    biCompression As Long
    biSizeImage As Long
    biXPelsPerMeter As Long
    biYPelsPerMeter As Long
    biClrUsed As Long
    biClrImportant As Long
End Type
Private Type BLENDFUNCTION
  BlendOp As Byte
  BlendFlags As Byte
  SourceConstantAlpha As Byte
  AlphaFormat As Byte
End Type
' APIs Declaration
Private Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Ptr() As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function DeleteObject Lib "gdi32.dll" (ByVal hObject As Long) As Long
Private Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPINFOHEADER, ByVal wUsage As Long) As Long
Private Declare Function SetDIBits Lib "gdi32" (ByVal hdc As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPINFOHEADER, ByVal wUsage As Long) As Long
Private Declare Function LoadImage Lib "user32" Alias "LoadImageA" (ByVal hInst As Long, ByVal lpsz As String, ByVal un1 As Long, ByVal n1 As Long, ByVal n2 As Long, ByVal un2 As Long) As Long
Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Declare Function AlphaBlend Lib "MSIMG32.DLL" (ByVal hdcDest As Long, ByVal nXOriginDest As Long, ByVal nYOriginDest As Long, ByVal nWidthDest As Long, ByVal nHeightDest As Long, ByVal hdcSrc As Long, ByVal nXOriginSrc As Long, ByVal nYOriginSrc As Long, ByVal nWidthSrc As Long, ByVal nHeightSrc As Long, ByVal lBlendFunction As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function GetWindowDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetTickCount Lib "kernel32" () As Long
' Constants Declaration
Private Const BI_RGB = 0&
Private Const DIB_RGB_COLORS = 0
Private Const LR_LOADFROMFILE = &H10
Private Const LR_CREATEDIBSECTION = &H2000
Private Const AC_SRC_OVER = &H0
Private Const AC_SRC_ALPHA = &H1

' Personal Declaration
Dim DIB As Long, OldDIB As Long, DC As Long, ti As Long
Dim Pixel() As Byte
Dim BM As BITMAP, BIH As BITMAPINFOHEADER
Dim x0 As Double, y0 As Double, Z0 As Double
Dim h As Double, a As Double, b As Double, c As Double
Dim nxscale As Long, nyscale As Long, lBlend As Long
Dim bf As BLENDFUNCTION
Dim deskDC As Long, ColRed As Long, ColGreen As Long, ColBlue As Long


Private Sub Command1_Click()
Form1.Hide
ti = GetTickCount()
Timer2.Enabled = True
Call Timer2_Timer
Timer1.Enabled = True
End Sub

Private Sub Form_Load()
DC = CreateCompatibleDC(0) ' Container DC
If DC <> 0 Then
    ' Loading the 32-BIT BMP called Shape1.bmp residing in the Application Directory
    DIB = LoadImage(ByVal 0&, App.Path & "\Shape1.bmp", 0, 0, 0, LR_LOADFROMFILE Or LR_CREATEDIBSECTION)
    If DIB <> 0 Then
        GetObject DIB, Len(BM), BM ' Getting the properties for the loaded BMP
        OldDIB = SelectObject(DC, DIB) ' Selecting the loaded bmp in the DC
        With BIH ' Filling the BITMAPINFORHEADER
            .biSize = 40
            .biPlanes = 1
            .biHeight = -BM.bmHeight
            .biWidth = BM.bmWidth
            .biBitCount = BM.bmBitsPixel
        End With
        ReDim Pixel(1 To 4, 1 To BM.bmWidth, 1 To BM.bmHeight) As Byte ' Redifing the Array to the new limits
        Call GetDIBits(DC, DIB, 0&, BM.bmHeight, Pixel(1, 1, 1), BIH, 0) ' Getting the Pixels
        ' Pixel(1,x,y) = Blue, Pixel(2,x,y) = Green , Pixel(3,x,y) = Red,Pixel(4,x,y) = Alpha Channel
         ' Following are the few settings must be made for the Animation routine to follow
        x0 = 6
        y0 = 2
        Z0 = 10
        h = 0.009
        a = 13
        b = 30
        c = 8# / 2#
        ' DeskDC is the DC where the Animation will be shown
        deskDC = GetWindowDC(0)
        ' Following is the required structure for AlphaBlend API which does nothing more than BitBlt except it takes an extra  transparency element
        With bf
              .BlendOp = AC_SRC_OVER
              .BlendFlags = 0
              .SourceConstantAlpha = 50
              .AlphaFormat = AC_SRC_ALPHA
        End With
        CopyMemory lBlend, bf, 4 ' Just like wraping the whole structure in a single variable so that we may pass this variable to the API
    Else
        MsgBox "Error"
    End If
End If
End Sub

Private Sub Timer1_Timer() ' With the precision of 40 milliseconds.
' Calculating new (x,y,z)
X1 = x0 + h * a * (y0 - x0)
Y1 = y0 + h * (x0 * (b - Z0) - y0)
Z1 = Z0 + h * (x0 * y0 - c * Z0)
' Calculating new width and height based upon the z value
nxscale = Z0 * 6
nyscale = Z0 * 6
' Finally calling the AlphaBlend API to copy the Picture on the Desktop at the calculated x,y
Call AlphaBlend(deskDC, (x0 * 10 + 180) + 50, (y0 * 10 + 180), nxscale, nyscale, DC, 0, 0, BM.bmWidth, BM.bmHeight, lBlend)
x0 = X1
y0 = Y1
Z0 = Z1
' Following is a trick to stop the animation after almost 10 seconds
If (GetTickCount() - ti) = 10000 Then
Timer1.Enabled = False
Timer2.Enabled = False
Form1.Show
End If
End Sub

Private Sub Timer2_Timer() ' Schedualed up 800 milliseconds. It changes the colour of the Shape
Dim Alpha As Long, Dis As Double, x As Long, y As Long
' Following is the way we calculate the random colour.
ColRed = Rnd() * 255
ColGreen = Rnd() * 255
ColBlue = Rnd() * 255
For y = 1 To BM.bmHeight
    For x = 1 To BM.bmWidth
         ' if the pixel is not the transparent one
        If (Pixel(1, x, y) <> Pixel(1, 1, 1)) And (Pixel(2, x, y) <> Pixel(2, 1, 1)) And (Pixel(3, x, y) <> Pixel(3, 1, 1)) Then
' Calculating the distance b/w the considered pixel and the center pixel
                Dis = Int(Math.Sqr((x - BM.bmWidth \ 2) * (x - BM.bmWidth \ 2) + (y - BM.bmHeight \ 2) * (y - BM.bmHeight \ 2)) * 256 \ (Max(BM.bmWidth, BM.bmHeight) \ 2))
                Alpha = Max(Min(255 - Dis, 255), 0)
' Finally setting the colour with its newly calculated Alpha
                Pixel(1, x, y) = ColBlue * Alpha \ 256
                Pixel(2, x, y) = ColGreen * Alpha \ 256
                Pixel(3, x, y) = ColRed * Alpha \ 256
                Pixel(4, x, y) = Alpha
        Else
                Pixel(1, x, y) = Empty
                Pixel(2, x, y) = Empty
                Pixel(3, x, y) = Empty
                Pixel(4, x, y) = Empty
        End If
     Next x
Next y
Call SetDIBits(DC, DIB, 0, BM.bmHeight, Pixel(1, 1, 1), BIH, 0) ' Finally setting the Bits back.Its like refreshing the Memory
End Sub

Private Function Max(ByVal v1 As Long, ByVal v2 As Long) As Long
  If v1 > v2 Then Max = v1 Else Max = v2
End Function

Private Function Min(ByVal v1 As Long, ByVal v2 As Long) As Long
  If v1 > v2 Then Min = v2 Else Min = v1
End Function

Private Sub Form_Unload(Cancel As Integer) ' I believe the most important subroutine of all my projects is the Form_Unload.After all it can cause my system crash if not called
Erase Pixel()
CopyMemory lBlend, 0&, 4
Call SelectObject(DC, OldDIB)
Call DeleteObject(DIB)
Call DeleteDC(DC)
End Sub

Its a simple program and I suppose well-commented so I'm not going to define it at all. Just one thing that anyone can fetch out another Graphic random algorithm of his own and put it here in this project. Its easy to do it. Another example of the random algorithm is the following routine. I just edited the Form_Load and Timer1_Timer subroutines. Now a flower will be drawn on the screen. Its quite beautiful..

' Personal Declarations
Dim PI As Double, i As Long
Dim Xangle As Long, Yangle As Long
Dim Xspeed As Double, Yspeed As Double, Xradius As Double, Yradius As Double
Dim Xrad As Double, Yrad As Double, nx As Long, ny As Long

Private Sub Form_Load()
Xspeed =  0.83
Yspeed =  0.52
Xradius = 200
Yradius = 200
PI = (4 * Atn(1)) / 180
End Sub

Private Sub Timer1_Timer()
Xspeed = xs.Value / 100 ' 0.83
Yspeed = ys.Value / 100 ' 0.52
Xangle = Xangle + Xspeed
Yangle = Yangle + Yspeed
Xradius = Xradius - 10
Yradius = Yradius - 10
If (Xradius = 0) Or (Yradius = 0) Then
i = i + 0.5
Xradius = 200 + (i * 20)
Yradius = 200 + (i * 20)
End If
Xrad = Xangle * PI
Yrad = Yangle * PI
nx = Math.Sin(Xrad) * Xradius + 400
ny = Math.Cos(Yrad) * Yradius + 300
'  here now AlphaBlend the picture to the calculated (nx,ny)
End Sub

16-07-2006 at 11:20 PM
View Profile Send Email to User Show All Posts | Add Comment
AndreaVB OnLine : Articles and tutorials : Animations using DIB Section
Previous Topic (Testing and Debugging Windows Services and Web Services in .NET Framework)Next Topic (Ways of doing Image Processing)New Topic Post Reply
Surf To:


Not Logged In? Username: Password: Lost your password?
Partners: Download Actual Software | Free Software Download
borderAndreaVB free resources for Visual Basic developersborder

borderAndreaVB Visual Basic and VB.NET source code resources - Copyright © 1999-2007 Andrea Tincaniborder