Ye olde water algorithm Mk. 2 by Tinkerer10th May 2005 23:48
|
---|
Summary An old and well-known water effect, plus quick and dirty normals calculation. Description Quick and dirty normals calculation used to illuminate the matrix from three light sources. Spacebar selects matrix behaviour, mouse2 selects interference type, and mouse1 affects interference amount. Code ` This code was downloaded from The Game Creators ` It is reproduced here with full permission ` http://www.thegamecreators.com rem Set sync up. sync on : sync rate 30 rem Hide the mouse pointer. hide mouse rem Declare the two arrays that will be used to hold height information. dim imgbuffer1(1024, 1024) AS FLOAT dim imgbuffer2(1024, 1024) AS FLOAT rem Make this as big as your system can handle! gridsize = 128 rem This value determines how large the matrix will be rendered. gridmultiplier = 8 rem Fill the arrays with zeros. for z = 0 to gridsize + 1 for x = 0 to gridsize + 1 imgbuffer1(x, z) = 0.0 imgbuffer2(x, z) = 0.0 next x next z rem Create a set of vectors that will be used to calculate the normal of rem each matrix tile. for vc = 1 to 6 rtmp = make vector3(vc) set vector3 vc, 0.0, 0.0, 0.0 next vc rem Determine where the middle of the matrix will be middle = gridsize / 2 rem Set this to a value BELOW ZERO. Or don't and enjoy the fireworks. rem 0.90 to 0.99 are "sensible" values. damping AS FLOAT damping = 0.96 rem Making this higher will slow the wave frequency of the mouse+sine effect. wavefreq AS FLOAT wavefreq = 2 rem Adjusting these two variables will determine how much mouse button 1 affects rem the interference generators. lowheight = 10 highheight = 100 rem You can customize your own water behaviour using the above three variables together rem The current pattern value is stored here pattern AS INTEGER pattern = 0 rem The current algorithm (water or mousepad foam) mtype = 0 rem The next two variables are used together to stop the pattern changing in a loop when rem mouse 2 is held down. clik AS INTEGER clik = 0 lastclik AS INTEGER lastclik = 0 rem The next two variables are used together to stop the matrix behaviour changing in a rem loop when the spacebar is held down. lastspace = 0 space = 0 rem A temporary variable. Used later on. tmp AS FLOAT rem Current mouse position and mouse+sine wave generator height go here. mouseposx AS INTEGER mouseposz AS INTEGER waveheight AS INTEGER waveheight = lowheight rem Load matrix texture here. MImg = 1 : load image "wtex2.jpg", MImg rem Calculate matrix size and place in these two variables. matrixsize AS FLOAT matrixsize = gridsize * gridmultiplier matrixmiddle AS FLOAT matrixmiddle = matrixsize / 2.0 rem Declare and set the matrix here. MObj = 1 : make matrix MObj, matrixsize, matrixsize, gridsize, gridsize prepare matrix texture MObj, MImg, 1,1 rem Set the initial position of the camera here. position camera 0,(sin(timer() / 100.0) * 100.0) + matrixsize,300.0,(cos(timer() / 110.0) * 100.0) + matrixsize rem Define a light to follow the camera. CLight = 1 : make light CLight set point light CLight, 0, 0, 0 color light CLight, 0, 255, 0 set light range CLight, 1500 rem Define two lights to roam around. RLighta = 2 : make light RLighta set point light RLighta, 0, 0, 0 color light RLighta, 255, 0, 0 set light range RLighta, 1500 RLightb = 3 : make light RLightb set point light RLightb, 0, 0, 0 color light RLightb, 0, 0, 255 set light range RLightb, 1500 rem Hide the default light. hide light 0 rem Main loop. do rem Get the new mouse position. mouseposx = mouseposx + (mousemovex() / 5) mouseposz = mouseposz + -(mousemovey() / 5) rem Limit the mouse position to valid array indices. if mouseposx > gridsize then mouseposx = gridsize if mouseposz > gridsize then mouseposz = gridsize if mouseposx < 1 then mouseposx = 1 if mouseposz < 1 then mouseposz = 1 rem Move the camera around slowly. position camera 0,matrixmiddle - (sin(timer() / 100.0) * 200.0),300.0,(cos(timer() / 110.0) * 100.0) point camera matrixmiddle,-300,matrixmiddle rem Reposition any moving lights here. position light CLight, camera position x(), camera position y(), camera position z() position light RLighta, matrixmiddle - (cos(timer() / 40.0) * 200.0),100.0, matrixmiddle + (sin(timer() / 110.0) * 100.0) position light RLightb, matrixmiddle - (sin(timer() / 100.0) * 200.0),100.0, matrixmiddle + (cos(timer() / 40.0) * 100.0) rem Calculate current wave generator values. sinfreq = timer() / wavefreq sincalc = sin(sinfreq) * waveheight coscalc = cos(sinfreq) * waveheight rem Capture mouse values and change pattern and waveheight values accordingly. lastclik = clik clik = mouseclick() if clik <> lastclik select clik case 0 waveheight = lowheight endcase case 1 waveheight = highheight endcase case 2 waveheight = lowheight inc pattern endcase case 3 waveheight = highheight inc pattern endcase endselect endif if pattern > 2 then pattern = 0 select pattern case 0 print "Interference type: mouse + sine" imgbuffer1(mouseposx, mouseposz) = imgbuffer1(mouseposx, mouseposz) + sincalc endcase case 1 print "Inteference type: rain" randomize timer() tx = rnd(gridsize - 1) + 1 ty = rnd(gridsize - 1) + 1 imgbuffer1(tx, ty) = imgbuffer1(tx, ty) - waveheight endcase case 2 print "Interference type: none" endcase endselect rem Get the spacebar state. lastspace = space space = spacekey() rem Ignore if state is same as last state. if space <> lastspace if space = 1 inc mtype if mtype > 1 then mtype = 0 endif endif select mtype case 0 print "Matrix behaviour: water" endcase case 1 print "Matrix behaviour: memory foam" endcase endselect remstart This is the place where algorithms are calculated and applied. The first set of embedded loops are for water, the second for a low rebound foam-like behaviour. The third set of loops is used by both behaviours to swap the contents of the two buffers and calculate a simple tile normal detection algorithm. Accuracy of the normals map is traded for execution speed in this script. With a few extra lines of code, an averaged normals map can be created, however this strains an Athlon XP 2000 when rendering a map with a grid size of 128. Remarks left out for speed. remend select mtype case 0 for z = 1 to gridsize for x = 1 to gridsize imgbuffer2(x, z) = (imgbuffer1(x - 1, z) + imgbuffer1(x + 1, z) + imgbuffer1(x, z + 1) + imgbuffer1(x, z - 1)) / 2 - imgbuffer2(x, z) imgbuffer2(x, z) = imgbuffer2(x, z) * damping next x next z endcase case 1 for z = 1 to gridsize for x = 1 to gridsize imgbuffer2(x, z) = imgbuffer1(x, z) * damping next x next z endcase endselect for z = 1 to gridsize for x = 1 to gridsize tmp = imgbuffer1(x, z) imgbuffer1(x, z) = imgbuffer2(x, z) imgbuffer2(x, z) = tmp set matrix height MObj, x, z, imgbuffer2(x, z) set vector3 1,0.0,imgbuffer2(x, z),0.0 set vector3 2,-1.0,imgbuffer2(x - 1, z),0.0 set vector3 3,0.0,imgbuffer2(x, z + 1),1.0 subtract vector3 4, 1, 2 subtract vector3 5, 2, 3 cross product vector3 6, 4, 5 normalize vector3 6, 6 set matrix normal MObj, x, z, x vector3(6), y vector3(6), z vector3(6) next x next z rem done with algorithms. Update matrix with new values. update matrix MObj rem print out a status display. sfps = screen fps() rem mouse pointer values and frames per second. set cursor 0,1 : print "mpx: "; mouseposx; " mpz: "; mouseposz; " fps: "; sfps rem quick polygons per second calculation. pps = statistic(1) * sfps print pps;" polygons per second." rem flip the buffers. sync rem end of main loop. loop rem That's it, folks! end |