Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 'use strict';
      6 
      7 base.require('base.gl_matrix');
      8 
      9 base.exportTo('base', function() {
     10   var tmpVec2s = [];
     11   for (var i = 0; i < 8; i++)
     12     tmpVec2s[i] = vec2.create();
     13 
     14   var tmpVec2a = vec4.create();
     15   var tmpVec4a = vec4.create();
     16   var tmpVec4b = vec4.create();
     17   var tmpMat4 = mat4.create();
     18   var tmpMat4b = mat4.create();
     19 
     20   var p00 = vec2.createXY(0, 0);
     21   var p10 = vec2.createXY(1, 0);
     22   var p01 = vec2.createXY(0, 1);
     23   var p11 = vec2.createXY(1, 1);
     24 
     25   var lerpingVecA = vec2.create();
     26   var lerpingVecB = vec2.create();
     27   function lerpVec2(out, a, b, amt) {
     28     vec2.scale(lerpingVecA, a, amt);
     29     vec2.scale(lerpingVecB, b, 1 - amt);
     30     vec2.add(out, lerpingVecA, lerpingVecB);
     31     vec2.normalize(out, out);
     32     return out;
     33   }
     34 
     35   /**
     36    * @constructor
     37    */
     38   function Quad() {
     39     this.p1 = vec2.create();
     40     this.p2 = vec2.create();
     41     this.p3 = vec2.create();
     42     this.p4 = vec2.create();
     43   }
     44 
     45   Quad.FromXYWH = function(x, y, w, h) {
     46     var q = new Quad();
     47     vec2.set(q.p1, x, y);
     48     vec2.set(q.p2, x + w, y);
     49     vec2.set(q.p3, x + w, y + h);
     50     vec2.set(q.p4, x, y + h);
     51     return q;
     52   }
     53 
     54   Quad.FromRect = function(r) {
     55     return new Quad.FromXYWH(
     56         r.x, r.y,
     57         r.width, r.height);
     58   }
     59 
     60   Quad.From4Vecs = function(p1, p2, p3, p4) {
     61     var q = new Quad();
     62     vec2.set(q.p1, p1[0], p1[1]);
     63     vec2.set(q.p2, p2[0], p2[1]);
     64     vec2.set(q.p3, p3[0], p3[1]);
     65     vec2.set(q.p4, p4[0], p4[1]);
     66     return q;
     67   }
     68 
     69   Quad.From8Array = function(arr) {
     70     if (arr.length != 8)
     71       throw new Error('Array must be 8 long');
     72     var q = new Quad();
     73     q.p1[0] = arr[0];
     74     q.p1[1] = arr[1];
     75     q.p2[0] = arr[2];
     76     q.p2[1] = arr[3];
     77     q.p3[0] = arr[4];
     78     q.p3[1] = arr[5];
     79     q.p4[0] = arr[6];
     80     q.p4[1] = arr[7];
     81     return q;
     82   };
     83 
     84   Quad.prototype = {
     85     vecInside: function(vec) {
     86       return vecInTriangle2(vec, this.p1, this.p2, this.p3) ||
     87           vecInTriangle2(vec, this.p1, this.p3, this.p4);
     88     },
     89 
     90     boundingRect: function() {
     91       var x0 = Math.min(this.p1[0], this.p2[0], this.p3[0], this.p4[0]);
     92       var y0 = Math.min(this.p1[1], this.p2[1], this.p3[1], this.p4[1]);
     93 
     94       var x1 = Math.max(this.p1[0], this.p2[0], this.p3[0], this.p4[0]);
     95       var y1 = Math.max(this.p1[1], this.p2[1], this.p3[1], this.p4[1]);
     96 
     97       return new base.Rect.FromXYWH(x0, y0, x1 - x0, y1 - y0);
     98     },
     99 
    100     clone: function() {
    101       var q = new Quad();
    102       vec2.copy(q.p1, this.p1);
    103       vec2.copy(q.p2, this.p2);
    104       vec2.copy(q.p3, this.p3);
    105       vec2.copy(q.p4, this.p4);
    106       return q;
    107     },
    108 
    109     scale: function(s) {
    110       var q = new Quad();
    111       this.scaleFast(q, s);
    112       return q;
    113     },
    114 
    115     scaleFast: function(dstQuad, s) {
    116       vec2.copy(dstQuad.p1, this.p1, s);
    117       vec2.copy(dstQuad.p2, this.p2, s);
    118       vec2.copy(dstQuad.p3, this.p3, s);
    119       vec2.copy(dstQuad.p3, this.p3, s);
    120     },
    121 
    122     isRectangle: function() {
    123       // Simple rectangle check. Note: will not handle out-of-order components.
    124       var bounds = this.boundingRect();
    125       return (
    126           bounds.x == this.p1[0] &&
    127           bounds.y == this.p1[1] &&
    128           bounds.width == this.p2[0] - this.p1[0] &&
    129           bounds.y == this.p2[1] &&
    130           bounds.width == this.p3[0] - this.p1[0] &&
    131           bounds.height == this.p3[1] - this.p2[1] &&
    132           bounds.x == this.p4[0] &&
    133           bounds.height == this.p4[1] - this.p2[1]
    134       );
    135     },
    136 
    137     projectUnitRect: function(rect) {
    138       var q = new Quad();
    139       this.projectUnitRectFast(q, rect);
    140       return q;
    141     },
    142 
    143     projectUnitRectFast: function(dstQuad, rect) {
    144       var v12 = tmpVec2s[0];
    145       var v14 = tmpVec2s[1];
    146       var v23 = tmpVec2s[2];
    147       var v43 = tmpVec2s[3];
    148       var l12, l14, l23, l43;
    149 
    150       vec2.sub(v12, this.p2, this.p1);
    151       l12 = vec2.length(v12);
    152       vec2.scale(v12, v12, 1 / l12);
    153 
    154       vec2.sub(v14, this.p4, this.p1);
    155       l14 = vec2.length(v14);
    156       vec2.scale(v14, v14, 1 / l14);
    157 
    158       vec2.sub(v23, this.p3, this.p2);
    159       l23 = vec2.length(v23);
    160       vec2.scale(v23, v23, 1 / l23);
    161 
    162       vec2.sub(v43, this.p3, this.p4);
    163       l43 = vec2.length(v43);
    164       vec2.scale(v43, v43, 1 / l43);
    165 
    166       var b12 = tmpVec2s[0];
    167       var b14 = tmpVec2s[1];
    168       var b23 = tmpVec2s[2];
    169       var b43 = tmpVec2s[3];
    170       lerpVec2(b12, v12, v43, rect.y);
    171       lerpVec2(b43, v12, v43, 1 - rect.bottom);
    172       lerpVec2(b14, v14, v23, rect.x);
    173       lerpVec2(b23, v14, v23, 1 - rect.right);
    174 
    175       vec2.addTwoScaledUnitVectors(tmpVec2a,
    176                                    b12, l12 * rect.x,
    177                                    b14, l14 * rect.y);
    178       vec2.add(dstQuad.p1, this.p1, tmpVec2a);
    179 
    180       vec2.addTwoScaledUnitVectors(tmpVec2a,
    181                                    b12, l12 * -(1.0 - rect.right),
    182                                    b23, l23 * rect.y);
    183       vec2.add(dstQuad.p2, this.p2, tmpVec2a);
    184 
    185 
    186       vec2.addTwoScaledUnitVectors(tmpVec2a,
    187                                    b43, l43 * -(1.0 - rect.right),
    188                                    b23, l23 * -(1.0 - rect.bottom));
    189       vec2.add(dstQuad.p3, this.p3, tmpVec2a);
    190 
    191       vec2.addTwoScaledUnitVectors(tmpVec2a,
    192                                    b43, l43 * rect.left,
    193                                    b14, l14 * -(1.0 - rect.bottom));
    194       vec2.add(dstQuad.p4, this.p4, tmpVec2a);
    195     },
    196 
    197     toString: function() {
    198       return 'Quad(' +
    199           vec2.toString(this.p1) + ', ' +
    200           vec2.toString(this.p2) + ', ' +
    201           vec2.toString(this.p3) + ', ' +
    202           vec2.toString(this.p4) + ')';
    203     }
    204   };
    205 
    206   function sign(p1, p2, p3) {
    207     return (p1[0] - p3[0]) * (p2[1] - p3[1]) -
    208         (p2[0] - p3[0]) * (p1[1] - p3[1]);
    209   }
    210 
    211   function vecInTriangle2(pt, p1, p2, p3) {
    212     var b1 = sign(pt, p1, p2) < 0.0;
    213     var b2 = sign(pt, p2, p3) < 0.0;
    214     var b3 = sign(pt, p3, p1) < 0.0;
    215     return ((b1 == b2) && (b2 == b3));
    216   }
    217 
    218   return {
    219     vecInTriangle2: vecInTriangle2,
    220     Quad: Quad
    221   };
    222 });
    223