Was this page helpful?
Your feedback about this content is important. Let us know what you think.
Additional feedback?
1500 characters remaining
Export (0) Print
Expand All

WebGL demos, references, and resources

Here's a list of WebGL resources that will help you learn and create great 2D and 3D graphics.

Microsoft websites

Demos

  • Lookaround A cool Three.js based demo where you can view a waterfront boardwalk in 360 degrees.
  • Flight to Everest Find your base camp, check ice flows, and scale heights with this 3D demo.
  • Warp The full version of the trimmed down demo presented here.

Reference content

  • WebGL API reference Reference pages for the WebGL API supported by Internet Explorer 11.
  • GLSL errors pages for the WebGL and GLSL features supported by IE11.

Third-party websites

Learning sites

Libraries

  • Three.js One of the most widely used general purpose WebGL libraries.
  • GLMatrix A commonly used library to simplify using matrices.
  • PhiloGL A framework for game development, data visualization, and creative coding.
  • GLGE: WebGL for the lazy A general purpose library that abstracts graphics and 3D concepts.
  • Babylon.js A general purpose library with an emphasis on gaming.

The full example

For this WebGL discussion, we've used snippets of code from a larger example. Here's the complete code listing. There are two files, demo.js and default.html. We've combined the Cascading Style Sheets (CSS) portion with the HTML file, while it's a separate file in the Warp sample.

This is the default.html file

<!DOCTYPE html>
<html>
<head>
  <!-- Copyright � Microsoft Corporation. All Rights Reserved. -->
  <!-- Demo Author: Frank Olivier, Microsoft Corporation -->   
  <!-- Updates by Jay Munro -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
   <title>Photo warping with WebGL</title>
  <style>
  /* Prevent text selection from being displayed when the user drags out of the canvas */
*::selection {
  background:transparent;
}

#DemoContent {
  margin-top:10px;
}

#DemoContent {
  width:600px;
  margin-left:auto;
  margin-right:auto;
  margin-top:10px;
}

#Details {
  margin-top:10px;
  margin-bottom:10px;
  padding:20px;
   border-radius:4px;
}

body {
 -ms-user-select: none; /* turn off user selection */
 font-size: 12pt;
}

canvas {
  -ms-touch-action: none; /* turn off panning and zooming */
}

.heading
{
  font-size: 20pt;
  font-weight: normal;
}

#ErrorMessage {
  position:absolute;
  top:100px;
  left:20%;
  right:20%;
  background-color:lightcoral;
  padding:20px;
  border-radius:4px;
}

  </style>


</head>
<body>
  <h1 id="DemoTitle">
    Photo warping with WebGL
  </h1>
  <h2>click and drag</h2>
  
  <div id="DemoContent">
    <div style='width:600px; height:600px'>
        <div style='position: relative'>          
        <!-- WebGL canvas -->
        <canvas style='position: absolute' id='webglcanvas' width='600' height='600'></canvas>
  
        <!-- notation cavas --> 
          <canvas style='position: absolute' id='2dcanvas' width='600' height='600'></canvas>
        </div>
    </div>
    <div style="text-align:center">
      
      <button id="openphoto1" onclick="OpenPhoto1()">Open a photo</button>      
      <span id="openphoto2" style="display:none">Pick a photo: <input type="file" id="files" /></span> <br />
      <button onclick="undo()">Undo</button>         
      <button onclick="reset()">Start over</button>        
      <button onclick="save()">Save</button>      
    </div>
  </div>
  
  <div id="ErrorMessage" style="display:none">
    <div class="heading">Sorry!</div>
      This demonstation requires a browser with WebGL support.
    </div>
    <div id="log"></div>
  
   <div id="Details">
      <div class="heading">WebGL 101</div>        
      To render the warped photo above, a mesh of 400 triangle coordinates, a photo, a vertex & 
      fragment shader program and uniform points are uploaded to the GPU using WebGL.<br />                                      
      <br />        
   <!-- The show uniform points checkbox -->
      <label><input type="checkbox" name="showUniforms" id="showUniforms" onchange="renderer.changeMode();renderer.render()" />Show uniform points</label> 
      <div>
        <label><input type="radio" name="rendertype" id="renderLines" onclick="renderer.render()" />Show triangle mesh</label>
        <label><input type="radio" name="rendertype" id="renderTriangles" onclick="renderer.render()" checked />Show rendered photo</label>
      </div>
        <br />
      When you click and drag on the photo, new uniform points are set on the GPU...<br /><br />
      <div class="heading">Vertex shader</div>
      <img src="vertex.png"/><br />
      ...The GPU runs the vertex shader below to distort the mesh using the uniform points...<br /><br />
      <pre id="vertexshadersource"></pre>
        <br />
      <div class="heading">Fragment shader</div>
        <img src="fragment.png"/><br />
        ...and the fragment shader paints photo pixels using the distorted mesh.<br /><br />        
        <pre id="fragmentshadersource"></pre>        
        <br />
        <!-- For more information on WebGL, see <a href="http://docs.webplatform.org/wiki/webgl">webplatform.org</a>.</div> -->
  </div>
  
    <script type="text/javascript" src="demo.js"></script>


  <script id="2d-vertex-shader" type="x-shader/x-vertex">

     // outgoing coordinate
    varying vec2 v_texCoord;

    // incoming coordinate (point)
    attribute vec2 a_texCoord;  
    
    // maximum number of changes to grid
    #define MAXPOINTS 10 
    
    uniform vec2 p1[MAXPOINTS];    // Where the drag started
    uniform vec2 p2[MAXPOINTS];    // Where the drag ended

    void main() { 
      
      v_texCoord = a_texCoord;  
      // Set up position variable with current coordinate normalized from 0 - 1 to -1 to 1 range 
      vec2 position = a_texCoord * 2.0 - 1.0; 

      for (int i = 0; i < MAXPOINTS; i++) // loop through 
      {
        float dragdistance = distance(p1[i], p2[i]); // Calculate the distance between two start and end of mouse drag for each of the drags
        float mydistance = distance(p1[i], position);  // Calculate the distance between the start of the mouse drag and the last position  
        if (mydistance < dragdistance) 
        {
          vec2 maxdistort = (p2[i] - p1[i]) / 4.0;    // only affect vertices within 4 x the drag distance ( 
          float normalizeddistance = mydistance / dragdistance;                
          float normalizedimpact = (cos(normalizeddistance*3.14159265359)+1.0)/2.0;
          position += (maxdistort * normalizedimpact);  
        }
      }
    // gl_Position always specifies where to render this vector 
      gl_Position = vec4(position, 0.0, 1.0);     // x,y,z,
    }
  </script>

<!-- fragment shader -->
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;

  // uniform to use for texture 
  uniform sampler2D u_image;

  // Output of the vertex shader 
  varying vec2 v_texCoord;

  void main() {
    // gl_FragColor always specifies the color to make the current pixel 
    gl_FragColor = texture2D(u_image, v_texCoord);                                                   
  }
</script>
<!-- fragment shader -->
<script id="red" type="x-shader/x-fragment">
  precision mediump float;

  varying vec2 v_texCoord;

  // Set a solid color for the grid 
  void main() {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  } 
</script>

</body>
</html>


This is the demo.js file

'use strict';

window.onload = main;    // Startup

// Point object - converts incoming values to a -1 to 1 range).
function Point(x, y) {
    if (x<-1) x = -1;
    if (y<-1) y = -1;
    if (x>1) x = 1;
    if (y>1) y = 1;
    
    this.x = x;
    this.y = y;
}

// A new mouse manipulation.
function Move(point) { 
    this.point1 = new Point(point.x, point.y);
    this.point2 = new Point(point.x, point.y);
    
    this.move = function (point) {
        this.point2.x = point.x;
        this.point2.y = point.y;
    }
    
}

var renderer = new function () {

    var gl;                 // Handle to the context.
    var lineprogram;        // Handle to GLSL program that draws lines.
    var pictureprogram;     // Handle to GLSL program that draws a picture.

    this.texCoordLocation;   // Location of the texture for the picture fragment shader.
    this.texCoordLocation2;  // Location of the texture for the line fragment shader.

    this.texCoordBuffer;   // The buffer for the texture for the picture fragment shader.
    this.texCoordBuffer2;   // The buffer for the texture for the line fragment shader.
    
    var moves = new Array;  
    var MAXMOVES = 10;
    var currentMove = 0;

    var resolution = 20;  // Resolution of the mesh.


    // First init called by main().
    // Initialize the gl context variable.

    this.init = function () {
      // Get a context from our canvas object with id = "webglcanvas".
      var canvas = document.getElementById("webglcanvas"); 
        try {
          // Get the context into a local gl and and a public gl.
          // Use preserveDrawingBuffer:true to keep the drawing buffer after presentation
          var gl = this.gl = canvas.getContext("experimental-webgl", { preserveDrawingBuffer: true });
        }
          catch (e) {
          // Fail quietly 
        }

        // If we can't get a WebGL context (no WebGL support), then display an error message.
        if (!this.gl) {
          document.getElementById("ErrorMessage").style.display = "block";
          return;
        }


        try {
        // Load the GLSL source written in the HTML file.
        // Create a program with the two shaders
        this.lineprogram = loadProgram(gl, getShader(gl, "2d-vertex-shader"), getShader(gl, "red"));

          // Tell webGL to use this program
        gl.useProgram(this.lineprogram);

          // Look up where the vertex data needs to go.
        this.texCoordLocation2 = gl.getAttribLocation(this.lineprogram, "a_texCoord");

          // Provide texture coordinates for the rectangle.
        this.texCoordBuffer2 = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer2);
      
        // Create a buffer and set it use the array set up above.
        // Set it to be modified once, use many.
        // createRedGrid sets up the vector array itself.        
        gl.bufferData(gl.ARRAY_BUFFER, createRedGrid(), gl.STATIC_DRAW); // Fill buffer data

        // Turns on the vertex attributes in the GPU program. 
        gl.enableVertexAttribArray(this.texCoordLocation2);

        // Set up the data format for the vertex array - set to points (x/y). 
        // Use floats.
        gl.vertexAttribPointer(this.texCoordLocation2, 2, gl.FLOAT, false, 0, 0);
        }

        catch (e) {
            // Display the fail on the screen if the shaders/program fail.
            log('shader fail');
            return;
        }

        try {
          var vertexshader = getShader(gl, "2d-vertex-shader");
          var fragmentshader = getShader(gl, "2d-fragment-shader");
        
          this.pictureprogram = loadProgram(gl, vertexshader, fragmentshader);
          gl.useProgram(this.pictureprogram);

          // Put the shader source into the <divs>. 
          document.getElementById("vertexshadersource").innerText = gl.getShaderSource(vertexshader);
          document.getElementById("fragmentshadersource").innerText = gl.getShaderSource(fragmentshader);

          // Look up where the vertex data needs to go.
          this.texCoordLocation = gl.getAttribLocation(this.pictureprogram, "a_texCoord");

          // Provide texture coordinates for the rectangle.
          this.texCoordBuffer = gl.createBuffer();
          gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer);

          // createImageGrid sets up the vector array itself
          gl.bufferData(gl.ARRAY_BUFFER, createImageGrid(), gl.STATIC_DRAW);  // Fill buffer data             
          gl.vertexAttribPointer(this.texCoordLocation, 2, gl.FLOAT, false, 0, 0);
          gl.enableVertexAttribArray(this.texCoordLocation);
          // Set up uniforms variables (image).
          this.pictureprogram.u_image = gl.getUniformLocation(this.pictureprogram, "u_image");

          // Set the texture to use.
          gl.uniform1i(this.pictureprogram.u_image, 0);
        }
        catch (e) {
            log('shader fail');
            return;
        }
             
        this.loadImage();
    }

    // Load a default image.
    this.loadImage = function () {
    var image = new Image();
        image.onload = function () {
        renderer.loadImage2(image);
  }
        image.src = "photos/demophoto.jpg"; // Default image 
    }
// load a the user's image.
    this.loadImageX = function (dataURL) {
        var image = new Image();
        
        image.onload = function () {
            renderer.loadImage2(image);
        }

        image.src = dataURL;
    }

    // This function does the heavy lifting of creating the texture from the image.
    this.loadImage2 = function (image) {
        // Convert the image to a square image via the temporary 2d canvas. 
        var canvas = document.getElementById("2dcanvas");
        var ctx = canvas.getContext("2d");
        var canvHeight = document.getElementById("2dcanvas").height;

        var x = 0;
        var y = 0;
        var xx = canvHeight;
        var yy = canvHeight;

        ctx.clearRect(0, 0, canvHeight, canvHeight);
        // If image isn't square, adjust width, height, and origin so it's centered.
           if (image.width < image.height) {
            // Change origin and dimensions if the image isn't square.
            // Change x, xx
            xx = image.width / image.height * canvHeight;
            x = (canvHeight - xx) / 2;
        }
        if (image.width > image.height) {
            // Change y, yy 
          yy = image.height / image.width * canvHeight;
          y = (canvHeight - yy) / 2;
        }

    // Put the image on the canvas, scaled using xx & yy.
        ctx.drawImage(image, 0, 0, image.width, image.height, x, y, xx, yy);
        var gl = this.gl;

    // Create a texture object that will contain the image.
    var texture = gl.createTexture();

    // Bind the texture the target (TEXTURE_2D) of the active texture unit.
    gl.bindTexture(gl.TEXTURE_2D, texture);

    // Flip the image's Y axis to match the WebGL texture coordinate space.
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
        
    // Set the parameters so we can render any size image.        
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

      // Upload the resized canvas image into the texture.
    //    Note: a canvas is used here but can be replaced by an image object. 
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
    ctx.clearRect(0, 0, canvHeight, canvHeight);

    this.reset();

    }
  // This code checks the Show uniform points checkbox and changes the mode and initializes the canvas.
    this.modeOff = 0;
    this.modeHint = 1;
    this.modeHint2 = 2;
    this.modeUniform = 3;

  //  Modes tell the app to show uniforms or not
    this.canvasMode = this.modeHint;

    this.changeMode = function () {
        if (document.getElementById("showUniforms").checked) {
            this.canvasMode = this.modeUniform;
        }
        else {
            this.canvasMode = this.modeOff;
            var canvas = document.getElementById("2dcanvas");
            var ctx = canvas.getContext("2d");
            ctx.clearRect(0, 0, canvas.width, canvas.height);
        }

    }

    this.render = function () {
   
      var gl = this.gl;

        // Create two arrays to hold start and end point uniforms
        var p1 = new Float32Array(MAXMOVES * 2); //x and y
        var p2 = new Float32Array(MAXMOVES * 2); //x and y

      // Set up the arrays of points
        {
          var index = 0;
          for (var i = 0; i < MAXMOVES; i++) {
        // Working values
            var x1, y1, x2, y2;

            if (moves[i]) {
                x1 = moves[i].point1.x;
                y1 = moves[i].point1.y;
                x2 = moves[i].point2.x;
                y2 = moves[i].point2.y;
            }
            else {
                x1 = 1;
                y1 = 1;
                x2 = 0.9999999;
                y2 = 0.9999999;
            }

            p1[index] = x1;
            p1[index + 1] = y1;
            p2[index] = x2;
            p2[index + 1] = y2;
            index += 2;
            }
        }
        
    //  Clear color buffer and set it to light gray
        gl.clearColor(1.0, 1.0, 1.0, 0.5);
        gl.clear(this.gl.COLOR_BUFFER_BIT);
                
    // This draws either the grid or the photo for stretching
        if (document.getElementById("renderLines").checked)
        {
          gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer2);

          gl.useProgram(this.lineprogram);

          gl.uniform2fv(gl.getUniformLocation(this.lineprogram, "p1"), p1);
          gl.uniform2fv(gl.getUniformLocation(this.lineprogram, "p2"), p2);

          gl.vertexAttribPointer(this.texCoordLocation2, 2, gl.FLOAT, false, 0, 0);

          gl.enableVertexAttribArray(this.texCoordLocation2);

          gl.drawArrays(gl.LINES, 0, resolution * resolution * 10);
        }
        else
        { 
          gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer);
          
          gl.useProgram(this.pictureprogram);


          gl.uniform2fv(gl.getUniformLocation(this.pictureprogram, "p1"), p1);
          gl.uniform2fv(gl.getUniformLocation(this.pictureprogram, "p2"), p2);

          gl.vertexAttribPointer(this.texCoordLocation, 2, gl.FLOAT, false, 0, 0);

          gl.enableVertexAttribArray(this.texCoordLocation);


          gl.drawArrays(gl.TRIANGLES, 0, resolution * resolution * 2 * 3);
        }
    // Draw uniform points 
        if (this.canvasMode == this.modeUniform) {
      var canvas = document.getElementById("2dcanvas");
        var ctx = canvas.getContext("2d");
        ctx.clearRect(0, 0, canvas.width, canvas.height);

          for (var i = 0; i < MAXMOVES; i++) {
            if (moves[i]) {
              var x1 = (moves[i].point1.x + 1) * canvas.width / 2;
              var y1 = (-moves[i].point1.y + 1) * canvas.height / 2;
              var x2 = (moves[i].point2.x + 1) * canvas.width / 2;
              var y2 = (-moves[i].point2.y + 1) * canvas.height / 2;

          // The raio is used here to show where the pixel started and ended
              var ratio = 0.3;
              x2 = x1 + (x2 - x1) * ratio;
              y2 = y1 + (y2 - y1) * ratio;

              var radius = 6;            
              ctx.beginPath();  // Start a fresh path 

          // Create a 2D gradient 
              var grd = ctx.createLinearGradient(x1, y1, x2, y2);
              grd.addColorStop(0, 'pink'); // Set one side to pink
              grd.addColorStop(1, 'red');  // The other side to red

              ctx.setLineDash([5, 5]);  // Use a dotted line
              ctx.lineWidth = radius / 2; 
              ctx.moveTo(x1, y1); // Create a line from start to end poing
              ctx.lineTo(x2, y2);
              ctx.strokeStyle = grd;
              ctx.stroke();

              ctx.beginPath(); // Start a new path for pink dot
              ctx.arc(x1, y1, radius, 0, 2 * Math.PI, false); // full circle (2*pi)
              ctx.fillStyle = 'pink';
              ctx.fill();

              ctx.beginPath(); // Start a new path for red dot
              ctx.arc(x2, y2, radius, 0, 2 * Math.PI, false);
              ctx.fillStyle = 'red';
              ctx.fill();
            }
          }
        }
    }
    // (point) is where the mouse was clicked
    this.newMove = function(point) // Where the warp starts (-1 to 1 range)
    {
        var move = new Move(point);
        // Adds move to beginning of moves array (pushes onto array)
        moves.unshift(move);

        return move;
    }
    this.reset = function () {
        moves = [];
        this.render();
    }

    this.undo = function () {
        // Removes the first element in moves array (pops off array)
        moves.shift();
        this.render();
    }
    this.save = function () {
    // First create a dataURL string from the canvas in jpeg format.
      var dataURL = document.getElementById("webglcanvas").toDataURL("image/png");

      // Split the dataURL and decode it from ASCII to base-64 binary.
      var binArray = atob(dataURL.split(',')[1]);

      // Create an 8-bit unsigned array
      var array = [];
    // Add the unicode numeric value of each element to the new array.
      for (var i = 0; i < binArray.length; i++) {
        array.push(binArray.charCodeAt(i));
      }

      var blobObject = new Blob([new Uint8Array(array)], { type: 'image/png' }); 

      if (window.navigator.msSaveBlob) {
        window.navigator.msSaveBlob(blobObject, 'warpedphoto.png');
      }else if (window.navigator.saveBlob) {
        window.navigator.saveBlob(blobObject, 'warpedphoto.png');
      }
      else {
        dataURL = dataURL.replace("image/png", "image/octet-stream");
        window.location.href = dataURL;
        // alert("Sorry, your browser does not support navigator.saveBlob");
      }
  }


    // Grid making section 
    function createRedGrid() {
    // Make a 0,0 to 1,1 triangle mesh, using n = resolution steps.
    var q = 0.001; // A fudge factor to ensure that the wireframe lines are rendered inside the canvas boundary.
    var r = (1 - q * 2) / resolution;
    //2 numbers per coord; three coords per triangle; 2 triagles per square; resolution * resolution squares.
    var c = new Float32Array(resolution * resolution * 20);
    // Array index.
    var i = 0;
    
    // Build the mesh top to bottom, left to right.             
    for (var xs = 0; xs < resolution; xs++) {
      for (var ys = 0; ys < resolution; ys++) {
        var x = r * xs + q;
        var y = r * ys + q;
        // Top of square - first triangle.
        c[i++] = x;
        c[i++] = y;
        c[i++] = x + r;
        c[i++] = y;

        // Center line - hypotonose of triangles.
        c[i++] = x;
        c[i++] = y + r;
        c[i++] = x + r;
        c[i++] = y;

        // Bottom line of 2nd triangle.
        c[i++] = x;
        c[i++] = y + r;
        c[i++] = x + r;
        c[i++] = y + r;

        // First triangle, left side.
        c[i++] = x;
        c[i++] = y;
        c[i++] = x;
        c[i++] = y + r;

        // Right side of 2nd triangle. 
        c[i++] = x + r;
        c[i++] = y;
        c[i++] = x + r;
        c[i++] = y + r;
      }
    }
    return c;
    }
    function createImageGrid() {
      var q = 0.001;

      var r = (1 - q * 2) / resolution;
      var c = new Float32Array(resolution * resolution * 12); //2 numbers per coord; three coords per triangle; 2 triagles per square; resolution * resolution squares.

      var i = 0;

      for (var xs = 0; xs < resolution; xs++) {
        for (var ys = 0; ys < resolution; ys++) {

         var x = r * xs + q;
         var y = r * ys + q;

         c[i++] = x;
         c[i++] = y;

         c[i++] = x + r;
         c[i++] = y;

         c[i++] = x;
         c[i++] = y + r;

         c[i++] = x + r;
         c[i++] = y;

         c[i++] = x;
         c[i++] = y + r;

         c[i++] = x + r;
         c[i++] = y + r;

        }
      }
      return c;
    }
}

// getMousePoint
// input - mouse event e
function getMousePoint(e) {
    var x;
    var y;
    // The standard way to get mouse coordinates
    if (e.offsetX) {
        x = e.offsetX;
        y = e.offsetY;
    }
    // LayerX and layerY are provided for cross-browser compatibility
    else if (e.layerX) {
        x = e.layerX;
        y = e.layerY;
    }
    else {
        return undefined; //Work around Chrome
    }

    return normalizedPoint(x, y); // Converts pixels to -1 to 1
}
var inputHandler = new function() {
    var move; // Pointer to a uniform variable in the renderer object

    this.init = function () {
        var canvas = document.getElementById("2dcanvas");
      //  Set up mouse events on the canvas object. 
        canvas.onmousedown = function (e) {
          console.log("onmousedown");
          this.move = renderer.newMove(getMousePoint(e));            
        }

        canvas.onmouseup = function (e) {
          console.log("onmouseup");
            this.move = undefined;
            renderer.render();
        }

        canvas.onmouseout = function (e) {
          console.log("onmouseout");
          this.move = undefined;
            renderer.render();
        };

        canvas.onmousemove = function (e) {
          console.log("onmousemove");

          var point = getMousePoint(e);

            if (typeof this.move != 'undefined')
            {
                if (typeof point != 'undefined')
                {
                    this.move.move(point);
                }
                renderer.render();
            }

        };

        canvas.ondragstart = function (e) { //Workaround for Chrome
          console.log("ondragstart");
          e.preventDefault();
        };
    }

}


// Program starts here
function main() {
    renderer.init();  // Initialize WebGL shapes and image
    inputHandler.init(); // Initialize mouse and UI handler        
}

// Resets the current distortion to 0
function reset(point) {
    point1[currentPoint].x = 1;
    point1[currentPoint].y = 1;
    point2[currentPoint].x = 1.00001;
    point2[currentPoint].y = 1.00001;
    
    setVec2PointArray("p1", point1);
    setVec2PointArray("p2", point2);
}

function undo() {
    renderer.undo();
}

function reset() {
    renderer.reset();
}


function save() {
    renderer.save();
}

function normalizedPoint(x, y) 
{
  // converts screen coordinates to -1 to 1
  var canvas = document.getElementById("2dcanvas");
    x = (x / canvas.width) * 2 - 1;
    y = (1 - (y / canvas.height)) * 2 - 1;
    
    return new Point(x, y);
}


function setVec2(id, a, b) {
    gl.uniform2f(gl.getUniformLocation(program, id), a, b);
}


// Adds a string to the log in the web page
function log(result) {
  var resultDiv = document.getElementById("log");
  resultDiv.innerHTML += result + "<br />";
}

// Adds a string to the log in the web page; overwrites everything in the log with the new string
function logi(result) {
  var resultDiv = document.getElementById('log');
  resultDiv.innerHTML = result;
}

// Loads a shader from a script tag
// Parameters:
//   WebGL context
//   id of script element containing the shader to load
function getShader(gl, id) {
  var shaderScript = document.getElementById(id);

  // error - element with supplied id couldn't be retrieved
  if (!shaderScript) {
    return null;
  }

  // If successful, build a string representing the shader source
  var str = "";
  var k = shaderScript.firstChild;
  while (k) {
    if (k.nodeType == 3) {
      str += k.textContent;
    }
    k = k.nextSibling;
  }

  var shader;

  // Create shaders based on the type we set
  //   note: these types are commonly used, but not required
  if (shaderScript.type == "x-shader/x-fragment") {
    shader = gl.createShader(gl.FRAGMENT_SHADER);
  } else if (shaderScript.type == "x-shader/x-vertex") {
    shader = gl.createShader(gl.VERTEX_SHADER);
  } else {
    return null;
  }

  gl.shaderSource(shader, str);
  gl.compileShader(shader);

  // Check the compile status, return an error if failed
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    console.log(gl.getShaderInfoLog(shader));
    return null;
  }

  return shader;
}


function loadProgram(gl, vertexShader, fragmentShader)
{
  // create a progam object
  var program = gl.createProgram();

  // attach the two shaders 
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);

  // link everything 
  gl.linkProgram(program);

  // Check the link status
  var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
  if (!linked) {

    // An error occurred while linking
    var lastError = gl.getProgramInfoLog(program);
    console.warn("Error in program linking:" + lastError);

    gl.deleteProgram(program);
    return null;
  }

  // if all is well, return the program object
  return program;
};

function handleFileSelect(evt) {

  document.getElementById("openphoto1").style.display = "inline";
  document.getElementById("openphoto2").style.display = "none";
  
  var files = evt.target.files; // FileList object
  
  // files is a FileList of File objects. List some properties.
  var file = files[0];
  
  var reader = new FileReader();
  
  // Closure to capture the file information.
  reader.onload = function (e) {
      renderer.loadImageX(this.result);
  };
  
  // Read in the image file as a data URL.
  
  reader.readAsDataURL(file);
}

document.getElementById('files').addEventListener('change', handleFileSelect, false);


function OpenPhoto1() {
  document.getElementById("openphoto1").style.display = "none";
  document.getElementById("openphoto2").style.display = "inline";
}


 

 

Show:
© 2015 Microsoft