// 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
};
});