dynamic water (b3d port-over)

BlitzMax Modules Forums/MiniB3D/dynamic water (b3d port-over)

I took the source from the codearcs (http://www.blitzbasic.com/codearcs/codearcs.php?code=991) and converted it to bmax using the import bb feature of maxide, and a little handy work.

The only way it will run is using klepto2's extended version (not to mention VERY slowly), under the original it crashes at RenderWorld. I'm posting this because my lack of programming knowledge. If anyone knows why this is so slow or why it crashes with the original minib3d, please, post.

heres a zipped up version: http://files.filefront.com/dynamic+waterrar/;9543932;/fileinfo.html (ORIGINAL)
http://files.filefront.com/dynamic+waterv2zip/;9549915;/fileinfo.html (NEW)



EDIT: SELF ERRROR !!
as i was playing around with it in blitz3d, i changed the demo_water_height and demo_water_depth values, this is what slowed it down. heres the fix
'--- change this:
Global DEMO_WATER_WIDTH	 = 75
Global DEMO_WATER_DEPTH  = 75
'--- to this:
Global DEMO_WATER_WIDTH	 = 40
Global DEMO_WATER_DEPTH  = 40


However, using sidesign.minib3d still crashes at 'RenderWorld.' FIXED

Changed the code a bit to show control info.

Framework brl.max2d
'Import brl.retro
Import brl.timer

Import "bbtype.bmx"
'Import "bbvkey.bmx"

Import klepto.minib3d
'Import sidesign.minib3d

SetGraphicsDriver(GLMax2DDriver(), GRAPHICS_BACKBUFFER | GRAPHICS_DEPTHBUFFER | GRAPHICS_ACCUMBUFFER)

Global fxWaterWave_list:TList=New TList


'Ported to BlitzMax by Plash - 1/30/08


' fxWater Module by Danny van der Ark - dendanny@...
'
' (Heavily) inpired by samples by Reda Borchardt and Rob Cummings.
' use as you like - send me a sample would be cool.
'
' april '04
'

'
' Usage:
'
' 1. Create a water surface using: fxWater_Create( name$, xsize, zsize, dampening#, parent )
'    This function returns the 'type-handle' to the water surface wich you will need later.
'
' 2. Obtain the entity handle (to apply color, texture, alpha, etc) using the function
'	 fxWater_get_entity( typehandle) -> typehandle is the value returned by fxWater_Create()
'
' 3. Then simply call 'fxWater_Update()' every frame during your main loop.
'
'
' 4. To create a splah in the water use the fxWater_Dimple() function. The function needs the
'	 type handle that was returned by 'fxWater_Create', the coordinates of the splash, the
'	 force/strength of the splash and the 'range' or size of the splash.
'
'	 fxWater_Dimple( hand, x,z, force#=1.0, range#=1.0)
'
' 5. Freeing stuff not done yet because I want to alter it to use memory banks in stead of
'	 a large static array to store the vertex data - wich should give a more efficient use
'	 of memory...
'
' You can create as many surfaces of any size as you wish. If you wish surfaces larger than 100x100
' then adjust the fxwater_max_depth/width globals. If you want more than 5 surfaces at the same time
' adjust the fxwater_max accordingly. 
' 
' It is necesary To 'UpdateNormals' every frame to ensure the highlights are re-calculated every
' frame. Without this the ripples are there, but just not visible. This slows things down
' dramatically ofcourse. Any other ideas welcome....
'
' He ho, enjoy!
'
' ooo
' (_) Danny v.d. Ark



Global fxWATER_MAX = 5				'max number of active surfaces/effects at one time
Global fxWATER_NUM = 0				'current number of active water effects.

Global FXWATER_MAX_WIDTH = 100		'max sub-division for water meshes
Global FXWATER_MAX_DEPTH = 100		'max sub-division for water meshes

Global FXWATER_MAX_BANKS = fxWATER_MAX * 2
Global FXWATER_NUM_BANKS = 0


Global DEMO_WATER_WIDTH	 = 40	'--> Adjust these for different plane sizes / mesh resolution
Global DEMO_WATER_DEPTH  = 40


'reserve memory banks for vertice altitudes
Global fxWaterBank#[FXWATER_MAX_BANKS+1, FXWATER_MAX_WIDTH+1, FXWATER_MAX_DEPTH +1]


Type bbfxWaterWave Extends TBBType

	Method New()
		Add(fxWaterWave_list)
	End Method

	Method After:bbfxWaterWave()
		Local t:TLink
		t=_link.NextLink()
		If t Return bbfxWaterWave(t.Value())
	End Method

	Method Before:bbfxWaterWave()
		Local t:TLink
		t=_link.PrevLink()
		If t Return bbfxWaterWave(t.Value())
	End Method


	Field id
	Field name$
	
	Field FXWATER_MAX_WIDTH		'max sub-division for water meshes
	Field FXWATER_MAX_DEPTH
	
	Field active		'if not ripples then fx is not active
	
	Field parent		'parent entity (if any)
	Field entity		'water mesh
	Field surface		'water surface

	Field bank1			'pointers to array for mem storage
	Field bank2

	Field width			'width of plane / surface
	Field depth			'depth of plane / surface
	Field dampening#	'water dynamics

End Type

'Demo options
Global OPT_WIREFRAME = 0
Global OPT_REFRSH 	 = 0
Global OPT_BALLFREEZE= 0
Global OPT_CEILING	 = 1

'--------------------------------------------------------------------------------------------------

'Graphics3D 640,480,32,1
Graphics3D 640,480,0,2

' Camera + Light
Global campivot = CreatePivot()
Global camera = CreateCamera(campivot)

PositionEntity camera, 0, 0, -35
PointEntity camera, campivot

light = CreateLight(2)
PositionEntity light,-60,0,100
LightColor light,240,240,210
PointEntity light, campivot

light = CreateLight(2)
PositionEntity light,50,0,-50
LightColor light,150,150,180
PointEntity light, campivot

AmbientLight 40,40,40

'load texture
tex = LoadTexture ("water.bmp",1+64)
'tex = create_noise_map()

'create water planes
Global w1 = fxWater_Create( "floor",  DEMO_WATER_WIDTH, DEMO_WATER_DEPTH, 0.025 )
water = fxWater_get_entity( w1 )
PositionEntity water, 0, -10, 0
EntityColor water, 30,50,200
EntityShininess water, 0.1
EntityTexture water,tex

Global w2 = fxWater_Create( "ceiling",  DEMO_WATER_WIDTH, DEMO_WATER_DEPTH, 0.025 )
water = fxWater_get_entity( w2 )
FlipMesh water ' flip it because the camera is underneath it
PositionEntity water, 0, 10, 0
EntityColor water, 250,100,100
EntityColor water, 140,130,20
EntityShininess water, 0.1
EntityTexture water,tex

'force refresh
fxWater_dimple( w1, 1,1, 0.001, 0.001)
fxWater_dimple( w2, 1,1, 0.001, 0.001)

'set random ball direction/speed
Global bx#=  0.2
Global by#= -1.75
Global bz#= -0.25

Global bmaxx# =  DEMO_WATER_WIDTH * 0.5	'half the width of the water plane
Global bmaxy# = 10.0
Global bmaxz# =  DEMO_WATER_DEPTH * 0.5	'half the depth of the water plane

'create ball
ball = CreateSphere(6)
EntityColor ball, 0,0,0
EntityShininess ball, 1.0
EntityTexture ball, tex

SeedRnd MilliSecs()

' Main Loop
tstart = MilliSecs() + 1000
frame = 0

Global lastx# = 0
Global lasty# = 0
Global bb_list = 0

tim = CreateTimer(50)

Local l:String = "WavyWaterFx by Danny van der Ark"

While Not KeyHit(key_escape)

	'update bouncing ball
	update_ball( ball )
	
	'update fxWater
	fxWater_update()
	
	'render
	'UpdateWorld
	'RenderWorld

	'debug

	'orbit camera
	'TurnEntity campivot, 0, 0.25, 0

	'check fps
	frame = frame + 1
	If MilliSecs() >= tstart Then
		fps = frame
		frame = 0
		tstart = MilliSecs() + 1000
	EndIf

	'toggle ceiling [C]
	If KeyHit(key_c) Then
		OPT_CEILING = 1 - OPT_CEILING
		If OPT_CEILING Then
			water = fxWater_Get_Entity(w2)
			ShowEntity water
		Else
			water = fxWater_Get_Entity(w2)
			HideEntity water
		EndIf
	EndIf
	
	'pause all [P]
	If KeyHit(key_p) Then
		FlushKeys
		While Not KeyHit(key_p) Wend
	EndIf

	'pause ball [B]
	If KeyHit(key_b) Then
		OPT_BALLFREEZE = 1 - OPT_BALLFREEZE
		If OPT_BALLFREEZE Then
			PositionEntity ball, 0,0,0
			bx# = 0
			by# = 0
			bz# = 0
		Else
			bx#=Rnd(-1,1)
			by#=Rnd(-2,2)
			bz#=Rnd(-1,1)
		EndIf
	EndIf

	'wireframe [W]
	If KeyHit(key_w) Then
		OPT_WIREFRAME = 1 - OPT_WIREFRAME
		Wireframe OPT_WIREFRAME
	EndIf
	
	'Dirty refresh [D]
	If KeyHit(key_d) Then
		OPT_REFRESH = 1 - OPT_REFRESH
	EndIf	
	
	UpdateWorld
	RenderWorld
	
	  'Rem
		TGlobal.BeginMax2D
		  SetBlend alphablend
		   	SetAlpha 0.5
			SetColor 100, 100, 100
			DrawText "based on samples from Reda Borchardt And Rob Cummings.", 2, 12
			SetColor 20, 140, 255
			DrawText "[ESC] to quit - [D] for fast but dirty refresh(" + OPT_REFRESH + ") - [W] To toggle WireFrame (" + OPT_WIREFRAME + ")", 2, 454
			DrawText "[P] To pause  - [B] to pause/reset ball - [C] to toggle ceiling", 2, 466
			SetColor 250, 250, 220
			DrawText "FPS  " + fps, 10, 220
			DrawText "TRIS " + TrisRendered(), 10, 232
		  SetBlend solidblend
		TGlobal.EndMax2D
	  'EndRem
	
	'check refresh mode
	If OPT_REFRESH Then
		'fast and dirty (pot noodle style)
	    Flip False
	Else
		'slow but clean
		Flip True
		WaitTimer(tim)
	EndIf

	If MouseHit(1) Then
		x = Rnd(1,DEMO_WATER_WIDTH)
		z = Rnd(1,DEMO_WATER_DEPTH)
		fxWater_Dimple( w1, x, z, 1, 5)
	EndIf
Wend

End

'--------------------------------------------------------------------------------------------------

Function update_ball( ent )

	'move the ball
	TranslateEntity ent, bx,by,bz

	DoDimple = False
	
	'check left/right walls
	If EntityX#(ent) >  bmaxx-2 Then bx# = bx# * -1
	If EntityX#(ent) < -bmaxx+2 Then bx# = bx# * -1

	'check ceiling bounce
	If EntityY#(ent) >  bmaxy-2 Then
		'reverse vertical direction
		by# = by# * -1.0
		'create dimple
		fxWater_Dimple(w2, EntityX(ent)+bmaxx,EntityZ(ent)+bmaxz, -1.0, 5.0)
		'slightly alter direction
		bx# = bx# + Rnd(-0.25, 0.25)
		bz# = bz# + Rnd(-0.25, 0.25)
	EndIf

	'check floor bounce
	If EntityY#(ent) < -bmaxy+2 Then
		'reverse vertical direction
		by# = by# * -1.0
		'create dimple
		fxWater_Dimple(w1, EntityX(ent)+bmaxx,EntityZ(ent)+bmaxz, 1.0, 2.0)
		'slightly alter direction
		bx# = bx# + Rnd(-0.25, 0.25)
		bz# = bz# + Rnd(-0.25, 0.25)
	EndIf

	'check front/back walls
	If EntityZ#(ent) >  bmaxz-2 Then bz# = bz# * -1
	If EntityZ#(ent) < -bmaxz+2 Then bz# = bz# * -1

End Function

'--------------------------------------------------------------------------------------------------

Function fxWater_Create( name$="", width=1, depth=1, damp#=0.01, parent=0 )


	'create new Wavy water effect plane
	w:bbfxWaterWave = New bbfxWaterWave

	w.id		= 1
	w.name$		= name$
	
	w.active	= True
	
	'create rectangular grid mesh
	w.width		= width
	w.depth		= depth
	w.dampening#= 1 - damp#
	
	w.parent	= parent
	w.entity	= create_mesh_plane( w.width, w.depth, False, parent )
	w.surface	= GetSurface(w.entity,1)
	
	'store handle for quick retrieval during collision
	NameEntity w.entity, HandleFromObject(w)
	
	'reserve memory banks to hold vertex energy
	w.bank1		= fxWater_Create_Buffer()
	w.bank2		= fxWater_Create_Buffer()
	
	'return mesh handle
	Return HandleFromObject(w)
	
End Function

'--------------------------------------------------------------------------------------------------

Function fxWater_update()

	For w:bbfxWaterWave = EachIn fxWaterWave_list

		'if the surface is perfectly flat then this value remains 0
		dyna# = 0
		
		'process water
	    For x = 1 To w.width-1
	        For z = 1 To w.depth-1
				fxWaterBank#(w.bank2,x,z) = (fxWaterBank#(w.bank1,x-1,z) + fxWaterBank#(w.bank1,x+1,z) + fxWaterBank#(w.bank1,x,z+1) + fxWaterBank#(w.bank1,x,z-1)) / 2.1-fxWaterBank#(w.bank2,x,z) 
				fxWaterBank#(w.bank2,x,z) = fxWaterBank#(w.bank2,x,z) * w.dampening#
				dyna# = dyna# + fxWaterBank#(w.bank2,x,z)
	        Next
	    Next

		'Only deform patch if necesary
		If Abs(dyna#) > 0.2 Then
		    'PatchTransform
		    k=0
		    For i = 0 To w.depth
		       For j = 0 To w.width
			  h#=fxwaterbank(w.bank2,j,i)		
			  VertexCoords(w.surface,k,VertexX(w.surface,k),h,VertexZ(w.surface,k))
			  VertexNormal(w.surface,k,-0.8-h*0.25,h*0.1,0.2-h*0.25)
			  k=k+1
			Next
		    Next
		EndIf

		'should be optional - depending on type of texture (slows down seriously!)
		UpdateNormals w.entity
		
	    'SwapWaterBuffer
		tmp = w.bank1
		w.bank1 = w.bank2
		w.bank2 = tmp

	Next

End Function

'--------------------------------------------------------------------------------------------------

Function fxWater_Dimple( hand, x,z, force#=1.0, range#=1.0)
	
	w:bbfxWaterWave = bbfxWaterWave(HandleToObject(hand))

	For xg = x - range# * 0.5 To x+range# * 0.5
		For zg = z - range# * 0.5 To z+range# * 0.5
			If xg> 0 And xg < w.width And zg>0 And zg<w.depth Then
				fxWaterBank#(w.bank2, xg,zg) = force#
			EndIf
		Next
	Next

End Function

'--------------------------------------------------------------------------------------------------

Function fxWater_get_surface( hand )

	w:bbfxWaterWave = bbfxWaterWave(HandleToObject( hand ))
	Return w.surface

End Function

'--------------------------------------------------------------------------------------------------

Function fxWater_get_entity( hand )

	w:bbfxWaterWave = bbfxWaterWave(HandleToObject( hand ))
	Return w.entity

End Function

'--------------------------------------------------------------------------------------------------

Function fxWater_Create_Buffer() ' xsize=1, zsize=1 )

	If FXWATER_NUM_BANKS >= FXWATER_MAX_BANKS Then 
		RuntimeError "[fxWater::Create_buffer] Max amount of fxWater memory banks reached!"
	Else
		'create a new memory bank and resize it to fit
		FXWATER_NUM_BANKS = FXWATER_NUM_BANKS + 1
		'NOTE: convert array into memory bank
	EndIf

	Return FXWATER_NUM_BANKS
	
End Function

'--------------------------------------------------------------------------------------------------

Function fxWater_Free_Buffers( )

'| Frees all buffers. Call as a part of when scene/level is removed from memory.


	'NOTE: resize memory banks to 0 (once implemented).

	Return 0
	
End Function

'--------------------------------------------------------------------------------------------------

'Creates a flat grid mesh
Function create_mesh_plane(width=1,depth=1,doublesided=False,parent=0)

	tot = width + (depth*width)
	mix#= (width+depth) * 0.5
	
	mesh=CreateMesh( parent )
	surf=CreateSurface( mesh )
	
	stx#=-.5
	sty#=stx
	stp#=Float(1)/Float(mix#)
	y#=sty#
	
	For a=0 To depth
		x#=stx
		v#=a/Float(depth)
		
		For b=0 To width
			u#=b/Float(width)
			AddVertex(surf,x,0,y,u,v)
			x=x+stp
		Next
		y=y+stp
	Next
	
	For a=0 To depth-1
		For b=0 To width-1
			v0=a*(width+1)+b;v1=v0+1
			v2=(a+1)*(width+1)+b+1;v3=v2-1
			AddTriangle( surf,v0,v2,v1 )
			AddTriangle( surf,v0,v3,v2 )
		Next
	Next
	
	UpdateNormals mesh

	If doublesided=True Then EntityFX mesh,16
	
	FitMesh mesh, -width*0.5, 0, -depth*0.5, width, 1, depth
	
	Return mesh

	
End Function

'--------------------------------------------------------------------------------------------------
Rem
Function create_noise_map()

' creates a noise map to be used as a generic reflection map

	sq = 128

	tex = CreateTexture(sq,sq,65,1)
	tbuf = TextureBuffer(tex)
	SetBuffer(tbuf)
	
	For x = 0 To sq-1
		For y = 0 To sq-1
			r = Rnd(100,120)
			g = Rnd(100,130)
			b = Rnd(190,240)
			Color r,g,b
			Rect x,y,1,1
		Next
	Next	
	
	SetBuffer(BackBuffer())
	
	Return tex

End Function
EndRem

'--------------------------------------------------------------------------------------------------
'[end of stuff]



But it's showing the 3d stuff shaded, as if i drew an alpha'd rectangle over everything.
(since sidesign.minib3d is crashing i modified klepto.minib3d for 2d, using the same exact code from sidesign.minib3d)
FIXED: http://www.blitzbasic.com/Community/posts.php?topic=74544


using this test, however, it isn't shaded.
Import klepto.minib3d
Graphics3D 800,600
Global camera=CreateCamera()
Global light=CreateLight()
Global world=CreateSphere(12)
PositionEntity camera,-5,0,-10		'***
PositionEntity world,0,0,0
PointEntity camera, world		'***


While Not KeyHit(KEY_ESCAPE)           '***
		
	RenderWorld
	
	'Rem                                         '***
	
	TGlobal.BeginMax2D
	SetBlend AlphaBlend
	SetAlpha(0.5)
	SetColor 255,0,0
	DrawText("Hello",50,50)
	SetBlend SolidBlend
	TGlobal.EndMax2D
	
	'EndRem                                    '***
	
	Flip

Wend

End


Soo, can someone point out what's wrong in the dynamic water demo? FIXED: See above.

Hmmm, it runs here on my version, although it does highlight an error with FitMesh not scaling the flat grids properly (they appear invisible).

Can you step into RenderWorld to find out what specific line it's failing on?

It fails the second render through the loop at TMesh.bmx:ln1947
If surf.vbo_enabled=True
	<i>glDrawElements(GL_TRIANGLES,surf.no_tris*3,GL_UNSIGNED_SHORT,Null)</i>
Else
	glDrawElements(GL_TRIANGLES,surf.no_tris*3,GL_UNSIGNED_SHORT,surf.tris)
EndIf


Probably just a graphics card problem.

Very slowly sounds like you didn't use the imported bb code as base and convert it to true BM ... because if you don't it will use int -> obj conversion which is 20+ times slower.

@Dreamora : Ofcourse you're right with this, but he also stated (edited) that this was because of modified values( actual the grid dense). For me I have tested the bbcode with the B3D demo and it is nearly the same speed as the bmx code.

@simonh: I think this may rely on the same fitmesh bug i have reported to you. For the moment you could simply replace it by Scalemesh mesh,width,1,depth .

@Plash: Add the BeginMax2D and EndMax2D code out of this thread at the end of your code and delete the TGlobal. in front of the related function calls in your main loop.
http://www.blitzbasic.com/Community/posts.php?topic=74544

That fixed the shading problem with 2d.

@Dreamora: I did an Import BB Project, and changed things until it ran. As for the slow-down, i simply forgot i had the quality values really high.

klepto - no it was a different FitMesh bug. This one related to resizing flat surfaces.

Plash, what happens when you set USE_VBO=False in minib3d.bmx? What gfx card do you have?

ATI Radeon 7500
Turning off VBO's makes it run, but neither of the surfaces are visible. All I see is the ball bouncing around.

Also, with the 2d part, TrisRendered() is not a function in sidesign.minib3d. (should it be?)

With the functions klepto posted for max2d I get rectangles around where the text would be drawn.
rectangles

Using TBlitz2d.BeginMax2D and TBlitz2d.EndMax2D I get the shaded problem again.
shaded

Plash, in that case the crash bug might be driver related - the latest ATI driver is 8.1, do you have that? It might also fix your other problems.

The invisible planes are due to a FitMesh bug, here's a fixed version:

	Method FitMesh(x#,y#,z#,width#,height#,depth#,uniform=False)
	
		' if uniform=true than adjust fitmesh dimensions
		
		If uniform=True
						
			Local wr#=MeshWidth()/width
			Local hr#=MeshHeight()/height
			Local dr#=MeshDepth()/depth
		
			If wr>=hr And wr>=dr
	
				y=y+((height-(MeshHeight()/wr))/2.0)
				z=z+((depth-(MeshDepth()/wr))/2.0)
				
				height=MeshHeight()/wr
				depth=MeshDepth()/wr
			
			Else If hr>dr
			
				x=x+((width-(MeshWidth()/hr))/2.0)
				z=z+((depth-(MeshDepth()/hr))/2.0)
			
				width=MeshWidth()/hr
				depth=MeshDepth()/hr
						
			Else
			
				x=x+((width-(MeshWidth()/dr))/2.0)
				y=y+((height-(MeshHeight()/dr))/2.0)
			
				width=MeshWidth()/dr
				height=MeshHeight()/dr
								
			EndIf

		EndIf
		
		' old to new dimensions ratio, used to update mesh normals
		Local wr#=MeshWidth()/width
		Local hr#=MeshHeight()/height
		Local dr#=MeshDepth()/depth
		
		' find min/max dimensions
	
		Local minx#=9999999999
		Local miny#=9999999999
		Local minz#=9999999999
		Local maxx#=-9999999999
		Local maxy#=-9999999999
		Local maxz#=-9999999999
	
		For Local s=1 To CountSurfaces()
			
			Local surf:TSurface=GetSurface(s)
				
			For Local v=0 To surf.CountVertices()-1
		
				Local vx#=surf.VertexX#(v)
				Local vy#=surf.VertexY#(v)
				Local vz#=surf.VertexZ#(v)
				
				If vx#<minx# Then minx#=vx#
				If vy#<miny# Then miny#=vy#
				If vz#<minz# Then minz#=vz#
				
				If vx#>maxx# Then maxx#=vx#
				If vy#>maxy# Then maxy#=vy#
				If vz#>maxz# Then maxz#=vz#

			Next
							
		Next
		
		For Local s=1 To CountSurfaces()
			
			Local surf:TSurface=GetSurface(s)
				
			For Local v=0 To surf.CountVertices()-1
		
				' update vertex positions
		
				Local vx#=surf.VertexX#(v)
				Local vy#=surf.VertexY#(v)
				Local vz#=surf.VertexZ#(v)
								
				Local mx#=maxx#-minx#
				Local my#=maxy#-miny#
				Local mz#=maxz#-minz#
				
				Local ux#,uy#,uz#
				
				If mx#<0.0001 And mx#>-0.0001 Then ux#=0.0 Else ux#=(vx#-minx#)/mx# ' 0-1
				If my#<0.0001 And my#>-0.0001 Then uy#=0.0 Else uy#=(vy#-miny#)/my# ' 0-1
				If mz#<0.0001 And mz#>-0.0001 Then uz#=0.0 Else uz#=(vz#-minz#)/mz# ' 0-1
										
				vx#=x#+(ux#*width#)
				vy#=y#+(uy#*height#)
				vz#=z#+(uz#*depth#)
				
				surf.VertexCoords(v,vx#,vy#,vz#)
				
				' update normals
				
				Local nx#=surf.VertexNX#(v)
				Local ny#=surf.VertexNY#(v)
				Local nz#=surf.VertexNZ#(v)
				
				nx#=nx#*wr#
				ny#=ny#*hr#
				nz#=nz#*dr#
				
				surf.VertexNormal(v,nx#,ny#,nz#)

			Next
			
			' mesh shape has changed - update reset flag
			surf.reset_vbo:|1|4

		Next
		
		' mesh shape has changed - update reset flags
		reset_bounds=True
		reset_col_tree=True
		
	End Method


Woah!! that FitMesh function made it run ALOT faster (50fps, 20fps up from my avg), though i still have the problem with the text boundary rectangles (using klepto's begin and end max2d - gfx driver didnt fix TBlitz2d shading).
The 8.1 update didn't change anything, not even the driver version. That was an update for newer models I think. The most recent version for radeon is 6.11, which I have.

heres the funtion for klepto.minib3d (fixes the ceiling being invisible at beginning and the lag)
	Method FitMesh(x#,y#,z#,width#,height#,depth#,uniform=False) 'Simon - update bug 1/31/08 Plash was here
	
		' if uniform=true than adjust fitmesh dimensions
		
		If uniform=True
						
			Local wr#=MeshWidth()/width
			Local hr#=MeshHeight()/height
			Local dr#=MeshDepth()/depth
		
			If wr>=hr And wr>=dr
	
				y=y+((height-(MeshHeight()/wr))/2.0)
				z=z+((depth-(MeshDepth()/wr))/2.0)
				
				height=MeshHeight()/wr
				depth=MeshDepth()/wr
			
			Else If hr>dr
			
				x=x+((width-(MeshWidth()/hr))/2.0)
				z=z+((depth-(MeshDepth()/hr))/2.0)
			
				width=MeshWidth()/hr
				depth=MeshDepth()/hr
						
			Else
			
				x=x+((width-(MeshWidth()/dr))/2.0)
				y=y+((height-(MeshHeight()/dr))/2.0)
			
				width=MeshWidth()/dr
				height=MeshHeight()/dr
								
			EndIf

		EndIf
		
		' old to new dimensions ratio, used to update mesh normals
		Local wr#=MeshWidth()/width
		Local hr#=MeshHeight()/height
		Local dr#=MeshDepth()/depth
		
		' find min/max dimensions
	
		Local minx#=9999999999
		Local miny#=9999999999
		Local minz#=9999999999
		Local maxx#=-9999999999
		Local maxy#=-9999999999
		Local maxz#=-9999999999
	
		For Local s=1 To CountSurfaces()
			
			Local surf:TSurface=GetSurface(s)
				
			For Local v=0 To surf.CountVertices()-1
		
				Local vx#=surf.VertexX#(v)
				Local vy#=surf.VertexY#(v)
				Local vz#=surf.VertexZ#(v)
				
				If vx#<minx# Then minx#=vx#
				If vy#<miny# Then miny#=vy#
				If vz#<minz# Then minz#=vz#
				
				If vx#>maxx# Then maxx#=vx#
				If vy#>maxy# Then maxy#=vy#
				If vz#>maxz# Then maxz#=vz#

			Next
							
		Next
		
		For Local s=1 To CountSurfaces()
			
			Local surf:TSurface=GetSurface(s)
				
			For Local v=0 To surf.CountVertices()-1
		
				' update vertex positions
		
				Local vx#=surf.VertexX#(v)
				Local vy#=surf.VertexY#(v)
				Local vz#=surf.VertexZ#(v)
								
				Local mx#=maxx#-minx#
				Local my#=maxy#-miny#
				Local mz#=maxz#-minz#
				
				Local ux#,uy#,uz#
				
				If mx#<0.0001 And mx#>-0.0001 Then ux#=0.0 Else ux#=(vx#-minx#)/mx# ' 0-1
				If my#<0.0001 And my#>-0.0001 Then uy#=0.0 Else uy#=(vy#-miny#)/my# ' 0-1
				If mz#<0.0001 And mz#>-0.0001 Then uz#=0.0 Else uz#=(vz#-minz#)/mz# ' 0-1
										
				vx#=x#+(ux#*width#)
				vy#=y#+(uy#*height#)
				vz#=z#+(uz#*depth#)
				
				surf.VertexCoords(v,vx#,vy#,vz#)
				
				' update normals
				
				Local nx#=surf.VertexNX#(v)
				Local ny#=surf.VertexNY#(v)
				Local nz#=surf.VertexNZ#(v)
				
				nx#=nx#*wr#
				ny#=ny#*hr#
				nz#=nz#*dr#
				
				surf.VertexNormal(v,nx#,ny#,nz#)

			Next
			
			' mesh shape has changed - update reset flag bug fix: no vbo in klepto.minib3d Plash was here
			'surf.reset_vbo:|1|4

		Next
		
		' mesh shape has changed - update reset flag  bug fix: changed Plash was here
		'reset_bounds=True
		'reset_col_tree=True
		new_bounds=True
		
	End Method


Current dynamic water code (still needs location correction for pickmode):
Framework brl.max2d
'Import brl.retro
Import brl.timer

Import "bbtype.bmx"
'Import "bbvkey.bmx"

Import klepto.minib3d
'Import sidesign.minib3d

SetGraphicsDriver(GLMax2DDriver(), GRAPHICS_BACKBUFFER | GRAPHICS_DEPTHBUFFER | GRAPHICS_ACCUMBUFFER)

Global fxWaterWave_list:TList=New TList


'Ported to BlitzMax by Plash - 1/30/08


' fxWater Module by Danny van der Ark - dendanny@...
'
' (Heavily) inpired by samples by Reda Borchardt and Rob Cummings.
' use as you like - send me a sample would be cool.
'
' april '04
'

'
' Usage:
'
' 1. Create a water surface using: fxWater_Create( name$, xsize, zsize, dampening#, parent )
'    This function returns the 'type-handle' to the water surface wich you will need later.
'
' 2. Obtain the entity handle (to apply color, texture, alpha, etc) using the function
'	 fxWater_get_entity( typehandle) -> typehandle is the value returned by fxWater_Create()
'
' 3. Then simply call 'fxWater_Update()' every frame during your main loop.
'
'
' 4. To create a splah in the water use the fxWater_Dimple() function. The function needs the
'	 type handle that was returned by 'fxWater_Create', the coordinates of the splash, the
'	 force/strength of the splash and the 'range' or size of the splash.
'
'	 fxWater_Dimple( hand, x,z, force#=1.0, range#=1.0)
'
' 5. Freeing stuff not done yet because I want to alter it to use memory banks in stead of
'	 a large static array to store the vertex data - wich should give a more efficient use
'	 of memory...
'
' You can create as many surfaces of any size as you wish. If you wish surfaces larger than 100x100
' then adjust the fxwater_max_depth/width globals. If you want more than 5 surfaces at the same time
' adjust the fxwater_max accordingly. 
' 
' It is necesary To 'UpdateNormals' every frame to ensure the highlights are re-calculated every
' frame. Without this the ripples are there, but just not visible. This slows things down
' dramatically ofcourse. Any other ideas welcome....
'
' He ho, enjoy!
'
' ooo
' (_) Danny v.d. Ark



Global fxWATER_MAX = 5				'max number of active surfaces/effects at one time
Global fxWATER_NUM = 2				'current number of active water effects.

Global FXWATER_MAX_WIDTH = 100		'max sub-division for water meshes
Global FXWATER_MAX_DEPTH = 100		'max sub-division for water meshes

Global FXWATER_MAX_BANKS = fxWATER_MAX * 2
Global FXWATER_NUM_BANKS = 0


Global DEMO_WATER_WIDTH	 = 40	'--> Adjust these for different plane sizes / mesh resolution
Global DEMO_WATER_DEPTH  = 40


'reserve memory banks for vertice altitudes
Global fxWaterBank#[FXWATER_MAX_BANKS+1, FXWATER_MAX_WIDTH+1, FXWATER_MAX_DEPTH +1]


Type FXWaterWave Extends TBBType

	Method New()
		Add(fxWaterWave_list)
	End Method

	Method After:FXWaterWave()
		Local t:TLink
		t=_link.NextLink()
		If t Return FXWaterWave(t.Value())
	End Method

	Method Before:FXWaterWave()
		Local t:TLink
		t=_link.PrevLink()
		If t Return FXWaterWave(t.Value())
	End Method


	Field id
	Field name$
	
	Field FXWATER_MAX_WIDTH		'max sub-division for water meshes
	Field FXWATER_MAX_DEPTH
	
	Field active		'if not ripples then fx is not active
	
	Field parent		'parent entity (if any)
	Field entity		'water mesh
	Field surface		'water surface

	Field bank1			'pointers to array for mem storage
	Field bank2

	Field width			'width of plane / surface
	Field depth			'depth of plane / surface
	Field dampening#	'water dynamics

End Type

'Demo options
Global OPT_WIREFRAME = 0
Global OPT_REFRSH 	 = 0
Global OPT_BALLFREEZE= 0
Global OPT_CEILING	 = 1

'--------------------------------------------------------------------------------------------------

'Graphics3D 640,480,32,1
Graphics3D 800,600,32,2

' Camera + Light
Global campivot = CreatePivot()
Global camera = CreateCamera(campivot)

PositionEntity camera, 0, 0, -35
PointEntity camera, campivot

light = CreateLight(2)
PositionEntity light,-60,0,100
LightColor light,240,240,210
PointEntity light, campivot

light = CreateLight(2)
PositionEntity light,50,0,-50
LightColor light,150,150,180
PointEntity light, campivot

AmbientLight 40,40,40

'camerapick cursor
Local marker:TMesh=CreateSphere()
ScaleEntity marker,0.2,0.2,0.2
EntityColor marker,255,0,0

'load texture
tex = LoadTexture ("water.bmp",1+64)
'tex = create_noise_map()

'create water planes
Global w1 = fxWater_Create( "floor",  DEMO_WATER_WIDTH, DEMO_WATER_DEPTH, 0.025 )
water = fxWater_get_entity( w1 )
PositionEntity water, 0, -10, 0
EntityColor water, 30,50,200
EntityShininess water, 0.1
EntityTexture water,tex
EntityPickMode water,2

Global w2 = fxWater_Create( "ceiling",  DEMO_WATER_WIDTH, DEMO_WATER_DEPTH, 0.025 )
water = fxWater_get_entity( w2 )
FlipMesh water ' flip it because the camera is underneath it
PositionEntity water, 0, 10, 0
EntityColor water, 250,100,100
EntityColor water, 140,130,20
EntityShininess water, 0.1
EntityTexture water,tex
'EntityPickMode water,3

'force refresh
fxWater_dimple( w1, 1,1, 0.001, 0.001)
fxWater_dimple( w2, 1,1, 0.001, 0.001)

'set random ball direction/speed
Global bx#=  0.2
Global by#= -1.75
Global bz#= -0.25

Global bmaxx# =  DEMO_WATER_WIDTH * 0.5	'half the width of the water plane
Global bmaxy# = 10.0
Global bmaxz# =  DEMO_WATER_DEPTH * 0.5	'half the depth of the water plane

'create ball
ball = CreateSphere(6)
EntityColor ball, 0,0,0
EntityShininess ball, 1.0
EntityTexture ball, tex

SeedRnd MilliSecs()

' Main Loop
tstart = MilliSecs() + 1000
frame = 0

Global lastx# = 0
Global lasty# = 0
Global bb_list = 0

tim = CreateTimer(50)

Local l:String = "WavyWaterFx by Danny van der Ark"

While Not KeyHit(key_escape)

	'update bouncing ball
	update_ball( ball )
	
	'update fxWater
	fxWater_update()
	
	'render
	'UpdateWorld
	'RenderWorld

	'debug

	'orbit camera
	'TurnEntity campivot, 0, 0.25, 0

	'check fps
	frame = frame + 1
	If MilliSecs() >= tstart Then
		fps = frame
		frame = 0
		tstart = MilliSecs() + 1000
	EndIf

	'toggle ceiling [C]
	If KeyHit(key_c) Then
		OPT_CEILING = 1 - OPT_CEILING
		If OPT_CEILING Then
			water = fxWater_Get_Entity(w2)
			ShowEntity water
		Else
			water = fxWater_Get_Entity(w2)
			HideEntity water
		EndIf
	EndIf
	
	'pause all [P]
	If KeyHit(key_p) Then
		FlushKeys
		While Not KeyHit(key_p) Wend
	EndIf

	'pause ball [B]
	If KeyHit(key_b) Then
		OPT_BALLFREEZE = 1 - OPT_BALLFREEZE
		If OPT_BALLFREEZE Then
			PositionEntity ball, 0,0,0
			bx# = 0
			by# = 0
			bz# = 0
		Else
			bx#=Rnd(-1,1)
			by#=Rnd(-2,2)
			bz#=Rnd(-1,1)
		EndIf
	EndIf

	'wireframe [W]
	If KeyHit(key_w) Then
		OPT_WIREFRAME:~1
		Wireframe OPT_WIREFRAME
	EndIf
	
	'Dirty refresh [D]
	If KeyHit(key_d) Then
		OPT_REFRESH = 1 - OPT_REFRESH
	EndIf	
	
	UpdateWorld
	RenderWorld
	
	  'Rem
		BeginMax2D
		  SetBlend alphablend
		   	'SetAlpha 0.5
			SetColor 100, 100, 100
			DrawText "based on samples from Reda Borchardt And Rob Cummings.", 2, 12
			SetColor 20, 140, 255
			DrawText "[ESC] to quit - [D] for fast but dirty refresh(" + OPT_REFRESH + ") - [W] To toggle WireFrame (" + OPT_WIREFRAME + ")", 2, 454
			DrawText "[P] To pause  - [B] to pause/reset ball - [C] to toggle ceiling", 2, 466
			SetColor 250, 250, 220
			DrawText "FPS  " + fps, 10, 220
			'DrawText "TRIS " + TrisRendered(), 10, 232
		  SetBlend solidblend
		EndMax2D
	  'EndRem
	
	'check refresh mode
	
	If OPT_REFRESH Then
		'fast and dirty (pot noodle style)
	    Flip False
	
	Else
		'slow but clean
		Flip True
		WaitTimer(tim)
		
	EndIf

	'If MouseHit(1) Then
	'	x = Rnd(1, DEMO_WATER_WIDTH)
	'	z = Rnd(1, DEMO_WATER_DEPTH)
	'	fxWater_Dimple(w1, x, z, 1, 5)
	'EndIf
	
	If MouseDown(1)
	
		' reset entity colors
		'EntityColor sphere,255,255,255
		'EntityColor mesh,255,255,255
		'EntityColor box,255,255,255

		Local pick:TEntity=CameraPick(camera,MouseX(),MouseY())
		Local pe:TEntity=PickedEntity()
		Local ps:TSurface=PickedSurface()
		
		If pick<>Null
			'DebugLog "Picked!"
			'DebugLog "PickedX(): " + PickedX()
			'DebugLog "PickedY(): " + PickedY()
			'DebugLog "PickedZ(): " + PickedZ()
			'DebugLog "PickedNX(): " + PickedNX()
			'DebugLog "PickedNY(): " + PickedNY()
			'DebugLog "PickedNZ(): " + PickedNZ()
			'DebugLog "PickedTime(): " + PickedTime()
			'DebugLog "PickedEntity(): " + (pe).tostring()
			'DebugLog "PickedSurface(): " + (ps).tostring()
			'DebugLog "PickedTriangle(): " + PickedTriangle()
			'EntityColor PickedEntity(), 255, 255, 0
			PositionEntity marker,PickedX(), PickedY(), PickedZ()
			fxWater_Dimple(w1, PickedX()/2, PickedZ()/2, .5, 4)
			'fxWater_Dimple(w1, MouseX(), MouseY(), .5, 4)
			DebugLog "x " + Int(PickedX()) + " y " + Int(PickedY()) + " z " + Int(PickedZ())
		'Else
		'	DebugLog "Not Picked"
			
		EndIf
	
	EndIf
	
Wend

End

'--------------------------------------------------------------------------------------------------

Function update_ball( ent )

	'move the ball
	TranslateEntity ent, bx,by,bz

	DoDimple = False
	
	'check left/right walls
	If EntityX#(ent) >  bmaxx-2 Then bx# = bx# * -1
	If EntityX#(ent) < -bmaxx+2 Then bx# = bx# * -1

	'check ceiling bounce
	If EntityY#(ent) >  bmaxy-2 Then
		'reverse vertical direction
		by# = by# * -1.0
		'create dimple
		fxWater_Dimple(w2, EntityX(ent)+bmaxx,EntityZ(ent)+bmaxz, -1.0, 5.0)
		'slightly alter direction
		bx# = bx# + Rnd(-0.25, 0.25)
		bz# = bz# + Rnd(-0.25, 0.25)
	EndIf

	'check floor bounce
	If EntityY#(ent) < -bmaxy+2 Then
		'reverse vertical direction
		by# = by# * -1.0
		'create dimple
		fxWater_Dimple(w1, EntityX(ent)+bmaxx,EntityZ(ent)+bmaxz, 1.0, 2.0)
		'slightly alter direction
		bx# = bx# + Rnd(-0.25, 0.25)
		bz# = bz# + Rnd(-0.25, 0.25)
	EndIf

	'check front/back walls
	If EntityZ#(ent) >  bmaxz-2 Then bz# = bz# * -1
	If EntityZ#(ent) < -bmaxz+2 Then bz# = bz# * -1

End Function

'--------------------------------------------------------------------------------------------------

Function fxWater_Create( name$="", width=1, depth=1, damp#=0.01, parent=0 )


	'create new Wavy water effect plane
	w:FXWaterWave = New FXWaterWave

	w.id		= 1
	w.name$		= name$
	
	w.active	= True
	
	'create rectangular grid mesh
	w.width		= width
	w.depth		= depth
	w.dampening#= 1 - damp#
	
	w.parent	= parent
	w.entity	= create_mesh_plane( w.width, w.depth, False, parent )
	w.surface	= GetSurface(w.entity,1)
	'w.surface.vbo_enabled=False
	
	'store handle for quick retrieval during collision
	NameEntity w.entity, HandleFromObject(w)
	
	'reserve memory banks to hold vertex energy
	w.bank1		= fxWater_Create_Buffer()
	w.bank2		= fxWater_Create_Buffer()
	
	'return mesh handle
	Return HandleFromObject(w)
	
End Function

'--------------------------------------------------------------------------------------------------

Function fxWater_update()

	For w:FXWaterWave = EachIn fxWaterWave_list

		'if the surface is perfectly flat then this value remains 0
		dyna# = 0
		
		'process water
	    For x = 1 To w.width-1
	        For z = 1 To w.depth-1
				fxWaterBank#(w.bank2,x,z) = (fxWaterBank#(w.bank1,x-1,z) + fxWaterBank#(w.bank1,x+1,z) + fxWaterBank#(w.bank1,x,z+1) + fxWaterBank#(w.bank1,x,z-1)) / 2.1-fxWaterBank#(w.bank2,x,z) 
				fxWaterBank#(w.bank2,x,z) = fxWaterBank#(w.bank2,x,z) * w.dampening#
				dyna# = dyna# + fxWaterBank#(w.bank2,x,z)
	        Next
	    Next

		'Only deform patch if necesary
		If Abs(dyna#) > 0.2 Then
		    'PatchTransform
		    k=0
		    For i = 0 To w.depth
		       For j = 0 To w.width
			  h#=fxwaterbank(w.bank2,j,i)		
			  VertexCoords(w.surface,k,VertexX(w.surface,k),h,VertexZ(w.surface,k))
			  VertexNormal(w.surface,k,-0.8-h*0.25,h*0.1,0.2-h*0.25)
			  k=k+1
			Next
		    Next
		EndIf

		'should be optional - depending on type of texture (slows down seriously!)
		UpdateNormals w.entity
		
	    'SwapWaterBuffer
		tmp = w.bank1
		w.bank1 = w.bank2
		w.bank2 = tmp

	Next

End Function

'--------------------------------------------------------------------------------------------------

Function fxWater_Dimple( hand, x,z, force#=1.0, range#=1.0)
	
  w:FXWaterWave = FXWaterWave(HandleToObject(hand))
	DebugLog x + "," + z
	
	For xg = x - range# * 0.5 To x+range# * 0.5
	
		For zg = z - range# * 0.5 To z+range# * 0.5
		
			If xg> 0 And xg < w.width And zg>0 And zg<w.depth Then
				fxWaterBank#(w.bank2, xg,zg) = force#
				
			EndIf
			
		Next
		
	Next

End Function

'--------------------------------------------------------------------------------------------------

Function fxWater_get_surface( hand )

	w:FXWaterWave = FXWaterWave(HandleToObject( hand ))
	Return w.surface

End Function

'--------------------------------------------------------------------------------------------------

Function fxWater_get_entity( hand )

	w:FXWaterWave = FXWaterWave(HandleToObject( hand ))
	Return w.entity

End Function

'--------------------------------------------------------------------------------------------------

Function fxWater_Create_Buffer() ' xsize=1, zsize=1 )

	If FXWATER_NUM_BANKS >= FXWATER_MAX_BANKS Then 
		RuntimeError "[fxWater::Create_buffer] Max amount of fxWater memory banks reached!"
	Else
		'create a new memory bank and resize it to fit
		FXWATER_NUM_BANKS = FXWATER_NUM_BANKS + 1
		'NOTE: convert array into memory bank
	EndIf

	Return FXWATER_NUM_BANKS
	
End Function

'--------------------------------------------------------------------------------------------------

Function fxWater_Free_Buffers( )

'| Frees all buffers. Call as a part of when scene/level is removed from memory.


	'NOTE: resize memory banks to 0 (once implemented).

	Return 0
	
End Function

'--------------------------------------------------------------------------------------------------

Function BeginMax2D()

Local x,y,w,h
		GetViewport(x,y,w,h)
		
		glDisable(GL_LIGHTING)
		glDisable(GL_DEPTH_TEST)
		glDisable(GL_SCISSOR_TEST)
		glDisable(GL_FOG)
		glDisable(GL_CULL_FACE)

		glMatrixMode GL_TEXTURE
		glLoadIdentity
		
		glMatrixMode GL_PROJECTION
		glLoadIdentity
		glOrtho 0,GraphicsWidth(),GraphicsHeight(),0,-1,1
		
		glMatrixMode GL_MODELVIEW
		glLoadIdentity
		
		SetViewport x,y,w,h
		
		
		Local MaxTex:Int 
		glGetIntegerv(GL_MAX_TEXTURE_UNITS, Varptr(MaxTex))

		
		For Local Layer = 0 Until MaxTex
			glActiveTexture(GL_TEXTURE0+Layer)
					
			glDisable(GL_TEXTURE_CUBE_MAP)
			glDisable(GL_TEXTURE_GEN_S)
			glDisable(GL_TEXTURE_GEN_T)
			glDisable(GL_TEXTURE_GEN_R)
	
			glDisable(GL_TEXTURE_2D)
		Next
		
		glActiveTexture(GL_TEXTURE0)
		
		'DrawRect - 10 , - 10 , 5 , 5
		
		glViewport(0,0,TGlobal.Width,TGlobal.Height)
		glScissor(0,0,TGlobal.Width,TGlobal.Height)
		

End Function

Function EndMax2D()

		glDisable(GL_TEXTURE_CUBE_MAP)
		glDisable(GL_TEXTURE_GEN_S)
		glDisable(GL_TEXTURE_GEN_T)
		glDisable(GL_TEXTURE_GEN_R)
	
		glDisable(GL_TEXTURE_2D)

		TGlobal.EnableStates()

End Function

'Creates a flat grid mesh
Function create_mesh_plane(width=1,depth=1,doublesided=False,parent=0)

	tot = width + (depth*width)
	mix#= (width+depth) * 0.5
	
	mesh=CreateMesh( parent )
	surf=CreateSurface( mesh )
	
	stx#=-.5
	sty#=stx
	stp#=Float(1)/Float(mix#)
	y#=sty#
	
	For a=0 To depth
		x#=stx
		v#=a/Float(depth)
		
		For b=0 To width
			u#=b/Float(width)
			AddVertex(surf,x,0,y,u,v)
			x=x+stp
		Next
		y=y+stp
	Next
	
	For a=0 To depth-1
		For b=0 To width-1
			v0=a*(width+1)+b;v1=v0+1
			v2=(a+1)*(width+1)+b+1;v3=v2-1
			AddTriangle( surf,v0,v2,v1 )
			AddTriangle( surf,v0,v3,v2 )
		Next
	Next
	
	UpdateNormals mesh

	If doublesided=True Then EntityFX mesh,16
	
	FitMesh mesh, -width*0.5, 0, -depth*0.5, width, 1, depth
	
	Return mesh

	
End Function


Using the updated fitmesh function in klepto.minib3d, I get nearly half the fps that I get with USE_VBO=False on sidesign.minib3d (about 25, using sidesign.minib3d 48-51).

Edit - never mind, the newer driver is only for Radeons 9500 and newer.

The reason for the current speed advantage over klepto's version is probably due to the UpdateNormals function written in C++.


The reason for the current speed advantage over klepto's version is probably due to the UpdateNormals function written in C++


Considering that fact, it all should be written in C++ ;)

Not really, as there wouldn't be much speed gain elsewhere.

Changed it over to OO, I don't know what I'm doing wrong but after many variations I can't get the arrays to work in this:
Framework brl.max2d
'Import brl.retro
Import brl.timer

'Import "bbtype.bmx"
'Import "bbvkey.bmx"

'Import klepto.minib3d
Import sidesign.minib3d

'SetGraphicsDriver(GLMax2DDriver(), GRAPHICS_BACKBUFFER | GRAPHICS_DEPTHBUFFER | GRAPHICS_ACCUMBUFFER)


'------------------------------------------------------------------------------------------------------
'Ported to BlitzMax by Plash - 1/30/08

' fxWater Module by Danny van der Ark - dendanny@...
'
' (Heavily) inpired by samples by Reda Borchardt and Rob Cummings.
' use as you like - send me a sample would be cool.
'
' april '04
'
' Usage:
'
' 1. Create a water surface using: fxWater_Create( name$, xsize, zsize, dampening#, parent )
'    This function returns the 'type-handle' to the water surface wich you will need later.
'
' 2. Obtain the entity handle (to apply color, texture, alpha, etc) using the function
'	 fxWater_get_entity( typehandle) -> typehandle is the value returned by fxWater_Create()
'
' 3. Then simply call 'fxWater_Update()' every frame during your main loop.
'
'
' 4. To create a splah in the water use the fxWater_Dimple() function. The function needs the
'	 type handle that was returned by 'fxWater_Create', the coordinates of the splash, the
'	 force/strength of the splash and the 'range' or size of the splash.
'
'	 fxWater_Dimple( hand, x,z, force#=1.0, range#=1.0)
'
' 5. Freeing stuff not done yet because I want to alter it to use memory banks in stead of
'	 a large static array to store the vertex data - wich should give a more efficient use
'	 of memory...
'
' You can create as many surfaces of any size as you wish. If you wish surfaces larger than 100x100
' then adjust the fxwater_max_depth/width globals. If you want more than 5 surfaces at the same time
' adjust the fxwater_max accordingly. 
' 
' It is necesary To 'UpdateNormals' every frame to ensure the highlights are re-calculated every
' frame. Without this the ripples are there, but just not visible. This slows things down
' dramatically ofcourse. Any other ideas welcome....
'
' He ho, enjoy!
'
' ooo
' (_) Danny v.d. Ark



Global fxWATER_MAX = 5				'max number of active surfaces/effects at one time
Global fxWATER_NUM = 1				'current number of active water effects.

Global FXWATER_MAX_WIDTH = 100		'max sub-division for water meshes
Global FXWATER_MAX_DEPTH = 100		'max sub-division for water meshes

Global FXWATER_MAX_BANKS = fxWATER_MAX * 2
Global FXWATER_NUM_BANKS = 0


Global DEMO_WATER_WIDTH	 = 40	'--> Adjust these for different plane sizes / mesh resolution
Global DEMO_WATER_DEPTH  = 40


'reserve memory banks for vertice altitudes
'Global fxWaterBank:Float[FXWATER_MAX_BANKS + 1, FXWATER_MAX_WIDTH + 1, FXWATER_MAX_DEPTH + 1] 


Type FX_WaterArea' Extends TBBType

  Global _list:TList = New TList

	Method New()
		_list.AddLast(Self) 
		
	End Method
	
	rem
		Method After:FX_WaterArea()
		  Local t:TLink
		
			t = _link.NextLink()
			
		   If t Return FX_WaterArea(t.Value())
		
		End Method
	
		Method Before:FX_WaterArea()
		  Local t:TLink
		
			t=_link.PrevLink()
			
		   If t Return FX_WaterArea(t.Value())
		
		End Method
	endrem

	Field id:Int
	Field name:String
	
	Field FXWATER_MAX_WIDTH:Int		'max sub-division for water meshes
	Field FXWATER_MAX_DEPTH:Int
	
	Field Active:Int			'if not ripples then fx is not active
	
	Field Parent:TEntity			'parent entity (if any)
	Field entity:TMesh			'water mesh
	Field SURFACE:TSurface			'water surface

	Field dmpx:Float 		'dimple values
	Field dmpz:Float
	
	Field bank1:Float[0, 0] 
	Field bank2:Float[0, 0] 

	Field WIDTH:Int				'width of plane / surface
	Field depth:Int				'depth of plane / surface
	Field dampening:Float	'water dynamics
	

		Function Create:FX_WaterArea(Name:String = "", WIDTH:Int = 1, depth:Int = 1, damp:Float = 0.01, Parent:TEntity = Null) 
		
			'create new Wavy water effect plane
			w:FX_WaterArea = New FX_WaterArea
		
			W.id = 1
			W.Name = Name
			
			W.Active = True
			
			'create rectangular grid mesh
			W.WIDTH = WIDTH
			W.depth = depth
			W.dampening = damp - 1
			
			W.Parent = Parent
			W.entity = create_mesh_plane(W.WIDTH, W.depth, False, Parent) 
			W.SURFACE = getSurface(W.entity, 1) 
			
			'dimple XZ values - for calculating dimple coordinates
			w.dmpx = width * 0.5
			w.dmpz = depth * 0.5
			
			'store handle for quick retrieval during collision
			NameEntity W.entity, "FX_WA::" + Name
			
			'reserve memory banks to hold vertex energy
			W.bank1[FXWATER_MAX_WIDTH + 1, FXWATER_MAX_DEPTH + 1] 
			W.bank2[FXWATER_MAX_WIDTH + 1, FXWATER_MAX_DEPTH + 1] 
			
			'return mesh handle
		  Return W
			
		End Function
		
		'--------------------------------------------------------------------------------------------------
		
		Function UpdateWA() 
		
			For W:FX_WaterArea = EachIn _list
		
			'if the surface is perfectly flat then this value remains 0
			  Local dyna:Float = 0
				
				'process water
				    For X = 1 To W.WIDTH - 1
				        For Z = 1 To W.depth - 1
						
							W.bank2[X, Z] = (W.bank1[X - 1, Z] + W.bank1[X + 1, Z] + W.bank1[X, Z + 1] + W.bank1[X, Z - 1] ) / 2.1 - W.bank2[X, Z] 
							W.bank2[X, Z] = W.bank2[X, Z] * W.dampening
							
						  dyna:+W.bank2[X, Z] 
						  
				        Next
				    Next
		
				'Only deform patch if necesary ;patch transform
					If Abs(dyna) > 0.2 Then
					  Local k:Int = 0
					  
						For i = 0 To W.depth
						
							For j = 0 To W.WIDTH
							  Local h:Float = W.bank2[j, i] 
							  
								VertexCoords(W.SURFACE, k, VertexX(W.SURFACE, k), h, VertexZ(W.SURFACE, k)) 
								VertexNormal(W.SURFACE, k, - 0.8 - h * 0.25, h * 0.1, 0.2 - h * 0.25) 
								
							   k = k + 1
								
							Next
							
						Next
						
					EndIf
		
			  'should be optional - depending on type of texture (slows down seriously!)
			   updateNormals W.entity
				
			 'SwapWaterBuffer
			  Local tmp:Float[,] = W.bank1
			  W.bank1 = W.bank2
			  W.bank2 = tmp
		
			Next
		
		End Function
		
		'--------------------------------------------------------------------------------------------------
		
		Method Dimple(X:Int, Z:Int, force:Float = 1.0, Range:Float = 1.0) 
			
		  'w:FX_WaterArea = FX_WaterArea(HandleToObject(hand))
			DebugLog x + "," + z
			
			For Local xg:Int = X - Range * 0.5 To X + Range * 0.5
			
				For Local zg:Int = Z - Range * 0.5 To Z + Range * 0.5
				
					If xg > 0 And xg < WIDTH And zg > 0 And zg < depth Then
						bank2[xg, zg] = force
						
					EndIf
					
				Next
				
			Next
		
		End Method
		
		'--------------------------------------------------------------------------------------------------
		
		Method Get_Surface:TSurface() 
		
			'w:FX_WaterArea = FX_WaterArea(HandleToObject( hand ))
			'Return w.surface
			Return Self.SURFACE
			
		End Method
		
		'--------------------------------------------------------------------------------------------------
		
		Method Get_Entity:TEntity() 
		
			'Return w.entity
			Return Self.entity
			
		End Method
		
		'----------------------------------NOTE: NEEDS TO BE IMPLEMENTED-----------------------------------
		Method free_buffers() 
		
		'| Frees all buffers. Call as a part of when scene/level is removed from memory.
		
		
			'NOTE: resize memory banks to 0 (once implemented).
		
			Return 0
			
		End Method

End Type

'Demo options
Global OPT_WIREFRAME = 0
Global OPT_REFRSH 	 = 0
Global OPT_BALLFREEZE= 0
Global OPT_CEILING	 = 1

Graphics3D 800,600,32,2

' Camera + Light
Global campivot = CreatePivot()
Global camera = CreateCamera(campivot)
	PositionEntity camera, 0, 0, -35
	PointEntity camera, campivot

light = CreateLight(2)
	PositionEntity light,-60,0,100
	LightColor light,240,240,210
	PointEntity light, campivot

light = CreateLight(2)
	PositionEntity light,50,0,-50
	LightColor light,150,150,180
	PointEntity light, campivot

AmbientLight 40,40,40


'camerapick cursor
Local marker:TMesh=CreateSphere()
	ScaleEntity marker,0.2,0.2,0.2
	EntityColor marker,255,0,0

'load texture
Local tex:TTexture = LoadTexture ("water.bmp", 1 + 64) 

'create water planes
Global w1:FX_WaterArea = FX_WaterArea.Create("floor", DEMO_WATER_WIDTH, DEMO_WATER_DEPTH, 0.025) 
  Local water = w1.get_entity() 
	PositionEntity water, 0, - 10, 0
	EntityColor water, 30, 50, 200
	EntityShininess water, 0.1
	EntityTexture water, tex
	EntityPickMode water, 2
	
w1.dimple 1, 1, 0.001, 0.001   'force refresh

'Global w2:FX_WaterArea = FX_WaterArea.Create("ceiling", DEMO_WATER_WIDTH, DEMO_WATER_DEPTH, 0.025) 
'  water = w2.get_entity() 
'	flipMesh water ' flip it because the camera is underneath it
'	PositionEntity water, 0, 10, 0
'	EntityColor water, 250, 100, 100
'	EntityColor water, 140, 130, 20
'	EntityShininess water, 0.1
'	EntityTexture water, tex
'	EntityPickMode water, 3

'w2.dimple 1, 1, 0.001, 0.001	'force refresh

 
 

'set random ball direction/speed
Global bx:Float = 0.2
Global by:Float = -0.50
Global bz:Float = -0.25

Global bmaxx:Float = DEMO_WATER_WIDTH * 0.5	'half the width of the water plane
Global bmaxy:Float = 10.0
Global bmaxz:Float = DEMO_WATER_DEPTH * 0.5	'half the depth of the water plane

'create ball
Local ball:TEntity = CreateSphere(6)
	EntityColor ball, 45, 45, 45
	EntityShininess ball, 1.0
	EntityTexture ball, tex
	
SeedRnd MilliSecs()

Local tstart:Int = MilliSecs() + 1000
Local localframe:Int = 0

Global LastX:Float = 0
Global lasty:Float = 0

Local tim:TTimer = CreateTimer(60) 

Local l:String = "WavyWaterFx by Danny van der Ark"

While Not KeyHit(key_escape)

	'update bouncing ball
	update_ball ball
	
	'update fxWater
	FX_WaterArea.UpdateWA
	
	'TurnEntity campivot, 0, 0.25, 0
	If KeyDown(key_right) 
		TurnEntity campivot, 0, 0.75, 0
		
	ElseIf KeyDown(KEY_LEFT) 
		TurnEntity campivot, 0, - 0.75, 0
		
	EndIf
	
	'fps
	  frame = frame + 1
		If MilliSecs() >= tstart Then
			fps = frame
			frame = 0
			tstart = MilliSecs() + 1000
			
		EndIf

	'toggle ceiling [C]
	'If KeyHit(key_c) Then
	'	OPT_CEILING = 1 - OPT_CEILING
	'	If OPT_CEILING Then
	'		water = fxWater_Get_Entity(w2)
	'		ShowEntity water
	'	Else
	'		water = fxWater_Get_Entity(w2)
	'		HideEntity water
	'	EndIf
	'EndIf
	
	'pause all [P]
	If KeyHit(KEY_P) Then
	   FlushKeys
	   
		While Not KeyHit(KEY_P) Wend
		
	EndIf

	'pause ball [B]
	If KeyHit(KEY_B) Then
	  OPT_BALLFREEZE:~1
		
		If OPT_BALLFREEZE Then
		   PositionEntity ball, 0, 0, 0
			bx = 0 ; by = 0 ; bz = 0
			
		Else
			bx = Rnd(- 1, 1) ; by = Rnd(- 2, 2) ; bz = Rnd(- 1, 1) 
			
		EndIf
		
	EndIf

	'wireframe [W]
	If KeyHit(KEY_W) Then
	  OPT_WIREFRAME:~1
	  
		Wireframe OPT_WIREFRAME
		
	EndIf
	
	'Dirty refresh [D]
	If KeyHit(KEY_D) Then
	  OPT_REFRESH:~1
		
	EndIf	
	
	UpdateWorld
	RenderWorld
	
	'sidesign.minib3d - text
	TBlitz2D.Text 10, 220, "FPS  " + fps
	
	  Rem
		'TBlitz2d.BeginMax2D
		BeginMax2D
		  SetBlend alphablend
		   	'SetAlpha 0.5
			SetColor 100, 100, 100
			DrawText "based on samples from Reda Borchardt And Rob Cummings.", 2, 12
			SetColor 20, 140, 255
			DrawText "[ESC] to quit - [D] for fast but dirty refresh(" + OPT_REFRESH + ") - [W] To toggle WireFrame (" + OPT_WIREFRAME + ")", 2, 454
			DrawText "[P] To pause  - [B] to pause/reset ball - [C] to toggle ceiling", 2, 466
			SetColor 250, 250, 220
			DrawText "FPS  " + fps, 10, 220
			'DrawText "TRIS " + TrisRendered(), 10, 232
		  SetBlend solidblend
		EndMax2D
		'TBlitz2d.EndMax2D
	  EndRem
	
	'check refresh mode
	
	If OPT_REFRESH Then
		'fast and dirty (pot noodle style)
	    Flip False
	
	Else
		'slow but clean
		Flip True
	   WaitTimer tim
		
	EndIf

	'If MouseHit(1) Then
	'	x = Rnd(1, DEMO_WATER_WIDTH)
	'	z = Rnd(1, DEMO_WATER_DEPTH)
	'	fxWater_Dimple(w1, x, z, 1, 5)
	'EndIf
	
	If MouseHit(1)
	
		' reset entity colors
		'EntityColor sphere,255,255,255
		'EntityColor mesh,255,255,255
		'EntityColor box,255,255,255

		Local Pick:TEntity = CameraPick(CAMERA, MouseX(), MouseY()) 
		Local pe:TEntity = PickedEntity() 
		Local ps:TSurface = PickedSurface() 
		
		If pick <> Null
			'DebugLog "Picked!"
			'DebugLog "PickedX(): " + PickedX()
			'DebugLog "PickedY(): " + PickedY()
			'DebugLog "PickedZ(): " + PickedZ()
			'DebugLog "PickedNX(): " + PickedNX()
			'DebugLog "PickedNY(): " + PickedNY()
			'DebugLog "PickedNZ(): " + PickedNZ()
			'DebugLog "PickedTime(): " + PickedTime()
			'DebugLog "PickedEntity(): " + (pe).tostring()
			'DebugLog "PickedSurface(): " + (ps).tostring()
			'DebugLog "PickedTriangle(): " + PickedTriangle()
			'EntityColor PickedEntity(), 255, 255, 0
			
			PositionEntity marker, PickedX(), PickedY(), PickedZ() 
			w1.Dimple EntityX(marker) + bmaxx, EntityZ(marker) + bmaxz, 1.5, 2.0
			'fxWater_Dimple(w1, EntityX(ent)+bmaxx,EntityZ(ent)+bmaxz, 1.0, 2.0
			DebugLog "x " + Int(PickedX()) + " y " + Int(PickedY()) + " z " + Int(PickedZ()) 
			
		'Else
		'	DebugLog "Not Picked"
			
		EndIf
	
	EndIf
	
Wend

End

'--------------------------------------------------------------------------------------------------

Function update_ball( ent:TEntity )

	'move the ball
	TranslateEntity ent, bx, by, bz

	DoDimple = False
	
	'check left/right walls
	If EntityX(ent) > bmaxx - 2 Then bx = bx * -1
	If EntityX(ent) < - bmaxx + 2 Then bx = bx * -1

	'check ceiling bounce
	If EntityY(ent) > bmaxy - 2 Then
		'reverse vertical direction
		by = by * -1.0
		'create dimple
		'w2.Dimple EntityX(ent) + bmaxx, EntityZ(ent) + bmaxz, - 1.0, 5.0
		'slightly alter direction
		bx = bx + Rnd(- 0.25, 0.25) 
		bz = bz + Rnd(- 0.25, 0.25) 
		
	EndIf

	'check floor bounce
	If EntityY(ent) < - bmaxy + 2 Then
	
	 'reverse vertical direction
	   by = by * -1.0
	   
		'create dimple
		w1.Dimple EntityX(ent) + bmaxx, EntityZ(ent) + bmaxz, 1.0, 2.0
		
		'slightly alter direction
	   bx = bx + Rnd(- 0.25, 0.25) 
	   bz = bz + Rnd(- 0.25, 0.25) 
		
	EndIf

	'check front/back walls
	If EntityZ(ent) > bmaxz - 2 Then bz = bz * -1
	If EntityZ(ent) < - bmaxz + 2 Then bz = bz * -1

End Function

'--------------------------------------------------------------------------------------------------


Function BeginMax2D()

Local X:Int, Y:Int, W:Int, h:Int
		GetViewport(X, Y, W, h) 
		
		glDisable(GL_LIGHTING)
		glDisable(GL_DEPTH_TEST)
		glDisable(GL_SCISSOR_TEST)
		glDisable(GL_FOG)
		glDisable(GL_CULL_FACE)

		glMatrixMode GL_TEXTURE
		glLoadIdentity
		
		glMatrixMode GL_PROJECTION
		glLoadIdentity
		glOrtho 0, GraphicsWidth(), GraphicsHeight(), 0, - 1, 1
		
		glMatrixMode GL_MODELVIEW
		glLoadIdentity
		
		SetViewport X, Y, W, h
		
		
		Local MaxTex:Int 
		glGetIntegerv(GL_MAX_TEXTURE_UNITS, Varptr(MaxTex))

		
		For Local Layer:Int = 0 Until MaxTex
			glActiveTexture(GL_TEXTURE0 + Layer) 
					
			glDisable(GL_TEXTURE_CUBE_MAP)
			glDisable(GL_TEXTURE_GEN_S)
			glDisable(GL_TEXTURE_GEN_T)
			glDisable(GL_TEXTURE_GEN_R)
	
			glDisable(GL_TEXTURE_2D)
		Next
		
		glActiveTexture(GL_TEXTURE0)
		
		'DrawRect - 10 , - 10 , 5 , 5
		
		glViewport(0, 0, TGlobal.WIDTH, TGlobal.HEIGHT) 
		glScissor(0, 0, TGlobal.WIDTH, TGlobal.HEIGHT) 
		

End Function

Function EndMax2D()

		glDisable(GL_TEXTURE_CUBE_MAP)
		glDisable(GL_TEXTURE_GEN_S)
		glDisable(GL_TEXTURE_GEN_T)
		glDisable(GL_TEXTURE_GEN_R)
	
		glDisable(GL_TEXTURE_2D)

		TGlobal.EnableStates()

End Function

'Creates a flat grid mesh
Function create_mesh_plane:TMesh(WIDTH:Int = 1, depth:Int = 1, doublesided:Int = False, Parent:TEntity = Null) 

	Local tot:Int = WIDTH + (depth * WIDTH) 
	Local Mix:Float = (WIDTH + depth) * 0.5
	
	Local MESH:TMesh = createMesh(Parent) 
	Local surf:TSurface = CreateSurface(MESH) 
	
	Local stx:Float = -.5
	Local sty:Float = stx
	Local stp:Float = Float(1) / Float(Mix) 
	Local Y:Float = sty
	
		For Local a:Int = 0 To depth
		  Local X:Float = stx
		  Local v:Float = a / Float(depth) 
			
			For Local b:Int = 0 To WIDTH
			  Local u:Float = b / Float(WIDTH) 
			  
				addVertex(surf, X, 0, Y, u, v) 
				 
			   X = X + stp
			Next
			
		   Y = Y + stp
		Next
		
		For Local a:Int = 0 To depth - 1
		
			For Local b:Int = 0 To WIDTH - 1
			  Local v0:Int = a * (WIDTH + 1) + b ; Local v1:Int = v0 + 1
			  Local v2:Int = (a + 1) * (WIDTH + 1) + b + 1 ; Local v3:Int = v2 - 1
			  
				addTriangle(surf, v0, v2, v1) 
				addTriangle(surf, v0, v3, v2) 
				
			Next
			
		Next
	
	  updateNormals MESH

	If doublesided = True Then EntityFX MESH, 16
	
	FitMesh MESH, - WIDTH * 0.5, 0, - depth * 0.5, WIDTH, 1, depth
	'ScaleEntity mesh, 1.5, 0, 1.5
	
  Return MESH
	
End Function


your problem is that you init the arrays at 0,0 and try to access them with anything larger.

This

W.bank1[FXWATER_MAX_WIDTH + 1, FXWATER_MAX_DEPTH + 1]
W.bank2[FXWATER_MAX_WIDTH + 1, FXWATER_MAX_DEPTH + 1]

Should be

W.bank1 = new Float[FXWATER_MAX_WIDTH + 1, FXWATER_MAX_DEPTH + 1]
W.bank2 = new Float[FXWATER_MAX_WIDTH + 1, FXWATER_MAX_DEPTH + 1]

Thank you.

SuperStrict version will be posted shortly, after I fix this weird update glitch.

Fixed: OO & SuperStrict version.
SuperStrict

Framework brl.max2d
Import brl.timer

'Import klepto.minib3d
Import sidesign.minib3d

'SetGraphicsDriver(GLMax2DDriver(), GRAPHICS_BACKBUFFER | GRAPHICS_DEPTHBUFFER | GRAPHICS_ACCUMBUFFER)


'------------------------------------------------------------------------------------------------------
'Ported to BlitzMax by Plash - 1/30/08

' fxWater Module by Danny van der Ark - dendanny@... april '04
'
' (Heavily) inpired by samples by Reda Borchardt and Rob Cummings.
' use as you like - send me a sample would be cool.
'
'
' Usage:
'
' 1. Create a water surface using: FX_WaterArea.Create( name$, xsize, zsize, dampening#, parent )
'    This function returns the object to the water surface which you will need later.
'
' 2. Obtain the entity handle (to apply color, texture, alpha, etc) using the function get_entity()
'
' 3. Then simply call 'FX_WaterArea.UpdateWA()' every frame during your main loop.
'
' 4. To create a splash in the water use the Dimple() function. The function needs the
'	 the coordinates of the splash, the force/strength of the splash and the 'range'
'	 or size of the splash.
'
'	 Dimple( x, z, force#=1.0, range#=1.0)
'
' 5. Freeing stuff not done yet because I want to alter it to use memory banks in stead of
'	 a large static array to store the vertex data - wich should give a more efficient use
'	 of memory...
'
'
' You can create as many surfaces of any size as you wish. If you wish to use surfaces larger 
' than 100x100, adjust the FXWATER_MAX_DEPTH/WIDTH globals. If you want more than 5 surfaces
' at the same time, adjust the fxwater_max accordingly. 
' 
' It is necesary To 'UpdateNormals' every frame to ensure the highlights are re-calculated every
' frame. Without this the ripples are there, but just not visible. This slows things down
' dramatically ofcourse. Any other ideas welcome....
'
' He ho, enjoy!
'
' ooo
' (_) Danny v.d. Ark



'Global fxWATER_MAX:Int = 5				'max number of active surfaces/effects at one time
'Global fxWATER_NUM:Int = 0				'current number of active water effects.

'Global FXWATER_MAX_BANKS:Int = fxWATER_MAX * 2
'Global FXWATER_NUM_BANKS:Int = 0

Global FXWATER_MAX_WIDTH:Int = 100		'max sub-division for water meshes
Global FXWATER_MAX_DEPTH:Int = 100		'max sub-division for water meshes

Global DEMO_WATER_WIDTH:Int = 40	'--> Adjust these for different plane sizes / mesh resolution
Global DEMO_WATER_DEPTH:Int = 40

'reserve memory banks for vertice altitudes
'Global fxWaterBank:Float[FXWATER_MAX_BANKS + 1, FXWATER_MAX_WIDTH + 1, FXWATER_MAX_DEPTH + 1] 


Type FX_WaterArea

  Global _list:TList = New TList

	Field id:Int
	Field name:String
	
	'Field FXWATER_MAX_WIDTH:Int		'max sub-division for water meshes
	'Field FXWATER_MAX_DEPTH:Int
	
	Field Active:Int				'if not ripples then fx is not active
	
	Field Parent:TEntity			'parent entity (if any)
	Field entity:TMesh				'water mesh
	Field SURFACE:TSurface			'water surface

	Field dmpx:Float 				'dimple values
	Field dmpz:Float
	
	Field waterbanks:Float[,,] 
	Field bank1:Int = 0
	Field bank2:Int = 1
	'Field bank1:Float[,] 
	'Field bank2:Float[,] 

	Field WIDTH:Int					'width of plane / surface
	Field depth:Int					'depth of plane / surface
	Field dampening:Float			'water dynamics
	
		Method New() 
			_list.AddLast(Self) 
			
		End Method

		
		Function Create:FX_WaterArea(Name:String, WIDTH:Int = 1, depth:Int = 1, damp:Float = 0.01, Parent:TEntity = Null) 
		
		  Local W:FX_WaterArea = New FX_WaterArea
		
			W.id = 1
			W.Name = Name
			
			W.Active = True
			
			'create rectangular grid mesh
			W.WIDTH = WIDTH
			W.depth = depth
			W.dampening = 1 - damp
			
			W.Parent = Parent
			W.entity = create_mesh_plane(W.WIDTH, W.depth, False, Parent) 
			W.SURFACE = getSurface(W.entity, 1) 
			
			'dimple XZ values - for calculating dimple coordinates
			w.dmpx = width * 0.5
			w.dmpz = depth * 0.5
			
			'store handle for quick retrieval during collision
			NameEntity W.entity, "FX_WA::" + Name
			
			'reserve memory banks to hold vertex energy
			'W.bank1 = New Float[FXWATER_MAX_WIDTH + 1, FXWATER_MAX_DEPTH + 1] 
			'W.bank2 = New Float[FXWATER_MAX_WIDTH + 1, FXWATER_MAX_DEPTH + 1] 
			W.waterbanks = New Float[2, FXWATER_MAX_WIDTH + 1, FXWATER_MAX_DEPTH + 1] 
			
		 'return object
		   Return W
			
		End Function
		
		'--------------------------------------------------------------------------------------------------
		Function UpdateWA() 
		
			For Local W:FX_WaterArea = EachIn _list
		
			'if the surface is perfectly flat then this value remains 0
			  Local dyna:Float = 0
				
				'process water
				    For Local X:Int = 1 To W.WIDTH - 1
				        For Local Z:Int = 1 To W.depth - 1
						
							W.waterbanks[W.bank2, X, Z] = (W.waterbanks[W.bank1, X - 1, Z] + W.waterbanks[W.bank1, X + 1, Z] + W.waterbanks[W.bank1, X, Z + 1] + W.waterbanks[W.bank1, X, Z - 1] ) / 2.1 - W.waterbanks[W.bank2, X, Z] 
							W.waterbanks[W.bank2, X, Z] = W.waterbanks[W.bank2, X, Z] * W.dampening
							
						  dyna = dyna + W.waterbanks[W.bank2, X, Z] 
						  
				        Next
				    Next
		
				'Only deform patch if necesary ;patch transform
					If Abs(dyna) > 0.2 Then
					  Local k:Int = 0
					  
						For Local i:Int = 0 To W.depth
						
							For Local j:Int = 0 To W.WIDTH
							  Local h:Float = W.waterbanks[W.bank2, j, i] 
							  
								VertexCoords(W.SURFACE, k, VertexX(W.SURFACE, k), h, VertexZ(W.SURFACE, k)) 
								VertexNormal(W.SURFACE, k, - 0.8 - h * 0.25, h * 0.1, 0.2 - h * 0.25) 
								
							   k = k + 1
								
							Next
							
						Next
						
					EndIf
		
			  'should be optional - depending on type of texture (slows down seriously!)
			   updateNormals W.entity
				
			 'Swap Buffers
			  Local tmp:Int = W.bank1
				W.bank1 = W.bank2
				W.bank2 = tmp
		
			Next
		
		End Function
		
		'--------------------------------------------------------------------------------------------------
		Method Dimple(X:Int, Z:Int, force:Float = 1.0, Range:Float = 1.0) 
			
		  'w:FX_WaterArea = FX_WaterArea(HandleToObject(hand))
			DebugLog x + "," + z
			
			For Local xg:Int = X - Range * 0.5 To X + Range * 0.5
			
				For Local zg:Int = Z - Range * 0.5 To Z + Range * 0.5
				
					If xg > 0 And xg < WIDTH And zg > 0 And zg < depth Then
						waterbanks[bank2, xg, zg] = force
						
					EndIf
					
				Next
				
			Next
		
		End Method
		
		'--------------------------------------------------------------------------------------------------
		Method Get_Surface:TSurface() 
		
			'w:FX_WaterArea = FX_WaterArea(HandleToObject( hand ))
			'Return w.surface
			Return Self.SURFACE
			
		End Method
		
		'--------------------------------------------------------------------------------------------------
		Method Get_Entity:TMesh() 
		
			'Return w.entity
			Return Self.entity
			
		End Method
		
		'----------------------------------NOTE: NEEDS TO BE IMPLEMENTED-----------------------------------
		Method Free_Buffers:Int() 
		
		'| Frees all buffers. Call as a part of when scene/level is removed from memory.
		
		
			'NOTE: resize memory banks to 0 (once implemented).
		
			Return 0
			
		End Method

End Type

'Demo options
Global OPT_WIREFRAME:Int = 0
Global OPT_REFRESH:Int = 0
Global OPT_BALLFREEZE:Int = 0
Global OPT_CEILING:Int = 1

Graphics3D 800, 600, 32, 2

' Camera + Light
Global campivot:TPivot = createPivot() 
Global CAMERA:TCamera = createCamera(campivot) 
	PositionEntity camera, 0, 0, -35
	PointEntity camera, campivot

Local LIGHT:TLight = createLight(2) 
	PositionEntity LIGHT, - 60, 0, 100
	LightColor LIGHT, 240, 240, 210
	PointEntity light, campivot

light = CreateLight(2)
	PositionEntity light,50,0,-50
	LightColor LIGHT, 150, 150, 180
	PointEntity light, campivot

AmbientLight 40, 40, 40

'camerapick cursor
Local marker:TMesh = createSphere() 
	ScaleEntity marker, 0.2, 0.2, 0.2
	EntityColor marker, 255, 0, 0

'load texture
Local tex:TTexture = LoadTexture ("water.bmp", 1 + 64) 

'create water planes
Global w1:FX_WaterArea = FX_WaterArea.Create("floor", DEMO_WATER_WIDTH, DEMO_WATER_DEPTH, 0.025) 
  Local water:TMesh = w1.Get_Entity() 
	PositionEntity water, 0, - 10, 0
	EntityColor water, 30, 50, 200
	EntityShininess water, 0.1
	EntityTexture water, tex
	EntityPickMode water, 2
	
w1.dimple 1, 1, 0.001, 0.001   'force refresh

'Global w2:FX_WaterArea = FX_WaterArea.Create("ceiling", DEMO_WATER_WIDTH, DEMO_WATER_DEPTH, 0.025) 
'  water = w2.Get_Entity() 
'	flipMesh water ' flip it because the camera is underneath it
'	PositionEntity water, 0, 10, 0
'	EntityColor water, 250, 100, 100
'	EntityColor water, 140, 130, 20
'	EntityShininess water, 0.1
'	EntityTexture water, tex
'	EntityPickMode water, 2

'w2.dimple 1, 1, 0.001, 0.001	'force refresh

 
 

'set random ball direction/speed
Global bx:Float = 0.2
Global by:Float = -0.25
Global bz:Float = -0.25

Global bmaxx:Float = DEMO_WATER_WIDTH * 0.5	'half the width of the water plane
Global bmaxy:Float = 10.0
Global bmaxz:Float = DEMO_WATER_DEPTH * 0.5	'half the depth of the water plane

'create ball
Local ball:TEntity = CreateSphere(6)
	EntityColor ball, 45, 45, 45
	EntityShininess ball, 1.0
	EntityTexture ball, tex
	
SeedRnd MilliSecs()

Local tstart:Int = MilliSecs() + 1000
Local frame:Int = 0
Local fps:Int = 0

Global LastX:Float = 0
Global lasty:Float = 0

Local tim:TTimer = CreateTimer(60) 

Local l:String = "WavyWaterFx by Danny van der Ark"

While Not KeyHit(key_escape)

	'update bouncing ball
	update_ball ball
	
	'update fxWater
	FX_WaterArea.UpdateWA
	
	'TurnEntity campivot, 0, 0.25, 0
	If KeyDown(key_right) 
		TurnEntity campivot, 0, 0.75, 0
		
	ElseIf KeyDown(KEY_LEFT) 
		TurnEntity campivot, 0, - 0.75, 0
		
	EndIf
	
	'fps
	    frame:+1
		If MilliSecs() >= tstart Then
			fps = frame
			frame = 0
			tstart = MilliSecs() + 1000
			
		EndIf

	'toggle ceiling [C]
	'If KeyHit(key_c) Then
	'	OPT_CEILING = 1 - OPT_CEILING
	'	If OPT_CEILING Then
	'		water = fxWater_Get_Entity(w2)
	'		ShowEntity water
	'	Else
	'		water = fxWater_Get_Entity(w2)
	'		HideEntity water
	'	EndIf
	'EndIf
	
	'pause all [P]
	If KeyHit(KEY_P) Then
	   FlushKeys
	   
		While Not KeyHit(KEY_P) Wend
		
	EndIf

	'pause ball [B]
	If KeyHit(KEY_B) Then
	  OPT_BALLFREEZE:~1
		
		If OPT_BALLFREEZE Then
		   PositionEntity ball, 0, 0, 0
			bx = 0 ; by = 0 ; bz = 0
			
		Else
			bx = Rnd(- 1, 1) ; by = Rnd(- 2, 2) ; bz = Rnd(- 1, 1) 
			
		EndIf
		
	EndIf

	'wireframe [W]
	If KeyHit(KEY_W) Then
	  OPT_WIREFRAME:~1
	  
		Wireframe OPT_WIREFRAME
		
	EndIf
	
	'Dirty refresh [D]
	If KeyHit(KEY_D) Then
	  OPT_REFRESH:~1
		
	EndIf	
	
	UpdateWorld
	RenderWorld
	
	'sidesign.minib3d - text
	TBlitz2D.Text 10, 220, "FPS  " + fps
	
	  Rem
		'TBlitz2d.BeginMax2D
		BeginMax2D
		  SetBlend alphablend
		   	'SetAlpha 0.5
			SetColor 100, 100, 100
			DrawText "based on samples from Reda Borchardt And Rob Cummings.", 2, 12
			SetColor 20, 140, 255
			DrawText "[ESC] to quit - [D] for fast but dirty refresh(" + OPT_REFRESH + ") - [W] To toggle WireFrame (" + OPT_WIREFRAME + ")", 2, 454
			DrawText "[P] To pause  - [B] to pause/reset ball - [C] to toggle ceiling", 2, 466
			SetColor 250, 250, 220
			DrawText "FPS  " + fps, 10, 220
			'DrawText "TRIS " + TrisRendered(), 10, 232
		  SetBlend solidblend
		EndMax2D
		'TBlitz2d.EndMax2D
	  EndRem
	
	'check refresh mode
	
	If OPT_REFRESH Then
		'fast and dirty (pot noodle style)
	    Flip False
	
	Else
		'slow but clean
		Flip True
	   WaitTimer tim
		
	EndIf

	'If MouseHit(1) Then
	'	x = Rnd(1, DEMO_WATER_WIDTH)
	'	z = Rnd(1, DEMO_WATER_DEPTH)
	'	fxWater_Dimple(w1, x, z, 1, 5)
	'EndIf
	
	If MouseHit(1)
	
		' reset entity colors
		'EntityColor sphere,255,255,255
		'EntityColor mesh,255,255,255
		'EntityColor box,255,255,255

		Local Pick:TEntity = CameraPick(CAMERA, MouseX(), MouseY()) 
		Local pe:TEntity = PickedEntity() 
		Local ps:TSurface = PickedSurface() 
		
		If pick <> Null
			'DebugLog "Picked!"
			'DebugLog "PickedX(): " + PickedX()
			'DebugLog "PickedY(): " + PickedY()
			'DebugLog "PickedZ(): " + PickedZ()
			'DebugLog "PickedNX(): " + PickedNX()
			'DebugLog "PickedNY(): " + PickedNY()
			'DebugLog "PickedNZ(): " + PickedNZ()
			'DebugLog "PickedTime(): " + PickedTime()
			'DebugLog "PickedEntity(): " + (pe).tostring()
			'DebugLog "PickedSurface(): " + (ps).tostring()
			'DebugLog "PickedTriangle(): " + PickedTriangle()
			'EntityColor PickedEntity(), 255, 255, 0
			
			PositionEntity marker, PickedX(), PickedY(), PickedZ() 
			w1.Dimple EntityX(marker) + bmaxx, EntityZ(marker) + bmaxz, 1.5, 2.0
			'fxWater_Dimple(w1, EntityX(ent)+bmaxx,EntityZ(ent)+bmaxz, 1.0, 2.0
			DebugLog "x " + Int(PickedX()) + " y " + Int(PickedY()) + " z " + Int(PickedZ()) 
			
		'Else
		'	DebugLog "Not Picked"
			
		EndIf
	
	EndIf
	
Wend

End

'--------------------------------------------------------------------------------------------------

Function update_ball( ent:TEntity )

	'move the ball
	TranslateEntity ent, bx, by, bz

	Local DoDimple:Int = False
	
	'check left/right walls
	If EntityX(ent) > bmaxx - 2 Then bx = bx * -1
	If EntityX(ent) < - bmaxx + 2 Then bx = bx * -1

	'check ceiling bounce
	If EntityY(ent) > bmaxy - 2 Then
		'reverse vertical direction
		by = by * -1.0
		'create dimple
		'w2.Dimple EntityX(ent) + bmaxx, EntityZ(ent) + bmaxz, - 1.0, 5.0
		'slightly alter direction
		bx = bx + Rnd(- 0.25, 0.25) 
		bz = bz + Rnd(- 0.25, 0.25) 
		
	EndIf

	'check floor bounce
	If EntityY(ent) < - bmaxy + 2 Then
	
	 'reverse vertical direction
	   by = by * -1.0
	   
		'create dimple
		w1.Dimple EntityX(ent) + bmaxx, EntityZ(ent) + bmaxz, 1.0, 2.0
		
		'slightly alter direction
	   bx = bx + Rnd(- 0.25, 0.25) 
	   bz = bz + Rnd(- 0.25, 0.25) 
		
	EndIf

	'check front/back walls
	If EntityZ(ent) > bmaxz - 2 Then bz = bz * -1
	If EntityZ(ent) < - bmaxz + 2 Then bz = bz * -1

End Function

'--------------------------------------------------------------------------------------------------


Function BeginMax2D()

Local X:Int, Y:Int, W:Int, h:Int
		GetViewport(X, Y, W, h) 
		
		glDisable(GL_LIGHTING)
		glDisable(GL_DEPTH_TEST)
		glDisable(GL_SCISSOR_TEST)
		glDisable(GL_FOG)
		glDisable(GL_CULL_FACE)

		glMatrixMode GL_TEXTURE
		glLoadIdentity
		
		glMatrixMode GL_PROJECTION
		glLoadIdentity
		glOrtho 0, GraphicsWidth(), GraphicsHeight(), 0, - 1, 1
		
		glMatrixMode GL_MODELVIEW
		glLoadIdentity
		
		SetViewport X, Y, W, h
		
		
		Local MaxTex:Int 
		glGetIntegerv(GL_MAX_TEXTURE_UNITS, Varptr(MaxTex))

		
		For Local Layer:Int = 0 Until MaxTex
			glActiveTexture(GL_TEXTURE0 + Layer) 
					
			glDisable(GL_TEXTURE_CUBE_MAP)
			glDisable(GL_TEXTURE_GEN_S)
			glDisable(GL_TEXTURE_GEN_T)
			glDisable(GL_TEXTURE_GEN_R)
	
			glDisable(GL_TEXTURE_2D)
		Next
		
		glActiveTexture(GL_TEXTURE0)
		
		'DrawRect - 10 , - 10 , 5 , 5
		
		glViewport(0, 0, TGlobal.WIDTH, TGlobal.HEIGHT) 
		glScissor(0, 0, TGlobal.WIDTH, TGlobal.HEIGHT) 
		

End Function

Function EndMax2D()

		glDisable(GL_TEXTURE_CUBE_MAP)
		glDisable(GL_TEXTURE_GEN_S)
		glDisable(GL_TEXTURE_GEN_T)
		glDisable(GL_TEXTURE_GEN_R)
	
		glDisable(GL_TEXTURE_2D)

		TGlobal.EnableStates()

End Function

'Creates a flat grid mesh
Function create_mesh_plane:TMesh(WIDTH:Int = 1, depth:Int = 1, doublesided:Int = False, Parent:TEntity = Null) 

	Local tot:Int = WIDTH + (depth * WIDTH) 
	Local Mix:Float = (WIDTH + depth) * 0.5
	
	Local MESH:TMesh = createMesh(Parent) 
	Local surf:TSurface = CreateSurface(MESH) 
	
	Local stx:Float = -.5
	Local sty:Float = stx
	Local stp:Float = Float(1) / Float(Mix) 
	Local Y:Float = sty
	
		For Local a:Int = 0 To depth
		  Local X:Float = stx
		  Local v:Float = a / Float(depth) 
			
			For Local b:Int = 0 To WIDTH
			  Local u:Float = b / Float(WIDTH) 
			  
				addVertex(surf, X, 0, Y, u, v) 
				 
			   X = X + stp
			Next
			
		   Y = Y + stp
		Next
		
		For Local a:Int = 0 To depth - 1
		
			For Local b:Int = 0 To WIDTH - 1
			  Local v0:Int = a * (WIDTH + 1) + b ; Local v1:Int = v0 + 1
			  Local v2:Int = (a + 1) * (WIDTH + 1) + b + 1 ; Local v3:Int = v2 - 1
			  
				addTriangle(surf, v0, v2, v1) 
				addTriangle(surf, v0, v3, v2) 
				
			Next
			
		Next
	
	  updateNormals MESH

	If doublesided = True Then EntityFX MESH, 16
	
	FitMesh MESH, - WIDTH * 0.5, 0, - depth * 0.5, WIDTH, 1, depth
	'ScaleEntity mesh, 1.5, 0, 1.5
	
  Return MESH
	
End Function


How would this work on an irregular surface? (i.e. same surface it uses but some faces deleted to create different shapes, like for terrain lakes/ponds etc)

Just looking for a point in the right direction..

EDIT: Use a TMap (uneducated guess), or a type for each individual face? Another idea is to use the same setup, only to define different boundaries for the edges of the effect (no clue how.)