# Building the Water Ripples Sample in Silverlight

## Algorithm

The algorithm is based on Hugo Elias’ 2D water tutorial.

On each render step we have the state of the water for the current frame and the previous frame.

The state is stored in two 2-dimensional arrays of integers that are as big as the image.

For each pixel position of the image we store the height of the water (or wave) in that position. 0 means “sea level”. Larger than 0 means that we have a raised wave, less than zero means that we have wave below “sea level”. We need information for both raised and low waves in order to be able to combine them.

On each render step we use data from the current frame (Buffer2) and the previous frame (Buffer1) and   write the results into Buffer1.

damping = some non-integer between 0 and 1 (I use 0.94)

for every non-edge element:

loop

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

end loop

Swap the buffers

Display Buffer1

end loop

You can go ahead and look at Hugo’s explanation about why does this work, or continue reading here.

Because the 2 buffers contain consecutive steps for the water, we can get the water velocity at a given location [x, y] by subtracting: Buffer2[x, y] – Buffer1[x, y]

Also we want the waves to spread out, so we smooth the buffers on every frame:

Smoothed[x,y] = (Buffer1[x-1, y] +

Buffer1[x+1, y] +

Buffer1[x, y-1] +

Buffer1[x, y+1]) / 4

In the actual algorithm we multiply the smoothed value by 2 in order to decrease the effect of velocity.

And last, the waves lose energy as they travel:

Buffer2[x,y] = Buffer2[x,y] * damping

## Rendering the Water

The render buffer contains heights of the water in each pixel. We’ll render it using shading and refraction.

The shading variable below determines the direction and intensity of the light. For example, if you set shading = xoffset, you’ll get light straight from the left. I decided to set the light at the bottom-right part of the screen.

For every non-edge pixel in the buffer

Xoffset = buffer[x-1, y] – buffer[x+1, y]

Yoffset = buffer[x, y-1] – buffer[x, y+1]

shading = (xoffset - yoffset) / 2

// note: x+xoffset and y+yoffset do not wrap around the texture

t = texture[x+Xoffset, y+Yoffset]

// make sure the color is within limits

resultColor = SaturateTo255Max(resultColor)

plot pixel at (x,y) with color resultColor

End loop

## Creating Drops/Splashes

I made a simple function to create a circular splash, although you can create different splashes to simulate dropping irregular shapes into the water or other motion effects (e.g. star, line or use the letters of your name).

The function creates a splash given its radius at location (cx, cy). The splash begins below water level and rises above at the end.

dist = distance from point (x,y) to (cx, cy)

if (dist < radius) // if within splash circle

buffer1[x, y] = 255 - (512 * 1 - dist / radius)

end if

end loop

end loop

## The Silverlight Side

The rendering loop is called every 60ms and does this:

1. Add a random splash (rain drop) on the image

2. Calculate the next frame to render

3. Display the next frame

There are 3 components used to render each frame:

Renderer has the “raw” buffers of integers containing wave height for each pixel in the frame. On each frame the renderer mixes its raw buffer with the background image (decoded using FluxJpeg.Core.Image component) and outputs each it to a dynamic image generation surface (EditableImage).