Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: VB6: SetDIBits plasma

Rykker [22.01.2005 14:46:50]

#

Pieni esimerkinpoikanen SetDIBits funktion käytöstä.
Plasmaefekti pohjautuu pitkälti pekin oppaaseen.

Suhteellisen vähän kommentoitu koodi, mutta samalla sen verran yksinkertainen kuitenkin, että eiköhän tuo kaikille avaudu.

Plasman saisi toki VB:llä tehtyä huomattavasti nopeamminkin, esim. hyödyntäen gdi32:sta löytyviä palettifunktioita. No, tuskinpa ainakaan mikään hitain variaatio VB:llä luodusta plasmaefektistä.

Eli tee formi, johon laitat yhden pictureboxin nimeltä Picture1 ja liitä koodi projektiin.
Ja on sitten aika nihkeetä yrittää pyörittää tuota debugmodessa, että kääntäkää suoraan vaan exeksi.

Toimiva esimerkki löytynee osoitteesta: http://www.omena.org/~rykker/plasmi.zip

Declarations

Option Explicit
Private Const leveys As Long = 640
Private Const korkeus As Long = 480
Private X As Long, Y As Long, i As Long, j As Long
Private Type paletti
 Punane As Byte
 Vihree As Byte
 Sinine As Byte
End Type
Private lasku As Long, lasku2 As Long, dumb As Single
Private liiku1 As Long
Private arvoo(1 To leveys * 4, 1 To korkeus * 4) As Long
Private aika As Long
Private Const pii As Long = 3 'jep, kolme.
Private Declare Function GetInputState Lib "user32" () 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 BITMAPINFO, ByVal wUsage As Long) As Long
Private Type BITMAP '14 tavua
    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 '40 tavua
    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 RGBQUAD
    rgbBlue As Byte
    rgbGreen As Byte
    rgbRed As Byte
    rgbReserved As Byte
End Type
Private Type BITMAPINFO
    bmiHeader As BITMAPINFOHEADER
    bmiColors As RGBQUAD
End Type
Private Const DIB_RGB_COLORS = 0&
Private Const BI_RGB = 0&

plasma

Private Sub plasma()
Dim varit(1 To 256) As paletti
Dim wid As Integer
Dim hgt As Integer
Dim bitmap_info As BITMAPINFO
Dim pixels() As Byte
Dim bytes_per_scanLine As Integer
Dim pad_per_scanLine As Integer

    'Otetaan bittikartan tietoja ylös, näistä ei kannata niin paljoa välittää :p
    wid = Picture1.ScaleWidth
    hgt = Picture1.ScaleHeight
    With bitmap_info.bmiHeader
        .biSize = 40
        .biWidth = wid
        ' Negatiivinen arvo = ylhäältä alas
        .biHeight = -hgt
        .biPlanes = 1
        .biBitCount = 32
        .biCompression = BI_RGB
        bytes_per_scanLine = ((((.biWidth * .biBitCount) + 31) \ 32) * 4)
        pad_per_scanLine = bytes_per_scanLine - (((.biWidth * .biBitCount) + 7) \ 8)
        .biSizeImage = bytes_per_scanLine * Abs(.biHeight)
    End With
    'luodaan oikean kokoinen rgb-kartta pikseleille
    ReDim pixels(1 To 4, 1 To wid, 1 To hgt)
Do
If GetInputState Then End
   aika = aika + 5
   dumb = aika * pii / 360
   lasku = leveys * 2 + 100 * Sin(dumb)
   lasku2 = korkeus * 2 + 100 * Cos(dumb)

    For i = 1 To 256
    With varit(i)
     .Punane = 72 + 71 * Cos(i * pii / 128 + aika / 74)
     .Sinine = 72 - 71 * Cos(i * pii / 128 + aika / 71)
     .Vihree = 72 + 71 * Sin(i * pii / 128 + aika / 64)
    End With
    Next i

    ' Muokataan pikseleitä
    For Y = 1 To korkeus
        For X = 1 To leveys
            liiku1 = arvoo(lasku + X, lasku2 + Y)
            If liiku1 > 255 Then liiku1 = 255
            pixels(3, X, Y) = varit(liiku1).Punane 'r
            pixels(2, X, Y) = varit(liiku1).Vihree 'g
            pixels(1, X, Y) = varit(liiku1).Sinine 'b
        Next X
    Next Y

    ' Näytetään muunneltu kuva
    SetDIBits Picture1.hdc, Picture1.Image, 0, hgt, pixels(1, 1, 1), bitmap_info, DIB_RGB_COLORS
    Picture1.Picture = Picture1.Image
Loop
End Sub

Form_Load

Private Sub Form_Load()
Me.ScaleMode = vbPixels
Picture1.AutoRedraw = False
Picture1.ScaleMode = vbPixels
Picture1.Width = 640
Picture1.Height = 480
Me.Width = 640 * 15
Me.Height = 480 * 15
Picture1.Left = 0
Picture1.Top = 0
Picture1.BorderStyle = 0
Me.Show
'luodaan palettikartta
For i = 1 To leveys * 4
For j = 1 To korkeus * 4
arvoo(i, j) = 64 + 63 * Sin(i / (90 + 10 * Cos(j / 74))) * Cos(j / (110 + 10 * Sin(i / 60)))
Next j
Next i
plasma
End Sub

sooda [22.01.2005 18:39:42]

#

Form_Load on aika jännästi sisennetty. Ja mä laittasin GetInputState sinne form_loadiin just ennen plasma-subin kutsumista sen pufferin tyhjentämiseks että sulkeutuu vasta sitten ku oikeesti halutaan eikä ennen sitä jopa. Mulla ainaki sun exe sulkeutui vähän väliä ennen aikojaan. Mutta hieno efekti ja hyvin näkee ton funkkarin käytön. En uskalla kuvitellakaan kuinka hidas tosta tulis jos pikselit psettais yks kerrallaan :D

tuomas [22.01.2005 19:52:10]

#

Tuonne silmukkaan olisi ihan hyvä lisätä Doevents, niin onnistuisi ohjelmasta poistuminen nopeammin..
Hieno efekti.

Rykker [23.01.2005 11:31:45]

#

Kuten ohjelmoinninopettajallani on tapana sanoa "Koodilla ei oo väliä miltä näyttää, kunhan se toimii ja itse tajuaa mitä tapahtuu." Jotenkin syöpyny päähän toi :P

Ja unohin ihan ton GetInputStaten käyttäytymisen :D
Koittakaa siis olla painelematta turhia nappeja ja käynnistäkää toi .exe vaikka enterillä...

Ja tuomas: GetInputState hoitaa tossa sen ohjelmasta poistumisen. Tai ainakin pitäisi.

sooda [24.01.2005 12:14:17]

#

DoEventsiä ei muutenkaa kannata käyttää tommosessa. Hidastais turhan paljon kun pitäs käsitellä jotain muutaki ku effua ;)

Spongi [25.01.2005 13:00:52]

#

Ohhoh, Rykker on hengissä :)

Rykker [29.01.2005 12:55:28]

#

Joissain määrin ainakin.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta