Javascript  |  223行  |  5.98 KB

// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

base.require('base.gl_matrix');

base.exportTo('base', function() {
  var tmpVec2s = [];
  for (var i = 0; i < 8; i++)
    tmpVec2s[i] = vec2.create();

  var tmpVec2a = vec4.create();
  var tmpVec4a = vec4.create();
  var tmpVec4b = vec4.create();
  var tmpMat4 = mat4.create();
  var tmpMat4b = mat4.create();

  var p00 = vec2.createXY(0, 0);
  var p10 = vec2.createXY(1, 0);
  var p01 = vec2.createXY(0, 1);
  var p11 = vec2.createXY(1, 1);

  var lerpingVecA = vec2.create();
  var lerpingVecB = vec2.create();
  function lerpVec2(out, a, b, amt) {
    vec2.scale(lerpingVecA, a, amt);
    vec2.scale(lerpingVecB, b, 1 - amt);
    vec2.add(out, lerpingVecA, lerpingVecB);
    vec2.normalize(out, out);
    return out;
  }

  /**
   * @constructor
   */
  function Quad() {
    this.p1 = vec2.create();
    this.p2 = vec2.create();
    this.p3 = vec2.create();
    this.p4 = vec2.create();
  }

  Quad.FromXYWH = function(x, y, w, h) {
    var q = new Quad();
    vec2.set(q.p1, x, y);
    vec2.set(q.p2, x + w, y);
    vec2.set(q.p3, x + w, y + h);
    vec2.set(q.p4, x, y + h);
    return q;
  }

  Quad.FromRect = function(r) {
    return new Quad.FromXYWH(
        r.x, r.y,
        r.width, r.height);
  }

  Quad.From4Vecs = function(p1, p2, p3, p4) {
    var q = new Quad();
    vec2.set(q.p1, p1[0], p1[1]);
    vec2.set(q.p2, p2[0], p2[1]);
    vec2.set(q.p3, p3[0], p3[1]);
    vec2.set(q.p4, p4[0], p4[1]);
    return q;
  }

  Quad.From8Array = function(arr) {
    if (arr.length != 8)
      throw new Error('Array must be 8 long');
    var q = new Quad();
    q.p1[0] = arr[0];
    q.p1[1] = arr[1];
    q.p2[0] = arr[2];
    q.p2[1] = arr[3];
    q.p3[0] = arr[4];
    q.p3[1] = arr[5];
    q.p4[0] = arr[6];
    q.p4[1] = arr[7];
    return q;
  };

  Quad.prototype = {
    vecInside: function(vec) {
      return vecInTriangle2(vec, this.p1, this.p2, this.p3) ||
          vecInTriangle2(vec, this.p1, this.p3, this.p4);
    },

    boundingRect: function() {
      var x0 = Math.min(this.p1[0], this.p2[0], this.p3[0], this.p4[0]);
      var y0 = Math.min(this.p1[1], this.p2[1], this.p3[1], this.p4[1]);

      var x1 = Math.max(this.p1[0], this.p2[0], this.p3[0], this.p4[0]);
      var y1 = Math.max(this.p1[1], this.p2[1], this.p3[1], this.p4[1]);

      return new base.Rect.FromXYWH(x0, y0, x1 - x0, y1 - y0);
    },

    clone: function() {
      var q = new Quad();
      vec2.copy(q.p1, this.p1);
      vec2.copy(q.p2, this.p2);
      vec2.copy(q.p3, this.p3);
      vec2.copy(q.p4, this.p4);
      return q;
    },

    scale: function(s) {
      var q = new Quad();
      this.scaleFast(q, s);
      return q;
    },

    scaleFast: function(dstQuad, s) {
      vec2.copy(dstQuad.p1, this.p1, s);
      vec2.copy(dstQuad.p2, this.p2, s);
      vec2.copy(dstQuad.p3, this.p3, s);
      vec2.copy(dstQuad.p3, this.p3, s);
    },

    isRectangle: function() {
      // Simple rectangle check. Note: will not handle out-of-order components.
      var bounds = this.boundingRect();
      return (
          bounds.x == this.p1[0] &&
          bounds.y == this.p1[1] &&
          bounds.width == this.p2[0] - this.p1[0] &&
          bounds.y == this.p2[1] &&
          bounds.width == this.p3[0] - this.p1[0] &&
          bounds.height == this.p3[1] - this.p2[1] &&
          bounds.x == this.p4[0] &&
          bounds.height == this.p4[1] - this.p2[1]
      );
    },

    projectUnitRect: function(rect) {
      var q = new Quad();
      this.projectUnitRectFast(q, rect);
      return q;
    },

    projectUnitRectFast: function(dstQuad, rect) {
      var v12 = tmpVec2s[0];
      var v14 = tmpVec2s[1];
      var v23 = tmpVec2s[2];
      var v43 = tmpVec2s[3];
      var l12, l14, l23, l43;

      vec2.sub(v12, this.p2, this.p1);
      l12 = vec2.length(v12);
      vec2.scale(v12, v12, 1 / l12);

      vec2.sub(v14, this.p4, this.p1);
      l14 = vec2.length(v14);
      vec2.scale(v14, v14, 1 / l14);

      vec2.sub(v23, this.p3, this.p2);
      l23 = vec2.length(v23);
      vec2.scale(v23, v23, 1 / l23);

      vec2.sub(v43, this.p3, this.p4);
      l43 = vec2.length(v43);
      vec2.scale(v43, v43, 1 / l43);

      var b12 = tmpVec2s[0];
      var b14 = tmpVec2s[1];
      var b23 = tmpVec2s[2];
      var b43 = tmpVec2s[3];
      lerpVec2(b12, v12, v43, rect.y);
      lerpVec2(b43, v12, v43, 1 - rect.bottom);
      lerpVec2(b14, v14, v23, rect.x);
      lerpVec2(b23, v14, v23, 1 - rect.right);

      vec2.addTwoScaledUnitVectors(tmpVec2a,
                                   b12, l12 * rect.x,
                                   b14, l14 * rect.y);
      vec2.add(dstQuad.p1, this.p1, tmpVec2a);

      vec2.addTwoScaledUnitVectors(tmpVec2a,
                                   b12, l12 * -(1.0 - rect.right),
                                   b23, l23 * rect.y);
      vec2.add(dstQuad.p2, this.p2, tmpVec2a);


      vec2.addTwoScaledUnitVectors(tmpVec2a,
                                   b43, l43 * -(1.0 - rect.right),
                                   b23, l23 * -(1.0 - rect.bottom));
      vec2.add(dstQuad.p3, this.p3, tmpVec2a);

      vec2.addTwoScaledUnitVectors(tmpVec2a,
                                   b43, l43 * rect.left,
                                   b14, l14 * -(1.0 - rect.bottom));
      vec2.add(dstQuad.p4, this.p4, tmpVec2a);
    },

    toString: function() {
      return 'Quad(' +
          vec2.toString(this.p1) + ', ' +
          vec2.toString(this.p2) + ', ' +
          vec2.toString(this.p3) + ', ' +
          vec2.toString(this.p4) + ')';
    }
  };

  function sign(p1, p2, p3) {
    return (p1[0] - p3[0]) * (p2[1] - p3[1]) -
        (p2[0] - p3[0]) * (p1[1] - p3[1]);
  }

  function vecInTriangle2(pt, p1, p2, p3) {
    var b1 = sign(pt, p1, p2) < 0.0;
    var b2 = sign(pt, p2, p3) < 0.0;
    var b3 = sign(pt, p3, p1) < 0.0;
    return ((b1 == b2) && (b2 == b3));
  }

  return {
    vecInTriangle2: vecInTriangle2,
    Quad: Quad
  };
});