Demo_Water

skorpio

29-09-2007 08:08:43

Hello

I have been trying to get Demo_Water to run but I get this problem. I'm not sure how to fix it.
I cleaned up most of the code but I can't get pass this. Hopefully I can get to run and post the changes later.

Thanks,




application.go()
File "C:\Python24\lib\site-packages\ogre\renderer\OGRE\sf_OIS.py", line 60, in
go
if not self._setUp():
File "C:\Python24\lib\site-packages\ogre\renderer\OGRE\sf_OIS.py", line 99, in
_setUp
self._createScene()
File "C:\PythonOgre10\demos\ogre\Demo_Water.py", line 560, in _createScene
self.WaterMesh = WaterMesh.WaterMesh(MESH_NAME, PLANE_SIZE, COMPLEXITY)
File "C:\PythonOgre10\demos\ogre\WaterMesh.py", line 92, in __init__
texcoordsBufData,True)
Boost.Python.ArgumentError: Python argument types in
HardwareVertexBuffer.writeData(HardwareVertexBuffer, int, int, c_float_Array
_8450, bool)
did not match C++ signature:
writeData(class Ogre::SharedPtr<struct HardwareVertexBuffer_wrapper> {lvalue
}, unsigned int, unsigned int, void const *, bool)
writeData(class Ogre::HardwareVertexBuffer {lvalue}, unsigned int offset, un
signed int length, void const * pSource, bool discardWholeBuffer=False)
Exception exceptions.AttributeError: "WaterMesh instance has no attribute 'verte
xBuffers'" in <bound method WaterMesh.__del__ of <WaterMesh.WaterMesh instance a
t 0x01A87CB0>> ignored

Danaugrs

29-09-2007 13:28:38

I know this doesn't help hehe, but I had been trying to make it runable a couple of weeks ago and, like you, with no success.

I really would like to see water features in Python-Ogre. If we could have the Water, Ocean and Fresnel demos working it would be very nice. My game's water looks too silly, just a plane with an animation. Hehe.

Cya.

andy

29-09-2007 15:52:36

The Fresnel demo is converted and works OK (let me know if this is not the case -- does need a decent graphics card)..

I never finished porting the water or ocean demos and would be happy to help debug the work being done by others..

Perhaps you could post your current Demo_Water (either here or on the google mailing list) and I'll have a look

regards
Andy

skorpio

30-09-2007 08:39:42

Here is the code.

I cleaned up most of error but it needs more work

Demo_water.py

# This code is in the Public Domain
# -----------------------------------------------------------------------------
# This source file is part of Python-Ogre
# For the latest info, see http://python-ogre.org/
#
# It is likely based on original code from OGRE and/or PyOgre
# For the latest info, see http://www.ogre3d.org/
#
# You may use this sample code for anything you like, it is not covered by the
# LGPL.
# -----------------------------------------------------------------------------
# */
# /* Static water simulation by eru
# * Started 29.05.2003, 20:54:37
# */

#include "ExampleApplication.h"
import ogre.renderer.OGRE as Ogre
import WaterMesh
import math
import SampleFramework as sf
import random
import ctypes

#AnimationState* self.mAnimState

## Mesh stuff
MESH_NAME ="WaterMesh"
ENTITY_NAME ="WaterEntity"
MATERIAL_PREFIX ="Examples/Water"
MATERIAL_NAME ="Examples/Water0"
COMPLEXITY =64 ## watch out - number of polys is 2*ACCURACY*ACCURACY !
PLANE_SIZE =3000.0

CIRCLE_MATERIAL ="Examples/Water/Circles"

# /* Some global variables */

# MeshPtr mesh ;
# SubMesh *subMesh ;
# float *vertexBuffers[3] ; // we need 3 vertex buffers
# int currentBuffNumber ;
# int complexity ;
# String meshName ;
# int numFaces ;
# int numVertices ;
# Vector3* vNormals ;

# HardwareVertexBufferSharedPtr posVertexBuffer ;
# HardwareVertexBufferSharedPtr normVertexBuffer ;
# HardwareVertexBufferSharedPtr texcoordsVertexBuffer ;
# HardwareIndexBufferSharedPtr indexBuffer ;

# Real lastTimeStamp ;
# Real lastAnimationTimeStamp;
# Real lastFrameTime ;

# bool useFakeNormals ;





##
## Note that this function makes use of CTypes and def ptr casting to access Ogre Library functions
##
def prepareCircleMaterial():
#global circles_MATERIAL

storageclass = ctypes.c_float * (256 * 256 * 4)
bmap=storageclass(1.0) # you just need to put some value in this to get it started...
#print ctypes.sizeof(bmap)
#ctypes.memset ( bmap, 127, 256 * 256 )

for b in range(16):
x0 = b % 4
y0 = b >> 2
radius = 4.0 + 1.4 * b
for x in range(64):
for y in range (64) :
dist = math.sqrt((x-32)*(x-32)+(y-32)*(y-32)) ## 0..ca.45
dist = math.fabs(dist-radius-2) / 2.0
dist = dist * 255
if (dist>255):
dist=255
colour = 255-dist
colour = ((15-b))/15.0 * colour

bmap[4*(256*(y+64*y0)+x+64*x0)+0]=colour
bmap[4*(256*(y+64*y0)+x+64*x0)+1]=colour
bmap[4*(256*(y+64*y0)+x+64*x0)+2]=colour
bmap[4*(256*(y+64*y0)+x+64*x0)+3]=colour

### Need to pass the address to MemoryDataStream and size in bytes
imgstream = Ogre.MemoryDataStream(ctypes.addressof(bmap), ctypes.sizeof(bmap) )

Ogre.TextureManager.getSingleton().loadRawData(
CIRCLE_MATERIAL,
Ogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
imgstream ,
256,
256,
Ogre.PixelFormat.PF_A8R8G8B8)


material = Ogre.MaterialManager.getSingleton().create( CIRCLE_MATERIAL,
Ogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME)
texLayer = material.getTechnique(0).getPass(0).createTextureUnitState( CIRCLE_MATERIAL )
texLayer.setTextureAddressingMode( ogre.TextureUnitState.TAM_CLAMP )
material.setSceneBlending( ogre.SceneBlendType.SBT_ADD )
material.setDepthWriteEnabled( False )
material.load()



# /* =========================================================================*/
# /* WaterCircle class */
# /* =========================================================================*/
CIRCLE_SIZE = 500.0
CIRCLE_TIME = 0.5
class WaterCircle:
def __init_(self):
self.name = ""
# SceneNode *node
# MeshPtr mesh
# SubMesh *subMesh
# Entity *entity
# Real tm
# static bool first
# ## some buffers shared by all self.circles
# static HardwareVertexBufferSharedPtr posnormVertexBuffer
# static HardwareIndexBufferSharedPtr indexBuffer ## indices for 2 faces
# static HardwareVertexBufferSharedPtr *texcoordsVertexBuffers

# float *texBufData
self.headNode = None
self.waterOverlay = None
self.particleSystem = None
self.particleEmitter = None
self.sceneMgr = None

_prepareMesh()

mesh = Ogre.MeshManager.getSingleton().createManual(name,
Ogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME)
subMesh = mesh.createSubMesh()
subMesh.useSharedVertices=False
numVertices = 4
first = True

if (first) : ## first Circle, create some static common data:
first = False

## static buffer for position and normals
size = 2 * ogre.VertexElement.getTypeSize(ogre.VertexElementType.VET_FLOAT3) ## 6 * float
posnormVertexBuffer = \
Ogre.HardwareBufferManager.getSingleton().createVertexBuffer(
size, ## size of one vertex data 6 * float
4, ## number of vertices
Ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY, ## usage
False) ## no shadow buffer
posnormBufData = posnormVertexBuffer.lock(Ogre.HardwareBuffer.HBL_DISCARD)

buff=[]
for i in range(numVertices):
buf.append(((i%2)-0.5)*CIRCLE_SIZE ) ## pos X
buf.append(0) ## pos Y
buf.append(((i/2)-0.5)*CIRCLE_SIZE ) ## pos Z
buf.append(0) ## normal X
buf.append(1) ## normal Y
buf.append(0) ## normal Z
ogre.setFloat( posnormBufData , buff ) # write unsigned ints...
posnormVertexBuffer.unlock()

## static buffers for 16 sets of texture coordinates
texcoordsVertexBuffers = []
for lvl in range (16):
texcoordsVertexBuffers.append(
Ogre.HardwareBufferManager.getSingleton().createVertexBuffer(
Ogre.VertexElement.getTypeSize(ogre.VertexElementType.VET_FLOAT2), ## size of one vertex data
numVertices, ## number of vertices
Ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY, ## usage
False) ## no shadow buffer
)
texcoordsBufData = texcoordsVertexBuffers[lvl].lock(Ogre.HardwareBuffer.HBL_DISCARD)
x0 = (lvl % 4) * 0.25
y0 = (lvl / 4) * 0.25
y0 = 0.75-y0 ## upside down
for i in range (4):
texcoordsBufData[i*2 + 0]= \
x0 + 0.25 * (i%2)
texcoordsBufData[i*2 + 1]= \
y0 + 0.25 * (i/2)

texcoordsVertexBuffers[lvl].unlock()


## Index buffer for 2 faces
faces[6] = (2,1,0, 2,3,1)
indexBuffer = \
Ogre.HardwareBufferManager.getSingleton().createIndexBuffer(
Ogre.HardwareIndexBuffer.IT_16BIT,
6,
Ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY)
indexBuffer.writeData(0,
indexBuffer.getSizeInBytes(),
faces,
True) ## true?


## Initialize vertex data
subMesh.vertexData = Ogre.VertexData()
subMesh.vertexData.vertexStart = 0
subMesh.vertexData.vertexCount = 4
## first, set vertex buffer bindings
vbind = subMesh.vertexData.vertexBufferBinding
vbind.setBinding(0, posnormVertexBuffer)
vbind.setBinding(1, texcoordsVertexBuffers[0])
## now, set vertex buffer declaration
vdecl = subMesh.vertexData.vertexDeclaration
vdecl.addElement(0, 0, Ogre.VET_FLOAT3, VOgre.ES_POSITION)
vdecl.addElement(0, 3*4, Ogre.VET_FLOAT3, Ogre.VES_NORMAL)
vdecl.addElement(1, 0, Ogre.VET_FLOAT2, Ogre.VES_TEXTURE_COORDINATES)

## Initialize index data
subMesh.indexData.indexBuffer = indexBuffer
subMesh.indexData.indexStart = 0
subMesh.indexData.indexCount = 6

## set mesh bounds
circleBounds(-CIRCLE_SIZE/2.0, 0, -CIRCLE_SIZE/2.0,
CIRCLE_SIZE/2.0, 0, CIRCLE_SIZE/2.0)
mesh._setBounds(circleBounds)
mesh.load()
mesh.touch()

def setTextureLevel():
subMesh.vertexData.vertexBufferBinding.setBinding(1, texcoordsVertexBuffers[lvl])

def WaterCircle( name, x, y):

self.name = name
_prepareMesh()
node = self.sceneMgr.getRootSceneNode().createChild(name)
node.translate(x*(PLANE_SIZE/COMPLEXITY), 10, y*(PLANE_SIZE/COMPLEXITY))
entity = self.sceneMgr.createEntity(name, name)
entity.setMaterialName(self.circles_MATERIAL)
node.attachObject(entity)
tm = 0
lvl = 0
setTextureLevel()

def __del__(self, ):
Ogre.MeshManager.getSingleton().remove(mesh.getHandle())
self.sceneMgr.destroyEntity(entity.getName())
self.sceneMgr.getRootSceneNode().removeChildnode.getName()

def animate(self, timeSinceLastFrame):
lastlvl = lvl
tm += timeSinceLastFrame
lvl = (int) ( (Real)(tm)/CIRCLE_TIME * 16 )
if (lvl<16 and lvl!=lastlvl) :
setTextureLevel()


def clearStaticBuffers(self):
posnormVertexBuffer = Ogre.HardwareVertexBufferSharedPtr()
indexBuffer = Ogre.HardwareIndexBufferSharedPtr()
for i in range (16):
texcoordsVertexBuffers[i] = Ogre.HardwareVertexBufferSharedPtr()

del texcoordsVertexBuffers


# bool WaterCircle.first = True
# HardwareVertexBufferSharedPtr WaterCircle.posnormVertexBuffer =
# HardwareVertexBufferSharedPtr()
# HardwareIndexBufferSharedPtr WaterCircle.indexBuffer =
# HardwareIndexBufferSharedPtr()
# HardwareVertexBufferSharedPtr* WaterCircle.texcoordsVertexBuffers = 0

# /* =========================================================================*/
# /* WaterListener class */
# /* =========================================================================*/
## Event handler
class WaterListener(sf.FrameListener):

def processselfcircles(self,timeSinceLastFrame):

for i in range (self.circles.size() ) :
self.circles[i].animate(timeSinceLastFrame)

# # # do :
# # # found = False
# # # for it = self.circles :
# # # it != self.circles.end()
# # # ++it) {
# # # if ((*it).lvl>=16) {:
# # # delete (*it)
# # # self.circles.erase(it)
# # # found = True
# # # break


# # # while (found)


def processParticles(self):
global PLANE_SIZE, COMPLEXITY, RAIN_HEIGHT_RANDOM, RAIN_HEIGHT_CONSTANT
pit = Ogre.self.particleSystem._getIterator()
while not pit.end():
particle = pit.getNext()
ppos = particle.position
if ppos.y<=0 and particle.timeToLive>0 : ## hits the water!:
## delete particle
particle.timeToLive = 0.0
## push the water
x = ppos.x / PLANE_SIZE * COMPLEXITY
y = ppos.z / PLANE_SIZE * COMPLEXITY
h = random.random() % self.RAIN_HEIGHT_RANDOM + self.RAIN_HEIGHT_CONSTANT
if (x<1):
x=1
if (x>COMPLEXITY-1):
x=COMPLEXITY-1
if (y<1):
y=1
if (y>COMPLEXITY-1):
y=COMPLEXITY-1
self.WaterMesh.push(x,y,-h)
circle = WaterCircle(
"Circle#"+Ogre.StringConverter.toString(self.pindex),
x, y)
self.pindex+=1
self.circles.push_back(circle)




## Head animation */
def animateHead(self, timeSinceLastFrame):

## sine track? :)
for i in range(4):
self.sines[i]+=self.adds[i]*timeSinceLastFrame

tx = ((sin(self.sines[0]) + sin(self.sines[1])) / 4 + 0.5 ) * (COMPLEXITY-2) + 1
ty = ((sin(self.sines[2]) + sin(self.sines[3])) / 4 + 0.5 ) * (COMPLEXITY-2) + 1
self.WaterMesh.push(tx,ty, -self.headDepth)
step = PLANE_SIZE / COMPLEXITY
self.headNode.resetToInitialState()
self.headNode.scale(3,3,3)
newPos = Ogre.Vector3(step*tx, self.headDepth, step*ty)
diffPos = newPos - self.oldPos
headRotation = Vector3.UNIT_Z.getRotationTo(diffPos)
self.oldPos = newPos
self.headNode.translate(newPos)
self.headNode.rotate(headRotation)


## GUI updaters
def updateInfoParamC(self):
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/Param_C") \
.setCaption("[1/2]Ripple speed: "+Ogre.StringConverter.toString(self.WaterMesh.PARAM_C))

def updateInfoParamD(self):
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/Param_D") \
.setCaption("[3/4]Distance: "+Ogre.StringConverter.toString(self.WaterMesh.PARAM_D))

def updateInfoParamU(self):
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/Param_U") \
.setCaption("[5/6]Viscosity: "+Ogre.StringConverter.toString(self.WaterMesh.PARAM_U))

def updateInfoParamT(self):
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/Param_T") \
.setCaption("[7/8]Frame time: "+Ogre.StringConverter.toString(self.WaterMesh.PARAM_T))

def updateInfoNormals(self):
cap = "[N]Normals: "
if self.WaterMesh.useFakeNormals:
cap += "fake"
else: cap += "real"
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/Normals") \
.setCaption(cap)

def switchNormals(self):
self.WaterMesh.useFakeNormals = not self.WaterMesh.useFakeNormals
updateInfoNormals()

def updateInfoselfHeadDepth(self):
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/Depth") \
.setCaption(String("[U/J]Head depth: ")+Ogre.StringConverter.toString(self.headDepth))

def updateInfoSkyBox(self):
cap = "[B]SkyBox: "
if self.skyBoxOn:
cap += "On"
else: cap += "Off"
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/SkyBox").setCaption(cap)

def updateMaterial(self):
global MATERIAL_PREFIX
materialName = MATERIAL_PREFIX+Ogre.StringConverter.toString(self.materialNumber)
material = Ogre.MaterialManager.getSingleton().getByName(materialName)
if (material.isNull()):
if(self.materialNumber):
self.materialNumber = 0
updateMaterial()
return
else:
OGRE_EXCEPT(Exception.ERR_INTERNAL_ERROR,
"Material "+materialName+"doesn't exist!",
"WaterListener.updateMaterial")

self.waterEntity.setMaterialName(materialName)
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/Material") \
.setCaption(String("[M]Material: ")+materialName)


def switchMaterial(self):
self.materialNumber+=1
updateMaterial()

def switchSkyBox(self):
self.skyBoxOn = not self.skyBoxOn
self.sceneMgr.setSkyBox(self.skyBoxOn, "Examples/SceneSkyBox2")
updateInfoSkyBox()


def __init__(self, renderWindow, camera, WaterMesh, waterEntity ):

sf.FrameListener.__init__(self, renderWindow, camera)
self.camera = camera
self.WaterMesh = WaterMesh
self.self.waterEntity = self.waterEntity
self.materialNumber = 8
self.timeoutDelay = 0.0
self.headDepth = 2.0
self.skyBoxOn = False
self.RAIN_HEIGHT_RANDOM = 5
self.RAIN_HEIGHT_CONSTANT =m5
self.sines = [0,100,200,300]
self.adds=[0.3,-1.6,1.1,0.5]
self.oldPos = Vector3.UNIT_Z
self.pindex = 0
self.headDepth =0.0

updateMaterial()
updateInfoParamC()
updateInfoParamD()
updateInfoParamU()
updateInfoParamT()
updateInfoNormals()
updateInfoself.headDepth()
updateInfoSkyBox()


def __del__ ( self ):
## If when you finish the application is still raining there
## are water self.circles that are still being processed
activeself.circles = self.self.circles.size ()

## Kill the active water self.circles
for i in range ( activeself.circles ):
del (self.self.circles[i])


def frameStarted(self, frameEvent):
result = sf.FrameListener.frameStarted(self,frameEvent)

if( result == False ):
## check if we are exiting, if so, clear static HardwareBuffers to adef segfault
WaterCircle.clearStaticBuffers()
return False

self.mAnimState.addTime(evt.timeSinceLastFrame)

## process keyboard events
changeSpeed = evt.timeSinceLastFrame

## adjust keyboard speed with SHIFT (increase) and CONTROL (decrease)
if (self.Keyboard.isKeyDown(OIS.KC_LSHIFT) or self.Keyboard.isKeyDown(OIS.KC_RSHIFT)):
changeSpeed *= 10.0

if (self.Keyboard.isKeyDown(OIS.KC_LCONTROL)):
changeSpeed /= 10.0

## rain
processself.circles(evt.timeSinceLastFrame)
if (self.Keyboard.isKeyDown(OIS.KC_SPACE)):
self.particleEmitter.setEmissionRate(20.0)
else:
self.particleEmitter.setEmissionRate(0.0)

processParticles()

## adjust values (some macros for faster change
def ADJUST_RANGE(_value,_plus,_minus,_minVal,_maxVal,_change,_macro):
if (self.Keyboard.isKeyDown(_plus)):
_value+=_change
if (_value>=_maxVal):
_value = _maxVal
# _macro
# if (self.Keyboard.isKeyDown(_minus)):
# _value-=_change
# if (_value<=_minVal):
# _value = _minVal
# _macro ; }


ADJUST_RANGE(headDepth, OIS.KC_U, OIS.KC_J, 0, 10, 0.5*changeSpeed, updateInfoHeadDepth())

ADJUST_RANGE(self.WaterMesh.PARAM_C, OIS.KC_2, OIS.KC_1, 0, 10, 0.1*changeSpeed, updateInfoParamC())

ADJUST_RANGE(self.WaterMesh.PARAM_D, OIS.KC_4, OIS.KC_3, 0.1, 10, 0.1*changeSpeed, updateInfoParamD())

ADJUST_RANGE(self.WaterMesh.PARAM_U, OIS.KC_6, OIS.KC_5, -2, 10, 0.1*changeSpeed, updateInfoParamU())

ADJUST_RANGE(self.WaterMesh.PARAM_T, OIS.KC_8, OIS.KC_7, 0, 10, 0.1*changeSpeed, updateInfoParamT())

self.timeoutDelay-=evt.timeSinceLastFrame
if (self.timeoutDelay<=0):
self.timeoutDelay = 0

def SWITCH_VALUE(_key,_timeDelay, _macro):
if (self.Keyboard.isKeyDown(_key) and self.timeoutDelay==0) :
self.timeoutDelay = _timeDelay
_macro

SWITCH_VALUE(KC_N, 0.5, switchNormals())

SWITCH_VALUE(KC_M, 0.5, switchMaterial())

SWITCH_VALUE(KC_B, 0.5, switchSkyBox())

animateHead(evt.timeSinceLastFrame)

self.WaterMesh.updateMesh(evt.timeSinceLastFrame)

return True



class WaterApplication(sf.Application):##,ogre.RenderTargetListener):

def __init__(self):
#self.animationStates = []
#self.sceneEntNodes=[]
sf.Application.__init__(self)


def _createScene(self):
#global PLANE_SIZE, MESH_NAME, COMPLEXITY, ENTITY_NAME
sceneManager = self.sceneManager
camera = self.camera
## Set ambient light
sceneManager.ambientLight = Ogre.ColourValue(0.75, 0.75, 0.75)

## Create a light
l = sceneManager.createLight("MainLight")
## Accept default settings: point light, white diffuse, just set position
l.setPosition(200,300,100)

## Create water mesh and entity
self.WaterMesh = WaterMesh.WaterMesh(MESH_NAME, PLANE_SIZE, COMPLEXITY)
self.waterEntity = sceneManager.createEntity(ENTITY_NAME, MESH_NAME)

self.waterEntity.setMaterialName(MATERIAL_NAME)
waterNode = sceneManager.getRootSceneNode().createChildSceneNode()
#waterNode.attachObject(self.waterEntity)

## Add a head, give it it's own node
self.headNode = waterNode.createChildSceneNode()
ent = sceneManager.createEntity("head", "ogrehead.mesh")
self.headNode.attachObject(ent)

## Make sure the camera track self node
## self.camera.setAutoTracking(True, self.headNode)

## Create the camera node, set its position & attach camera
camNode = sceneManager.getRootSceneNode().createChildSceneNode()
camNode.translate(0, 500, PLANE_SIZE)
camNode.yaw(Ogre.Degree(-45))
camNode.attachObject(self.camera)

## Create light node
lightNode = sceneManager.getRootSceneNode().createChildSceneNode()
lightNode.attachObject(l)

## set up spline animation of light node
anim = sceneManager.createAnimation("WaterLight", 20)

## create a random spline for light
track = anim.createNodeTrack(0, lightNode)
key = track.createNodeKeyFrame(0)
for ff in range (1,20):
key = track.createNodeKeyFrame(ff)
lpos = Ogre.Vector3(
random.random()%PLANE_SIZE , ##- PLANE_SIZE/2,
random.random()%300+100,
random.random()%PLANE_SIZE ##- PLANE_SIZE/2
)
key.setTranslate(lpos)

key = track.createNodeKeyFrame(20)

## Create a new animation state to track self
self.mAnimState = sceneManager.createAnimationState("WaterLight")
self.mAnimState.setEnabled(True)

## Put in a bit of fog for the hell of it
##sceneManager.setFog(FOG_EXP, ColourValue.White, 0.0002)

## show overlay
self.waterOverlay = Ogre.OverlayManager.getSingleton().getByName("Example/WaterOverlay")
self.waterOverlay.show()

## Let there be rain
self.particleSystem = sceneManager.createParticleSystem("rain",
"Examples/Water/Rain")
self.ParticleEmitter = self.particleSystem.getEmitter(0)
rNode = sceneManager.getRootSceneNode().createChildSceneNode()
rNode.translate(PLANE_SIZE/2.0, 3000, PLANE_SIZE/2.0)
rNode.attachObject(self.particleSystem)
## Fast-forward the rain so it looks more natural
self.particleSystem.fastForward(20)
## It can't be set in .particle file, and we need it )
# static_cast<BillboardParticleRenderer*>(self.particleSystem.getRenderer()).setBillboardOrigin(BBO_BOTTOM_CENTER)

prepareCircleMaterial()


## Create new frame listener
def _createFrameListener():
self.frameListener = WaterListener(self.renderWindow, self.camera,
self.WaterMesh, self.waterEntity)
self.root.addFrameListener(self.frameListener)



if __name__ == '__main__':
# try:
application = WaterApplication()
application.go()
# except ogre.Exception, e:
# print e






WaterMesh.py


# /*
# -----------------------------------------------------------------------------
# This source file is part of OGRE
# (Object-oriented Graphics Rendering Engine)
# For the latest info, see http:##www.ogre3d.org/

# Copyright (c) 2000-2006 Torus Knot Software Ltd
# Also see acknowledgements in Readme.html

# You may use self sample code for anything you like, it is not covered by the
# LGPL like the rest of the engine.
# -----------------------------------------------------------------------------
# */

import ctypes, math
import ogre.renderer.OGRE as Ogre
import random

ANIMATIONS_PER_SECOND = 100.0
class WaterMesh:
def __init__ ( self, meshName, planeSize, complexity ):
self.meshName = meshName
self.complexity = complexity
numFaces = 2 * complexity * complexity
numVertices = (complexity + 1) * (complexity + 1)
lastTimeStamp = 0
lastAnimationTimeStamp = 0
lastFrameTime = 0

## initialize algorithm parameters
PARAM_C = 0.3 ## ripple speed
PARAM_D = 0.4 ## distance
PARAM_U = 0.05 ## viscosity
PARAM_T = 0.13 ## time
useFakeNormals = False

## allocate space for normal calculation
self.vNormals = Ogre.Vector3(0,0,0)[numVertices]

## create mesh and submesh
mesh = Ogre.MeshManager.getSingleton().createManual(meshName,
Ogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME)
subMesh = mesh.createSubMesh()
subMesh.useSharedVertices=False

## Vertex buffers
subMesh.vertexData = Ogre.VertexData()
subMesh.vertexData.vertexStart = 0
subMesh.vertexData.vertexCount = numVertices

vdecl = subMesh.vertexData.vertexDeclaration
vbind = subMesh.vertexData.vertexBufferBinding


vdecl.addElement(0, 0, Ogre.VertexElementType.VET_FLOAT3, Ogre.VertexElementSemantic.VES_POSITION)
vdecl.addElement(1, 0, Ogre.VertexElementType.VET_FLOAT3, Ogre.VertexElementSemantic.VES_NORMAL)
vdecl.addElement(2, 0, Ogre.VertexElementType.VET_FLOAT2, Ogre.VertexElementSemantic.VES_TEXTURE_COORDINATES)

## Prepare buffer for positions - todo: first attempt, slow
posVertexBuffer = \
Ogre.HardwareBufferManager.getSingleton().createVertexBuffer(
3 * ctypes.sizeof(ctypes.c_float),
numVertices,
Ogre.HardwareBuffer.HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE)
vbind.setBinding(0, posVertexBuffer)

## Prepare buffer for normals - write only
normVertexBuffer = \
Ogre.HardwareBufferManager.getSingleton().createVertexBuffer(
3*ctypes.sizeof(ctypes.c_float),
numVertices,
Ogre.HardwareBuffer.HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE)
vbind.setBinding(1, normVertexBuffer)

## Prepare texture coords buffer - static one
## todo: optimize to write directly into buffer
storageclass = ctypes.c_float * (numVertices*2)
texcoordsBufData=storageclass(1.1)

for y in range (complexity) :
for x in range(complexity) :
texcoordsBufData[2*(y*(complexity+1)+x)+0] = x / complexity
texcoordsBufData[2*(y*(complexity+1)+x)+1] = 1.0 - (y / (complexity))


texcoordsVertexBuffer = Ogre.HardwareBufferManager.getSingleton().createVertexBuffer(
2*ctypes.sizeof(ctypes.c_float),
numVertices,
Ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY)

texcoordsVertexBuffer.writeData(0,texcoordsVertexBuffer.getSizeInBytes(),
texcoordsBufData,True)

## true?
vbind.setBinding(2, texcoordsVertexBuffer)

## Prepare buffer for indices
indexBuffer = \
Ogre.HardwareBufferManager.getSingleton().createIndexBuffer(
Ogre.HardwareIndexBuffer.IT_16BIT,
3*numFaces,
Ogre.HardwareBuffer.HBU_STATIC, True)

## get the point to the indexbuffer
faceVertexIndices = indexBuffer.lock(0, numFaces*3*2, Ogre.HardwareBuffer.HBL_DISCARD)
buf=[]
for y in range (complexity) :
for x in range (complexity ) :
# unsigned short *twoface = faceVertexIndices + (y*complexity+x)*2*3
p0 = y*(complexity+1) + x
p1 = y*(complexity+1) + x + 1
p2 = (y+1)*(complexity+1) + x
p3 = (y+1)*(complexity+1) + x + 1
buf.append(p2)
buf.append(p1)
buf.append(p0)
buf.append(p2)
buf.append(p3)
buf.append(p1)

# twoface[0]=p2 ##first tri
# twoface[1]=p1
# twoface[2]=p0
# twoface[3]=p2 ##second tri
# twoface[4]=p3
# twoface[5]=p1

ogre.setUint16 ( faceVertexIndices, buf )
indexBuffer.unlock()
## Set index buffer for self submesh
subMesh.indexData.indexBuffer = indexBuffer
subMesh.indexData.indexStart = 0
subMesh.indexData.indexCount = 3*numFaces

# prepare vertex positions
# note - we use 3 vertex buffers, since algorighm uses two last phases
# to calculate the next one
self.vertexBuffers=[]
storageclass2 = ctypes.c_float * (numVertices*3)
for b in range(3) :
self.vertexBuffers.append ( storageclass2(1.1) ) ### new float[numVertices * 3]
for y in range(complexity) :
for x in range (complexity) :
numPoint = y*(complexity+1) + x
vertex = vertexBuffers[b] + 3*numPoint
self.vertexBuffers[b][0]= x / (complexity * planeSize )
self.vertexBuffers[b][1]= 0
self.vertexBuffers[b][2] = y / (complexity * planeSize )

#AxisAlignedBox #continued next line YA
meshBounds = Ogre.AxisAlignedBox(0,0,0, planeSize,0, planeSize)
mesh._setBounds(meshBounds)

currentBuffNumber = 0
posVertexBuffer.writeData(0,
posVertexBuffer.getSizeInBytes(), ## size
ctypes.addressof(self.vertexBuffers[currentBuffNumber]), ## source
True) ## discard?

mesh.load()
mesh.touch()

# =========================================================================
def __del__ (self):
del self.vertexBuffers

# del vertexBuffers[0]
# del vertexBuffers[1]
# del vertexBuffers[2]
#
# del self.vNormals

# ===========================================================================
# /** "pushes" a mesh at position [x,y]. Note, that x,y are float, hence
# * 4 vertices are actually pushed
# * @note
# * This should be replaced by push with 'radius' parameter to simulate
# * big objects falling into water
# */

def push( self, x, y, depth, absolute):
return
buf = self.vertexBuffers[currentBuffNumber]+1
## scale pressure according to time passed
depth = depth * lastFrameTime * ANIMATIONS_PER_SECOND
self._PREP(0,0)
self._PREP(0,1)
self._PREP(1,0)
self._PREP(1,1)

def _PREP(self, addx,addy) :
return
# *vertex=buf+3*((int)(y+addy)*(complexity+1)+(int)(x+addx))
# diffy = y - floor(y+addy)
# diffx = x - floor(x+addx)
# dist=sqrt(diffy*diffy + diffx*diffx)
# power = 1 - dist
# if (power<0):
# power = 0
# if (absolute):
# *vertex = depth*power
# else:
# *vertex += depth*power

def hat(self, _x,_y):
self.buf[3*(_y*(complexity+1)+(_x))]


# /* ========================================================================= */
# gets height at given x and y, takes average value of the closes nodes */

def getHeight(self, x, y):

self.buf = vertexBuffers[currentBuffNumber]
xa = floor(x)
xb = xa + 1
ya = floor(y)
yb = ya + 1
yaxavg = hat(xa,ya) * (1.0-fabs(xa-x)) + hat(xb,ya) * (1.0-fabs(xb-x))
ybxavg = hat(xa,yb) * (1.0-fabs(xa-x)) + hat(xb,yb) * (1.0-fabs(xb-x))
yavg = yaxavg * (1.0-fabs(ya-y)) + ybxavg * (1.0-fabs(yb-y))
return yavg

# /* ========================================================================= */
def calculateFakeNormals(self):
buf = self.vertexBuffers[currentBuffNumber] + 1
pNormals = normVertexBuffer.lock(
0,normVertexBuffer.getSizeInBytes(), Ogre.HardwareBuffer.HBL_DISCARD)
buf = []
for y in (complexity) :
# # # nrow = pNormals + 3*y*(complexity+1)
row = buf + 3*y*(complexity+1)
rowup = buf + 3*(y-1)*(complexity+1)
rowdown = buf + 3*(y+1)*(complexity+1)
for x in (complexity) :
xdiff = row[3*x+3] - row[3*x-3]
ydiff = rowup[3*x] - rowdown[3*x-3]
norm = Ogre.Vector3(xdiff,30,ydiff)
norm.normalise()
buf.append( norm.x )
buf.append( norm.y )
buf.append( norm.z )
# # # nrow[3*x+0] = norm.x
# # # nrow[3*x+1] = norm.y
# # # nrow[3*x+2] = norm.z

ogre.setUint16 ( pNormals, buf )
normVertexBuffer.unlock()

# /* ========================================================================= */
def calculateNormals(self):
buf = self.vertexBuffers[currentBuffNumber] + 1
## zero normals
for i in range(numVertices) :
self.vNormals[i] = Ogre.Vector3.ZERO

## first, calculate normals for faces, add them to proper vertices
buf = vertexBuffers[currentBuffNumber]
vinds = indexBuffer.lock(
0, indexBuffer.getSizeInBytes(), Ogre.HardwareBuffer.HBL_READ_ONLY)
pNormals = normVertexBuffer.lock(
0, normVertexBuffer.getSizeInBytes(), Ogre.HardwareBuffer.HBL_DISCARD)
for i in range(numFaces) :
p0 = vinds[3*i]
p1 = vinds[3*i+1]
p2 = vinds[3*i+2]
v0=Ogre.Vector3 (buf[3*p0], buf[3*p0+1], buf[3*p0+2])
v1 = Ogre.Vector3 (buf[3*p1], buf[3*p1+1], buf[3*p1+2])
v3 = Ogre.Vector3 (buf[3*p2], buf[3*p2+1], buf[3*p2+2])
diff1 = v2 - v1
diff2 = v0 - v1
fn = diff1.crossProduct(diff2)
self.vNormals[p0] += fn
self.vNormals[p1] += fn
self.vNormals[p2] += fn

## now normalize vertex normals
for y in (complexity) :
for x in (complexity) :
numPoint = y*(complexity+1) + x
n = self.vNormals[numPoint]
n.normalise()
normal = pNormals + 3*numPoint
normal[0]=n.x
normal[1]=n.y
normal[2]=n.z


indexBuffer.unlock()
normVertexBuffer.unlock()

# /* ======================================================================== */
def updateMesh(self, timeSinceLastFrame):
lastFrameTime = timeSinceLastFrame
lastTimeStamp += timeSinceLastFrame

## do rendering to get ANIMATIONS_PER_SECOND
while(lastAnimationTimeStamp <= lastTimeStamp):

## switch buffer numbers
currentBuffNumber = (currentBuffNumber + 1) % 3
buf = vertexBuffers[currentBuffNumber] + 1 ## +1 for Y coordinate
buf1 = vertexBuffers[(currentBuffNumber+2)%3] + 1
buf2 = vertexBuffers[(currentBuffNumber+1)%3] + 1

# /* we use an algorithm from
# * http:##collective.valve-erc.com/index.php?go=water_simulation
# * The params could be dynamically changed every frame ofcourse
# */
C = PARAM_C ## ripple speed
D = PARAM_D ## distance
U = PARAM_U ## viscosity
T = PARAM_T ## time
TERM1 = ( 4.0 - 8.0*C*C*T*T/(D*D) ) / (U*T+2)
TERM2 = ( U*T-2.0 ) / (U*T+2.0)
TERM3 = ( 2.0 * C*C*T*T/(D*D) ) / (U*T+2)
# for y in range(complexity) : ## don't do anything with border values
# *row = buf + 3*y*(complexity+1)
# *row1 = buf1 + 3*y*(complexity+1)
# *row1up = buf1 + 3*(y-1)*(complexity+1)
# *row1down = buf1 + 3*(y+1)*(complexity+1)
# *row2 = buf2 + 3*y*(complexity+1)
# for x in range (complexity) :
# row[3*x] = TERM1 * row1[3*x]
# + TERM2 * row2[3*x]
# + TERM3 * ( row1[3*x-3] + row1[3*x+3] + row1up[3*x]+row1down[3*x] )
# lastAnimationTimeStamp += (1.0 / ANIMATIONS_PER_SECOND)


if (useFakeNormals):
calculateFakeNormals()
else :
calculateNormals()


## set vertex buffer
posVertexBuffer.writeData(0,
posVertexBuffer.getSizeInBytes(), ## size
vertexBuffers[currentBuffNumber], ## source
True) ## discard?


skorpio

17-11-2007 18:13:44

Hello,

I have been working of Demo_Water andI think it is 80% done!!

I have made a lot of progress. Now I can see the ogre head animation but not the water.

The water mesh gets created ok,
I think the problem is in the Normal calculation because none of that code seems to compile.
I can understand the original C code but my Python skills are basic and I couldn't get it to work unless putting dummy values.

I think if the Normal calculations and the Update mesh are fix properly I think it will work.

Perhaps, some other python-ogre entuthiast may want a crack at it. My thought is that somebody may be able to solve these problems faster than I could but
I'll keep working on it in the mean time.

Sorry about posting code here but I used to use file share with "filewind.c o m" but it no longer works.


Best Regards,


Original C-code water mesh (for reference)


/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2005 The OGRE Team
Also see acknowledgements in Readme.html

You may use this sample code for anything you like, it is not covered by the
LGPL like the rest of the engine.
-----------------------------------------------------------------------------
*/


#include "WaterMesh.h"

#define ANIMATIONS_PER_SECOND 100.0f

WaterMesh::WaterMesh(const String& meshName, Real planeSize, int complexity)
{
int x,y,b; // I prefer to initialize for() variables inside it, but VC doesn't like it ;(

this->meshName = meshName ;
this->complexity = complexity ;
numFaces = 2 * complexity * complexity;
numVertices = (complexity + 1) * (complexity + 1) ;
lastTimeStamp = 0 ;
lastAnimationTimeStamp = 0;
lastFrameTime = 0 ;

// initialize algorithm parameters
PARAM_C = 0.3f ; // ripple speed
PARAM_D = 0.4f ; // distance
PARAM_U = 0.05f ; // viscosity
PARAM_T = 0.13f ; // time
useFakeNormals = false ;

// allocate space for normal calculation
vNormals = new Vector3[numVertices];

// create mesh and submesh
mesh = MeshManager::getSingleton().createManual(meshName,
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
subMesh = mesh->createSubMesh();
subMesh->useSharedVertices=false;

// Vertex buffers
subMesh->vertexData = new VertexData();
subMesh->vertexData->vertexStart = 0;
subMesh->vertexData->vertexCount = numVertices;

VertexDeclaration* vdecl = subMesh->vertexData->vertexDeclaration;
VertexBufferBinding* vbind = subMesh->vertexData->vertexBufferBinding;


vdecl->addElement(0, 0, VET_FLOAT3, VES_POSITION);
vdecl->addElement(1, 0, VET_FLOAT3, VES_NORMAL);
vdecl->addElement(2, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES);

// Prepare buffer for positions - todo: first attempt, slow
posVertexBuffer =
HardwareBufferManager::getSingleton().createVertexBuffer(
3*sizeof(float),
numVertices,
HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
vbind->setBinding(0, posVertexBuffer);

// Prepare buffer for normals - write only
normVertexBuffer =
HardwareBufferManager::getSingleton().createVertexBuffer(
3*sizeof(float),
numVertices,
HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
vbind->setBinding(1, normVertexBuffer);

// Prepare texture coords buffer - static one
// todo: optimize to write directly into buffer
float *texcoordsBufData = new float[numVertices*2];
for(y=0;y<=complexity;y++) {
for(x=0;x<=complexity;x++) {
texcoordsBufData[2*(y*(complexity+1)+x)+0] = (float)x / complexity ;
texcoordsBufData[2*(y*(complexity+1)+x)+1] = 1.0f - ((float)y / (complexity)) ;
}
}
texcoordsVertexBuffer =
HardwareBufferManager::getSingleton().createVertexBuffer(
2*sizeof(float),
numVertices,
HardwareBuffer::HBU_STATIC_WRITE_ONLY);
texcoordsVertexBuffer->writeData(0,
texcoordsVertexBuffer->getSizeInBytes(),
texcoordsBufData,
true); // true?
delete [] texcoordsBufData;
vbind->setBinding(2, texcoordsVertexBuffer);

// Prepare buffer for indices
indexBuffer =
HardwareBufferManager::getSingleton().createIndexBuffer(
HardwareIndexBuffer::IT_16BIT,
3*numFaces,
HardwareBuffer::HBU_STATIC, true);
unsigned short *faceVertexIndices = (unsigned short*)
indexBuffer->lock(0, numFaces*3*2, HardwareBuffer::HBL_DISCARD);
for(y=0 ; y<complexity ; y++) {
for(int x=0 ; x<complexity ; x++) {
unsigned short *twoface = faceVertexIndices + (y*complexity+x)*2*3;
int p0 = y*(complexity+1) + x ;
int p1 = y*(complexity+1) + x + 1 ;
int p2 = (y+1)*(complexity+1) + x ;
int p3 = (y+1)*(complexity+1) + x + 1 ;
twoface[0]=p2; //first tri
twoface[1]=p1;
twoface[2]=p0;
twoface[3]=p2; //second tri
twoface[4]=p3;
twoface[5]=p1;
}
}
indexBuffer->unlock();
// Set index buffer for this submesh
subMesh->indexData->indexBuffer = indexBuffer;
subMesh->indexData->indexStart = 0;
subMesh->indexData->indexCount = 3*numFaces;

/* prepare vertex positions
* note - we use 3 vertex buffers, since algorighm uses two last phases
* to calculate the next one
*/
for(b=0;b<3;b++) {
vertexBuffers[b] = new float[numVertices * 3] ;
for(y=0;y<=complexity;y++) {
for(x=0;x<=complexity;x++) {
int numPoint = y*(complexity+1) + x ;
float* vertex = vertexBuffers[b] + 3*numPoint ;
vertex[0]=(float)(x) / (float)(complexity) * (float) planeSize ;
vertex[1]= 0 ; // rand() % 30 ;
vertex[2]=(float)(y) / (float)(complexity) * (float) planeSize ;
}
}
}

AxisAlignedBox meshBounds(0,0,0,
planeSize,0, planeSize);
mesh->_setBounds(meshBounds);

currentBuffNumber = 0 ;
posVertexBuffer->writeData(0,
posVertexBuffer->getSizeInBytes(), // size
vertexBuffers[currentBuffNumber], // source
true); // discard?

mesh->load();
mesh->touch();
}
/* ========================================================================= */
WaterMesh::~WaterMesh ()
{
delete[] vertexBuffers[0];
delete[] vertexBuffers[1];
delete[] vertexBuffers[2];

delete[] vNormals;
}
/* ========================================================================= */
void WaterMesh::push(Real x, Real y, Real depth, bool absolute)
{
float *buf = vertexBuffers[currentBuffNumber]+1 ;
// scale pressure according to time passed
depth = depth * lastFrameTime * ANIMATIONS_PER_SECOND ;
#define _PREP(addx,addy) { \
float *vertex=buf+3*((int)(y+addy)*(complexity+1)+(int)(x+addx)) ; \
float diffy = y - floor(y+addy); \
float diffx = x - floor(x+addx); \
float dist=sqrt(diffy*diffy + diffx*diffx) ; \
float power = 1 - dist ; \
if (power<0) \
power = 0; \
if (absolute) \
*vertex = depth*power ; \
else \
*vertex += depth*power ; \
} /* #define */
_PREP(0,0);
_PREP(0,1);
_PREP(1,0);
_PREP(1,1);
#undef _PREP
}
/* ========================================================================= */
Real WaterMesh::getHeight(Real x, Real y)
{
#define hat(_x,_y) buf[3*((int)_y*(complexity+1)+(int)(_x))]
float *buf = vertexBuffers[currentBuffNumber] ;
Real xa = floor(x);
Real xb = xa + 1 ;
Real ya = floor(y);
Real yb = ya + 1 ;
Real yaxavg = hat(xa,ya) * (1.0f-fabs(xa-x)) + hat(xb,ya) * (1.0f-fabs(xb-x));
Real ybxavg = hat(xa,yb) * (1.0f-fabs(xa-x)) + hat(xb,yb) * (1.0f-fabs(xb-x));
Real yavg = yaxavg * (1.0f-fabs(ya-y)) + ybxavg * (1.0f-fabs(yb-y)) ;
return yavg ;
}
/* ========================================================================= */
void WaterMesh::calculateFakeNormals()
{
int x,y;
float *buf = vertexBuffers[currentBuffNumber] + 1;
float *pNormals = (float*) normVertexBuffer->lock(
0,normVertexBuffer->getSizeInBytes(), HardwareBuffer::HBL_DISCARD);
for(y=1;y<complexity;y++) {
float *nrow = pNormals + 3*y*(complexity+1);
float *row = buf + 3*y*(complexity+1) ;
float *rowup = buf + 3*(y-1)*(complexity+1) ;
float *rowdown = buf + 3*(y+1)*(complexity+1) ;
for(x=1;x<complexity;x++) {
Real xdiff = row[3*x+3] - row[3*x-3] ;
Real ydiff = rowup[3*x] - rowdown[3*x-3] ;
Vector3 norm(xdiff,30,ydiff);
norm.normalise();
nrow[3*x+0] = norm.x;
nrow[3*x+1] = norm.y;
nrow[3*x+2] = norm.z;
}
}
normVertexBuffer->unlock();
}
/* ========================================================================= */
void WaterMesh::calculateNormals()
{
int i,x,y;
float *buf = vertexBuffers[currentBuffNumber] + 1;
// zero normals
for(i=0;i<numVertices;i++) {
vNormals[i] = Vector3::ZERO;
}
// first, calculate normals for faces, add them to proper vertices
buf = vertexBuffers[currentBuffNumber] ;
unsigned short* vinds = (unsigned short*) indexBuffer->lock(
0, indexBuffer->getSizeInBytes(), HardwareBuffer::HBL_READ_ONLY);
float *pNormals = (float*) normVertexBuffer->lock(
0, normVertexBuffer->getSizeInBytes(), HardwareBuffer::HBL_DISCARD);
for(i=0;i<numFaces;i++) {
int p0 = vinds[3*i] ;
int p1 = vinds[3*i+1] ;
int p2 = vinds[3*i+2] ;
Vector3 v0(buf[3*p0], buf[3*p0+1], buf[3*p0+2]);
Vector3 v1(buf[3*p1], buf[3*p1+1], buf[3*p1+2]);
Vector3 v2(buf[3*p2], buf[3*p2+1], buf[3*p2+2]);
Vector3 diff1 = v2 - v1 ;
Vector3 diff2 = v0 - v1 ;
Vector3 fn = diff1.crossProduct(diff2);
vNormals[p0] += fn ;
vNormals[p1] += fn ;
vNormals[p2] += fn ;
}
// now normalize vertex normals
for(y=0;y<=complexity;y++) {
for(x=0;x<=complexity;x++) {
int numPoint = y*(complexity+1) + x ;
Vector3 n = vNormals[numPoint] ;
n.normalise() ;
float* normal = pNormals + 3*numPoint ;
normal[0]=n.x;
normal[1]=n.y;
normal[2]=n.z;
}
}
indexBuffer->unlock();
normVertexBuffer->unlock();
}
/* ========================================================================= */
void WaterMesh::updateMesh(Real timeSinceLastFrame)
{
int x, y ;

lastFrameTime = timeSinceLastFrame ;
lastTimeStamp += timeSinceLastFrame ;

// do rendering to get ANIMATIONS_PER_SECOND
while(lastAnimationTimeStamp <= lastTimeStamp) {

// switch buffer numbers
currentBuffNumber = (currentBuffNumber + 1) % 3 ;
float *buf = vertexBuffers[currentBuffNumber] + 1 ; // +1 for Y coordinate
float *buf1 = vertexBuffers[(currentBuffNumber+2)%3] + 1 ;
float *buf2 = vertexBuffers[(currentBuffNumber+1)%3] + 1;

/* we use an algorithm from
* http://collective.valve-erc.com/index.php?go=water_simulation
* The params could be dynamically changed every frame ofcourse
*/
double C = PARAM_C; // ripple speed
double D = PARAM_D; // distance
double U = PARAM_U; // viscosity
double T = PARAM_T; // time
Real TERM1 = ( 4.0f - 8.0f*C*C*T*T/(D*D) ) / (U*T+2) ;
Real TERM2 = ( U*T-2.0f ) / (U*T+2.0f) ;
Real TERM3 = ( 2.0f * C*C*T*T/(D*D) ) / (U*T+2) ;
for(y=1;y<complexity;y++) { // don't do anything with border values
float *row = buf + 3*y*(complexity+1) ;
float *row1 = buf1 + 3*y*(complexity+1) ;
float *row1up = buf1 + 3*(y-1)*(complexity+1) ;
float *row1down = buf1 + 3*(y+1)*(complexity+1) ;
float *row2 = buf2 + 3*y*(complexity+1) ;
for(x=1;x<complexity;x++) {
row[3*x] = TERM1 * row1[3*x]
+ TERM2 * row2[3*x]
+ TERM3 * ( row1[3*x-3] + row1[3*x+3] + row1up[3*x]+row1down[3*x] ) ;
}
}

lastAnimationTimeStamp += (1.0f / ANIMATIONS_PER_SECOND);
}

if (useFakeNormals) {
calculateFakeNormals();
} else {
calculateNormals();
}

// set vertex buffer
posVertexBuffer->writeData(0,
posVertexBuffer->getSizeInBytes(), // size
vertexBuffers[currentBuffNumber], // source
true); // discard?
}




WaterMesh.py


# /*
# -----------------------------------------------------------------------------
# This source file is part of OGRE
# (Object-oriented Graphics Rendering Engine)
# For the latest info, see http:##www.ogre3d.org/

# Copyright (c) 2000-2006 Torus Knot Software Ltd
# Also see acknowledgements in Readme.html

# You may use self sample code for anything you like, it is not covered by the
# LGPL like the rest of the engine.
# -----------------------------------------------------------------------------
# */

import ctypes, math
import ogre.renderer.OGRE as Ogre
import random

ANIMATIONS_PER_SECOND = 100.0
class WaterMesh:
def __init__ ( self, meshName, planeSize, complexity ):
self.meshName = meshName
self.complexity = complexity
self.numFaces = 2 * complexity * complexity
self.numVertices = (complexity + 1) * (complexity + 1)
self.lastTimeStamp = 0
self.lastAnimationTimeStamp = 0
self.lastFrameTime = 0

## initialize algorithm parameters
self.PARAM_C = 0.3 ## ripple speed
self.PARAM_D = 0.4 ## distance
self.PARAM_U = 0.05 ## viscosity
self.PARAM_T = 0.13 ## time
self.useFakeNormals = False

## allocate space for normal calculation
self.vNormals = Ogre.Vector3(0,0,0)[self.numVertices]

## create mesh and submesh
mesh = Ogre.MeshManager.getSingleton().createManual(self.meshName,
Ogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME)
subMesh = mesh.createSubMesh()
subMesh.useSharedVertices=False

self.VertexData = Ogre.VertexData()
## Vertex buffers
subMesh.vertexData = self.VertexData
subMesh.vertexData.vertexStart = 0
subMesh.vertexData.vertexCount = self.numVertices

vdecl = subMesh.vertexData.vertexDeclaration
vbind = subMesh.vertexData.vertexBufferBinding


vdecl.addElement(0, 0, Ogre.VertexElementType.VET_FLOAT3, Ogre.VertexElementSemantic.VES_POSITION)
vdecl.addElement(1, 0, Ogre.VertexElementType.VET_FLOAT3, Ogre.VertexElementSemantic.VES_NORMAL)
vdecl.addElement(2, 0, Ogre.VertexElementType.VET_FLOAT2, Ogre.VertexElementSemantic.VES_TEXTURE_COORDINATES)

## Prepare buffer for positions - todo: first attempt, slow
self.posVertexBuffer = \
Ogre.HardwareBufferManager.getSingleton().createVertexBuffer(
3 * ctypes.sizeof(ctypes.c_float),
self.numVertices,
Ogre.HardwareBuffer.HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE)
vbind.setBinding(0, self.posVertexBuffer)

## Prepare buffer for normals - write only
self.normVertexBuffer = \
Ogre.HardwareBufferManager.getSingleton().createVertexBuffer(
3*ctypes.sizeof(ctypes.c_float),
self.numVertices,
Ogre.HardwareBuffer.HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE)
vbind.setBinding(1, self.normVertexBuffer)

## Prepare texture coords buffer - static one
## todo: optimize to write directly into buffer
storageclass = ctypes.c_float * (self.numVertices*2)
texcoordsBufData=storageclass(1.1)

for y in range (self.complexity) :
for x in range(self.complexity) :
texcoordsBufData[2*(y*(self.complexity+1)+x)+0] = x / self.complexity
texcoordsBufData[2*(y*(self.complexity+1)+x)+1] = 1.0 - (y / (self.complexity))


texcoordsVertexBuffer = Ogre.HardwareBufferManager.getSingleton().createVertexBuffer(
2*ctypes.sizeof(ctypes.c_float),
self.numVertices,
Ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY)

texcoordsVertexBuffer.writeData(0,texcoordsVertexBuffer.getSizeInBytes(),
ctypes.addressof(texcoordsBufData),True)
## true?
vbind.setBinding(2, texcoordsVertexBuffer)

## Prepare buffer for indices
self.indexBuffer = \
Ogre.HardwareBufferManager.getSingleton().createIndexBuffer(
Ogre.HardwareIndexBuffer.IT_16BIT,
3*self.numFaces,
Ogre.HardwareBuffer.HBU_STATIC, True)

## get the point to the indexbuffer
faceVertexIndices = self.indexBuffer.lock(0, self.numFaces*3*2, Ogre.HardwareBuffer.HBL_DISCARD)
buf=[]
for y in range (self.complexity) :
for x in range (self.complexity ) :
p0 = y*(self.complexity+1) + x
p1 = y*(self.complexity+1) + x + 1
p2 = (y+1)*(self.complexity+1) + x
p3 = (y+1)*(self.complexity+1) + x + 1
buf.append(p2)
buf.append(p1)
buf.append(p0)
buf.append(p2)
buf.append(p3)
buf.append(p1)
Ogre.setUint16 ( faceVertexIndices, buf )
self.indexBuffer.unlock()
## Set index buffer for self submesh
subMesh.indexData.indexBuffer = self.indexBuffer
subMesh.indexData.indexStart = 0
subMesh.indexData.indexCount = 3*self.numFaces

# prepare vertex positions
# note - we use 3 vertex buffers, since algorighm uses two last phases
# to calculate the next one
self.vertexBuffers=[]
storageclass2 = ctypes.c_float * (self.numVertices*3)
for b in range(3) :
self.vertexBuffers.append ( storageclass2(1.1) ) ### new float[self.numVertices * 3]
for y in range(self.complexity) :
for x in range (self.complexity) :
numPoint = y*(self.complexity+1) + x
#vertex = self.vertexBuffers[b][0] + 3*numPoint
self.vertexBuffers[b][0]= x / (self.complexity * planeSize )
self.vertexBuffers[b][1]= 0
self.vertexBuffers[b][2] = y / (self.complexity * planeSize )

#AxisAlignedBox #continued next line YA
meshBounds = Ogre.AxisAlignedBox(0,0,0, planeSize,0, planeSize)
mesh._setBounds(meshBounds)

self.currentBuffNumber = 0
self.posVertexBuffer.writeData(0,
self.posVertexBuffer.getSizeInBytes(), ## size
ctypes.addressof(self.vertexBuffers[self.currentBuffNumber]), ## source
True) ## discard?

mesh.load()
mesh.touch()

# =========================================================================
def __del__ (self):
del self.vertexBuffers
# del vertexBuffers[0]
# del vertexBuffers[1]
# del vertexBuffers[2]
#
# del self.vNormals

# =========================================================================

faceVertexIndices = self.indexBuffer.lock(0, self.numFaces*3*2, Ogre.HardwareBuffer.HBL_DISCARD)
buf=[]
for y in range (self.complexity) :
for x in range (self.complexity ) :
p0 = y*(self.complexity+1) + x
p1 = y*(self.complexity+1) + x + 1
p2 = (y+1)*(self.complexity+1) + x
p3 = (y+1)*(self.complexity+1) + x + 1
buf.append(p2)


def calculateFakeNormals(self):
buf = ctypes.addressof(self.vertexBuffers[self.currentBuffNumber]) + 1

pNormals = self.normVertexBuffer.lock(
0,self.normVertexBuffer.getSizeInBytes(), Ogre.HardwareBuffer.HBL_DISCARD)

buf = []
for y in range (1,self.complexity) :
#nrow = pNormals + 3*y*(self.complexity+1)
row = 3*y*(self.complexity+1)
rowup = 3*(y-1)*(self.complexity+1)
rowdown = 3*(y+1)*(self.complexity+1)
for x in range (1,self.complexity) :
#xdiff = row[3*x+3] - row[3*x-3]
#ydiff = rowup[3*x] - rowdown[3*x-3]
xdiff = 10 ##dummy values
ydiff = 10 ##dummy values
norm = Ogre.Vector3(xdiff,30,ydiff)
norm.normalise()
buf.append( norm.x )
buf.append( norm.y )
buf.append( norm.z )


#Ogre.setUint16 ( pNormals, buf )
self.normVertexBuffer.unlock()

# /* ========================================================================= */
def calculateNormals(self):
buf = ctypes.addressof( self.vertexBuffers[self.currentBuffNumber]) + 1

## zero normals
for i in range(self.numVertices) :
self.vNormals = 0 ##Ogre.Vector3.ZERO

## first, calculate normals for faces, add them to proper vertices
buf = self.vertexBuffers[self.currentBuffNumber]
vinds = self.indexBuffer.lock( 0, self.indexBuffer.getSizeInBytes(),
Ogre.HardwareBuffer.HBL_READ_ONLY)
pNormals = self.normVertexBuffer.lock( 0, self.normVertexBuffer.getSizeInBytes(),
Ogre.HardwareBuffer.HBL_DISCARD)

#for i in range(self.numFaces) :
#p0 = vinds[3*i]
#p1 = vinds[3*i+1]
#p2 = vinds[3*i+2]
#v0 = Ogre.Vector3 (buf[3*p0], buf[3*p0+1], buf[3*p0+2])
#v1 = Ogre.Vector3 (buf[3*p1], buf[3*p1+1], buf[3*p1+2])
#v2 = Ogre.Vector3 (buf[3*p2], buf[3*p2+1], buf[3*p2+2])
#diff1 = v2 - v1
#diff2 = v0 - v1
#fn = diff1.crossProduct(diff2)
#self.vNormals[p0] = self.vNormals[p0] + fn
#self.vNormals[p1] += fn
#self.vNormals[p2] += fn

## now normalize vertex normals
#for y in (self.complexity) :
# for x in (self.complexity) :
# numPoint = y*(self.complexity+1) + x
# n = self.vNormals[numPoint]
# n.normalise()
# normal = pNormals + 3*numPoint
# normal[0]=n.x
# normal[1]=n.y
# normal[2]=n.z


self.indexBuffer.unlock()
self.normVertexBuffer.unlock()

# /* ======================================================================== */
def updateMesh(self, timeSinceLastFrame):
self.lastFrameTime = timeSinceLastFrame
self.lastTimeStamp = self.lastFrameTime + timeSinceLastFrame

## do rendering to get ANIMATIONS_PER_SECOND
while(self.lastAnimationTimeStamp <= self.lastTimeStamp):

## switch buffer numbers
self.currentBuffNumber = (self.currentBuffNumber + 1) % 3
buf = ctypes.addressof(self.vertexBuffers[self.currentBuffNumber]) + 1 ## +1 for Y coordinate
buf1 = ctypes.addressof(self.vertexBuffers[(self.currentBuffNumber+2)%3]) + 1
buf2 = ctypes.addressof(self.vertexBuffers[(self.currentBuffNumber+1)%3]) + 1

# /* we use an algorithm from
# * http:##collective.valve-erc.com/index.php?go=water_simulation
# * The params could be dynamically changed every frame ofcourse
# */
C = self.PARAM_C ## ripple speed
D = self.PARAM_D ## distance
U = self.PARAM_U ## viscosity
T = self.PARAM_T ## time
TERM1 = ( 4.0 - 8.0*C*C*T*T/(D*D) ) / (U*T+2)
TERM2 = ( U*T-2.0 ) / (U*T+2.0)
TERM3 = ( 2.0 * C*C*T*T/(D*D) ) / (U*T+2)

#for y in range(self.complexity):
# row = buf + 3*y*(self.complexity+1)
# row1 = buf1 + 3*y*(self.complexity+1)
# row1up = buf1 + 3*(y-1)*(self.complexity+1)
# row1down = buf1 + 3*(y+1)*(self.complexity+1)
# row2 = buf2 + 3*y*(self.complexity+1)
# for x in range (self.complexity) :
# row[3*x] = TERM1 * row1[3*x]
# + TERM2 * row2[3*x]
# + TERM3 * ( row1[3*x-3]
# + row1[3*x+3]
# + row1up[3*x]+row1down[3*x] )

self.lastAnimationTimeStamp += (1.0 / ANIMATIONS_PER_SECOND)


if (self.useFakeNormals):
self.calculateFakeNormals()
else :
self.calculateNormals()


## set vertex buffer
self.posVertexBuffer.writeData(0,
self.posVertexBuffer.getSizeInBytes(), ## size
ctypes.addressof(self.vertexBuffers[self.currentBuffNumber]), ## source
True) ## discard?

# ===========================================================================
# /** "pushes" a mesh at position [x,y]. Note, that x,y are float, hence
# * 4 vertices are actually pushed
# * @note
# * This should be replaced by push with 'radius' parameter to simulate
# * big objects falling into water
# */

def push( self, x, y, depth, absolute):
return
buf = self.vertexBuffers[self.currentBuffNumber]+1
## scale pressure according to time passed
depth = depth * lastFrameTime * ANIMATIONS_PER_SECOND
self._PREP(0,0)
self._PREP(0,1)
self._PREP(1,0)
self._PREP(1,1)

def _PREP(self, addx,addy) :
return
# *vertex=buf+3*((int)(y+addy)*(self.complexity+1)+(int)(x+addx))
# diffy = y - floor(y+addy)
# diffx = x - floor(x+addx)
# dist=sqrt(diffy*diffy + diffx*diffx)
# power = 1 - dist
# if (power<0):
# power = 0
# if (absolute):
# *vertex = depth*power
# else:
# *vertex += depth*power

def hat(self, _x,_y):
self.buf[3*(_y*(self.complexity+1)+(_x))]


# /* ========================================================================= */
# gets height at given x and y, takes average value of the closes nodes */

def getHeight(self, x, y):

self.buf = vertexBuffers[self.currentBuffNumber]
xa = floor(x)
xb = xa + 1
ya = floor(y)
yb = ya + 1
yaxavg = hat(xa,ya) * (1.0-fabs(xa-x)) + hat(xb,ya) * (1.0-fabs(xb-x))
ybxavg = hat(xa,yb) * (1.0-fabs(xa-x)) + hat(xb,yb) * (1.0-fabs(xb-x))
yavg = yaxavg * (1.0-fabs(ya-y)) + ybxavg * (1.0-fabs(yb-y))
return yavg



Demo_Water.py

# This code is in the Public Domain
# -----------------------------------------------------------------------------
# This source file is part of Python-Ogre
# For the latest info, see http://python-ogre.org/
#
# It is likely based on original code from OGRE and/or PyOgre
# For the latest info, see http://www.ogre3d.org/
#
# You may use this sample code for anything you like, it is not covered by the
# LGPL.
# -----------------------------------------------------------------------------
# */
# /* Static water simulation by eru
# * Started 29.05.2003, 20:54:37
# */

#include "ExampleApplication.h"
import ogre.renderer.OGRE as Ogre
import ogre.io.OIS as OIS
import WaterMesh
import math
import SampleFramework as sf
import random
import ctypes

#AnimationState* self.mAnimState

## Mesh stuff
MESH_NAME ="WaterMesh"
ENTITY_NAME ="WaterEntity"
MATERIAL_NAME ="Examples/Water0"
COMPLEXITY =64 ## watch out - number of polys is 2*ACCURACY*ACCURACY !
PLANE_SIZE =3000.0

CIRCLE_MATERIAL ="Examples/Water/Circles"

# /* Some global variables */

# MeshPtr mesh ;
# SubMesh *subMesh ;
# float *vertexBuffers[3] ; // we need 3 vertex buffers
# int currentBuffNumber ;
# int complexity ;
# String meshName ;
# int numFaces ;
# int numVertices ;
# Vector3* vNormals ;

# HardwareVertexBufferSharedPtr posVertexBuffer ;
# HardwareVertexBufferSharedPtr normVertexBuffer ;
# HardwareVertexBufferSharedPtr texcoordsVertexBuffer ;
# HardwareIndexBufferSharedPtr indexBuffer ;

# Real lastTimeStamp ;
# Real lastAnimationTimeStamp;
# Real lastFrameTime ;

# bool useFakeNormals ;





##
## Note that this function makes use of CTypes and def ptr casting to access Ogre Library functions
##
def prepareCircleMaterial():
#global circles_MATERIAL

storageclass = ctypes.c_float * (256 * 256 * 4)
bmap=storageclass(1.0) # you just need to put some value in this to get it started...
#print ctypes.sizeof(bmap)
#ctypes.memset ( bmap, 127, 256 * 256 )

for b in range(16):
x0 = b % 4
y0 = b >> 2
radius = 4.0 + 1.4 * b
for x in range(64):
for y in range (64) :
dist = math.sqrt((x-32)*(x-32)+(y-32)*(y-32)) ## 0..ca.45
dist = math.fabs(dist-radius-2) / 2.0
dist = dist * 255
if (dist>255):
dist=255
colour = 255-dist
colour = ((15-b))/15.0 * colour

bmap[4*(256*(y+64*y0)+x+64*x0)+0]=colour
bmap[4*(256*(y+64*y0)+x+64*x0)+1]=colour
bmap[4*(256*(y+64*y0)+x+64*x0)+2]=colour
bmap[4*(256*(y+64*y0)+x+64*x0)+3]=colour

### Need to pass the address to MemoryDataStream and size in bytes
imgstream = Ogre.MemoryDataStream(ctypes.addressof(bmap), ctypes.sizeof(bmap) )

Ogre.TextureManager.getSingleton().loadRawData(
CIRCLE_MATERIAL,
Ogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
imgstream ,
256,
256,
Ogre.PixelFormat.PF_A8R8G8B8)


material = Ogre.MaterialManager.getSingleton().create( CIRCLE_MATERIAL,
Ogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME)
texLayer = material.getTechnique(0).getPass(0).createTextureUnitState( CIRCLE_MATERIAL )
texLayer.setTextureAddressingMode( ogre.TextureUnitState.TAM_CLAMP )
material.setSceneBlending( ogre.SceneBlendType.SBT_ADD )
material.setDepthWriteEnabled( False )
material.load()



# /* =========================================================================*/
# /* WaterCircle class */
# /* =========================================================================*/
CIRCLE_SIZE = 500.0
CIRCLE_TIME = 0.5
class WaterCircle:
def __init_(self):
self.name = ""
# SceneNode *node
# MeshPtr mesh
# SubMesh *subMesh
# Entity *entity
# Real tm
# static bool first
# ## some buffers shared by all self.circles
# static HardwareVertexBufferSharedPtr posnormVertexBuffer
# static HardwareIndexBufferSharedPtr indexBuffer ## indices for 2 faces
# static HardwareVertexBufferSharedPtr *texcoordsVertexBuffers

# float *texBufData
self.headNode = None
self.waterOverlay = None
self.particleSystem = None
self.particleEmitter = None
self.sceneMgr = None

_prepareMesh()

mesh = Ogre.MeshManager.getSingleton().createManual(name,
Ogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME)
subMesh = mesh.createSubMesh()
subMesh.useSharedVertices=False
numVertices = 4
first = True

if (first) : ## first Circle, create some static common data:
first = False

## static buffer for position and normals
size = 2 * ogre.VertexElement.getTypeSize(ogre.VertexElementType.VET_FLOAT3) ## 6 * float
posnormVertexBuffer = \
Ogre.HardwareBufferManager.getSingleton().createVertexBuffer(
size, ## size of one vertex data 6 * float
4, ## number of vertices
Ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY, ## usage
False) ## no shadow buffer
posnormBufData = posnormVertexBuffer.lock(Ogre.HardwareBuffer.HBL_DISCARD)

buff=[]
for i in range(numVertices):
buf.append(((i%2)-0.5)*CIRCLE_SIZE ) ## pos X
buf.append(0) ## pos Y
buf.append(((i/2)-0.5)*CIRCLE_SIZE ) ## pos Z
buf.append(0) ## normal X
buf.append(1) ## normal Y
buf.append(0) ## normal Z
ogre.setFloat( posnormBufData , buff ) # write unsigned ints...
posnormVertexBuffer.unlock()

## static buffers for 16 sets of texture coordinates
texcoordsVertexBuffers = []
for lvl in range (16):
texcoordsVertexBuffers.append(
Ogre.HardwareBufferManager.getSingleton().createVertexBuffer(
Ogre.VertexElement.getTypeSize(ogre.VertexElementType.VET_FLOAT2), ## size of one vertex data
numVertices, ## number of vertices
Ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY, ## usage
False) ## no shadow buffer
)
texcoordsBufData = texcoordsVertexBuffers[lvl].lock(Ogre.HardwareBuffer.HBL_DISCARD)
x0 = (lvl % 4) * 0.25
y0 = (lvl / 4) * 0.25
y0 = 0.75-y0 ## upside down
for i in range (4):
texcoordsBufData[i*2 + 0]= \
x0 + 0.25 * (i%2)
texcoordsBufData[i*2 + 1]= \
y0 + 0.25 * (i/2)

texcoordsVertexBuffers[lvl].unlock()


## Index buffer for 2 faces
faces[6] = (2,1,0, 2,3,1)
indexBuffer = \
Ogre.HardwareBufferManager.getSingleton().createIndexBuffer(
Ogre.HardwareIndexBuffer.IT_16BIT,
6,
Ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY)
indexBuffer.writeData(0,
indexBuffer.getSizeInBytes(),
faces,
True) ## true?


## Initialize vertex data
subMesh.vertexData = Ogre.VertexData()
subMesh.vertexData.vertexStart = 0
subMesh.vertexData.vertexCount = 4
## first, set vertex buffer bindings
vbind = subMesh.vertexData.vertexBufferBinding
vbind.setBinding(0, posnormVertexBuffer)
vbind.setBinding(1, texcoordsVertexBuffers[0])
## now, set vertex buffer declaration
vdecl = subMesh.vertexData.vertexDeclaration
vdecl.addElement(0, 0, Ogre.VET_FLOAT3, VOgre.ES_POSITION)
vdecl.addElement(0, 3*4, Ogre.VET_FLOAT3, Ogre.VES_NORMAL)
vdecl.addElement(1, 0, Ogre.VET_FLOAT2, Ogre.VES_TEXTURE_COORDINATES)

## Initialize index data
subMesh.indexData.indexBuffer = indexBuffer
subMesh.indexData.indexStart = 0
subMesh.indexData.indexCount = 6

## set mesh bounds
circleBounds(-CIRCLE_SIZE/2.0, 0, -CIRCLE_SIZE/2.0,
CIRCLE_SIZE/2.0, 0, CIRCLE_SIZE/2.0)
mesh._setBounds(circleBounds)
mesh.load()
mesh.touch()

def setTextureLevel():
subMesh.vertexData.vertexBufferBinding.setBinding(1, texcoordsVertexBuffers[lvl])

def WaterCircle( name, x, y):

self.name = name
_prepareMesh()
node = self.sceneMgr.getRootSceneNode().createChild(name)
node.translate(x*(PLANE_SIZE/COMPLEXITY), 10, y*(PLANE_SIZE/COMPLEXITY))
entity = self.sceneMgr.createEntity(name, name)
entity.setMaterialName(self.circles_MATERIAL)
node.attachObject(entity)
tm = 0
lvl = 0
setTextureLevel()

def __del__(self, ):
Ogre.MeshManager.getSingleton().remove(mesh.getHandle())
self.sceneMgr.destroyEntity(entity.getName())
self.sceneMgr.getRootSceneNode().removeChildnode.getName()

def animate(self, timeSinceLastFrame):
lastlvl = lvl
tm += timeSinceLastFrame
lvl = (int) ( (Real)(tm)/CIRCLE_TIME * 16 )
if (lvl<16 and lvl!=lastlvl) :
setTextureLevel()


def clearStaticBuffers(self):
posnormVertexBuffer = Ogre.HardwareVertexBufferSharedPtr()
indexBuffer = Ogre.HardwareIndexBufferSharedPtr()
for i in range (16):
texcoordsVertexBuffers[i] = Ogre.HardwareVertexBufferSharedPtr()

del texcoordsVertexBuffers


# bool WaterCircle.first = True
# HardwareVertexBufferSharedPtr WaterCircle.posnormVertexBuffer =
# HardwareVertexBufferSharedPtr()
# HardwareIndexBufferSharedPtr WaterCircle.indexBuffer =
# HardwareIndexBufferSharedPtr()
# HardwareVertexBufferSharedPtr* WaterCircle.texcoordsVertexBuffers = 0

##=========================================================================
## WaterListener class
##=========================================================================

class WaterListener(sf.FrameListener):
def __init__(self, renderWindow, camera, manager, WaterMesh, WaterEntity, headNode ):

sf.FrameListener.__init__(self, renderWindow, camera)
self.camera = camera
self.Manager = manager
self.WaterMesh = WaterMesh
self.WaterEntity = WaterEntity
self.headNode = headNode

self.materialNumber = 0
self.timeoutDelay = 0.0
self.headDepth = 2.0
self.skyBoxOn = False
self.RAIN_HEIGHT_RANDOM = 5
self.RAIN_HEIGHT_CONSTANT = 5
self.sines = [0,100,200,300]
self.adds=[0.3,-1.6,1.1,0.5]
self.oldPos = Ogre.Vector3.UNIT_Z
self.pindex = 0
self.changeSpeed = 1

self.updateMaterial()
self.updateInfoParamC()
self.updateInfoParamD()
self.updateInfoParamU()
self.updateInfoParamT()
self.updateInfoNormals()
self.updateInfoHeadDepth()
self.updateInfoSkyBox()

self.switchSkyBox()

# def processselfcircles(self,timeSinceLastFrame):
#
# for i in range (self.circles.size() ) :
# self.circles[i].animate(timeSinceLastFrame)

# # # do :
# # # found = False
# # # for it = self.circles :
# # # it != self.circles.end()
# # # ++it) {
# # # if ((*it).lvl>=16) {:
# # # delete (*it)
# # # self.circles.erase(it)
# # # found = True
# # # break


# # # while (found)


def processParticles(self):
global PLANE_SIZE, COMPLEXITY, RAIN_HEIGHT_RANDOM, RAIN_HEIGHT_CONSTANT
pit = Ogre.self.particleSystem._getIterator()
while not pit.end():
particle = pit.getNext()
ppos = particle.position
if ppos.y<=0 and particle.timeToLive>0 : ## hits the water!:
## delete particle
particle.timeToLive = 0.0
## push the water
x = ppos.x / PLANE_SIZE * COMPLEXITY
y = ppos.z / PLANE_SIZE * COMPLEXITY
h = random.random() % self.RAIN_HEIGHT_RANDOM + self.RAIN_HEIGHT_CONSTANT
if (x<1):
x=1
if (x>COMPLEXITY-1):
x=COMPLEXITY-1
if (y<1):
y=1
if (y>COMPLEXITY-1):
y=COMPLEXITY-1
self.WaterMesh.push(x,y,-h)
circle = WaterCircle(
"Circle#"+Ogre.StringConverter.toString(self.pindex),
x, y)
self.pindex+=1
self.circles.push_back(circle)




## Head animation */
def animateHead(self, timeSinceLastFrame):

## sine track? :)
for i in range(4):
self.sines[i]+=self.adds[i]*timeSinceLastFrame

tx = ((math.sin(self.sines[0]) + math.sin(self.sines[1])) / 4 + 0.5 ) * (COMPLEXITY-2) + 1
ty = ((math.sin(self.sines[2]) + math.sin(self.sines[3])) / 4 + 0.5 ) * (COMPLEXITY-2) + 1
self.WaterMesh.push(self,tx,ty, -self.headDepth)
step = PLANE_SIZE / COMPLEXITY
self.headNode.resetToInitialState()
self.headNode.setScale (Ogre.Vector3(3.0,3.0,3.0))
newPos = Ogre.Vector3(step*tx, self.headDepth, step*ty)
diffPos = newPos - self.oldPos
headRotation = Ogre.Vector3.UNIT_Z.getRotationTo(diffPos)
self.oldPos = newPos
self.headNode.translate(newPos)
self.headNode.rotate(headRotation)


## GUI updaters
def updateInfoParamC(self):
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/Param_C") \
.setCaption("[1/2]Ripple speed: %s" % self.WaterMesh.PARAM_C)

def updateInfoParamD(self):
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/Param_D") \
.setCaption("[3/4]Distance: %s" % self.WaterMesh.PARAM_D)

def updateInfoParamU(self):
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/Param_U") \
.setCaption("[5/6]Viscosity: %s" % self.WaterMesh.PARAM_U)

def updateInfoParamT(self):
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/Param_T") \
.setCaption("[7/8]Frame time: %s" % self.WaterMesh.PARAM_T)

def updateInfoNormals(self):
cap = "[N]Normals: "
if self.WaterMesh.useFakeNormals:
cap += "fake"
else: cap += "real"
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/Normals") \
.setCaption(cap)

def switchNormals(self):
self.WaterMesh.useFakeNormals = not self.WaterMesh.useFakeNormals
self.updateInfoNormals()

def updateInfoHeadDepth(self):
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/Depth") \
.setCaption( "[U/J]Head depth: %s" % self.headDepth)

def updateInfoSkyBox(self):
cap = "[B]SkyBox: "
if self.skyBoxOn:
cap += "On"
else: cap += "Off"
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/SkyBox").setCaption(cap)

def updateMaterial(self):
materialName = "Examples/Water%s" % self.materialNumber
material = Ogre.MaterialManager.getSingleton().getByName(materialName)
if (material==0):
if(self.materialNumber):
self.materialNumber = 0
print "here"
updateMaterial()
return
else:
OGRE_EXCEPT(Exception.ERR_INTERNAL_ERROR,
"Material "+materialName+"doesn't exist!",
"WaterListener.updateMaterial")

self.WaterEntity.setMaterialName(materialName)
Ogre.OverlayManager.getSingleton().getOverlayElement("Example/Water/Material") \
.setCaption( "[M]Material: %s" % materialName)


def switchMaterial(self):
self.materialNumber+=1
if (self.materialNumber == 9):
self.materialNumber=0
self.updateMaterial()

def switchSkyBox(self):
self.skyBoxOn = not self.skyBoxOn
self.Manager.setSkyBox(self.skyBoxOn, "Examples/SceneSkyBox2")
self.updateInfoSkyBox()


def frameStarted(self, evt):
result = sf.FrameListener.frameStarted(self,evt)

# if( result == False ):
# ## check if we are exiting, if so, clear static HardwareBuffers to adef segfault
# WaterCircle.clearStaticBuffers()
# return False

## self.mAnimState.addTime(evt.timeSinceLastFrame)

## process keyboard events
self.changeSpeed = evt.timeSinceLastFrame

## adjust keyboard speed with SHIFT (increase) and CONTROL (decrease)
if (self.Keyboard.isKeyDown(OIS.KC_LSHIFT) or self.Keyboard.isKeyDown(OIS.KC_RSHIFT)):
self.changeSpeed *= 10.0

if (self.Keyboard.isKeyDown(OIS.KC_LCONTROL)):
self.changeSpeed /= 10.0

## rain
#self.circles(evt.timeSinceLastFrame)
#if (self.Keyboard.isKeyDown(OIS.KC_SPACE)):
# self.particleEmitter.setEmissionRate(20.0)
#else:
# self.particleEmitter.setEmissionRate(0.0)

#processParticles()



#ADJUST_RANGE(self.headDepth, OIS.KC_U, OIS.KC_J, 0, 10, 0.5*self.changeSpeed, self.updateInfoHeadDepth())
if (self._isToggleKeyDown(OIS.KC_U,0.5)):
self.headDepth+=0.5*self.changeSpeed
if (self.headDepth>=10):
self.headDepth = 10
print self.headDepth
self.updateInfoHeadDepth()

if (self._isToggleKeyDown(OIS.KC_J,0.5)):
self.headDepth-=0.5*self.changeSpeed
if (self.headDepth<=0):
self.headDepth = 0
print self.headDepth
self.updateInfoHeadDepth()

#ADJUST_RANGE(self.WaterMesh.PARAM_C, OIS.KC_2, OIS.KC_1, 0, 10, 0.1*self.changeSpeed, self.updateInfoParamC())
if (self._isToggleKeyDown(OIS.KC_2,0.5)):
self.WaterMesh.PARAM_C +=0.1*self.changeSpeed
if (self.WaterMesh.PARAM_C >=10):
self.WaterMesh.PARAM_C = 10
self.updateInfoParamC()

if (self._isToggleKeyDown(OIS.KC_1,0.5)):
self.WaterMesh.PARAM_C -=0.1*self.changeSpeed
if (self.WaterMesh.PARAM_C <=0):
self.WaterMesh.PARAM_C = 0
self.updateInfoParamC()

#ADJUST_RANGE(self.WaterMesh.PARAM_D, OIS.KC_4, OIS.KC_3, 0.1, 10, 0.1*self.changeSpeed, self.updateInfoParamD())
if (self._isToggleKeyDown(OIS.KC_4,0.5)):
self.WaterMesh.PARAM_D +=0.1*self.changeSpeed
if (self.WaterMesh.PARAM_D >=10):
self.WaterMesh.PARAM_D = 10
self.updateInfoParamD()

if (self._isToggleKeyDown(OIS.KC_3,0.5)):
self.WaterMesh.PARAM_D -=0.1*self.changeSpeed
if (self.WaterMesh.PARAM_D <=0.1):
self.WaterMesh.PARAM_D = 0
self.updateInfoParamD()

#ADJUST_RANGE(self.WaterMesh.PARAM_U, OIS.KC_6, OIS.KC_5, -2, 10, 0.1*self.changeSpeed, self.updateInfoParamU())
if (self._isToggleKeyDown(OIS.KC_6,0.5)):
self.WaterMesh.PARAM_U +=0.1*self.changeSpeed
if (self.WaterMesh.PARAM_U >=10):
self.WaterMesh.PARAM_U = 10
self.updateInfoParamU()

if (self._isToggleKeyDown(OIS.KC_5,0.5)):
self.WaterMesh.PARAM_U -=0.1*self.changeSpeed
if (self.WaterMesh.PARAM_U <=-2):
self.WaterMesh.PARAM_U = 0
self.updateInfoParamU()

#ADJUST_RANGE(self.WaterMesh.PARAM_T, OIS.KC_8, OIS.KC_7, 0, 10, 0.1*self.changeSpeed, self.updateInfoParamT())
if (self._isToggleKeyDown(OIS.KC_8,0.5)):
self.WaterMesh.PARAM_T +=0.1*self.changeSpeed
if (self.WaterMesh.PARAM_T >=10):
self.WaterMesh.PARAM_T = 10
self.updateInfoParamT()

if (self._isToggleKeyDown(OIS.KC_7,0.5)):
self.WaterMesh.PARAM_T -=0.1*self.changeSpeed
if (self.WaterMesh.PARAM_T <=0):
self.WaterMesh.PARAM_T = 0
self.updateInfoParamT()



## self.timeoutDelay-=evt.timeSinceLastFrame
## if (self.timeoutDelay<=0):
## self.timeoutDelay = 0


if self._isToggleKeyDown(OIS.KC_N,0.5):
self.switchNormals()

if self._isToggleKeyDown(OIS.KC_M,0.5):
self.switchMaterial()

if self._isToggleKeyDown(OIS.KC_B,0.5):
self.switchSkyBox()


self.animateHead(evt.timeSinceLastFrame)
self.WaterMesh.updateMesh(evt.timeSinceLastFrame)
return sf.FrameListener.frameStarted(self, evt)

# def __del__ ( self ):
# ## If when you finish the application is still raining there
# ## are water self.circles that are still being processed
# activeself.circles = self.self.circles.size ()
#
# ## Kill the active water self.circles
# for i in range ( activeself.circles ):
# del (self.self.circles[i])


## adjust values (some macros for faster change
## def ADJUST_RANGE(self,_value,_plus,_minus,_minVal,_maxVal,_change,_macro):
## if (self._isToggleKeyDown(_plus,0.5)):
## _value+=_change
## if (_value>=_maxVal):
## _value = _maxVal
## print _value
## _macro
##
## if (self._isToggleKeyDown(_minus,0.5)):
## _value-=_change
## if (_value<=_minVal):
## _value = _minVal
## print _value
## _macro


class WaterApplication(sf.Application):##,ogre.RenderTargetListener):

def __init__(self):
sf.Application.__init__(self)


def _createScene(self):
sceneManager = self.sceneManager
camera = self.camera

## Set ambient light
sceneManager.ambientLight = Ogre.ColourValue(0.75, 0.75, 0.75)

## Create a light
l = sceneManager.createLight("MainLight")
l.setPosition(200,300,100)
lightNode = sceneManager.getRootSceneNode().createChildSceneNode()
lightNode.attachObject(l)

## Create water mesh and entity
self.WaterMesh = WaterMesh.WaterMesh(MESH_NAME, PLANE_SIZE, COMPLEXITY)
self.WaterEntity = sceneManager.createEntity(ENTITY_NAME, MESH_NAME)
self.WaterEntity.setMaterialName(MATERIAL_NAME)

waterNode = sceneManager.getRootSceneNode().createChildSceneNode()
#waterNode = sceneManager.rootSceneNode.createChildSceneNode("WaterNode",Ogre.Vector3(0, 20,0))
waterNode.attachObject(self.WaterEntity)

## Add a head, give it it's own node
self.headNode = waterNode.createChildSceneNode()
ent = sceneManager.createEntity("head", "ogrehead.mesh")
#self.headNode.setScale (Ogre.Vector3(5.0,5.0,5.0))
self.headNode.attachObject(ent)

## Make sure the camera track self node
## self.camera.setAutoTracking(True, self.headNode)

## Create the camera node, set its position & attach camera
camNode = sceneManager.getRootSceneNode().createChildSceneNode()
camNode.translate(0, 500, PLANE_SIZE)
camNode.yaw(Ogre.Degree(-45))
camNode.attachObject(self.camera)


## set up spline animation of light node
anim = sceneManager.createAnimation("WaterLight", 20)

## create a random spline for light
track = anim.createNodeTrack(0, lightNode)
key = track.createNodeKeyFrame(0)
for ff in range (1,20):
key = track.createNodeKeyFrame(ff)
lpos = Ogre.Vector3(
random.random()%PLANE_SIZE , ##- PLANE_SIZE/2,
random.random()%300+100,
random.random()%PLANE_SIZE ##- PLANE_SIZE/2
)
key.setTranslate(lpos)
key = track.createNodeKeyFrame(20)

## Create a new animation state to track self
self.mAnimState = sceneManager.createAnimationState("WaterLight")
self.mAnimState.setEnabled(True)

## Put in a bit of fog for the hell of it
##sceneManager.setFog(FOG_EXP, ColourValue.White, 0.0002)

## show overlay
self.waterOverlay = Ogre.OverlayManager.getSingleton().getByName("Example/WaterOverlay")
self.waterOverlay.show()

## Let there be rain
# self.particleSystem = sceneManager.createParticleSystem("rain",
# "Examples/Water/Rain")
# self.ParticleEmitter = self.particleSystem.getEmitter(0)
# rNode = sceneManager.getRootSceneNode().createChildSceneNode()
# rNode.translate(PLANE_SIZE/2.0, 3000, PLANE_SIZE/2.0)
# rNode.attachObject(self.particleSystem)
# ## Fast-forward the rain so it looks more natural
# self.particleSystem.fastForward(20)
## It can't be set in .particle file, and we need it )
# static_cast<BillboardParticleRenderer*>(self.particleSystem.getRenderer()).setBillboardOrigin(BBO_BOTTOM_CENTER)

##prepareCircleMaterial()


## Create new frame listener
def _createFrameListener(self):

self.frameListener = WaterListener(self.renderWindow,
self.camera,
self.sceneManager,
self.WaterMesh,
self.WaterEntity,
self.headNode)
self.root.addFrameListener(self.frameListener)
self.frameListener.showDebugOverlay(False)


if __name__ == '__main__':
application = WaterApplication()
application.go()

andy

17-11-2007 23:19:54

Your water.py has an extra 'self' in it:
self.WaterMesh.push(tx,ty, -self.headDepth) # removed the self,
Other than that it's great (I have built a wrapper around the water_mesh.c code so have this as an external module - but didn't have a working Demo-Mesh.py ) and the demo now works cool..

I haven't checked if your python implementation of the water_mesh.c works but will do later (I'm testing the new gccxml wrappers and have an issue with some functions at the moment )

Many Thanks for working on this..

Andy

skorpio

19-11-2007 01:24:25

Cool, glad to help

The Demo_Water.py still needs some work to get rain working.
As far as the watermesh.py. I used the one provided in the "Tobefix" folder.
I did notice that there are lot of things commented out so I had to go back to the C++ implementation to see what they were trying to accomplish.

My problem is that python generates VOID* pointers to INT and FLOATS arrays and I do not know how access this data using python.

For example

vinds = self.indexBuffer.lock( 0, self.indexBuffer.getSizeInBytes(),
Ogre.HardwareBuffer.HBL_READ_ONLY)


creates the buffer and this accesses it

for i in range(self.numFaces) :
p0 = vinds[3*i]
p1 = vinds[3*i+1]
p2 = vinds[3*i+2]

the code is trying to get the data from those location but python returns an error.

Most of the WaterMesh.py is like that.
By the way, by removing the extra SELF as you describe, my version crashes, it says that is looking for 5 paramenters not 4.


Best regards,