long time ago, i wrote an article explaining how to to code an oldskool tablebased tunnel effect. the article has been published in the first issue of the german coding magazine "PB.CM"! (sadly still dead?) However, all rights are reserved.
Article (c) by Mr.Vain/Secretly! aka "thorsten will". all rights reserved!
GERMAN ARTICLE VERSION
DemoCoding - Tunnel Effect:
Hallo und herzlich willkommen in der Wunderwelt der sogenannten Tabellenbasierten DemoEffekte. Was sind Tabellenbasierte DemoEffekte und warum werden hierfür Tabellen benutzt? Viele ältere DemoEffekte wie Tunnel, Sphere, BumpMap usw. sind oft lediglich 3D fakes und basieren auf vorberechnete 2D Daten, welche für die spätere Verwendung in Tabellen (Arrays) gespeichert werden. Da die benötigen Daten vorberechnet werden, brauchen wir diese später nicht im MainLoop und in Echtzeit immer wieder neu zu berechnen. Hierdurch ersparen wir uns einige Berechnungen und können die Performance des einzelnen Effekts oft um einiges steigern.
Heute werden wir uns Schritt für Schritt die Grundlagen zur Programmierung eines TunnelEffektes anschauen und Schritt für Schritt einen solchen selber Programmieren.
Was brauchen wir überhaupt um unseren ersten TunnelEffekt zu realisieren und wie funktionert dieser Effekt? Der TunnelEffekt an sich besteht aus drei wichtige Elementen. Wir hätten da zum einen die Texture, welche wir später auf unseren Tunnel mappen (kleistern). Als Texture werden wir uns eine eigene 256x256 große - sogenannte XOR - Texture berechnen. Selbstverständlich könnten wir auch einfach per Zufall Punkte, Linien oder Kreise auf unserer Texture zeichen - oder sogar zum Beispiel eine 256x256 große "tileable" Texture als BMP benutzen.
Nun werden wir unsere erste XOR Texture berechnen, in dem wir ein 256x256 großes Image erstellen und dieses nach Fertigstellung auf unserer Festplatte unter ""c:\TunnelFx_Texture.bmp" speichern. Als Ergebniss erhalten wir unsere fertige Texture als BMP Datei.
Desweiteren benötigen wir zwei große Texturen (Distance und Angle), die unserer darzustellenden Bildschirmgröße 640x480 entsprechen. Wenn wir uns den Blick in einen runden Tunnel vorstellen, so könnte man dieses mit einer Röhre vergleichen, die aus vielen Ringen besteht und die Ringe mit zunehmender Distance immer kleiner werden. Wir werden nun eine entsprechende "Distance Texture" erstellen und diese ebenfalls als BMP speichern. Um einen kleinen Eindruck zu erhalten, wie eine solche "Distance Texture" ausschaut, einfach die fertige BMP Datei öffnen und anschauen.Code: Select all
Listing: Part1_Texture.pb
Nach dem wir nun die "Distance Texture" erstellt haben, benötigen wir noch die sogenannte "Angle-Texture" (Winkel). Diese Texture wird benötigt um unsere XOR Texture im Tunnel richtig anzupassen und unseren Tunnel später u.a. rotieren zu lassen. Die "Distance Texture" wird u.a. benötigt, um in den Tunnel zu fliegen.Code: Select all
Listing: Part2_Distance.pb
Bisher haben wir die drei wichtigsten Elemente für einen TunnelEffekt und ihre jeweiligen Routinen kennengelernt, dessen Ergebnisse wir bisher immer auf eine Bitmap darstellen und als BMP speichern. Nun werden wir die berechneten Daten direkt die Tabellen (Arrays) "aTexture", "aDistance" und "aAngle" speichern und die einzelnen Routinen von Part1-Part3 zusammenlegen und somit ein wenig optimieren. Im SourceCode von Part1 erstellen wir unsere 256x256 große XOR Texture, bei der wir die x und y Schleife von 0 bis 255 durchlaufen lassen. Da wir keine weitere Routine verwenden, in der wir ebenfalls von 0 bis 255 zählen, lassen wir diese Routine wie zuvor unverändert.Code: Select all
Listing: Part3_Angle.pb
Allerdings verwenden wir für die Berechnung der "Distance Table" und "Angle Table" in beiden Fällen Schleifen, dessen Werte in beiden Routinen identisch sind. Daher können wir diese beiden Routine ohne Probleme zusammenfassen und uns Zeit für die Vorberechnung sparen und kleineren Programmcode erzeugen.
Wir werden das bisher gelernte nun anwenden, einen Screen öffnen und das erste Resultat unseres Tunnels auf dem Bildschirm darstellen.Code: Select all
Listing: Part4_MergingStuff.pb
Um den Programmcode einfacher zu lesen, werden wir einfach den Plot() Befehl verwenden und nicht auf DirectScreenAccess aufbauen.
Mit unserer "aDistance" und "aAngle" Table können wir nun ohne Probleme einen Tunnel darstellen. Damit nun aber auch unsere 256x256 große XOR Texture (aTexture) im Tunnel richtig gemapped (abgebildet) wird, werden wir diese beiden Tabellen im Innerloop einfach auslesen und wir erhalten die entsprechende X und Y Koddinaten unserer XOR Texture. Das Ergebniss speichern wir in unsererm Array aBuffer, welches wir zuvor noch zu unserem Code hinzufügen müssen! Wir könnten nun in unserem aBuffer weitere Manipulationen vornehmen oder das Ergebniss wie in der nächsten Zeile zu sehen ist, mit Plot() auf den Bildschirm darstellen lassen.
Der komplette Sourcecode würde nun wie folgt aussehen und wir würdeb beim ausführen des Sources ein Standbild des TunnelEffektes erhalten..Code: Select all
aBuffer(x,y) = aTexture (aDistance(x,y), aAngle(x,y)) Plot(x, y, aBuffer(x,y) )
Um unseren Tunnel nun zu animieren, werden wir diesen drehen lassen und dabei in den Tunnel hineinfliegen. Hierzu benötigen wir die Variablen dSpeedX.d und SpeedY.d, um die Geschwindigkeit für die X und Y Bewegung des Tunnels zu defininieren. Desweiteren benötigen wir im Innerloop die Variablen lShiftX.l und lShiftY.l, um die entsprechenden Bewegungen in den Tabellen zu berechnen und später auszulesen. In unserem Beipspiel werden wir für die Animation die Variable dAnimation.d nehmen, welche wir pro Loop um 0.005 erhöhen! (Anmerkung: Bitte für eigene Projekte mit DeltaTimes arbeiten, damit der Effekt auf jeden Rechner gleich schnell läuft!).Code: Select all
Listing: Part5_FirstTunnel.pb
Nun haben wir alle wichtigen Berechnungen vorgenommen, damit der Tunnel animiert werden kann. Um nicht wieder wie zuvor nur ein Standbild zu erhalten, müssen wir bei der Darstellung des Tunnels folgende Zeilen hinzufügen bzw abändern.Code: Select all
dAnimation.d = dAnimation.d + 0.005 If dAnimation.d >= 1.0 : dAnimation = 0.0 : EndIf lShiftX.l = Int(lTextureSize * dSpeedX.d * dAnimation.d) lShiftY.l = Int(lTextureSize * dSpeedY.d * dAnimation.d)
Der komplette Sourcecode für einen komplett animierten Tunnel, würde nun wie folgt aussehen:Code: Select all
lCoordinateX.l = (aDistance(x,y) + lShiftX) % lTextureSize lCoordinateY.l = (aAngle(x,y) + lShiftY) % lTextureSize aBuffer(x,y) = aTexture (lCoordinateX.l , lCoordinateY.l) Plot(x, y, RGB(0, 0, aBuffer(x,y) ))
An dieser Stelle sind wir nun bei unseren animierten Tunnel angelangt. Leider wirkt das ganze auf eine Art doch noch ein etwas langweilig. Um unseren aktuellenCode: Select all
Listing: Part6_AnimateTunnel.pb
animierten Tunnel noch ein wenig aufzumotzen und interessanter wirken zu lassen, werden wir ein paar kleine Änderungen vornehmen. Dabei werden wir den
eigentichen Tunnel tanzen (bzw bewegen) lassen. Es ensteht der Eindruck, als würde man die Kamera im Tunnel bewegen
Da unserer Tunnel nur auf Tables und nicht auf echtes 3D basiert, werden sich nun sicher einige Fragen, wie man den Effekt mit der Kamera umsetzen will. Wir werden hierfür einen absolut einfachen und zugleich fiesen Trick verwenden. Unser Bildschirm und unserer aDistance und aAngle Tables sind alle für 640x480 ausgelegt. Wir werden nun die Breite und Höhe der Tables aDistance und aAngle verdoppeln, um später immer nur den gewünschten Ausschnitt auf den Bildschirm darzustellen.
Bei den Berechnungen unserer aDistance und aAngle Tables, haben wir bisher z.B. immer "lScreenWidth / 2" (geteilt durch 2) gerechnet, da lScreenWidth mit der Größe von aDistance und aAngle waren. Da wir aber nun die Größe von aDistance und aAngle verdoppelt haben, brauchen wir bei der Berechnung dieser Tabellen nicht mehr "/ 2" (geteilt durch 2) rechnen!! Vorsicht!Code: Select all
Dim aDistance (lScreenWidth*2, lScreenHeight*2) Dim aAngle (lScreenWidth*2, lScreenHeight*2)
Um unseren Tunnel nun schön tanzen zu lassen, verwenden wir einfach SIN() und fügen die Variablen lLookX und lLookY hinzu. Dafür werden folgende Zeilen geändert:
Bei der Darstellung des Tunnels müssen wir nun selbstverständlich die Werte lLookX und lLookY berücksichtigen. Dafür ändern wir den Code wie folgt ab:Code: Select all
lLookX = lScreenWidth /2 + Int(lScreenWidth /2 * Sin(dAnimation * 4.0 )) lLookY = lScreenHeight/2 + Int(lScreenHeight/2 * Sin(dAnimation * 6.0 ))
Wenn jetzt keine Fehler unterlaufen sind, sollten wir nun einen schönen texturierten und animierten Tunnel haben, dessen Kameraposition sich ständig zu verändern scheint. Hier nun nochmal der komplette Sourcecode:Code: Select all
lCoordinateX.l = (aDistance(x+lLookX, y+lLookY) + lShiftX) % lTextureSize lCoordinateY.l = (aAngle (x+lLookX, y+lLookY) + lShiftY) % lTextureSize
Ich hoffe, das dieses Tutorial halbwegs verständlich gestaltet ist und den einen oder anderen gefällt. Viel Spaß, Thorsten Will aka va!n.Code: Select all
Listing: Part7_MovingTunnel.pb
Sources and Tutorial (c) by Thorsten Will aka va!n
All rights reserved.
English Article Version (thanks to Jim)
Hello and cordially welcomely in the miracle world of the so-called table-based demo effects. What are table-based demo effects and why are tables used for this? Many older demo effects such as tunnel, Sphere, BumpMap etc. are often only 3D fakes and are based on pre-computed 2D data, which are stored for later use in tables (arrays). Since the data are pre-computed, we do not need to compute them later in the main loop in real time again and again again. Thereby we save some computations and can often increase the performance of the individual effect.
Today we will look at the step-by-step basics for the programming of a tunnel effect.
What do we need to know about our first tunnel effect and how it functions? The tunnel effect actually consists of three important elements. On one hand we have the Texture, which we later map on to our tunnel. For the Texture we will compute our own 256x256 - so-called XOR - Texture. Of course we could use a 256x256 “tileable” Texture also simply by drawing points, lines or circles on our Texture - or we could even use a BMP.
Now we will compute our first XOR Texture, in which we provide a 256x256 image and store it on the hard disk under "c:\TunnelFx _Texture.bmp".Furthermore we need two large textures (Distance and Angle), which correspond to our screen size of 640x480. If we imagine the view is a round tunnel, then we could compare this with a tube, which consists of many rings and which rings with increasing Distance become ever smaller. We will generate now an appropriate “Distance Texture” and will likewise store these as BMP. To get an idea what it looks like, you can open the “Distance Texture” BMP in an image viewer.Code: Select all
Listing: Part1_Texture.pb
Now we've generated the “Distance Texture”, we need the so-called “Angle Texture”. To wrap the Texture around our XOR Texture in the tunnel correctly and among other things to let our tunnel rotate. The “Distance Texture” is needed among other things, in order to make the tunnerl fly.Code: Select all
Listing: Part2_Distance.pb
So far we have become acquainted with the three most important elements for a tunnel effect and their respective routines, whose results we've represented on a bitmap and stored as BMP. Now we will store the computed data directly the arrays “aTexture”, “aDistance” and “aAngle” and will join together the individual routines of Part1-Part3 with a little optimisation. In the source code of Part1 we provide our 256x256 XOR Texture, with which we let the x and y loop from 0 to 255. We leave this unchanged, however because the same loops for computing the “Distance Table” and “fish Table” we put the code for them in the same loop as the XOR Texture. Therefore we can combine these two routines without problems and now it's time to work on the pre-calculation savings and smaller code.Code: Select all
Listing: Part3_Angle.pb
We will now apply what we've learned the so far. We will open a screen and will draw the first output of our tunnel to the screen. In order to read the program code more simply, we will use the Plot() function and not direct screen access. With our “aDistance” and “aAngle” arrays we can now easily draw a tunnel. Thus now together we use these two tables in the inner loop to select the appropriate X and Y coordinates of our 256x256 XOR Texture. Once we've done that we can put the value in the aBuffer, which we still have to add to our code! We could now make further manipulations on the output to the output before we write it to the screen using Plot().Code: Select all
Listing: Part4_MergingStuff.pb
The complete source code would now look as follows which will show us a fixed image of the tunnel effect .Code: Select all
aBuffer (x, y) = aTexture (aDistance (x, y), aAngle (x, y)) Plot (x, y, aBuffer (x, y))
We're going to animate our tunnel now, and make it look like we're flying into it. For this we need the variables dSpeedX.d and dSpeedY.d, which are the speed for the X and Y movement around those axes. Furthermore we need the variables in the inside loop lShiftX.l and lShiftY.l, in order to compute and later pick the appropriate movements from the arrays. In our example we will take the variable dAnimation.d, which we increase per loop by 0.005 for the animation! (Note: For your own projects, work with delta timing, so the effect on each computer runs correctly!).Code: Select all
Listing: Part5_FirstTunnel.pb
Now we have made all important computations, so that the tunnel can be animated. In order not to just get one fixed image, we must add and/or change the following lines during the representation of the tunnel.Code: Select all
dAnimation.d = dAnimation.d + 0.005 If dAnimation.d >= 1.0 : dAnimation = 0.0 : EndIf lShiftX.l = Int(lTextureSize * dSpeedX.d * dAnimation.d) lShiftY.l = Int(lTextureSize * dSpeedY.d * dAnimation.d)
The complete source code for a completely animated tunnel, would look as follows:Code: Select all
lCoordinateX.l = (aDistance(x,y) + lShiftX) % lTextureSize lCoordinateY.l = (aAngle(x,y) + lShiftY) % lTextureSize aBuffer(x,y) = aTexture (lCoordinateX.l , lCoordinateY.l) Plot(x, y, RGB(0, 0, aBuffer(x,y) ))
Here we have animated tunnel. Unfortunately the whole effect is somewhat nevertheless still boring. In order to make our current animated tunnel still more funky and more interesting, we can make a few small changes. We will make tunnel to move up and down to give the impresson of the camera moving in the tunnelCode: Select all
Listing: Part6_AnimateTunnel.pb
Since our tunnel's only made from arrays and not from genuine 3D, some questions become now need to be asked as one wants to convert the effect with the camera. We will use for this an absolutely simple and at the same time safe trick. As our aDistance and aAngle arrays are suitable only for a screen of 640x480, we will double now the width and height of the them, in order to represent in each case the desired section later on the screen.
With the computations our, we so far e.g. always counted aDistance and aAngle Tables “lScreenWidth/2” (divided by 2), since lScreenWidth was the size of aDistance and aAngle. However since we've now doubled the size of aDistance and aAngle, we do not need to "/ 2" (divided by 2) with the computation of these tables any longer!! Caution! In order to let our tunnel dance beautifully now, we use simply SIN () and add the variables lLookX and lLookY. The following lines are changed:Code: Select all
Dim aDistance (lScreenWidth*2, lScreenHeight*2) Dim aAngle (lScreenWidth*2, lScreenHeight*2)
During the drawing of the tunnel we must now change the values lLookX and lLookY to make it look natural. We change the code as follows:Code: Select all
lLookX = lScreenWidth /2 + Int(lScreenWidth /2 * Sin(dAnimation * 4.0 )) lLookY = lScreenHeight/2 + Int(lScreenHeight/2 * Sin(dAnimation * 6.0 ))
If we haven't made any mistakes now, we should have now a beautiful texturemapped and animated tunnel, whose camera position seems to constantly change. Here now again is the complete source code:Code: Select all
lCoordinateX.l = (aDistance(x+lLookX, y+lLookY) + lShiftX) % lTextureSize lCoordinateY.l = (aAngle (x+lLookX, y+lLookY) + lShiftY) % lTextureSize
I hope you and others enjoy this tutorial,Code: Select all
Listing: Part7_MovingTunnel.pb
Much fun, Thorsten Will aka va! n.
Part1_Texture.pb
Code: Select all
; *************************************************************************************
; * P r o j e c t : T u n n e l - F x
; *************************************************************************************
; *
; * Part1: Creating Mapping Texture:
; * --------------------------------
; * This small example shows you, how to create an easy XOR 256x256 sized texture.
; * We will use this texture later for texturemapping of our tunnel. Ofcourse you
; * can use any other created or loaded tileable texture too :)
; *
; * Source and Tutorial (c) by Thorsten Will aka va!n
; * All rights reserved.
; *
; *************************************************************************************
lTextureSize.l = 256
CreateImage (0, lTextureSize, lTextureSize)
; -------- Generating Mapping Texture --------
StartDrawing(ImageOutput(0))
For y.l = 0 To lTextureSize -1
For x.l = 0 To lTextureSize -1
lColor.l = (x * 256 / lTextureSize) ! (y * 256 / lTextureSize)
Plot (x, y, RGB( 0, 0, lColor.l) )
Next
Next
StopDrawing()
; -------- Saving Texture --------
SaveImage (0, "c:\TunnelFx_Texture.bmp")
End
; *************************************************************************************
Part2_Distance.pb
Code: Select all
; *************************************************************************************
; * P r o j e c t : T u n n e l - F x
; *************************************************************************************
; *
; * Part2: Creating Distance Table / Texture:
; * -----------------------------------------
; * This small example shows you, how to to create the needed distance table and how
; * does this looks like for doing the flying trip into our tunnel.
; *
; * Source and Tutorial (c) by Thorsten Will aka va!n
; * All rights reserved.
; *
; *************************************************************************************
lTextureSize.l = 256
lScreenWidth.l = 640
lScreenHeight.l = 480
CreateImage (0, lScreenWidth, lScreenHeight)
; -------- Generating Distance Table / Texture --------
StartDrawing(ImageOutput(0))
dDistance.d = 32.0
For x = 0 To lScreenWidth -1
For y = 0 To lScreenHeight -1
lColor.l = Int(dDistance * lTextureSize / Sqr( (x-lScreenWidth/2) * (x-lScreenWidth/2) + (y-lScreenHeight/2) * (y-lScreenHeight/2) )) % lTextureSize
Plot (x, y, RGB(lColor, lColor, lColor) )
Next
Next
StopDrawing()
; -------- Saving Table as Texture --------
SaveImage (0, "c:\TunnelFx_Distance.bmp")
End
; *************************************************************************************
Part3_Angle.pb
Code: Select all
; *************************************************************************************
; * P r o j e c t : T u n n e l - F x
; *************************************************************************************
; *
; * Part3: Creating Angle Table / Texture:
; * --------------------------------------
; * This small example shows you, how to to create the needed angle table and how
; * does this looks like for doing the rotations of our tunnel. Dont forget to enable
; * inline assembler. Otherwise as you see, you will see nothing. :D
; *
; * Source and Tutorial (c) by Thorsten Will aka va!n
; * All rigths reserved.
; *
; *************************************************************************************
Procedure.d ATan2(y.d, x.d)
!FLD qword[p.v_y]
!FLD qword[p.v_x]
!FPATAN
ProcedureReturn
EndProcedure
; -------- Init Code --------
lTextureSize.l = 256
lScreenWidth.l = 640
lScreenHeight.l = 480
CreateImage (0, lScreenWidth, lScreenHeight)
; -------- Generating Angle Table / Texture --------
StartDrawing(ImageOutput(0))
dParts.d = 0.5
For x = 0 To lScreenWidth -1
For y = 0 To lScreenHeight -1
dAngle.d = (dParts * lTextureSize * ATan2(y-lScreenHeight/2, x-lScreenWidth/2) / #PI)
lColor = Int (256 - dAngle) & 255
Plot (x, y, RGB(lColor, lColor, lColor) )
Next
Next
StopDrawing()
; -------- Saving Table as Texture --------
SaveImage (0, "c:\TunnelFx_Angle.bmp")
End
; *************************************************************************************
Part4_MergingStuff.pb
Code: Select all
; *************************************************************************************
; * P r o j e c t : T u n n e l - F x
; *************************************************************************************
; *
; * Part4: Merging routines from Part1-Part3 into two single loops:
; * ---------------------------------------------------------------
; * Now we are going to optimize our stuff from Part1-Part3 while merging Part2 and
; * Part3 into just a single loop and storing the data from Part1-Part3 directly into
; * our defined arrays. Merging Part2 with Part3 will reduce the generated ASM output
; * and increase the speed of our table pre-generation.
; *
; * Source and Tutorial (c) by Thorsten Will aka va!n
; * All rights reserved.
; *
; *************************************************************************************
Procedure.d ATan2(y.d, x.d)
!FLD qword[p.v_y]
!FLD qword[p.v_x]
!FPATAN
ProcedureReturn
EndProcedure
; -------- Init Code --------
lTextureSize.l = 256
lScreenWidth.l = 640
lScreenHeight.l = 480
Dim aTexture (lTextureSize, lTextureSize)
Dim aDistance (lScreenWidth, lScreenHeight)
Dim aAngle (lScreenWidth, lScreenHeight)
; -------- Generating Mapping Texture --------
For x.l = 0 To lTextureSize -1
For y.l = 0 To lTextureSize -1
aTexture(x,y) = (x * 256 / lTextureSize) ! (y * 256 / lTextureSize)
Next
Next
; -------- Generating Distance and Angle Table --------
dDistance.d = 32.0
dParts.d = 0.5
For x = 0 To lScreenWidth -1
For y = 0 To lScreenHeight -1
aDistance(x,y) = Int(dDistance * lTextureSize / Sqr( (x-lScreenWidth/2) * (x-lScreenWidth/2) + (y-lScreenHeight/2) * (y-lScreenHeight/2) )) % lTextureSize
dAngle.d = (dParts * lTextureSize * ATan2(y-lScreenHeight/2, x-lScreenWidth/2) / #PI)
aAngle(x,y) = Int (256 - dAngle) & 255
Next
Next
; *************************************************************************************
Part5_FirstTunnel.pb
Code: Select all
; *************************************************************************************
; * P r o j e c t : T u n n e l - F x
; *************************************************************************************
; *
; * Part5: Showing our first tunnel:
; * --------------------------------
; * As we learned in the first three basic tutorials, we need one texture and two
; * table based datas (aDistance and aAngle), also two images to produce our tunnel
; * like effect. Now we will try to merge this knowledge to produce our first tunnel
; * like effect in real on our screen :) Dont forget to enable inline ASM.
; *
; * Source and Tutorial (c) by Thorsten Will aka va!n
; * All rights reserved.
; *
; *************************************************************************************
Procedure.d ATan2(y.d, x.d)
!FLD qword[p.v_y]
!FLD qword[p.v_x]
!FPATAN
ProcedureReturn
EndProcedure
; -------- Init Code --------
lTextureSize.l = 256
lScreenWidth.l = 640
lScreenHeight.l = 480
Dim aTexture (lTextureSize, lTextureSize)
Dim aDistance (lScreenWidth, lScreenHeight)
Dim aAngle (lScreenWidth, lScreenHeight)
Dim aBuffer (lScreenWidth, lScreenHeight)
; -------- Generating Mapping Texture --------
For x.l = 0 To lTextureSize -1
For y.l = 0 To lTextureSize -1
aTexture(x,y) = (x * 256 / lTextureSize) ! (y * 256 / lTextureSize)
Next
Next
; -------- Generating Distance and Angle Table --------
dDistance.d = 32.0
dParts.d = 0.5
For x = 0 To lScreenWidth -1
For y = 0 To lScreenHeight -1
aDistance(x,y) = Int(dDistance * lTextureSize / Sqr( (x-lScreenWidth/2) * (x-lScreenWidth/2) + (y-lScreenHeight/2) * (y-lScreenHeight/2) )) % lTextureSize
dAngle.d = (dParts * lTextureSize * ATan2(y-lScreenHeight/2, x-lScreenWidth/2) / #PI)
aAngle(x,y) = Int (256 - dAngle) & 255
Next
Next
; *************************************************************************************
InitSprite()
OpenScreen(lScreenWidth, lScreenHeight, 32, "TunnelFx Tutorial")
Repeat
; -------- Calculate Texture coordinates and draw Tunnel -------
StartDrawing(ScreenOutput())
For x = 0 To lScreenWidth -1
For y = 0 To lScreenHeight-1
aBuffer(x,y) = aTexture (aDistance(x,y), aAngle(x,y))
Plot(x, y, RGB(0, 0, aBuffer(x,y) ))
Next
Next
StopDrawing()
FlipBuffers(2)
Until GetAsyncKeyState_(#VK_ESCAPE)
; *************************************************************************************
Part6_AnimateTunnel.pb
Code: Select all
; *************************************************************************************
; * P r o j e c t : T u n n e l - F x
; *************************************************************************************
; *
; * Part6: Lets animate the tunnel:
; * -------------------------------
; * After turorial part5, we will try to alive the tunnel and animate it a litte bit.
; *
; * Source and Tutorial (c) by Thorsten Will aka va!n
; * All rights reserved.
; *
; *************************************************************************************
Procedure.d ATan2(y.d, x.d)
!FLD qword[p.v_y]
!FLD qword[p.v_x]
!FPATAN
ProcedureReturn
EndProcedure
; -------- Init Code --------
lTextureSize.l = 256
lScreenWidth.l = 640
lScreenHeight.l = 480
Dim aTexture (lTextureSize, lTextureSize)
Dim aDistance (lScreenWidth, lScreenHeight)
Dim aAngle (lScreenWidth, lScreenHeight)
Dim aBuffer (lScreenWidth, lScreenHeight)
; -------- Generating Mapping Texture --------
For x.l = 0 To lTextureSize -1
For y.l = 0 To lTextureSize -1
aTexture(x,y) = (x * 256 / lTextureSize) ! (y * 256 / lTextureSize)
Next
Next
; -------- Generating Distance and Angle Table --------
dDistance.d = 32.0
dParts.d = 0.5
For x = 0 To lScreenWidth -1
For y = 0 To lScreenHeight -1
aDistance(x,y) = Int(dDistance * lTextureSize / Sqr( (x-lScreenWidth/2) * (x-lScreenWidth/2) + (y-lScreenHeight/2) * (y-lScreenHeight/2) )) % lTextureSize
dAngle.d = (dParts * lTextureSize * ATan2(y-lScreenHeight/2, x-lScreenWidth/2) / #PI)
aAngle(x,y) = Int (256 - dAngle) & 255
Next
Next
; *************************************************************************************
InitSprite()
OpenScreen(lScreenWidth, lScreenHeight, 32, "TunnelFx Tutorial")
dSpeedX.d = 2.0
dSpeedY.d = 2.0
Repeat
; ------- Stuff for doing the animation -------
dAnimation.d = dAnimation.d + 0.005 ; timeGetTime_() / 1000
If dAnimation.d >= 1.0 : dAnimation = 0.0 : EndIf
lShiftX.l = Int(lTextureSize * dSpeedX.d * dAnimation.d)
lShiftY.l = Int(lTextureSize * dSpeedY.d * dAnimation.d)
; -------- Calculate Texture coordinates and draw Tunnel -------
StartDrawing(ScreenOutput())
For x = 0 To lScreenWidth -1
For y = 0 To lScreenHeight-1
lCoordinateX.l = (aDistance(x,y) + lShiftX) % lTextureSize
lCoordinateY.l = (aAngle(x,y) + lShiftY) % lTextureSize
aBuffer(x,y) = aTexture (lCoordinateX.l , lCoordinateY.l)
Plot(x, y, RGB(0, 0, aBuffer(x,y) ))
Next
Next
StopDrawing()
FlipBuffers(1)
Until GetAsyncKeyState_(#VK_ESCAPE)
; *************************************************************************************
Part7_MovingTunnel.pb
Code: Select all
; *************************************************************************************
; * P r o j e c t : T u n n e l - F x
; *************************************************************************************
; *
; * Part7: Moving Tunnel:
; * ---------------------
; * This is the last turorial part, where we will try to get the tunnel fx more
; * interesting while moving the tunnel, by using SIN().
; *
; * Source and Tutorial (c) by Thorsten Will aka va!n
; * All rights reserved.
; *
; *************************************************************************************
Procedure.d ATan2(y.d, x.d)
!FLD qword[p.v_y]
!FLD qword[p.v_x]
!FPATAN
ProcedureReturn
EndProcedure
; -------- Init Code --------
lTextureSize.l = 256
lScreenWidth.l = 640
lScreenHeight.l = 480
Dim aTexture (lTextureSize , lTextureSize )
Dim aDistance (lScreenWidth*2, lScreenHeight*2)
Dim aAngle (lScreenWidth*2, lScreenHeight*2)
Dim aBuffer (lScreenWidth , lScreenHeight )
; -------- Generating Mapping Texture --------
For x.l = 0 To lTextureSize -1
For y.l = 0 To lTextureSize -1
aTexture(x,y) = (x * 256 / lTextureSize) ! (y * 256 / lTextureSize)
Next
Next
; -------- Generating Distance and Angle Table --------
dDistance.d = 32.0
dParts.d = 0.5
For x = 0 To lScreenWidth*2 -1
For y = 0 To lScreenHeight*2 -1
aDistance(x,y) = Int(dDistance * lTextureSize / Sqr( (x-lScreenWidth) * (x-lScreenWidth) + (y-lScreenHeight) * (y-lScreenHeight) )) % lTextureSize
dAngle.d = (dParts * lTextureSize * ATan2(y-lScreenHeight, x-lScreenWidth) / #PI)
aAngle(x,y) = Int (256 - dAngle) & 255
Next
Next
; *************************************************************************************
InitSprite()
OpenScreen(lScreenWidth, lScreenHeight, 32, "TunnelFx Tutorial")
dSpeedX.d = 2.0
dSpeedY.d = 2.0
Repeat
; ------- Stuff for doing the animation -------
dAnimation.d = dAnimation.d + 0.005
lShiftX.l = Int(lTextureSize * dSpeedX.d * dAnimation.d)
lShiftY.l = Int(lTextureSize * dSpeedY.d * dAnimation.d)
lLookX = lScreenWidth /2 + Int(lScreenWidth /2 * Sin(dAnimation * 4.0 ))
lLookY = lScreenHeight/2 + Int(lScreenHeight/2 * Sin(dAnimation * 6.0 ))
; -------- Calculate Texture coordinates and draw Tunnel -------
StartDrawing(ScreenOutput())
For y = 0 To lScreenHeight-1
For x = 0 To lScreenWidth -1
lCoordinateX.l = (aDistance(x+lLookX, y+lLookY) + lShiftX) % lTextureSize
lCoordinateY.l = (aAngle (x+lLookX, y+lLookY) + lShiftY) % lTextureSize
aBuffer(x,y) = aTexture (lCoordinateX.l , lCoordinateY.l)
Plot(x, y, RGB(0, 0, aBuffer(x,y) ))
Next
Next
StopDrawing()
FlipBuffers(1)
Until GetAsyncKeyState_(#VK_ESCAPE)
; *************************************************************************************
Have phun... if you have any optimisation ideas or better ways to do this, let me know...