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