package main import ( "image" "git.kirsle.net/go/render" ) // App holds the ripple applet state. type App struct { e render.Engine image image.Image source *image.RGBA data *image.RGBA tex render.Texturer // computed width int height int size int // frame buffers buffer0 []int buffer1 []int } // New creates the ripple applet. func New(e render.Engine, i image.Image) *App { var ( bounds = i.Bounds() width = bounds.Max.X height = bounds.Max.Y size = width * height ) a := &App{ e: e, image: i, source: render.ImageToRGBA(i), data: render.ImageToRGBA(i), width: width, height: height, size: size, buffer0: make([]int, size), buffer1: make([]int, size), } tex, err := a.e.StoreTexture("pic", a.data) if err != nil { panic(err) } a.tex = tex return a } // Disturb creates a disturbance in the water. func (a *App) Disturb(x, y, z int) { if x < 2 || x > Width-2 || y < 1 || y > Height-2 { return } var i = x + y*Width a.buffer0[i] += z a.buffer0[i-1] -= z } // Ripple runs the ripple algorithm. func (a *App) Ripple() { var ( width = a.width size = a.size ) // average cells to make the surface more even for i := width + 1; i < size-width-1; i += 2 { for x := 1; x < width-1; x++ { avg := (a.buffer0[i] + a.buffer0[i+1] + a.buffer0[i-1] + a.buffer0[i-width] + a.buffer0[i+width]) / 5 a.buffer0[i] = avg i++ } } // Loop for every non-edge element. y := 0 for i := width + 1; i < size-width-1; i += 2 { y++ for x := 1; x < width-1; x++ { // Wave propagation waveHeight := (a.buffer0[i-1]+ a.buffer0[i+1]+ a.buffer0[i+Width]+ a.buffer0[i-Width])/2 - a.buffer1[i] a.buffer1[i] = waveHeight // Some very fake lighting var light = int(float64(waveHeight)*2.0 - float64(a.buffer1[i-2])*0.6) if light < -10 { light = -10 } else if light > 100 { light = 100 } color := a.source.At(x, y) a.data.Set(x, y, render.FromColor(color).Lighten(light).ToColor()) i++ } } aux := a.buffer0 a.buffer0 = a.buffer1 a.buffer1 = aux a.tex, _ = a.e.StoreTexture("pic", a.data) } // Present the visual state. func (a *App) Present() { rect := render.Rect{ W: a.width, H: a.height, } a.e.Copy(a.tex, rect, rect) a.e.Present() }