# Water ripple effect - help with speed optimisation

I’ve implemented a water ripple effect based on the algorithm from here
http://freespace.virgin.net/hugo.elias/graphics/x_water.htm

Though it works, I’m finding it runs very slowly. I’m guessing the get and set with images isn’t the fastest, so is there an alternative (or is there something amiss with my code)?

``````
-- WaterRipple
-- Using http://freespace.virgin.net/hugo.elias/graphics/x_water.htm as a starting point
-- Use this function to perform your initial setup
function setup()

--damping = some non-integer between 0 and 1
damping=0.95
xsize=110
ysize=110
counter=0
buffer1={}
buffer2={}
buffertemp={}
for x=1,xsize do
buffer1[x]={}
buffer2[x]={}
buffertemp[x]={}
for y=1,ysize do
buffer1[x][y]=0
buffer2[x][y]=0
buffertemp[x][y]=0
end
end
end

-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)
counter = counter + 1
if counter>50 then
--creater a disturbance in the heightmap
buffer1[50][50]=1
counter=0
end
--display the counter
text(counter,400,460)
--  begin loop

for x=2,xsize-1 do
for y=2,ysize-1 do
--calculate the "height map"
buffer2[x][y] =(buffer1[x+1][y]+buffer1[x-1][y]+buffer1[x][y+1]+buffer1[x][y-1])/2-buffer2[x][y]
buffer2[x][y] = buffer2[x][y] * damping
--calculate the shift
xoffset=buffer2[x-1][y]-buffer2[x+1][y]
yoffset=buffer2[x][y-1]-buffer2[x][y+1]
local rt,gt,bt,at=waterimg:get(x+xoffset,y+yoffset)
rt=rt+xoffset
gt=gt+xoffset
bt=bt+xoffset
at=at+xoffset
waterimg2:set(x,y,color(rt,gt,bt,at))
end
end
sprite(waterimg2,400,400)
buffertemp=buffer2
buffer2=buffer1
buffer1=buffertemp
end
``````

Hello West. I’ve tried your code but i don’t understand what i should see: there is only a small icon (100x100?) in the middle of the screen, a counting above, and some very small variations on the image. Is it what i should see?

Yes, that’s right. a ripple water effect, but a very slow one. The counter should be incrementing faster

Sorry West, i don’t think it can real time with the way it is coded. I think it should be rewriten using meshes and some trick with scale/rotate/translate if you want a real time effect. I don’t even see any ‘‘watering’’ effect occuring here. Maybe a video would show what you want to achive?

(Further update) With some limited success, I tried replacing the image with a mesh and `waterimg` with a linear array, and caching the function `setRectColor()` in a local variable. That increases the speed by a factor of about three.

``````
--
-- WaterRipple with mesh
--
-- Using http://freespace.virgin.net/hugo.elias/graphics/x_water.htm
-- as a starting point
supportedOrientations(LANDSCAPE_ANY)
function setup()
waterimg = {}
m = mesh()
damping = 32
xsize = waterimg2.width
ysize = waterimg2.height
print("No. of cells: ", xsize * ysize)
dim = math.min(WIDTH, HEIGHT) / math.max(xsize, ysize)
dim = math.floor(dim)
local xm, ym = (WIDTH - xsize * dim) / 2, (HEIGHT - ysize * dim) / 2
counter = 0
buffer1 = {}
buffer2 = {}
for x=1, xsize do
for y=1, ysize do
local i = (x - 1) * ysize + y
buffer1[i] = 0
buffer2[i] = 0
waterimg[i] = color(waterimg2:get(x, y))
local idx = m:addRect(x * dim + xm, y * dim + xm, dim, dim)
m:setRectColor(idx, waterimg[i])
end
end
end

function draw()
background(0)
--display the counter
text(counter, WIDTH - 20, 460)
text(1/DeltaTime, WIDTH - 20, 420)
if counter % 50 == 0 then
--creater a disturbance in the heightmap
buffer1[54 * ysize + 55] = 1
end
counter = counter + 1
--  begin loop
for i = ysize + 2, (xsize - 1) * ysize - 1 do
local ixp1 = i + ysize
local ixm1 = i - ysize
buffer2[i] = (buffer1[ixp1] + buffer1[ixm1]
+ buffer1[i + 1] + buffer1[i - 1])/2 - buffer2[i]
buffer2[i] = buffer2[i] - buffer2[i] / damping
end
local src = m.setRectColor
for i = ysize + 2, (xsize - 1) * ysize - 1 do
local ixp1 = i + ysize
local ixm1 = i - ysize
local xoffset = math.floor(buffer2[ixm1] - buffer2[ixp1])
local yoffset = math.floor(buffer2[i - 1] - buffer2[i + 1])
local io = i + xoffset * ysize + yoffset
local col = waterimg[io]
src(m, i, col)
end
m:draw()
buffer2, buffer1 = buffer1, buffer2
end
``````

I also made the first perturbation occur at `counter = 0`, removed the redundant (I think) ripple in the alpha channel, `buffertemp` and (update) addition of `xoffset` to the colour channels. Looking at the original algorithm, I also moved the offset calculation for rendering into a separate loop to the update of the buffer.

Recently, I have been having problems with re-editing edited posts on the forum. I find myself editing the original post again, not re-editing the edit. My attempts to update the post above has suffered from that.

.@mpilgrem I’ve noticed the same thing, for perhaps the last 2 weeks or so.

.@mpilgrim many thanks for the response, I had tried meshes but didn’t get as far as you

I was looking towards this http://media.chikuyonok.ru/ripple/ implemented in JavaScript which was nice and smooth, and had assumed that this sort of performance would therefore be achievable here. :-/

.@West this is the sort of thing shaders will be very good at achieving in the next update.

.@mpilgrem @toadkick sorry about the editing bug. Sounds like it might be a vanilla forums issue. I’ll have a look at updating to the latest version.

.@Simeon OK, I’ll park this until the next update

omg, i lost something, there will be shaders in Codea? : ))