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
7base.require('base.gl_matrix');
8
9base.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