Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: VB6: Metapallojen paluu

Sivun loppuun

Merri [15.06.2005 04:05:08]

#

Alunperin pekin tekemä, sittemin soodan VB6:lle kääntämä ja nyt minun rankasti optimoimani. Korjasin samalla bugit pois. Eli jos metapallojen logiikasta on kysyttävää, niin kannattaa kurkata ensin nämä aiemmat koodit. Ja sitten itse asiaan.

Tämä on siis optimoitu ja muutenkin paranneltu versio jo aiemmin lähetetystä koodista. Käytännössä lähes kaikki on kirjoitettu uusiksi, vaikka muutamia vanhan koodin asioita olenkin säilyttänyt sellaisenaan. Huomattavaa on, että 1. tämä ei millään lailla rajoita metapallojen piirtoaluetta vaan pallot piirretään kokonaisina ja 2. palloja pyörii enemmän.

Koodin voi sellaisenaan liittää uuteen projektiin. Sen jälkeen ei kuitenkaan kannata IDE:n alla alkaa koodia ajamaan, koska nopeutta ei IDE:n alla saa. Sen sijaan ohjelma pitää kääntää. Ja sitäkään ei pidä tehdä ihan sillä perinteisellä tavalla, vaan File > Make Project1 > Options... > Compile-välilehti > Advanced Optimizations... > ruksaa kaikki ja paina OK. Tämän jälkeen käännetty EXE on oikeasti nopea.

Sitten teknisiä seikkoja. Tämä koodi siis luo 8-bitin eli 256 värin kuvan API:n avulla muistiin. Kuva luodaan itse asiassa joka kerta kun uusi frame piirretään. Tästä esimerkkikoodista oppii varsin suoraan tekniikan, millä voi piirtää 256-värisiä paletillisia grafiikkoja reaaliajassa. Eli tästä voi oppia vaikka sen, miten tehdä sellaisen hienon panoksen joka lentää ilman halki ja valaisee ympärillä olevia esineitä (jos siis taidot riittää). Tosin 256 väriä rajoittaa, mutta 24-bit tai 32-bit kuva on jo huomattavasti raskaampi ja kannattaa siirtyä ihan suosiolla DirectX:n puolelle.

Mutta joo, toivottavasti tästä on hyötyä.

LISÄYS
Kuten kommenteista saatoit jo huomata, niin olen tehnyt lisää kivoja muutoksia aikojen kuluessa. Koosteen muutoksista löytää mm. täältä kuvankaappauksien kera:
http://www.vbforums.com/showthread.php?t=344694
Varmaan teen osion kotisivuillenikin jahka jaksan.

Tässä vielä kopiointilinkit valmiisiin projekteihin:
http://merri.net/vb6/metapallo.zip - Metapallojen paluu
http://merri.net/vb6/metamato.zip - Metamato
http://merri.net/vb6/metademo.zip - Meta Demo

Option Explicit

Private Const BI_RGB As Long = 0&
Private Const CBM_CREATEDIB As Long = &H2
Private Const CBM_INIT As Long = &H4
Private Const DIB_RGB_COLORS As Long = 0&
Private Const PI As Double = 3.14159265358979

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 RGBQUAD
    rgbBlue As Byte
    rgbGreen As Byte
    rgbRed As Byte
    rgbReserved As Byte
End Type

Private Type BITMAPINFO_256
    bmiHeader As BITMAPINFOHEADER
    bmiColors(0 To 255) As RGBQUAD
End Type

Private Type POINTAPI
        X As Long
        Y As Long
End Type

Private Type METABALL
    Pos As POINTAPI
    Rad As Integer
    Mass As Integer
    Vel As POINTAPI
    X As Byte
    Y As Byte
End Type

Dim Balls() As METABALL
Dim BF() As Double

Dim STab(359) As Double
Dim CTab(359) As Double

Dim BMP_Info As BITMAPINFO_256, BMP_Buffer() As Byte
Dim Compat_DC As Long, hDIB As Long, Screen_hDC As Long
Dim RealWidth As Integer, RealHeight As Integer

Dim mX As Integer, mY As Integer
Dim Quit As Boolean

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hDC As Long) As Long
Private Declare Function CreateDIBitmap Lib "gdi32" (ByVal hDC As Long, lpInfoHeader As BITMAPINFOHEADER, ByVal dwUsage As Long, lpInitBits As Any, lpInitInfo As BITMAPINFO_256, ByVal wUsage As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, 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 StretchBlt Lib "gdi32" (ByVal hDC As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long
Private Sub Init_Palette(ByRef Paletti() As Byte)
    Dim A As Long, B As Long, C As Long
    ' luo mustavalkopaletti
    For A = 4 To 1020 Step 4
        B = A \ 4
        C = B * 1.2
        If C > 255 Then C = 255
        Paletti(A) = C
        Paletti(A + 1) = B
        Paletti(A + 2) = B
    Next A
End Sub
Private Sub Form_Activate()
    Static HereAlready As Boolean
    Dim tmpC As Double, tmpS As Double, tmpX As Long, tmpY As Long
    Dim iX As Long, iY As Long, aX As Long, aY As Long
    Dim X As Single, Y As Single, XX As Long, YX As Long, A As Long
    Dim Phi As Integer
    ' estetään tehokaasti ajamasta tätä moninkertaisena
    If HereAlready Then Exit Sub
    HereAlready = True
    ' nyt sitten tämä varsinainen luuppi
    Do Until Quit
        ' kasvata Phi-arvoa ja pidä se 360 alapuolella silleen viisaasti
        Phi = (Phi + 1) Mod 360
        ' seuraa hiiren sijaintia
        Balls(0).Pos.X = Balls(0).Pos.X + CLng(CSng(mX - Balls(0).Pos.X) / 10)
        Balls(0).Pos.Y = Balls(0).Pos.Y + CLng(CSng(mY - Balls(0).Pos.Y) / 10)
        ' optimointia
        tmpC = (RealWidth \ 2) + (CTab(Phi) * (RealWidth \ 4))
        tmpS = (RealHeight \ 2) + (STab(Phi) * (RealHeight \ 4))
        For A = 1 To UBound(Balls)
            ' liikutellaan palloa tämmöisen hienon kaavan mukaan
            Select Case A Mod 4
                Case 0
                    Balls(A).Pos.X = CLng(STab(Phi) * CDbl(Balls(A).X) + tmpC)
                    Balls(A).Pos.Y = CLng(CTab(Phi) * CDbl(Balls(A).Y) + tmpS)
                Case 1
                    Balls(A).Pos.X = CLng(CTab(Phi) * CDbl(Balls(A).X) + tmpC)
                    Balls(A).Pos.Y = CLng(CTab(Phi) * CDbl(Balls(A).Y) + tmpS)
                Case 2
                    Balls(A).Pos.X = CLng(CTab(Phi) * CDbl(Balls(A).X) + tmpC)
                    Balls(A).Pos.Y = CLng(STab(Phi) * CDbl(Balls(A).Y) + tmpS)
                Case 3
                    Balls(A).Pos.X = CLng(STab(Phi) * CDbl(Balls(A).X) + tmpC)
                    Balls(A).Pos.Y = CLng(STab(Phi) * CDbl(Balls(A).Y) + tmpS)
            End Select
        Next A
        For A = 0 To UBound(Balls) - 1
            tmpX = Balls(A).Rad * 1.5
            ' laske piirtoalue
            iX = Balls(A).Pos.X - tmpX
            If iX < 0 Then iX = 0
            aX = Balls(A).Pos.X + tmpX
            If aX > (RealWidth - 1) Then aX = RealWidth - 1
            iY = Balls(A).Pos.Y - tmpX
            If iY < 0 Then iY = 0
            aY = Balls(A).Pos.Y + tmpX
            If aY > (RealHeight - 1) Then aY = RealHeight - 1
            ' piirrä piirtoalueelle
            YX = iY * RealWidth
            For Y = iY To aY
                For X = iX To aX
                    XX = YX + X
                    tmpX = (Balls(A).Pos.X - X)
                    tmpY = (Balls(A).Pos.Y - Y)
                    If tmpX <> 0 Or tmpY <> 0 Then
                        BF(XX) = BF(XX) + Balls(A).Rad / CSng(tmpX * tmpX + tmpY * tmpY)
                    Else
                        BF(XX) = 1
                    End If
                Next X
                ' pieni optimointikikka, ei tarvitse tehdä niin paljon kertolaskua
                YX = YX + RealWidth
            Next Y
        Next A
        tmpX = Balls(A).Rad * 1.5
        ' laske piirtoalue
        iX = Balls(A).Pos.X - tmpX
        If iX < 0 Then iX = 0
        aX = Balls(A).Pos.X + tmpX
        If aX > (RealWidth - 1) Then aX = RealWidth - 1
        iY = Balls(A).Pos.Y - tmpX
        If iY < 0 Then iY = 0
        aY = Balls(A).Pos.Y + tmpX
        If aY > (RealHeight - 1) Then aY = RealHeight - 1
        ' piirrä piirtoalueelle
        YX = iY * RealWidth
        For Y = iY To aY
            For X = iX To aX
                XX = YX + X
                tmpX = (Balls(A).Pos.X - X)
                tmpY = (Balls(A).Pos.Y - Y)
                If tmpX <> 0 Or tmpY <> 0 Then
                    BF(XX) = BF(XX) + Balls(A).Rad / CSng(tmpX * tmpX + tmpY * tmpY)
                Else
                    BF(XX) = 1
                End If
            Next X
            ' pieni optimointikikka, ei tarvitse tehdä niin paljon kertolaskua
            YX = YX + RealWidth
        Next Y
        ' sitten itse piirtoalue ja nollaustemput
        YX = 0
        For Y = 0 To RealHeight - 1
            For X = 0 To RealWidth - 1
                XX = YX + X
                If BF(XX) > 1 Then BF(XX) = 1
                BMP_Buffer(XX) = CByte((BF(XX) * 255))
                BF(XX) = 0
            Next X
            ' pieni optimointikikka, ei tarvitse tehdä niin paljon kertolaskua
            YX = YX + RealWidth
        Next Y


        ' piirrä vain jos ohjelmaa ei ole lopetettu...
        If Not Quit Then
            ' luo bittikartta
            hDIB = CreateDIBitmap(Screen_hDC, BMP_Info.bmiHeader, CBM_INIT Or CBM_CREATEDIB, BMP_Buffer(0), BMP_Info, DIB_RGB_COLORS)

            ' linkitä bittikartta luomaamme Device Contextiin
            SelectObject Compat_DC, hDIB

            ' kopioi lopputulos näkyville
            StretchBlt hDC, 0, 0, ScaleWidth, ScaleHeight, Compat_DC, 0, ScaleHeight - 1, ScaleWidth, -ScaleHeight, vbSrcCopy

            ' tuhoa luomamme bittikartta
            DeleteObject hDIB

            ' päivitä näkymä
            'Refresh
            ' ja sitten ettei jää ohjelma ihan lukkoon
            DoEvents
        End If
    Loop
    ' ja nyt tämän voi jo pistää toimimaan toistamiseen
    HereAlready = False
End Sub
Private Sub Form_Load()
    Dim tmpDouble As Double
    Dim A As Integer
    Dim Paletti(1023) As Byte

    On Error Resume Next
    Debug.Print 1 \ 0
    If Err.Number Then Err.Clear: MsgBox "Käännä ohjelma ensin (ja muista törkätä jok'ikinen optimointi päälle!)": Quit = True: Exit Sub
    On Error GoTo 0

    ' jotta toimii varmasti oikein...
    ScaleMode = vbPixels

    ' aseta kooksi neljännes ruudun koosta
    Width = Screen.Width \ 4
    Height = Screen.Height \ 4

    ' muistissa tavujen leveysmäärän tulee olla aina jaollinen neljällä
    ' siksi tarvitsemme sen verran ylimääräisiä turhia tavuja myös 256-värin bittikartassa - jokaisella rivillä
    If ScaleWidth Mod 4 Then
        RealWidth = ScaleWidth + 4 - ScaleWidth Mod 4
    Else
        RealWidth = ScaleWidth
    End If
    RealHeight = ScaleHeight

    ' varaa muisti bittikarttaa varten
    ReDim BMP_Buffer(CLng(RealWidth) * CLng(RealHeight) - 1)

    ' mikä lie, en välitä kun olen optimoimassa tätä koodia
    ReDim BF(CLng(RealWidth) * CLng(RealHeight) - 1)
    tmpDouble = PI / 360
    For A = 0 To 359
        STab(A) = Sin((A + A) * tmpDouble)
        CTab(A) = Cos((A + A) * tmpDouble)
    Next

    ' alusta mustavalkopaletti
    Init_Palette Paletti

    ' kopioi paletti bittikartan tietoihin
    CopyMemory ByVal VarPtr(BMP_Info.bmiColors(0)), ByVal VarPtr(Paletti(0)), 1024

    ' alusta bittikartan tiedot
    With BMP_Info.bmiHeader
        .biSize = Len(BMP_Info.bmiHeader)
        .biWidth = ScaleWidth                   ' leveys pikseleinä
        .biHeight = ScaleHeight                 ' korkeus pikseleinä
        .biPlanes = 1                           ' yhden värin kerros
        .biBitCount = 8                         ' 8 bittiä pikseliä kohden
        .biCompression = BI_RGB                 ' ei pakkausta, tavanomista RGB:tä
        .biSizeImage = 0                        ' tarpeeton kun ei ole pakkausta
        .biXPelsPerMeter = 0                    ' ei tarvita
        .biYPelsPerMeter = 0                    ' ei tarvita
        .biClrUsed = 256                        ' kuvan käyttämien värien määrä väritaulukossa (0 = kaikki)
        .biClrImportant = 256                   ' tärkeiden värien määrä (ts. paletin värit, 0 = kaikki värit)
    End With

    ' tarvitsemme jonkin Device Contextin bittikarttaa varten, joten luo ruudun kanssa yhteensopiva
    Screen_hDC = GetDC(0)

    ' luo formin kanssa yhteensopiva Device Context
    Compat_DC = CreateCompatibleDC(hDC)

    ' alustetaan sitten ne pallotkin
    Randomize
    ' tee 5 - 10 palloa
    ReDim Balls(Int(Rnd * 6) + 5)
    ' alusta pallot
    For A = 0 To UBound(Balls)
        Balls(A).Rad = Int(Rnd * 210) + 90
        Balls(A).Mass = Int(Rnd * 290) + 10
        Balls(A).X = (Int(Rnd * 10) + 1) * 10
        Balls(A).Y = (Int(Rnd * 10) + 1) * 10
    Next
End Sub
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    mX = CInt(X)
    mY = CInt(Y)
End Sub
Private Sub Form_Unload(Cancel As Integer)
    ' merkkaa että olemme valmiita lopettamaan
    Quit = True

    ' vapauta tai tuhoa kaikki käytetyt elementit
    ReleaseDC 0, Screen_hDC     ' vapauta ruudun Device Context
    DeleteDC Compat_DC          ' tuhoa yhteensopiva Device Context
    Erase BMP_Buffer            ' tyhjennä byte array muistista
    Erase BF                    ' tyhjennä poikaystävä muistista
End Sub

Firsti [15.06.2005 09:36:04]

#

Huuhaahii siinäpä vasta koodi :)
Erittäin hyvin artikuloitu

tuomas [15.06.2005 11:50:10]

#

Hmm.. ehkäpä mä teen sitten vielä näistä metapalloista sen mainitsemasi directx version, joskus kun aikaa ja innostusta riittää :D Sitten voidaan vaikka mittailla miten suuria nopeuseroja eri tekniikoiden välillä on.
Hienolta näyttää.

Edit: Lisäsin koodiisi fps-mittarin ja keskimääräiseksi arvoksi muodostui noin. 13fps.

Merri [15.06.2005 12:46:58]

#

Tiedän jo miten voin optimoida tuota lisää, eri asia sitten on se, että kuinka kannattavaa se loppujen lopuksi on. Toisaalta mietin vähän enemmän 32-bit mahdollisuuttakin, eikä se enää niin pahalta päässä kuullosta: ainoa asia vain se, että en ole aiemmin 32-bitin kanssa paljoa värkkäillyt. Ainakin väreihin saisi mukavasti lisää potkua, jos ei muuta.

Meitsi [15.06.2005 12:50:51]

#

Hyvin pyörii.

miiro [15.06.2005 13:35:48]

#

Jaha. Minulla on Optionssin alla vain make-välilehti...ei mitään Compilea :(

T.M. [15.06.2005 13:47:09]

#

VB:llä? hmm... kuulostaa hitaalta, exeä missään?

tesmu [15.06.2005 16:29:42]

#

tosi hianolta näyttää

tesmu [15.06.2005 16:30:52]

#

T.M pistin omalle palvelimelle käännettynä

http://teemuk.no-ip.org/meta.exe

nomic [15.06.2005 19:13:49]

#

On kyllä nätti. Pidän :)

temu92 [15.06.2005 21:32:25]

#

tesmu kirjoitti:

http://teemuk.no-ip.org/meta.exe

ei toimi

tesmu [15.06.2005 22:20:19]

#

Joo huomasin että bootin jälkeen apache ei ollut käynnistynyt mutta nytten toimii

Merri [15.06.2005 23:15:20]

#

Metapallon paluu

Siinä sitten koko projekti ja käännetty exe. Tuo pyörii aika tasan tarkkaan yhtä nopeasti kuin vastaava C/C++ versio pyörisi: onhan VB6:n kääntäjä sentään "vain" kräkätty C-kääntäjä. Ainoa hitaus mikä tuossa on johtuu vain siitä, että tuo kuva lasketaan joka kerta kokonaan uudelleen, joka ikinen pallo.

Merri [16.06.2005 03:13:36]

#

Sitten hieman kehittyneempi versio:
Metamato

Vauhdiltaan pitäisi olla samaa luokkaa kuin tuo edellinen, mutta käsittelee viittä sataa (500!) metapalloa muodostaen madon, jonka kanssa voi leikkiä. Yhtenä parannuksena edelliseen bittikarttaa ei luoda ja tuhota enää jatkuvasti uudelleen, vaan vain sen sisältö päivitetään. Lisäksi pallot säilötään muistissa, joten sitä tietenkin kuluu hiukan enemmän. Muistia on käytössä se ~10 Mt. Joten aatella, VB6 jaksaa käsitellä ihan hyvää tahtia sitä kymmentä megatavua muistia...

Merri [16.06.2005 08:02:32]

#

Olen päivittänyt koodivinkin sepitettä, alkoi tulla liikaa koodia tänne kommentteihin... :) Lisäsin myös linkin VBForums.comiin, josta löytyy koostetopikki.

Meta Demo kannattaa muuten kurkata, se on "vähän" kehittyneempi.

T.M. [16.06.2005 20:37:44]

#

No huhhuh, ekaa kertaa näen VB:llä tehtyjä nopeita ohjelmia jotka eivät välky näytöllä tai muuta paskaa.

Hienoja nuo, mato oli vähän outo, mutta tuo demo oli siisti!
Voimakkaamman kentän kun saisi noihin palloihin, niin tulisi enemmän esille metapallojen ominaisuudet.

En koskaan olisi uskonut että VB:llä saisi mitään hyvää aikaiseksi :P

BlueByte [19.06.2005 01:39:07]

#

Ei toimi.

Merri [19.06.2005 13:12:42]

#

Tarkempi sepustus auttaa aina: Windowsin versio esimerkiksi (Winelle en edes takaa toimivuutta, se kun on vain emulaattori). "Ei toimi" on sama kuin sanoisi että telkkari ei toimi ja lopulta paljastuu ettei ole kytkenyt johtoa seinään.

BlueByte [20.06.2005 23:27:58]

#

Winellä tökkii.

crafn [23.06.2005 21:12:59]

#

en saa toimimaan koodia, mut exe on älyttöman upee :D:D:D

BlueByte [23.06.2005 22:05:45]

#

jännät metaympyrät

Merri [24.06.2005 06:40:23]

#

Tätä aamun huumaa tähän väliin:
http://www.google.fi/search?biw=1024&hl=fi&q­=metaympyrät&btnG=Google-haku&meta=
http://www.google.fi/search?hl=fi&biw=1024&q­=metacircles&btnG=Hae&meta=
http://images.google.fi/images?q=metacircles&hl­=fi&lr=&sa=N&tab=wi

Kunhan Google indeksoi tämän sivun, tulee siitä myös ainoa Googlen indeksoima sivu tuolla sanalla.

http://www.buginthemachine.com/eProggra.php

Lisäksi tämäntapainen kuvaus metapalloista on useilla sivustoilla: "Metaballs are a 2D rendering technique that blends and transforms an assembly of sheres into a complex shape, that can seems as a moving organic form."

Ja tietysti jopa Ohjelmointiputka on tätä mieltä:
https://www.ohjelmointiputka.net/oppaat/opas.php?tunnus=meta

Joten enköhän jatka ihan rauhassa metapalloillen :)

Basic 6.0 [02.04.2006 19:59:15]

#

Oli niin kaunista... *snif!*
Kauneimmat metapallot joita olen nähnyt...

fouli [06.04.2007 19:27:35]

#

todella hieno...


Sivun alkuun

Vastaus

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

Tietoa sivustosta