Kirjautuminen

Haku

Tehtävät

Koodit: VB.NET: Vesi

Kirjoittaja: peki

Kirjoitettu: 27.05.2004 – 27.05.2004

Tagit: koodi näytille, vinkki

Vesi -efekti. Toimii vain ja ainoastaan vb.net 2003:lla johtuen >> operaattorista.
Jos joku viitsii, niin voisi tehdä funkkarin, joka matkisi tuota. Sitten toimisi aiemmillakin versioilla.
Pyydän kommentteja.
Vaatii kuvan "Koe.jpg" suoraan C: aseman juureen.
Exe löytyy: http://koti.mbnet.fi/peku1/Water.exe (et voi ajaa ilman koe.jpg nimistä kuvaa c:n juuressa)

Kommentointi on aika hyvää, joten ohjelman toimintaa en kuvaa tässä sen tarkemmin.
Tästä koodista voisi oppia erittäin nopean bittikartan pikseleiden manipuloimisen, sekä tietysti vesiefektin toteuttamisen

Edit: jos joku ei ymmärrä koodia kommenttejakaan lukemalla, niin voi käydä täällä(oma lähdemateriaalini): http://freespace.virgin.net/hugo.elias/graphics/x_water.htm

Edit2: Koodiin on tehty parannuksia:
Hieman lisää nopeutta, fps -countteri, sade
Exe on myös päivitetty ja mainittakoon vielä kerran, exeni eivät sisällä mitään vakoiluohjelmia, vaikka jotkut niin väittävätkin.

Edit3: Älä aja exeä suoraan IEExecin läpi, vaan tallenna se kiintolevylle ja aja vasta siellä. Muuten c: asemalla sijaitsevaa kuvaa ei voida avata. (itsellä kävi näin)

Imports System.Drawing.Imaging
Imports System.Runtime.InteropServices

Public Class frmWater
    Inherits System.Windows.Forms.Form

    ' yleisiä muuttujia
    Private bmp As Bitmap
    Private waves As Long(,,)
    Private bmpWidth As Integer
    Private bmpHeight As Integer
    Private activeBuffer As Integer = 0
    Private weHaveWaves As Boolean
    Private bmpBytes As Byte()
    Private bmpBitmapData As BitmapData

    ' asettaa pisaran säteen
    Private dropRadius As Integer = 5

    ' Kuinka kauan aallot säilyvät. Mitä isompi arvo, sitä kauemmin aallot kestävät
    Private dampener As Integer = 3
    Dim fps As Integer

    Dim fnt As New Font("Arial", 10)

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Haluamme piirtää itse -> ei automaattipäivitystä
        SetStyle(ControlStyles.UserPaint, True)
        'Piirto tapahtuu vain ja ainoastaan paint metodissa
        SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        'Haluamme käyttää myös kaksoispuskurointia
        SetStyle(ControlStyles.DoubleBuffer, True)

    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.
    'Do not modify it using the code editor.
    Friend WithEvents EffectTimer As System.Windows.Forms.Timer
    Friend WithEvents picSurface As System.Windows.Forms.PictureBox
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container
        Me.EffectTimer = New System.Windows.Forms.Timer(Me.components)
        Me.picSurface = New System.Windows.Forms.PictureBox
        Me.SuspendLayout()
        '
        'EffectTimer
        '
        Me.EffectTimer.Enabled = True
        Me.EffectTimer.Interval = 1
        '
        'picSurface
        '
        Me.picSurface.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
                    Or System.Windows.Forms.AnchorStyles.Left) _
                    Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        Me.picSurface.Location = New System.Drawing.Point(0, 0)
        Me.picSurface.Name = "picSurface"
        Me.picSurface.Size = New System.Drawing.Size(448, 368)
        Me.picSurface.TabIndex = 0
        Me.picSurface.TabStop = False
        '
        'frmWater
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(448, 366)
        Me.Controls.Add(Me.picSurface)
        Me.Name = "frmWater"
        Me.Text = "Water"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Private Sub frmWater_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' Ladataan bittikartta
        bmp = New Bitmap("C:/koe.jpg")
        ' otetaan ylös arvot(lukeminen suoraan muuttujasta nopeampaa)
        bmpHeight = bmp.Height
        bmpWidth = bmp.Width
        ' alustetaan aaltotaulukko
        ReDim Me.waves(bmpWidth, bmpHeight, 2)
        ' hankitaan bittikartta dataa(NOPEA TAPA!!!)
        ReDim Me.bmpBytes(bmpWidth * bmpHeight * 4)
        bmpBitmapData = bmp.LockBits(New Rectangle(0, 0, bmpWidth, bmpHeight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
        Marshal.Copy(bmpBitmapData.Scan0, bmpBytes, 0, bmpWidth * bmpHeight * 4)
    End Sub

    Private Sub ProcessWaves()
        Dim wavesFound As Boolean = False
        Dim x, y As Integer
        Dim newBuffer As Integer

        If (activeBuffer = 0) Then
            newBuffer = 1
        Else
            newBuffer = 0
        End If
        x = 1
        Do While (x < (bmpWidth - 1))
            y = 1
            Do While (y < (bmpHeight - 1))
                ' aalto filtterin "kaava"
                waves(x, y, newBuffer) = CInt((waves(x - 1, y - 1, activeBuffer) + _
                      waves(x, y - 1, activeBuffer) + _
                      waves(x + 1, y - 1, activeBuffer) + _
                      waves(x - 1, y, activeBuffer) + _
                      waves(x + 1, y, activeBuffer) + _
                      waves(x - 1, y + 1, activeBuffer) + _
                      waves(x, y + 1, activeBuffer) + _
                      waves(x + 1, y + 1, activeBuffer) >> 2) - waves(x, y, newBuffer))

                'pehmennys(jotta aallot joskus häviäisivät :D)
                If Not (waves(x, y, newBuffer) = 0) Then
                    waves(x, y, newBuffer) -= CInt(waves(x, y, newBuffer) >> dampener)
                    wavesFound = True ' Jos tänne on päästy(ks. iffi) niin aaltoja (vielä) on
                End If
                y += 1
            Loop 'y++
            x += 1
        Loop 'x++
        weHaveWaves = wavesFound
        activeBuffer = newBuffer
    End Sub

    Private Sub picSurface_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles picSurface.Paint
        Dim tmp As Bitmap = bmp.Clone()
        Dim x, y As Integer
        Dim xOffset, yOffset As Integer
        Dim alpha As Integer

        If (weHaveWaves) Then
            Dim tmpData As BitmapData = tmp.LockBits(New Rectangle(0, 0, bmpWidth, bmpHeight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
            Dim tmpBytes(bmpWidth * bmpHeight * 4) As Byte
            Marshal.Copy(tmpData.Scan0, tmpBytes, 0, bmpWidth * bmpHeight * 4)

            x = 1
            Do While (x < (bmpWidth - 1))
                y = 1
                Do While (y < (bmpHeight - 1))
                    'tsekkaa törmäilyt
                    If (x <= 0) Then
                        x = 1
                    ElseIf (x >= bmpWidth - 1) Then
                        x = bmpWidth - 2
                    End If
                    If (y <= 0) Then
                        y = 1
                    ElseIf (y >= bmpHeight - 1) Then
                        y = bmpHeight - 2
                    End If
                    'Tämä on johdettu raytracingistä(AH!) heijastetaan oikea pikseli siten,
                    'että saadaan aikaan valoa taittava efekti.
                    xOffset = waves(x - 1, y, activeBuffer) - waves(x + 1, y, activeBuffer) >> 3
                    yOffset = waves(x, y - 1, activeBuffer) - waves(x, y + 1, activeBuffer) >> 3
                    If ((Not (xOffset = 0)) Or (Not (yOffset = 0))) Then
                        'tsekkaa törmailyt(heijastetuille pikseleille)
                        If (x + xOffset >= bmpWidth - 1) Then xOffset = bmpWidth - x - 1
                        If (x + xOffset < 0) Then xOffset = -x

                        If (y + yOffset >= bmpHeight - 1) Then yOffset = bmpHeight - y - 1
                        If (y + yOffset < 0) Then yOffset = -y
                        'luodaan alpha
                        alpha = CInt(200 - xOffset)
                        If (alpha < 0) Then
                            alpha = 0
                        ElseIf (alpha > 255) Then
                            alpha = 254
                        End If
                        'asetetaan värit oikeisiin kohtiin(napataan oikeasta kohdasta bittitaulukkoa)
                        tmpBytes(4 * (x + y * bmpWidth)) = bmpBytes(4 * (x + xOffset + (y + yOffset) * bmpWidth))
                        tmpBytes(4 * (x + y * bmpWidth) + 1) = bmpBytes(4 * (x + xOffset + (y + yOffset) * bmpWidth) + 1)
                        tmpBytes(4 * (x + y * bmpWidth) + 2) = bmpBytes(4 * (x + xOffset + (y + yOffset) * bmpWidth) + 2)
                        tmpBytes(4 * (x + y * bmpWidth) + 3) = alpha
                    End If
                    y += 1
                Loop 'y
                x += 1
            Loop 'x
            'kopioidaan data takasin
            Marshal.Copy(tmpBytes, 0, tmpData.Scan0, bmpWidth * bmpHeight * 4)
            tmp.UnlockBits(tmpData)
        End If
        e.Graphics.DrawImage(tmp, 0, 0, picSurface.ClientRectangle.Width, picSurface.ClientRectangle.Height)
        e.Graphics.DrawString("fps: " & fps, fnt, Brushes.Black, 50, 50)
    End Sub

    Private Sub PutDrop(ByVal x As Integer, ByVal y As Integer, ByVal height As Short)
        ' Simuloi pyöreää pisaraa
        ' täyttää aaltotaulukon sopivilla arvoilla
        ' Käytetään hyväksi kosiniaaltoa
        ' (Jos tykkäät geomatriasta/algebrasta RAKASTAT tätä aliohjelmaa
        ' Silloin tulet nauttimaan myös renderöinnin "raytracing" osuudesta)

        ' Nyt meillä ON aaltoja :D
        weHaveWaves = True
        Dim radius As Integer = dropRadius
        'etäisyyden neliö
        Dim distSquared As Double
        'aloitetaan "pallon" reunoilta
        Dim i As Integer = -radius
        Dim tmpX, tmpY As Integer

        Do While (i <= radius)
            Dim j As Integer = -radius
            Do While (j <= radius)
                tmpX = x + i
                tmpY = y + j
                If (((tmpX >= 0) And (tmpX < bmpWidth - 1)) And ((tmpY >= 0) And (tmpY < bmpHeight - 1))) Then
                    ' i:n ja j:n välisen etäisyyden neliö
                    distSquared = Math.Sqrt(i * i + j * j)
                    ' jos etäisyys on < säde silloin aalto "oikein"
                    If (distSquared < radius) Then
                        ' pistetään kosiniaaltoa silmukan osoittamaan paikkaan
                        waves(x + i, y + j, activeBuffer) = CShort(Math.Cos(distSquared * Math.PI / radius) * height)
                    End If
                End If
                j += 1
            Loop 'j
            i += 1
        Loop 'i
    End Sub

    Private Sub picSurface_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles picSurface.MouseMove
        ' Koska bittikarttaa skaalataan, täytyy hiiren koordinaatteja hieman säätää...
        Dim realX As Integer = CInt((e.X / CDbl(picSurface.ClientRectangle.Width)) * bmpWidth)
        Dim realY As Integer = CInt((e.Y / CDbl(picSurface.ClientRectangle.Height)) * bmpHeight)
        PutDrop(realX, realY, 200)
    End Sub

    Private Sub frmWater_Activated(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Activated
        Do
            Dim d As Long = Now().Millisecond
            Dim ft As Long
            ' jos aaltoja -> piirretään
            If weHaveWaves Then
                picSurface.Invalidate()
                ProcessWaves()
            End If
            If Int(Rnd() * 100) > 70 Then
                PutDrop(Int(Rnd() * bmpWidth), Int(Rnd() * bmpHeight), Int(Rnd() * 100) + 100)
            End If
            Application.DoEvents()
            ft = Now().Millisecond - d
            fps = 1 / ft * 1000
        Loop
    End Sub

    Private Sub frmWater_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Closed
        End
    End Sub
End Class

Kommentit

Antti Laaksonen [27.05.2004 21:33:29]

#

Hieno ja todentuntuinen efekti, nopeutta voisit vielä koettaa saada lisää.

hunajavohveli [27.05.2004 21:55:40]

#

Todella upea efekti tämä on.

Bill Keltanen [28.05.2004 07:12:28]

#

Ai että toi on kyllä hieno! Saispa saman VB:lle... Ei vaan löytyny :(

peki [28.05.2004 12:28:32]

#

Nopeutta saa lisää käyttämällä pienempää kuvaa, ja laskemalla damperin arvoa(tein jo muutoksen 4 -> 3 koodiin),
dropRadiusta pienentämällä nopeutta saa myös lisää.
Jos kiinostuneita riittää, ajattelin kirjoittaa tästä efektistä oppaan.

T.M. [28.05.2004 15:39:11]

#

Harmi ettei nuo exet toimi mulla :(
Whinee jostain rekisteriavaimesta...

sooda [28.05.2004 16:42:47]

#

Hanki .net-alusta mikkisoftalta.
Niijja itse vinkistä, TOSI UPEE EFEKTI! Sikahieano.

Linkku [28.05.2004 17:56:55]

#

Ei toimi mullakaan... Mitä lie vakoiluohjelmia sisältää....

peki [28.05.2004 18:15:58]

#

Öh. Käy lataamassa http://www.microsoft.com/downloads/details.aspx?FamilyId=262D25E3-F589-4842-8157-034D1E7CF3A3&displaylang=en tuolta microsoftin .NET framework 1.1
Edit: ja toisekseen, ohjelmani eivät sisällä vakoiluohjelmia, joten turha panettelu sikseen!
Edit2: koodia on päivitetty: Hieman lisää nopeutta, fps -countteri, sade

T.M. [29.05.2004 00:21:32]

#

Noniin, nyt toimii, kiitos tuosta linkistä!
Näyttää hienolta, mutta helvetin hidas vain on :(

setä [29.05.2004 11:00:21]

#

Onhan se hieno. Tosin meni hetki ennenkuin vanha hokasi mitä siinä itseasiassa tapahtuu. Näkyy parhaiten kun kuvassa on jyrkkiä kontrasteja. Mulla se on kyllä hidas, kuva päivittyy noin peri kertaa sekunnissa. Toi kuva on melkein puoli megaa, ehkä siinä syy.

Edit. Kokeilin pienemmällä kuvalla ( 4 kt ). Todella mahtava efekti, kerrassaan hieano ! Ihan itsekö kehittelit vai saitko jostain vinkkiä. Melkoisia osaajia täällä putkassa !!

peki [29.05.2004 11:46:39]

#

Itse vesiefekti on omani, mutta tuohon renderöimiseen korkeuskartan läpi sain netistä hieman apua englanninkielisen hieman "sekavan oppaan" muodossa. :D
Edit: Tuo lähdemateriaali, minkä mainitsin kuvauksessa siis.

miiro [30.05.2004 16:15:20]

#

osaisko kukaa kääntää tota vb 6:selle

tn [31.05.2004 22:29:24]

#

"Sovelluksen alustus epäonnistui..." -> Pitäisikö minun siis muka ladata 24 megan paketti Microsoftilta, että saan sen toimimaan?

peki [01.06.2004 09:34:32]

#

Kyllä. Ikävä kyllä näin on.
.NET sovellukset eivät toimi ilman Framework nimistä kirjastoa. Omat sovellukseni siis vaativat version 1.1 toistaiseksi.

Kingi [14.08.2005 18:05:46]

#

mulla se .net framework 1.1 oli win xp pro:n asennus levykkeellä. Muistaakseni siinä lisäosat tai lisätoiminnot tai jotain sinnepäin ni siin kohassa.

Kingi [14.08.2005 18:11:41]

#

ihan ärsygdävän bieniä dibboja, niin ja mulla on 2.jotain .net framwork ja sitä ei kyllä löydy siltä levyltä, mut jos kiinnostaa ni let's go to microsoft.com

Kingi [14.08.2005 18:12:05]

#

ei helvetti noit mun gommenddeja... lol

Kirjoita kommentti

Muista lukea kirjoitusohjeet.
Tietoa sivustosta