Skip to content

Instantly share code, notes, and snippets.

@luajalla
Created March 14, 2012 22:21
Show Gist options
  • Save luajalla/2040014 to your computer and use it in GitHub Desktop.
Save luajalla/2040014 to your computer and use it in GitHub Desktop.
F# Ripple version
namespace GLCameraRipple
open System
open System.Drawing
open System.Runtime.InteropServices
open Microsoft.FSharp.NativeInterop
open MonoTouch.CoreFoundation
[<AutoOpen>]
module Inlinings =
let inline set arr ind v = NativePtr.set arr ind v
//let inline (<~) arr (ind, v) = NativePtr.set arr ind v
let inline clamp min max v =
if v < min then min elif v > max then max else v
type FRippleModel(screenSize: Size, meshFactor: int, touchRadius: int, textureSize: Size) =
do Console.WriteLine "New RippleModel"
let poolWidth = screenSize.Width / meshFactor
let poolHeight = screenSize.Height / meshFactor
let texCoordFactorS, texCoordOffsetS, texCoordFactorT, texCoordOffsetT =
let screenHW = single screenSize.Height / single screenSize.Width
let textureWH = single textureSize.Width / single textureSize.Height
if screenHW < textureWH then
let factor = screenHW / textureWH
factor, (1.f - factor)*0.5f, 1.f, 0.f
else
let factor = textureWH / screenHW
1.f, 0.f, factor, (1.f - factor)*0.5f
let rippleCoeff =
let size = touchRadius*2 + 1 in Array2D.init size size (fun x y ->
let x', y' = x - touchRadius, y - touchRadius
let dist = sqrt (x'*x' + y'*y' |> single)
if dist <= single touchRadius then
let factor = dist / single touchRadius
- (cos (factor * 3.14159265358979323846f) + 1.f) * 256.f
else
0.f)
let mutable rippleSource = Array2D.zeroCreate (poolWidth + 2) (poolHeight + 2)
let mutable rippleDest = Array2D.zeroCreate (poolWidth + 2) (poolHeight + 2)
let poolSize2 = poolWidth * poolHeight * 2
//F# float = System.Double
let rippleVertices = Marshal.AllocHGlobal(poolSize2 * sizeof<single>) |> NativePtr.ofNativeInt<single>
let rippleTexCoords = Marshal.AllocHGlobal(poolSize2 * sizeof<single>) |> NativePtr.ofNativeInt<single>
let rippleIndicies = Marshal.AllocHGlobal((poolHeight - 1) * (poolWidth + 1) * 2 * sizeof<uint16>)
|> NativePtr.ofNativeInt<uint16>
// Init Mesh
do
let index = ref 0
let inline (<+) arr v = NativePtr.set arr !index v; incr index
for i in 0..poolHeight - 1 do
for j in 0..poolWidth - 1 do
let ind = (i*poolWidth + j) * 2
let revPoolWidth = single j / single (poolWidth-1)
let revPoolHeight = single i / single (poolHeight-1)
set rippleVertices ind (-1.f + 2.f * revPoolWidth)
set rippleVertices (ind+1) (1.f - 2.f * revPoolHeight)
set rippleTexCoords (ind) (revPoolHeight * texCoordFactorS + texCoordOffsetS)
set rippleTexCoords (ind+1) ((1.f - revPoolWidth) * texCoordFactorT + texCoordFactorT) // shouldn't texCoordOffsetT be there?
if i < poolHeight - 1 then
let v = i*poolWidth + j
// for even j add (i*poolWidth+j) then ((i+1)*poolWidth+j), for odd we need just to inverse them
let fstIndValue, sndIndValue =
let v = i*poolWidth + j
if i % 2 = 0 then uint16 v, uint16 (v + poolWidth) else uint16 (v + poolWidth), uint16 v
if j = 0 then rippleIndicies <+ fstIndValue
rippleIndicies <+ fstIndValue
rippleIndicies <+ sndIndValue
if j = poolWidth - 1 then rippleIndicies <+ sndIndValue
member this.RunSimulation() =
for y in 0..poolHeight - 1 do
for x in 0..poolWidth - 1 do
let a = rippleSource.[x+1, y]
let b = rippleSource.[x+1, y+2]
let c = rippleSource.[x, y+1]
let d = rippleSource.[x+2, y+1]
let res = (a+b+c+d)*0.5f - rippleDest.[x+1, y+1]
rippleDest.[x+1, y+1] <- res * 0.96875f //res - res/32
let s_tc_k = texCoordFactorS / single (poolHeight - 1)
let t_tc_k = -texCoordFactorT / single (poolWidth - 1)
for y in 0..poolHeight - 1 do
for x in 0..poolWidth - 1 do
let a = rippleDest.[x+1, y]
let b = rippleDest.[x+1, y+2]
let c = rippleDest.[x, y+1]
let d = rippleDest.[x+2, y+1]
let s_offset = clamp -0.5f 0.5f (single (b - a) / 2048.f)
let t_offset = clamp -0.5f 0.5f (single (c - d) / 2048.f)
let s_tc = s_tc_k * single y + texCoordOffsetS
let t_tc = t_tc_k * single x + texCoordFactorT + texCoordOffsetT
let ind = (y*poolWidth + x) * 2
set rippleTexCoords ind (s_tc + s_offset)
set rippleTexCoords (ind+1) (t_tc + t_offset)
let tmp = rippleSource
rippleSource <- rippleDest
rippleDest <- tmp
member this.InitiateRippleAtLocation (location: PointF) =
let xIndex = int (location.X / single screenSize.Width * single poolWidth)
let yIndex = int (location.Y / single screenSize.Height * single poolHeight)
let xMinusR = xIndex - touchRadius
let yMinusR = yIndex - touchRadius
for y in yMinusR..yIndex + touchRadius do
for x in xMinusR..xIndex + touchRadius do
if x >= 0 && x < poolWidth && y >= 0 && y < poolHeight then
rippleSource.[x+1,y+1] <- rippleSource.[x+1, y+1] + rippleCoeff.[y-yMinusR, x-xMinusR]
member this.Verticies with get() = NativePtr.toNativeInt rippleVertices
member this.TexCoords with get() = NativePtr.toNativeInt rippleTexCoords
member this.Indicies with get() = NativePtr.toNativeInt rippleIndicies
member this.VertexSize with get() = poolSize2 * sizeof<single>
member this.IndexCount with get() = (poolHeight-1) * (poolWidth+1) * 2
member this.IndexSize with get() = this.IndexCount * sizeof<uint16>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment