startshape realStart rule realStart { start { x 2 } } background { b -1 } rule start { terminal4 { r 12 } } rule start { terminal1 { r 12 } } rule start { terminal4 { r 12 } } rule start { terminal4 { r 12 } } rule start .05 { terminal2 { r 12 } } rule terminal4 { SQUARE { b 0.50 s .055 sat 0.40 hue 95 } SQUARE { b 1 s .055 a -.8 } train { x .06 } train { r 90 y .06 } train { r 180 x -.06 } train { r 270 y -.06 } } rule terminal2 2 { SQUARE { b 1 s .055 a -.85 } train { r 90 y .06 } train { r 270 y -.06 } } rule terminal2 1 { SQUARE { b 1 s .055 a -.8 } train { x .06 } train { r 90 y .06 } } rule terminal2 1 { SQUARE { b 1 s .055 a -.85 } train { x.06 } train { r 270 y -.06 } } rule terminal1 { CIRCLE { b 1 s .055 a -.9 } train { r 90 y .06 } } rule terminal1 { CIRCLE { b 1 s .055 a -.9 } train { r -90 y -.06 } } rule train 1 { CIRCLE { b 1 s .045 a -.9 } train { x .06 } } rule train 2 { terminal1 { } } rule train .02 { terminal2 { } } rule train .005 { terminal4 { } } rule train .03 { CIRCLE { b 1 s .03 a -.9 r -95 } }

Keith's Blog

A teen's .net musings

ProcessingFS

Posted on December 3, 2011 at 11:20 AM

Let me start with a bit of background. Processing is a library for Java that allows an almost sketching programming experience. It does this by simplifying the draw commands so that simple things like drawing a pixel are actually simple. This means that drawing more complex things is a lot simpler of a process. The original library can be found Here.

My new port of processing to F# is by no means a full port. I currently have a subset of it that includes most of the basic draw commands like rect, elipse, point, and line, but I do not have the complicated commands that deal with 3d graphics or transformations. Although it is a subset, I can still port with a high degree of efficiency the samples on the processing website. For example, the Distance2d sample source from the website is this:

float max_distance;

void setup() {
  size(200, 200); 
  smooth();
  noStroke();
  max_distance = dist(0, 0, width, height);
}

void draw() 
{
  background(51);

  for(int i = 0; i <= width; i += 20) {
    for(int j = 0; j <= height; j += 20) {
      float size = dist(mouseX, mouseY, i, j);
      size = size/max_distance * 66;
      ellipse(i, j, size, size);
    }
  }
}

The equivalent f# code is this:

type Sample () = 
    inherit PApp()
    let mutable max = 0.0
    let min = 3
    override this.Setup () = 
        this.Size 200 200
        this.Fill 255
        this.NoStroke()
        max <- this.Dist(0,0,this.Width,this.Height)
    override this.Draw () =
        this.Background 51
        for x in [0..20..this.Width] do
            for y in [0..20..this.Height] do
                let size = this.Dist(this.MouseX,this.MouseY,x,y)
                let size = int(size/max * 66.0)
                let size = match size with
                           | x when x < min -> min
                           | _ -> size
                this.Ellipse x y size size

As you can see, the similarity is very apparent. Unfortunately although the code is the same, there are some differences. For instance in my version there is no anti-aliasing. This is because to get the speed I needed in drawing, I needed to use the writeable bitmap instead of the cleaner shape objects already implemented in silverlight. However there are some things that this gives that processing proper can’t do like discriminated unions, other language interop, and .net library support. I created this on a whim and it was surprisingly satisfying and easy to create the code with the F# Async operator. The core loop is simply an async expression with a while loop and a async sleep command. What this means is that I am able to do whatever I want and can be sure that I will be recalled in 1 60th of a second.

    member this.Show () =
        this.Setup()
        async {
            let lagging = ref false
            let draw () = lagging := true
                          this.Draw()
                          pmouseX <- mouseX
                          pmouseY <- mouseY
                          lagging := false
            while true do
                do! Async.Sleep 16
                if clicked then
                    dispatch this.MousePressed
                    clicked <- false
                if released then
                    dispatch this.MouseReleased
                if setup then
                    if loop then
                        if not !lagging then
                            dispatch draw
                    elif redraw then
                        if not !lagging then
                            dispatch (fun () -> frameCount <- frameCount + 1)
                            dispatch draw
                            redraw <- false
                        
        } |> Async.StartImmediate
        
        let app = new Application()
        app.Run(window) |> ignore

That is all I need and it runs perfectly. Now you may have noticed the dispatch method that I am using, all that does is take a function as a param and run it on the UI thread. That way, although I only access the variables from this function, I can be sure that there will be no collisions between threads.

    let dispatch (func:unit->unit) =
        window.Dispatcher.BeginInvoke(Action(fun _ -> func())) |> ignore

This in my opinion really showcases the brevity of the F# syntax and shows how fun a language it is to work with.

Well, 1 project down, 4 to go

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading