Loic Denuziere's blog articles

0
comment
on 6/6/2011 1:29 AM
In our continuing effort to make the most powerful JavaScript tools available to WebSharper developers, we are releasing the extension for Google O3D. O3D is a 3D programming library built on top of WebGL. Its functionalities include:
  • A render graph allowing hierarchical management of objects, views and rendering passes;
  • Resource management: loading of individual resources (textures, models) or JSON object descriptions, convertible from COLLADA;
  • Algebraic operations for matrices, vectors and quaternions, integrated in the render graph;
  • Skinning primitives for bone-based animation and deformation.
    The following sample, displaying a rotating cube, shows how O3D abstracts away most of WebGL.

The following sample, displaying a rotating cube, shows how O3D abstracts away most of WebGL.

[<JavaScript>]
let vertexShaderString = "
    attribute vec4 position;
    uniform mat4 world;
    uniform mat4 view;
    uniform mat4 projection;

    void main() {
        gl_Position = projection * view * world * position;
    }"

[<JavaScript>]
let pixelShaderString = "
    void main() {
        gl_FragColor = vec4(1, 0, 0, 1);  // Red.
    }"

[<JavaScript>]
let createCube (pack : O3D.Pack) (material : O3D.Material) =
    let cubeShape = pack.CreateShape()
    let streamBank = pack.CreateStreamBank()
    let positionsArray = [|
        -0.5; -0.5;  0.5;    0.5; -0.5;  0.5;  // vertex 0, 1
        -0.5;  0.5;  0.5;    0.5;  0.5;  0.5;  // vertex 2, 3
        -0.5;  0.5; -0.5;    0.5;  0.5; -0.5;  // vertex 4, 5
        -0.5; -0.5; -0.5;    0.5; -0.5; -0.5;  // vertex 6, 7
    |]
    let indicesArray = [|
        0; 1; 2;   2; 1; 3;  // face 1
        2; 3; 4;   4; 3; 5;  // face 2
        4; 5; 6;   6; 5; 7;  // face 3
        6; 7; 0;   0; 7; 1;  // face 4
        1; 7; 3;   3; 7; 5;  // face 5
        6; 0; 4;   4; 0; 2;  // face 6
    |]
    let positionsBuffer = pack.CreateVertexBuffer()
    let positionsField = positionsBuffer.CreateFloatField(3)
    positionsBuffer.Set positionsArray |> ignore
    let indexBuffer = pack.CreateIndexBuffer()
    indexBuffer.Set indicesArray |> ignore
    streamBank.SetVertexStream(O3D.Stream.POSITION, 0, positionsField, 0) |> ignore
    let cubePrimitive = pack.CreatePrimitive(Material = material,
                                             Owner = cubeShape,
                                             StreamBank = streamBank,
                                             primitiveType = O3D.Primitive.TRIANGLELIST,
                                             NumberPrimitives = 12,
                                             NumberVertices = 8,
                                             IndexBuffer = indexBuffer)
    cubePrimitive.CreateDrawElement(pack, null)
    cubeShape

[<JavaScript>]
let g_clock = ref 0.

[<JavaScript>]
let renderCallback (cubeTransform : O3D.Transform) (event : O3D.RenderEvent) =
    g_clock := !g_clock + event.ElapsedTime
    cubeTransform.Identity()
    cubeTransform.RotateY(2. * float !g_clock)

[<JavaScript>]
let Samples() =
    Div [Attr.Id "o3d"; Attr.Style "width: 600px; height: 600px;"]
    |>! OnAfterRender (fun d ->
        O3DJS.Webgl.MakeClients (fun clients ->
            let client = As<O3D.Client> (JavaScript.Get "client" clients.[0])
            let pack = client.CreatePack()
            let viewInfo = O3DJS.Rendergraph.CreateBasicView(pack, client.Root,
                                                             client.RenderGraphRoot)
            viewInfo.DrawContext.Projection <-
                O3DJS.Math.Matrix4.Perspective(O3DJS.Math.DegToRad 30.,
                                               float client.Width/float client.Height,
                                               1., 5000.)
            viewInfo.DrawContext.View <- O3DJS.Math.Matrix4.LookAt((0., 1., 5.),
                                                                   (0., 0., 0.),
                                                                   (0., 1., 0.))
            let redEffect = pack.CreateEffect()
            redEffect.LoadVertexShaderFromString vertexShaderString |> ignore
            redEffect.LoadPixelShaderFromString pixelShaderString |> ignore
            let redMaterial = pack.CreateMaterial(DrawList = viewInfo.PerformanceDrawList,
                                                  Effect = redEffect)
            let cubeShape = createCube pack redMaterial
            let cubeTransform = pack.CreateTransform(Parent = client.Root)
            cubeTransform.AddShape cubeShape
            client.SetRenderCallback (renderCallback cubeTransform))
    )



You can download the WebSharper Extension for O3D at this address.
.
0
comment
on 4/12/2011 1:52 AM
Today we are happy to announce the release of a new extension for WebSharper: DHTMLX Touch.

"DHTMLX Touch is an HTML5-based JavaScript library for building mobile web applications. It’s not just a set of UI widgets, but a complete framework that allows you to create eye-catching, cross-platform web applications for mobile and touch-screen devices."

DHTMLX Touch is typically used as a full-page framework. It provides a lot of tools to ease the interaction between the application data, the display elements and the user, resulting in web applications with an impressive native feel.

The following sample displays a bar chart of the provided data alongside a table. It shows different ways to connect UI elements with application data.

type SalesData = { sales : float
                   year : int }

[<JavaScript>]
let salesData = [| {sales = 9.5; year = 2006}
                   {sales = 8.6; year = 2007}
                   {sales = 6.7; year = 2008}
                   {sales = 4.9; year = 2009}
                   {sales = 6.2; year = 2010} |]

[<JavaScript>]
let SimplePage () = 
    Div []
    |>! OnAfterRender (fun _ ->
        let chart = Chart(Type = ChartType.Bar,
                          Value = "#sales#",
                          Label = "#year#",
                          Data = salesData)
        let yearField = GridField(Id = "Year", Template = fun data ->
            let data = As<SalesData> data
            let d = Div [Text (string data.year)]
            d.Html)
        let figureField = GridField(Id = "Sales", Template = fun data ->
            let data = As<SalesData> data
            let d = Div [Text (string data.sales)]
            d.Html)
        let grid = Grid(Fields = [|yearField; figureField|],
                        Data = salesData)
        let page = Layout(Cols = [|chart; grid|])
        Dhx.Ui(page)
    )

This more complete sample shows how to build a simple shopping cart using DHTMLX Touch. It demonstrates user interaction and interaction with application data; it is reimplemented from a sample by the DHTMLX authors.
You can download the WebSharper extension for DHTMLX Touch at this address.
.
0
comment
on 4/1/2011 3:23 AM
Today we are happy to announce the release of not one, but two new WebSharper extensions: WebGL and glMatrix. Together, they bring the power of hardware-accelerated 3D into WebSharper.

WebGL

WebGL is a standard by the Khronos Consortium which allows to render hardware-accelerated, plugin-free 3D scenes directly inside web pages. It is gaining strong momentum, with impressive demos like Quake 3 maps or the recent No Comply by Mozilla.

WebGL is an adaptation for JavaScript of the OpenGL ES 2.0 standard. It is supported by the latest versions of Mozilla Firefox and Google Chrome, with more upcoming as Apple (Safari) and Opera are also members of the WebGL Working Group and support it in their beta builds.

The following is a sample program which displays the classic OpenGL hello world, a rotating triangle.

[<JavaScript>]
let RotatingTriangle() =
    let CreateContext (element : Element) =
        let canvas = As<CanvasElement> element.Dom
        canvas.Width <- 300
        canvas.Height <- 300
        ["webgl"; "experimental-webgl"]
        |> List.tryPick (fun s ->
            let gl = As<WebGLRenderingContext> (canvas.GetContext s)
            if gl = null then None else Some gl)

    let vertexSource = "precision highp float;
        attribute vec3 position;
        uniform mat4 perspectiveMatrix;
        uniform mat4 modelViewMatrix;
        void main(void)
        { gl_Position = perspectiveMatrix * modelViewMatrix
                        * vec4(position, 1.0); }"

    let fragmentSource = "precision highp float;
        void main(void) { gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }"

    let canvas = HTML5.Tags.Canvas []
    match CreateContext canvas with
    | None -> JavaScript.Alert "Your browser seems incompatible with WebGL."
    | Some gl ->
        // Create and bind the shader program
        let vertexShader = gl.CreateShader(gl.VERTEX_SHADER)
        gl.ShaderSource(vertexShader, vertexSource)
        gl.CompileShader(vertexShader)
        let fragmentShader = gl.CreateShader(gl.FRAGMENT_SHADER)
        gl.ShaderSource(fragmentShader, fragmentSource)
        gl.CompileShader(fragmentShader)
        let program = gl.CreateProgram()
        gl.AttachShader(program, vertexShader)
        gl.AttachShader(program, fragmentShader)
        gl.LinkProgram(program)
        gl.UseProgram(program)
        // Create and bind the vertex buffer
        let vertexPosition = gl.GetAttribLocation(program, "position")
        gl.EnableVertexAttribArray(vertexPosition)
        let vertexBuffer = gl.CreateBuffer()
        let vertices = Float32Array([| 0.0;  1.0; 0.0;
                                      -1.0; -1.0; 0.0;
                                       1.0; -1.0; 0.0; |])
        gl.BindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
        gl.BufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)
        gl.VertexAttribPointer(vertexPosition, 3, gl.FLOAT, false, 0, 0)
        // Setup the view matrices
        let perspectiveMatrix = Mat4.Perspective(45., 1., 1., 10000.)
        let uPerspectiveMatrix = gl.GetUniformLocation(program, "perspectiveMatrix")
        gl.UniformMatrix4fv(uPerspectiveMatrix, false, perspectiveMatrix)
        let uModelViewMatrix = gl.GetUniformLocation(program, "modelViewMatrix")
        // Finally, the main loop.
        gl.ClearColor(0., 0., 0., 0.)
        let rec RunFrame (i : int) () =
            let angle = 2. * float i * System.Math.PI / 1000.
            let modelViewMatrix = Mat4.Identity(Mat4.Create())
            Mat4.Translate(modelViewMatrix, [|0.; 0.; -4.|]) |> ignore
            Mat4.RotateY(modelViewMatrix, angle) |> ignore
            gl.UniformMatrix4fv(uModelViewMatrix, false, modelViewMatrix)
            gl.Clear(gl.COLOR_BUFFER_BIT ||| gl.DEPTH_BUFFER_BIT)
            gl.BindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
            gl.DrawArrays(gl.TRIANGLES, 0, 3)
            gl.Flush()
            JavaScript.SetTimeout (RunFrame ((i + 20) % 1000)) 20 |> ignore
        RunFrame 0 ()
    canvas
If you cannot run this example, make sure your browser and your system are compatible and your graphics drivers are up to date. In particular, we found that Firefox blacklists certain system/driver combinations, and Chrome excludes hardware acceleration on Windows XP altogether (this can be overridden by adding the command-line flag "--ignore-gpu-blacklist").

glMatrix

As an adaptation of the embedded version of OpenGL, WebGL doesn't provide matrix operations like translation and rotation, which can make the positioning of 3D objects cumbersome. This is why we also provide an extension for glMatrix. glMatrix is a highly optimized library which provides operations on matrices, vectors and quaternions, greatly facilitating the manipulation of 3D objects. You can see the Mat4 class from glMatrix in use in the above code.

You can retrieve these extensions at the following addresses: WebGL and glMatrix.
.
0
comment
on 3/24/2011 9:25 AM
The Bing Maps extension for WebSharper has been updated to version 7.0 of the library. It allows developers to use the latest features of Bing Maps, including info boxes and keyboard events. It also provides a convenient interface to the REST API for searches, routes and static map images.

The Bing Maps library has gone under a major overhaul when passing from version 6.3 to 7.0 - and so has the WebSharper Extension. It now uses our Interface Generator, which will allow us to make future updates to the API available lightning-fast to WebSharper developers.

The following is an example minimal code to display a map showing a specific location. credentials is a string containing your Bing Maps Developer key.

[<JavaScript>]
let MapElement () =
    Div []
    |>! OnAfterRender (fun el ->
	let options =
	    Bing.MapViewOptions(
		Credentials = credentials,
		Width = 400,
		Height = 400,
		MapTypeId = Bing.MapTypeId.Birdseye,
		Center = Bing.Location(48.86, 2.34),
		Zoom = 10
	    )
	Bing.Map(el.Body, options) |> ignore
    )
And here is a more complex sample showing several major features:
  • Adding entities on the map, like pushpins and info boxes;
  • Querying the REST service for a route between two locations, displaying it on the map and printing directions.
    [<JavaScript>]
    let MapWithRouteSearch() =
        let origin = Input [Attr.Type "text"]
        let destination = Input [Attr.Type "text"]
        let button = Button [Text "Request route"]
        let directions = Div []
        let routeCallback (map : Bing.Map) (result : Bing.RestResponse) =
            let route = result.ResourceSets.[0].Resources.[0] :?> RouteResource
            // Center the view on the route
            let corners = [| Bing.Location(route.Bbox.[0], route.Bbox.[1])
                             Bing.Location(route.Bbox.[2], route.Bbox.[3]) |]
            let viewBoundaries = Bing.LocationRect.FromLocations(corners)
            map.SetView(Bing.ViewOptions(Bounds = viewBoundaries))
            // Display the route
            let routeline = route.RoutePath.Line.Coordinates
            let routepoints = Array.init routeline.Length (fun i ->
                Bing.Location(routeline.[i].[0], routeline.[i].[1]))
            let routeshape = Bing.Polyline(routepoints)
            map.Entities.Push routeshape
            // Add a pushpin at the origin and an info box at the destination
            let originPin = Bing.Pushpin(routepoints.[0])
            map.Entities.Push originPin
            let destBox = Bing.Infobox(routepoints.[routepoints.Length-1],
                                       Bing.InfoboxOptions(
                                        Title = "Destination",
                                        Description = "You are at destination!"))
            map.Entities.Push destBox
            // Print directions under the map
            let getItems =
                Array.map (fun (inst : Bing.ItineraryItem) ->
                    TR [TD [Text inst.Instruction.Text]
                        TD [Text (string inst.TravelDistance + " " +
                                  string route.DistanceUnit)]])
            directions.Clear()
            route.RouteLegs
            |> Array.map (fun leg -> getItems leg.ItineraryItems)
            |> Array.concat
            |> Table
            |> directions.Append
        let mapContainer =
            Div []
            |>! OnAfterRender (fun el ->
                // Create the map
                let mapOptions = Bing.MapViewOptions(Credentials = credentials,
                                                     Width = 600,
                                                     Height = 500,
                                                     MapTypeId = Bing.MapTypeId.Road)
                let map = Bing.Map(el.Body, mapOptions)
                // Bind the REST request
                let callRequest (_:Element) (_:Events.MouseEvent) =
                    let waypoints = [| Bing.Waypoint origin.Value
                                       Bing.Waypoint destination.Value |]
                    let request = Bing.RouteRequest(
                                    Waypoints = waypoints,
                                    RoutePathOutput = Bing.RoutePathOutput.Points)
                    Bing.Rest.RequestRoute(credentials, request, routeCallback map)
                button |>! OnClick callRequest |> ignore
            )
        Div [
            mapContainer
            Span[Text "From:"]; origin
            Span[Text "To:"]; destination
            button
            directions
        ]
As you can see, we augmented the API with facilities to invoke the REST services. Request functions in the Bing.Rest module take a description of your request to build and call the url with all necessary parameters. Finally, the provided callback receives the response from the Bing service.

Below is a screenshot of the generated interactive map after searching for a route.



You can download the Bing Maps for WebSharper Extension at this address.
.
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us
Built with WebSharper