browser/devtools/tilt/TiltWorkerPicker.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/devtools/tilt/TiltWorkerPicker.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,186 @@
     1.4 +/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +"use strict";
    1.10 +
    1.11 +/**
    1.12 + * This worker handles picking, given a set of vertices and a ray (calculates
    1.13 + * the intersection points and offers back information about the closest hit).
    1.14 + *
    1.15 + * Used in the TiltVisualization.Presenter object.
    1.16 + */
    1.17 +self.onmessage = function TWP_onMessage(event)
    1.18 +{
    1.19 +  let data = event.data;
    1.20 +  let vertices = data.vertices;
    1.21 +  let ray = data.ray;
    1.22 +
    1.23 +  let intersection = null;
    1.24 +  let hit = [];
    1.25 +
    1.26 +  // calculates the squared distance between two points
    1.27 +  function dsq(p1, p2) {
    1.28 +    let xd = p2[0] - p1[0];
    1.29 +    let yd = p2[1] - p1[1];
    1.30 +    let zd = p2[2] - p1[2];
    1.31 +
    1.32 +    return xd * xd + yd * yd + zd * zd;
    1.33 +  }
    1.34 +
    1.35 +  // check each stack face in the visualization mesh for intersections with
    1.36 +  // the mouse ray (using a ray picking algorithm)
    1.37 +  for (let i = 0, len = vertices.length; i < len; i += 36) {
    1.38 +
    1.39 +    // the front quad
    1.40 +    let v0f = [vertices[i],      vertices[i + 1],  vertices[i + 2]];
    1.41 +    let v1f = [vertices[i + 3],  vertices[i + 4],  vertices[i + 5]];
    1.42 +    let v2f = [vertices[i + 6],  vertices[i + 7],  vertices[i + 8]];
    1.43 +    let v3f = [vertices[i + 9],  vertices[i + 10], vertices[i + 11]];
    1.44 +
    1.45 +    // the back quad
    1.46 +    let v0b = [vertices[i + 24], vertices[i + 25], vertices[i + 26]];
    1.47 +    let v1b = [vertices[i + 27], vertices[i + 28], vertices[i + 29]];
    1.48 +    let v2b = [vertices[i + 30], vertices[i + 31], vertices[i + 32]];
    1.49 +    let v3b = [vertices[i + 33], vertices[i + 34], vertices[i + 35]];
    1.50 +
    1.51 +    // don't do anything with degenerate quads
    1.52 +    if (!v0f[0] && !v1f[0] && !v2f[0] && !v3f[0]) {
    1.53 +      continue;
    1.54 +    }
    1.55 +
    1.56 +    // for each triangle in the stack box, check for the intersections
    1.57 +    if (self.intersect(v0f, v1f, v2f, ray, hit) || // front left
    1.58 +        self.intersect(v0f, v2f, v3f, ray, hit) || // front right
    1.59 +        self.intersect(v0b, v1b, v1f, ray, hit) || // left back
    1.60 +        self.intersect(v0b, v1f, v0f, ray, hit) || // left front
    1.61 +        self.intersect(v3f, v2b, v3b, ray, hit) || // right back
    1.62 +        self.intersect(v3f, v2f, v2b, ray, hit) || // right front
    1.63 +        self.intersect(v0b, v0f, v3f, ray, hit) || // top left
    1.64 +        self.intersect(v0b, v3f, v3b, ray, hit) || // top right
    1.65 +        self.intersect(v1f, v1b, v2b, ray, hit) || // bottom left
    1.66 +        self.intersect(v1f, v2b, v2f, ray, hit)) { // bottom right
    1.67 +
    1.68 +      // calculate the distance between the intersection hit point and camera
    1.69 +      let d = dsq(hit, ray.origin);
    1.70 +
    1.71 +      // we're picking the closest stack in the mesh from the camera
    1.72 +      if (intersection === null || d < intersection.distance) {
    1.73 +        intersection = {
    1.74 +          // each mesh stack is composed of 12 vertices, so there's information
    1.75 +          // about a node once in 12 * 3 = 36 iterations (to avoid duplication)
    1.76 +          index: i / 36,
    1.77 +          distance: d
    1.78 +        };
    1.79 +      }
    1.80 +    }
    1.81 +  }
    1.82 +
    1.83 +  self.postMessage(intersection);
    1.84 +  close();
    1.85 +};
    1.86 +
    1.87 +/**
    1.88 + * Utility function for finding intersections between a ray and a triangle.
    1.89 + */
    1.90 +self.intersect = (function() {
    1.91 +
    1.92 +  // creates a new instance of a vector
    1.93 +  function create() {
    1.94 +    return new Float32Array(3);
    1.95 +  }
    1.96 +
    1.97 +  // performs a vector addition
    1.98 +  function add(aVec, aVec2, aDest) {
    1.99 +    aDest[0] = aVec[0] + aVec2[0];
   1.100 +    aDest[1] = aVec[1] + aVec2[1];
   1.101 +    aDest[2] = aVec[2] + aVec2[2];
   1.102 +    return aDest;
   1.103 +  }
   1.104 +
   1.105 +  // performs a vector subtraction
   1.106 +  function subtract(aVec, aVec2, aDest) {
   1.107 +    aDest[0] = aVec[0] - aVec2[0];
   1.108 +    aDest[1] = aVec[1] - aVec2[1];
   1.109 +    aDest[2] = aVec[2] - aVec2[2];
   1.110 +    return aDest;
   1.111 +  }
   1.112 +
   1.113 +  // performs a vector scaling
   1.114 +  function scale(aVec, aVal, aDest) {
   1.115 +    aDest[0] = aVec[0] * aVal;
   1.116 +    aDest[1] = aVec[1] * aVal;
   1.117 +    aDest[2] = aVec[2] * aVal;
   1.118 +    return aDest;
   1.119 +  }
   1.120 +
   1.121 +  // generates the cross product of two vectors
   1.122 +  function cross(aVec, aVec2, aDest) {
   1.123 +    let x = aVec[0];
   1.124 +    let y = aVec[1];
   1.125 +    let z = aVec[2];
   1.126 +    let x2 = aVec2[0];
   1.127 +    let y2 = aVec2[1];
   1.128 +    let z2 = aVec2[2];
   1.129 +
   1.130 +    aDest[0] = y * z2 - z * y2;
   1.131 +    aDest[1] = z * x2 - x * z2;
   1.132 +    aDest[2] = x * y2 - y * x2;
   1.133 +    return aDest;
   1.134 +  }
   1.135 +
   1.136 +  // calculates the dot product of two vectors
   1.137 +  function dot(aVec, aVec2) {
   1.138 +    return aVec[0] * aVec2[0] + aVec[1] * aVec2[1] + aVec[2] * aVec2[2];
   1.139 +  }
   1.140 +
   1.141 +  let edge1 = create();
   1.142 +  let edge2 = create();
   1.143 +  let pvec = create();
   1.144 +  let tvec = create();
   1.145 +  let qvec = create();
   1.146 +  let lvec = create();
   1.147 +
   1.148 +  // checks for ray-triangle intersections using the Fast Minimum-Storage
   1.149 +  // (simplified) algorithm by Tomas Moller and Ben Trumbore
   1.150 +  return function intersect(aVert0, aVert1, aVert2, aRay, aDest) {
   1.151 +    let dir = aRay.direction;
   1.152 +    let orig = aRay.origin;
   1.153 +
   1.154 +    // find vectors for two edges sharing vert0
   1.155 +    subtract(aVert1, aVert0, edge1);
   1.156 +    subtract(aVert2, aVert0, edge2);
   1.157 +
   1.158 +    // begin calculating determinant - also used to calculate the U parameter
   1.159 +    cross(dir, edge2, pvec);
   1.160 +
   1.161 +    // if determinant is near zero, ray lines in plane of triangle
   1.162 +    let inv_det = 1 / dot(edge1, pvec);
   1.163 +
   1.164 +    // calculate distance from vert0 to ray origin
   1.165 +    subtract(orig, aVert0, tvec);
   1.166 +
   1.167 +    // calculate U parameter and test bounds
   1.168 +    let u = dot(tvec, pvec) * inv_det;
   1.169 +    if (u < 0 || u > 1) {
   1.170 +      return false;
   1.171 +    }
   1.172 +
   1.173 +    // prepare to test V parameter
   1.174 +    cross(tvec, edge1, qvec);
   1.175 +
   1.176 +    // calculate V parameter and test bounds
   1.177 +    let v = dot(dir, qvec) * inv_det;
   1.178 +    if (v < 0 || u + v > 1) {
   1.179 +      return false;
   1.180 +    }
   1.181 +
   1.182 +    // calculate T, ray intersects triangle
   1.183 +    let t = dot(edge2, qvec) * inv_det;
   1.184 +
   1.185 +    scale(dir, t, lvec);
   1.186 +    add(orig, lvec, aDest);
   1.187 +    return true;
   1.188 +  };
   1.189 +}());

mercurial