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 SubHuuhaahii siinäpä vasta koodi :)
Erittäin hyvin artikuloitu
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.
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.
Hyvin pyörii.
Jaha. Minulla on Optionssin alla vain make-välilehti...ei mitään Compilea :(
VB:llä? hmm... kuulostaa hitaalta, exeä missään?
tosi hianolta näyttää
T.M pistin omalle palvelimelle käännettynä
On kyllä nätti. Pidän :)
Joo huomasin että bootin jälkeen apache ei ollut käynnistynyt mutta nytten toimii
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.
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...
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.
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
Ei toimi.
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.
Winellä tökkii.
en saa toimimaan koodia, mut exe on älyttöman upee :D:D:D
jännät metaympyrät
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.
Joten enköhän jatka ihan rauhassa metapalloillen :)
Oli niin kaunista... *snif!*
Kauneimmat metapallot joita olen nähnyt...
todella hieno...
Aihe on jo aika vanha, joten et voi enää vastata siihen.