Created
March 14, 2012 22:21
-
-
Save luajalla/2040014 to your computer and use it in GitHub Desktop.
F# Ripple version
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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