· 8 years ago · Feb 20, 2018, 07:34 AM
1/*!
2// ??? ? ????? ????? ????? ????? ?????
3// ? ? ? ? ? ??? ? ??? ? ?? ? ? ??
4// ? ? ? ? ? ? ? ? ???? ????
5// ? ?? ???? ????? ? ? ?? ?? ? ?
6// ??? ? ? ? ????? ?
7// ?
8// The MIT License
9//
10// Copyright © 1986 - ?, Blotter / Bradley Griffith / http://bradley.computer
11//
12// Permission is hereby granted, free of charge, to any person obtaining a copy
13// of this software and associated documentation files (the "Software"), to deal
14// in the Software without restriction, including without limitation the rights
15// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16// copies of the Software, and to permit persons to whom the Software is
17// furnished to do so, subject to the following conditions:
18//
19// The above copyright notice and this permission notice shall be included in
20// all copies or substantial portions of the Software.
21//
22// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28// THE SOFTWARE.
29*/
30
31// Underscore.js 1.8.3
32// http://underscorejs.org
33// (c) 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
34// Underscore may be freely distributed under the MIT license.
35
36(function() {
37
38 // Baseline setup
39 // --------------
40
41 // Establish the root object, `window` (`self`) in the browser, `global`
42 // on the server, or `this` in some virtual machines. We use `self`
43 // instead of `window` for `WebWorker` support.
44 var root = typeof self == 'object' && self.self === self && self ||
45 typeof global == 'object' && global.global === global && global ||
46 this;
47
48 // Save the previous value of the `_` variable.
49 var previousUnderscore = root._;
50
51 // Save bytes in the minified (but not gzipped) version:
52 var ArrayProto = Array.prototype, ObjProto = Object.prototype;
53 var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;
54
55 // Create quick reference variables for speed access to core prototypes.
56 var push = ArrayProto.push,
57 slice = ArrayProto.slice,
58 toString = ObjProto.toString,
59 hasOwnProperty = ObjProto.hasOwnProperty;
60
61 // All **ECMAScript 5** native function implementations that we hope to use
62 // are declared here.
63 var nativeIsArray = Array.isArray,
64 nativeKeys = Object.keys,
65 nativeCreate = Object.create;
66
67 // Naked function reference for surrogate-prototype-swapping.
68 var Ctor = function(){};
69
70 // Create a safe reference to the Underscore object for use below.
71 var _ = function(obj) {
72 if (obj instanceof _) return obj;
73 if (!(this instanceof _)) return new _(obj);
74 this._wrapped = obj;
75 };
76
77 // Export the Underscore object for **Node.js**, with
78 // backwards-compatibility for their old module API. If we're in
79 // the browser, add `_` as a global object.
80 // (`nodeType` is checked to ensure that `module`
81 // and `exports` are not HTML elements.)
82 if (typeof exports != 'undefined' && !exports.nodeType) {
83 if (typeof module != 'undefined' && !module.nodeType && module.exports) {
84 exports = module.exports = _;
85 }
86 exports._ = _;
87 } else {
88 root._ = _;
89 }
90
91 // Current version.
92 _.VERSION = '1.8.3';
93
94 // Internal function that returns an efficient (for current engines) version
95 // of the passed-in callback, to be repeatedly applied in other Underscore
96 // functions.
97 var optimizeCb = function(func, context, argCount) {
98 if (context === void 0) return func;
99 switch (argCount == null ? 3 : argCount) {
100 case 1: return function(value) {
101 return func.call(context, value);
102 };
103 // The 2-parameter case has been omitted only because no current consumers
104 // made use of it.
105 case 3: return function(value, index, collection) {
106 return func.call(context, value, index, collection);
107 };
108 case 4: return function(accumulator, value, index, collection) {
109 return func.call(context, accumulator, value, index, collection);
110 };
111 }
112 return function() {
113 return func.apply(context, arguments);
114 };
115 };
116
117 var builtinIteratee;
118
119 // An internal function to generate callbacks that can be applied to each
120 // element in a collection, returning the desired result ? either `identity`,
121 // an arbitrary callback, a property matcher, or a property accessor.
122 var cb = function(value, context, argCount) {
123 if (_.iteratee !== builtinIteratee) return _.iteratee(value, context);
124 if (value == null) return _.identity;
125 if (_.isFunction(value)) return optimizeCb(value, context, argCount);
126 if (_.isObject(value)) return _.matcher(value);
127 return _.property(value);
128 };
129
130 // External wrapper for our callback generator. Users may customize
131 // `_.iteratee` if they want additional predicate/iteratee shorthand styles.
132 // This abstraction hides the internal-only argCount argument.
133 _.iteratee = builtinIteratee = function(value, context) {
134 return cb(value, context, Infinity);
135 };
136
137 // Similar to ES6's rest param (http://ariya.ofilabs.com/2013/03/es6-and-rest-parameter.html)
138 // This accumulates the arguments passed into an array, after a given index.
139 var restArgs = function(func, startIndex) {
140 startIndex = startIndex == null ? func.length - 1 : +startIndex;
141 return function() {
142 var length = Math.max(arguments.length - startIndex, 0);
143 var rest = Array(length);
144 for (var index = 0; index < length; index++) {
145 rest[index] = arguments[index + startIndex];
146 }
147 switch (startIndex) {
148 case 0: return func.call(this, rest);
149 case 1: return func.call(this, arguments[0], rest);
150 case 2: return func.call(this, arguments[0], arguments[1], rest);
151 }
152 var args = Array(startIndex + 1);
153 for (index = 0; index < startIndex; index++) {
154 args[index] = arguments[index];
155 }
156 args[startIndex] = rest;
157 return func.apply(this, args);
158 };
159 };
160
161 // An internal function for creating a new object that inherits from another.
162 var baseCreate = function(prototype) {
163 if (!_.isObject(prototype)) return {};
164 if (nativeCreate) return nativeCreate(prototype);
165 Ctor.prototype = prototype;
166 var result = new Ctor;
167 Ctor.prototype = null;
168 return result;
169 };
170
171 var property = function(key) {
172 return function(obj) {
173 return obj == null ? void 0 : obj[key];
174 };
175 };
176
177 // Helper for collection methods to determine whether a collection
178 // should be iterated as an array or as an object.
179 // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
180 // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
181 var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
182 var getLength = property('length');
183 var isArrayLike = function(collection) {
184 var length = getLength(collection);
185 return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
186 };
187
188 // Collection Functions
189 // --------------------
190
191 // The cornerstone, an `each` implementation, aka `forEach`.
192 // Handles raw objects in addition to array-likes. Treats all
193 // sparse array-likes as if they were dense.
194 _.each = _.forEach = function(obj, iteratee, context) {
195 iteratee = optimizeCb(iteratee, context);
196 var i, length;
197 if (isArrayLike(obj)) {
198 for (i = 0, length = obj.length; i < length; i++) {
199 iteratee(obj[i], i, obj);
200 }
201 } else {
202 var keys = _.keys(obj);
203 for (i = 0, length = keys.length; i < length; i++) {
204 iteratee(obj[keys[i]], keys[i], obj);
205 }
206 }
207 return obj;
208 };
209
210 // Return the results of applying the iteratee to each element.
211 _.map = _.collect = function(obj, iteratee, context) {
212 iteratee = cb(iteratee, context);
213 var keys = !isArrayLike(obj) && _.keys(obj),
214 length = (keys || obj).length,
215 results = Array(length);
216 for (var index = 0; index < length; index++) {
217 var currentKey = keys ? keys[index] : index;
218 results[index] = iteratee(obj[currentKey], currentKey, obj);
219 }
220 return results;
221 };
222
223 // Create a reducing function iterating left or right.
224 var createReduce = function(dir) {
225 // Wrap code that reassigns argument variables in a separate function than
226 // the one that accesses `arguments.length` to avoid a perf hit. (#1991)
227 var reducer = function(obj, iteratee, memo, initial) {
228 var keys = !isArrayLike(obj) && _.keys(obj),
229 length = (keys || obj).length,
230 index = dir > 0 ? 0 : length - 1;
231 if (!initial) {
232 memo = obj[keys ? keys[index] : index];
233 index += dir;
234 }
235 for (; index >= 0 && index < length; index += dir) {
236 var currentKey = keys ? keys[index] : index;
237 memo = iteratee(memo, obj[currentKey], currentKey, obj);
238 }
239 return memo;
240 };
241
242 return function(obj, iteratee, memo, context) {
243 var initial = arguments.length >= 3;
244 return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial);
245 };
246 };
247
248 // **Reduce** builds up a single result from a list of values, aka `inject`,
249 // or `foldl`.
250 _.reduce = _.foldl = _.inject = createReduce(1);
251
252 // The right-associative version of reduce, also known as `foldr`.
253 _.reduceRight = _.foldr = createReduce(-1);
254
255 // Return the first value which passes a truth test. Aliased as `detect`.
256 _.find = _.detect = function(obj, predicate, context) {
257 var keyFinder = isArrayLike(obj) ? _.findIndex : _.findKey;
258 var key = keyFinder(obj, predicate, context);
259 if (key !== void 0 && key !== -1) return obj[key];
260 };
261
262 // Return all the elements that pass a truth test.
263 // Aliased as `select`.
264 _.filter = _.select = function(obj, predicate, context) {
265 var results = [];
266 predicate = cb(predicate, context);
267 _.each(obj, function(value, index, list) {
268 if (predicate(value, index, list)) results.push(value);
269 });
270 return results;
271 };
272
273 // Return all the elements for which a truth test fails.
274 _.reject = function(obj, predicate, context) {
275 return _.filter(obj, _.negate(cb(predicate)), context);
276 };
277
278 // Determine whether all of the elements match a truth test.
279 // Aliased as `all`.
280 _.every = _.all = function(obj, predicate, context) {
281 predicate = cb(predicate, context);
282 var keys = !isArrayLike(obj) && _.keys(obj),
283 length = (keys || obj).length;
284 for (var index = 0; index < length; index++) {
285 var currentKey = keys ? keys[index] : index;
286 if (!predicate(obj[currentKey], currentKey, obj)) return false;
287 }
288 return true;
289 };
290
291 // Determine if at least one element in the object matches a truth test.
292 // Aliased as `any`.
293 _.some = _.any = function(obj, predicate, context) {
294 predicate = cb(predicate, context);
295 var keys = !isArrayLike(obj) && _.keys(obj),
296 length = (keys || obj).length;
297 for (var index = 0; index < length; index++) {
298 var currentKey = keys ? keys[index] : index;
299 if (predicate(obj[currentKey], currentKey, obj)) return true;
300 }
301 return false;
302 };
303
304 // Determine if the array or object contains a given item (using `===`).
305 // Aliased as `includes` and `include`.
306 _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
307 if (!isArrayLike(obj)) obj = _.values(obj);
308 if (typeof fromIndex != 'number' || guard) fromIndex = 0;
309 return _.indexOf(obj, item, fromIndex) >= 0;
310 };
311
312 // Invoke a method (with arguments) on every item in a collection.
313 _.invoke = restArgs(function(obj, method, args) {
314 var isFunc = _.isFunction(method);
315 return _.map(obj, function(value) {
316 var func = isFunc ? method : value[method];
317 return func == null ? func : func.apply(value, args);
318 });
319 });
320
321 // Convenience version of a common use case of `map`: fetching a property.
322 _.pluck = function(obj, key) {
323 return _.map(obj, _.property(key));
324 };
325
326 // Convenience version of a common use case of `filter`: selecting only objects
327 // containing specific `key:value` pairs.
328 _.where = function(obj, attrs) {
329 return _.filter(obj, _.matcher(attrs));
330 };
331
332 // Convenience version of a common use case of `find`: getting the first object
333 // containing specific `key:value` pairs.
334 _.findWhere = function(obj, attrs) {
335 return _.find(obj, _.matcher(attrs));
336 };
337
338 // Return the maximum element (or element-based computation).
339 _.max = function(obj, iteratee, context) {
340 var result = -Infinity, lastComputed = -Infinity,
341 value, computed;
342 if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object') && obj != null) {
343 obj = isArrayLike(obj) ? obj : _.values(obj);
344 for (var i = 0, length = obj.length; i < length; i++) {
345 value = obj[i];
346 if (value != null && value > result) {
347 result = value;
348 }
349 }
350 } else {
351 iteratee = cb(iteratee, context);
352 _.each(obj, function(v, index, list) {
353 computed = iteratee(v, index, list);
354 if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
355 result = v;
356 lastComputed = computed;
357 }
358 });
359 }
360 return result;
361 };
362
363 // Return the minimum element (or element-based computation).
364 _.min = function(obj, iteratee, context) {
365 var result = Infinity, lastComputed = Infinity,
366 value, computed;
367 if (iteratee == null || (typeof iteratee == 'number' && typeof obj[0] != 'object') && obj != null) {
368 obj = isArrayLike(obj) ? obj : _.values(obj);
369 for (var i = 0, length = obj.length; i < length; i++) {
370 value = obj[i];
371 if (value != null && value < result) {
372 result = value;
373 }
374 }
375 } else {
376 iteratee = cb(iteratee, context);
377 _.each(obj, function(v, index, list) {
378 computed = iteratee(v, index, list);
379 if (computed < lastComputed || computed === Infinity && result === Infinity) {
380 result = v;
381 lastComputed = computed;
382 }
383 });
384 }
385 return result;
386 };
387
388 // Shuffle a collection.
389 _.shuffle = function(obj) {
390 return _.sample(obj, Infinity);
391 };
392
393 // Sample **n** random values from a collection using the modern version of the
394 // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher?Yates_shuffle).
395 // If **n** is not specified, returns a single random element.
396 // The internal `guard` argument allows it to work with `map`.
397 _.sample = function(obj, n, guard) {
398 if (n == null || guard) {
399 if (!isArrayLike(obj)) obj = _.values(obj);
400 return obj[_.random(obj.length - 1)];
401 }
402 var sample = isArrayLike(obj) ? _.clone(obj) : _.values(obj);
403 var length = getLength(sample);
404 n = Math.max(Math.min(n, length), 0);
405 var last = length - 1;
406 for (var index = 0; index < n; index++) {
407 var rand = _.random(index, last);
408 var temp = sample[index];
409 sample[index] = sample[rand];
410 sample[rand] = temp;
411 }
412 return sample.slice(0, n);
413 };
414
415 // Sort the object's values by a criterion produced by an iteratee.
416 _.sortBy = function(obj, iteratee, context) {
417 var index = 0;
418 iteratee = cb(iteratee, context);
419 return _.pluck(_.map(obj, function(value, key, list) {
420 return {
421 value: value,
422 index: index++,
423 criteria: iteratee(value, key, list)
424 };
425 }).sort(function(left, right) {
426 var a = left.criteria;
427 var b = right.criteria;
428 if (a !== b) {
429 if (a > b || a === void 0) return 1;
430 if (a < b || b === void 0) return -1;
431 }
432 return left.index - right.index;
433 }), 'value');
434 };
435
436 // An internal function used for aggregate "group by" operations.
437 var group = function(behavior, partition) {
438 return function(obj, iteratee, context) {
439 var result = partition ? [[], []] : {};
440 iteratee = cb(iteratee, context);
441 _.each(obj, function(value, index) {
442 var key = iteratee(value, index, obj);
443 behavior(result, value, key);
444 });
445 return result;
446 };
447 };
448
449 // Groups the object's values by a criterion. Pass either a string attribute
450 // to group by, or a function that returns the criterion.
451 _.groupBy = group(function(result, value, key) {
452 if (_.has(result, key)) result[key].push(value); else result[key] = [value];
453 });
454
455 // Indexes the object's values by a criterion, similar to `groupBy`, but for
456 // when you know that your index values will be unique.
457 _.indexBy = group(function(result, value, key) {
458 result[key] = value;
459 });
460
461 // Counts instances of an object that group by a certain criterion. Pass
462 // either a string attribute to count by, or a function that returns the
463 // criterion.
464 _.countBy = group(function(result, value, key) {
465 if (_.has(result, key)) result[key]++; else result[key] = 1;
466 });
467
468 var reStrSymbol = /[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g;
469 // Safely create a real, live array from anything iterable.
470 _.toArray = function(obj) {
471 if (!obj) return [];
472 if (_.isArray(obj)) return slice.call(obj);
473 if (_.isString(obj)) {
474 // Keep surrogate pair characters together
475 return obj.match(reStrSymbol);
476 }
477 if (isArrayLike(obj)) return _.map(obj, _.identity);
478 return _.values(obj);
479 };
480
481 // Return the number of elements in an object.
482 _.size = function(obj) {
483 if (obj == null) return 0;
484 return isArrayLike(obj) ? obj.length : _.keys(obj).length;
485 };
486
487 // Split a collection into two arrays: one whose elements all satisfy the given
488 // predicate, and one whose elements all do not satisfy the predicate.
489 _.partition = group(function(result, value, pass) {
490 result[pass ? 0 : 1].push(value);
491 }, true);
492
493 // Array Functions
494 // ---------------
495
496 // Get the first element of an array. Passing **n** will return the first N
497 // values in the array. Aliased as `head` and `take`. The **guard** check
498 // allows it to work with `_.map`.
499 _.first = _.head = _.take = function(array, n, guard) {
500 if (array == null) return void 0;
501 if (n == null || guard) return array[0];
502 return _.initial(array, array.length - n);
503 };
504
505 // Returns everything but the last entry of the array. Especially useful on
506 // the arguments object. Passing **n** will return all the values in
507 // the array, excluding the last N.
508 _.initial = function(array, n, guard) {
509 return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
510 };
511
512 // Get the last element of an array. Passing **n** will return the last N
513 // values in the array.
514 _.last = function(array, n, guard) {
515 if (array == null) return void 0;
516 if (n == null || guard) return array[array.length - 1];
517 return _.rest(array, Math.max(0, array.length - n));
518 };
519
520 // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
521 // Especially useful on the arguments object. Passing an **n** will return
522 // the rest N values in the array.
523 _.rest = _.tail = _.drop = function(array, n, guard) {
524 return slice.call(array, n == null || guard ? 1 : n);
525 };
526
527 // Trim out all falsy values from an array.
528 _.compact = function(array) {
529 return _.filter(array, Boolean);
530 };
531
532 // Internal implementation of a recursive `flatten` function.
533 var flatten = function(input, shallow, strict, output) {
534 output = output || [];
535 var idx = output.length;
536 for (var i = 0, length = getLength(input); i < length; i++) {
537 var value = input[i];
538 if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
539 // Flatten current level of array or arguments object.
540 if (shallow) {
541 var j = 0, len = value.length;
542 while (j < len) output[idx++] = value[j++];
543 } else {
544 flatten(value, shallow, strict, output);
545 idx = output.length;
546 }
547 } else if (!strict) {
548 output[idx++] = value;
549 }
550 }
551 return output;
552 };
553
554 // Flatten out an array, either recursively (by default), or just one level.
555 _.flatten = function(array, shallow) {
556 return flatten(array, shallow, false);
557 };
558
559 // Return a version of the array that does not contain the specified value(s).
560 _.without = restArgs(function(array, otherArrays) {
561 return _.difference(array, otherArrays);
562 });
563
564 // Produce a duplicate-free version of the array. If the array has already
565 // been sorted, you have the option of using a faster algorithm.
566 // Aliased as `unique`.
567 _.uniq = _.unique = function(array, isSorted, iteratee, context) {
568 if (!_.isBoolean(isSorted)) {
569 context = iteratee;
570 iteratee = isSorted;
571 isSorted = false;
572 }
573 if (iteratee != null) iteratee = cb(iteratee, context);
574 var result = [];
575 var seen = [];
576 for (var i = 0, length = getLength(array); i < length; i++) {
577 var value = array[i],
578 computed = iteratee ? iteratee(value, i, array) : value;
579 if (isSorted) {
580 if (!i || seen !== computed) result.push(value);
581 seen = computed;
582 } else if (iteratee) {
583 if (!_.contains(seen, computed)) {
584 seen.push(computed);
585 result.push(value);
586 }
587 } else if (!_.contains(result, value)) {
588 result.push(value);
589 }
590 }
591 return result;
592 };
593
594 // Produce an array that contains the union: each distinct element from all of
595 // the passed-in arrays.
596 _.union = restArgs(function(arrays) {
597 return _.uniq(flatten(arrays, true, true));
598 });
599
600 // Produce an array that contains every item shared between all the
601 // passed-in arrays.
602 _.intersection = function(array) {
603 var result = [];
604 var argsLength = arguments.length;
605 for (var i = 0, length = getLength(array); i < length; i++) {
606 var item = array[i];
607 if (_.contains(result, item)) continue;
608 var j;
609 for (j = 1; j < argsLength; j++) {
610 if (!_.contains(arguments[j], item)) break;
611 }
612 if (j === argsLength) result.push(item);
613 }
614 return result;
615 };
616
617 // Take the difference between one array and a number of other arrays.
618 // Only the elements present in just the first array will remain.
619 _.difference = restArgs(function(array, rest) {
620 rest = flatten(rest, true, true);
621 return _.filter(array, function(value){
622 return !_.contains(rest, value);
623 });
624 });
625
626 // Complement of _.zip. Unzip accepts an array of arrays and groups
627 // each array's elements on shared indices.
628 _.unzip = function(array) {
629 var length = array && _.max(array, getLength).length || 0;
630 var result = Array(length);
631
632 for (var index = 0; index < length; index++) {
633 result[index] = _.pluck(array, index);
634 }
635 return result;
636 };
637
638 // Zip together multiple lists into a single array -- elements that share
639 // an index go together.
640 _.zip = restArgs(_.unzip);
641
642 // Converts lists into objects. Pass either a single array of `[key, value]`
643 // pairs, or two parallel arrays of the same length -- one of keys, and one of
644 // the corresponding values.
645 _.object = function(list, values) {
646 var result = {};
647 for (var i = 0, length = getLength(list); i < length; i++) {
648 if (values) {
649 result[list[i]] = values[i];
650 } else {
651 result[list[i][0]] = list[i][1];
652 }
653 }
654 return result;
655 };
656
657 // Generator function to create the findIndex and findLastIndex functions.
658 var createPredicateIndexFinder = function(dir) {
659 return function(array, predicate, context) {
660 predicate = cb(predicate, context);
661 var length = getLength(array);
662 var index = dir > 0 ? 0 : length - 1;
663 for (; index >= 0 && index < length; index += dir) {
664 if (predicate(array[index], index, array)) return index;
665 }
666 return -1;
667 };
668 };
669
670 // Returns the first index on an array-like that passes a predicate test.
671 _.findIndex = createPredicateIndexFinder(1);
672 _.findLastIndex = createPredicateIndexFinder(-1);
673
674 // Use a comparator function to figure out the smallest index at which
675 // an object should be inserted so as to maintain order. Uses binary search.
676 _.sortedIndex = function(array, obj, iteratee, context) {
677 iteratee = cb(iteratee, context, 1);
678 var value = iteratee(obj);
679 var low = 0, high = getLength(array);
680 while (low < high) {
681 var mid = Math.floor((low + high) / 2);
682 if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
683 }
684 return low;
685 };
686
687 // Generator function to create the indexOf and lastIndexOf functions.
688 var createIndexFinder = function(dir, predicateFind, sortedIndex) {
689 return function(array, item, idx) {
690 var i = 0, length = getLength(array);
691 if (typeof idx == 'number') {
692 if (dir > 0) {
693 i = idx >= 0 ? idx : Math.max(idx + length, i);
694 } else {
695 length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
696 }
697 } else if (sortedIndex && idx && length) {
698 idx = sortedIndex(array, item);
699 return array[idx] === item ? idx : -1;
700 }
701 if (item !== item) {
702 idx = predicateFind(slice.call(array, i, length), _.isNaN);
703 return idx >= 0 ? idx + i : -1;
704 }
705 for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
706 if (array[idx] === item) return idx;
707 }
708 return -1;
709 };
710 };
711
712 // Return the position of the first occurrence of an item in an array,
713 // or -1 if the item is not included in the array.
714 // If the array is large and already in sort order, pass `true`
715 // for **isSorted** to use binary search.
716 _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
717 _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
718
719 // Generate an integer Array containing an arithmetic progression. A port of
720 // the native Python `range()` function. See
721 // [the Python documentation](http://docs.python.org/library/functions.html#range).
722 _.range = function(start, stop, step) {
723 if (stop == null) {
724 stop = start || 0;
725 start = 0;
726 }
727 if (!step) {
728 step = stop < start ? -1 : 1;
729 }
730
731 var length = Math.max(Math.ceil((stop - start) / step), 0);
732 var range = Array(length);
733
734 for (var idx = 0; idx < length; idx++, start += step) {
735 range[idx] = start;
736 }
737
738 return range;
739 };
740
741 // Split an **array** into several arrays containing **count** or less elements
742 // of initial array.
743 _.chunk = function(array, count) {
744 if (count == null || count < 1) return [];
745
746 var result = [];
747 var i = 0, length = array.length;
748 while (i < length) {
749 result.push(slice.call(array, i, i += count));
750 }
751 return result;
752 };
753
754 // Function (ahem) Functions
755 // ------------------
756
757 // Determines whether to execute a function as a constructor
758 // or a normal function with the provided arguments.
759 var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
760 if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
761 var self = baseCreate(sourceFunc.prototype);
762 var result = sourceFunc.apply(self, args);
763 if (_.isObject(result)) return result;
764 return self;
765 };
766
767 // Create a function bound to a given object (assigning `this`, and arguments,
768 // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
769 // available.
770 _.bind = restArgs(function(func, context, args) {
771 if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
772 var bound = restArgs(function(callArgs) {
773 return executeBound(func, bound, context, this, args.concat(callArgs));
774 });
775 return bound;
776 });
777
778 // Partially apply a function by creating a version that has had some of its
779 // arguments pre-filled, without changing its dynamic `this` context. _ acts
780 // as a placeholder by default, allowing any combination of arguments to be
781 // pre-filled. Set `_.partial.placeholder` for a custom placeholder argument.
782 _.partial = restArgs(function(func, boundArgs) {
783 var placeholder = _.partial.placeholder;
784 var bound = function() {
785 var position = 0, length = boundArgs.length;
786 var args = Array(length);
787 for (var i = 0; i < length; i++) {
788 args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i];
789 }
790 while (position < arguments.length) args.push(arguments[position++]);
791 return executeBound(func, bound, this, this, args);
792 };
793 return bound;
794 });
795
796 _.partial.placeholder = _;
797
798 // Bind a number of an object's methods to that object. Remaining arguments
799 // are the method names to be bound. Useful for ensuring that all callbacks
800 // defined on an object belong to it.
801 _.bindAll = restArgs(function(obj, keys) {
802 keys = flatten(keys, false, false);
803 var index = keys.length;
804 if (index < 1) throw new Error('bindAll must be passed function names');
805 while (index--) {
806 var key = keys[index];
807 obj[key] = _.bind(obj[key], obj);
808 }
809 });
810
811 // Memoize an expensive function by storing its results.
812 _.memoize = function(func, hasher) {
813 var memoize = function(key) {
814 var cache = memoize.cache;
815 var address = '' + (hasher ? hasher.apply(this, arguments) : key);
816 if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
817 return cache[address];
818 };
819 memoize.cache = {};
820 return memoize;
821 };
822
823 // Delays a function for the given number of milliseconds, and then calls
824 // it with the arguments supplied.
825 _.delay = restArgs(function(func, wait, args) {
826 return setTimeout(function() {
827 return func.apply(null, args);
828 }, wait);
829 });
830
831 // Defers a function, scheduling it to run after the current call stack has
832 // cleared.
833 _.defer = _.partial(_.delay, _, 1);
834
835 // Returns a function, that, when invoked, will only be triggered at most once
836 // during a given window of time. Normally, the throttled function will run
837 // as much as it can, without ever going more than once per `wait` duration;
838 // but if you'd like to disable the execution on the leading edge, pass
839 // `{leading: false}`. To disable execution on the trailing edge, ditto.
840 _.throttle = function(func, wait, options) {
841 var timeout, context, args, result;
842 var previous = 0;
843 if (!options) options = {};
844
845 var later = function() {
846 previous = options.leading === false ? 0 : _.now();
847 timeout = null;
848 result = func.apply(context, args);
849 if (!timeout) context = args = null;
850 };
851
852 var throttled = function() {
853 var now = _.now();
854 if (!previous && options.leading === false) previous = now;
855 var remaining = wait - (now - previous);
856 context = this;
857 args = arguments;
858 if (remaining <= 0 || remaining > wait) {
859 if (timeout) {
860 clearTimeout(timeout);
861 timeout = null;
862 }
863 previous = now;
864 result = func.apply(context, args);
865 if (!timeout) context = args = null;
866 } else if (!timeout && options.trailing !== false) {
867 timeout = setTimeout(later, remaining);
868 }
869 return result;
870 };
871
872 throttled.cancel = function() {
873 clearTimeout(timeout);
874 previous = 0;
875 timeout = context = args = null;
876 };
877
878 return throttled;
879 };
880
881 // Returns a function, that, as long as it continues to be invoked, will not
882 // be triggered. The function will be called after it stops being called for
883 // N milliseconds. If `immediate` is passed, trigger the function on the
884 // leading edge, instead of the trailing.
885 _.debounce = function(func, wait, immediate) {
886 var timeout, result;
887
888 var later = function(context, args) {
889 timeout = null;
890 if (args) result = func.apply(context, args);
891 };
892
893 var debounced = restArgs(function(args) {
894 if (timeout) clearTimeout(timeout);
895 if (immediate) {
896 var callNow = !timeout;
897 timeout = setTimeout(later, wait);
898 if (callNow) result = func.apply(this, args);
899 } else {
900 timeout = _.delay(later, wait, this, args);
901 }
902
903 return result;
904 });
905
906 debounced.cancel = function() {
907 clearTimeout(timeout);
908 timeout = null;
909 };
910
911 return debounced;
912 };
913
914 // Returns the first function passed as an argument to the second,
915 // allowing you to adjust arguments, run code before and after, and
916 // conditionally execute the original function.
917 _.wrap = function(func, wrapper) {
918 return _.partial(wrapper, func);
919 };
920
921 // Returns a negated version of the passed-in predicate.
922 _.negate = function(predicate) {
923 return function() {
924 return !predicate.apply(this, arguments);
925 };
926 };
927
928 // Returns a function that is the composition of a list of functions, each
929 // consuming the return value of the function that follows.
930 _.compose = function() {
931 var args = arguments;
932 var start = args.length - 1;
933 return function() {
934 var i = start;
935 var result = args[start].apply(this, arguments);
936 while (i--) result = args[i].call(this, result);
937 return result;
938 };
939 };
940
941 // Returns a function that will only be executed on and after the Nth call.
942 _.after = function(times, func) {
943 return function() {
944 if (--times < 1) {
945 return func.apply(this, arguments);
946 }
947 };
948 };
949
950 // Returns a function that will only be executed up to (but not including) the Nth call.
951 _.before = function(times, func) {
952 var memo;
953 return function() {
954 if (--times > 0) {
955 memo = func.apply(this, arguments);
956 }
957 if (times <= 1) func = null;
958 return memo;
959 };
960 };
961
962 // Returns a function that will be executed at most one time, no matter how
963 // often you call it. Useful for lazy initialization.
964 _.once = _.partial(_.before, 2);
965
966 _.restArgs = restArgs;
967
968 // Object Functions
969 // ----------------
970
971 // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
972 var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
973 var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
974 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
975
976 var collectNonEnumProps = function(obj, keys) {
977 var nonEnumIdx = nonEnumerableProps.length;
978 var constructor = obj.constructor;
979 var proto = _.isFunction(constructor) && constructor.prototype || ObjProto;
980
981 // Constructor is a special case.
982 var prop = 'constructor';
983 if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
984
985 while (nonEnumIdx--) {
986 prop = nonEnumerableProps[nonEnumIdx];
987 if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
988 keys.push(prop);
989 }
990 }
991 };
992
993 // Retrieve the names of an object's own properties.
994 // Delegates to **ECMAScript 5**'s native `Object.keys`.
995 _.keys = function(obj) {
996 if (!_.isObject(obj)) return [];
997 if (nativeKeys) return nativeKeys(obj);
998 var keys = [];
999 for (var key in obj) if (_.has(obj, key)) keys.push(key);
1000 // Ahem, IE < 9.
1001 if (hasEnumBug) collectNonEnumProps(obj, keys);
1002 return keys;
1003 };
1004
1005 // Retrieve all the property names of an object.
1006 _.allKeys = function(obj) {
1007 if (!_.isObject(obj)) return [];
1008 var keys = [];
1009 for (var key in obj) keys.push(key);
1010 // Ahem, IE < 9.
1011 if (hasEnumBug) collectNonEnumProps(obj, keys);
1012 return keys;
1013 };
1014
1015 // Retrieve the values of an object's properties.
1016 _.values = function(obj) {
1017 var keys = _.keys(obj);
1018 var length = keys.length;
1019 var values = Array(length);
1020 for (var i = 0; i < length; i++) {
1021 values[i] = obj[keys[i]];
1022 }
1023 return values;
1024 };
1025
1026 // Returns the results of applying the iteratee to each element of the object.
1027 // In contrast to _.map it returns an object.
1028 _.mapObject = function(obj, iteratee, context) {
1029 iteratee = cb(iteratee, context);
1030 var keys = _.keys(obj),
1031 length = keys.length,
1032 results = {};
1033 for (var index = 0; index < length; index++) {
1034 var currentKey = keys[index];
1035 results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
1036 }
1037 return results;
1038 };
1039
1040 // Convert an object into a list of `[key, value]` pairs.
1041 _.pairs = function(obj) {
1042 var keys = _.keys(obj);
1043 var length = keys.length;
1044 var pairs = Array(length);
1045 for (var i = 0; i < length; i++) {
1046 pairs[i] = [keys[i], obj[keys[i]]];
1047 }
1048 return pairs;
1049 };
1050
1051 // Invert the keys and values of an object. The values must be serializable.
1052 _.invert = function(obj) {
1053 var result = {};
1054 var keys = _.keys(obj);
1055 for (var i = 0, length = keys.length; i < length; i++) {
1056 result[obj[keys[i]]] = keys[i];
1057 }
1058 return result;
1059 };
1060
1061 // Return a sorted list of the function names available on the object.
1062 // Aliased as `methods`.
1063 _.functions = _.methods = function(obj) {
1064 var names = [];
1065 for (var key in obj) {
1066 if (_.isFunction(obj[key])) names.push(key);
1067 }
1068 return names.sort();
1069 };
1070
1071 // An internal function for creating assigner functions.
1072 var createAssigner = function(keysFunc, defaults) {
1073 return function(obj) {
1074 var length = arguments.length;
1075 if (defaults) obj = Object(obj);
1076 if (length < 2 || obj == null) return obj;
1077 for (var index = 1; index < length; index++) {
1078 var source = arguments[index],
1079 keys = keysFunc(source),
1080 l = keys.length;
1081 for (var i = 0; i < l; i++) {
1082 var key = keys[i];
1083 if (!defaults || obj[key] === void 0) obj[key] = source[key];
1084 }
1085 }
1086 return obj;
1087 };
1088 };
1089
1090 // Extend a given object with all the properties in passed-in object(s).
1091 _.extend = createAssigner(_.allKeys);
1092
1093 // Assigns a given object with all the own properties in the passed-in object(s).
1094 // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
1095 _.extendOwn = _.assign = createAssigner(_.keys);
1096
1097 // Returns the first key on an object that passes a predicate test.
1098 _.findKey = function(obj, predicate, context) {
1099 predicate = cb(predicate, context);
1100 var keys = _.keys(obj), key;
1101 for (var i = 0, length = keys.length; i < length; i++) {
1102 key = keys[i];
1103 if (predicate(obj[key], key, obj)) return key;
1104 }
1105 };
1106
1107 // Internal pick helper function to determine if `obj` has key `key`.
1108 var keyInObj = function(value, key, obj) {
1109 return key in obj;
1110 };
1111
1112 // Return a copy of the object only containing the whitelisted properties.
1113 _.pick = restArgs(function(obj, keys) {
1114 var result = {}, iteratee = keys[0];
1115 if (obj == null) return result;
1116 if (_.isFunction(iteratee)) {
1117 if (keys.length > 1) iteratee = optimizeCb(iteratee, keys[1]);
1118 keys = _.allKeys(obj);
1119 } else {
1120 iteratee = keyInObj;
1121 keys = flatten(keys, false, false);
1122 obj = Object(obj);
1123 }
1124 for (var i = 0, length = keys.length; i < length; i++) {
1125 var key = keys[i];
1126 var value = obj[key];
1127 if (iteratee(value, key, obj)) result[key] = value;
1128 }
1129 return result;
1130 });
1131
1132 // Return a copy of the object without the blacklisted properties.
1133 _.omit = restArgs(function(obj, keys) {
1134 var iteratee = keys[0], context;
1135 if (_.isFunction(iteratee)) {
1136 iteratee = _.negate(iteratee);
1137 if (keys.length > 1) context = keys[1];
1138 } else {
1139 keys = _.map(flatten(keys, false, false), String);
1140 iteratee = function(value, key) {
1141 return !_.contains(keys, key);
1142 };
1143 }
1144 return _.pick(obj, iteratee, context);
1145 });
1146
1147 // Fill in a given object with default properties.
1148 _.defaults = createAssigner(_.allKeys, true);
1149
1150 // Creates an object that inherits from the given prototype object.
1151 // If additional properties are provided then they will be added to the
1152 // created object.
1153 _.create = function(prototype, props) {
1154 var result = baseCreate(prototype);
1155 if (props) _.extendOwn(result, props);
1156 return result;
1157 };
1158
1159 // Create a (shallow-cloned) duplicate of an object.
1160 _.clone = function(obj) {
1161 if (!_.isObject(obj)) return obj;
1162 return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
1163 };
1164
1165 // Invokes interceptor with the obj, and then returns obj.
1166 // The primary purpose of this method is to "tap into" a method chain, in
1167 // order to perform operations on intermediate results within the chain.
1168 _.tap = function(obj, interceptor) {
1169 interceptor(obj);
1170 return obj;
1171 };
1172
1173 // Returns whether an object has a given set of `key:value` pairs.
1174 _.isMatch = function(object, attrs) {
1175 var keys = _.keys(attrs), length = keys.length;
1176 if (object == null) return !length;
1177 var obj = Object(object);
1178 for (var i = 0; i < length; i++) {
1179 var key = keys[i];
1180 if (attrs[key] !== obj[key] || !(key in obj)) return false;
1181 }
1182 return true;
1183 };
1184
1185
1186 // Internal recursive comparison function for `isEqual`.
1187 var eq, deepEq;
1188 eq = function(a, b, aStack, bStack) {
1189 // Identical objects are equal. `0 === -0`, but they aren't identical.
1190 // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
1191 if (a === b) return a !== 0 || 1 / a === 1 / b;
1192 // A strict comparison is necessary because `null == undefined`.
1193 if (a == null || b == null) return a === b;
1194 // `NaN`s are equivalent, but non-reflexive.
1195 if (a !== a) return b !== b;
1196 // Exhaust primitive checks
1197 var type = typeof a;
1198 if (type !== 'function' && type !== 'object' && typeof b != 'object') return false;
1199 return deepEq(a, b, aStack, bStack);
1200 };
1201
1202 // Internal recursive comparison function for `isEqual`.
1203 deepEq = function(a, b, aStack, bStack) {
1204 // Unwrap any wrapped objects.
1205 if (a instanceof _) a = a._wrapped;
1206 if (b instanceof _) b = b._wrapped;
1207 // Compare `[[Class]]` names.
1208 var className = toString.call(a);
1209 if (className !== toString.call(b)) return false;
1210 switch (className) {
1211 // Strings, numbers, regular expressions, dates, and booleans are compared by value.
1212 case '[object RegExp]':
1213 // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
1214 case '[object String]':
1215 // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
1216 // equivalent to `new String("5")`.
1217 return '' + a === '' + b;
1218 case '[object Number]':
1219 // `NaN`s are equivalent, but non-reflexive.
1220 // Object(NaN) is equivalent to NaN.
1221 if (+a !== +a) return +b !== +b;
1222 // An `egal` comparison is performed for other numeric values.
1223 return +a === 0 ? 1 / +a === 1 / b : +a === +b;
1224 case '[object Date]':
1225 case '[object Boolean]':
1226 // Coerce dates and booleans to numeric primitive values. Dates are compared by their
1227 // millisecond representations. Note that invalid dates with millisecond representations
1228 // of `NaN` are not equivalent.
1229 return +a === +b;
1230 case '[object Symbol]':
1231 return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b);
1232 }
1233
1234 var areArrays = className === '[object Array]';
1235 if (!areArrays) {
1236 if (typeof a != 'object' || typeof b != 'object') return false;
1237
1238 // Objects with different constructors are not equivalent, but `Object`s or `Array`s
1239 // from different frames are.
1240 var aCtor = a.constructor, bCtor = b.constructor;
1241 if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
1242 _.isFunction(bCtor) && bCtor instanceof bCtor)
1243 && ('constructor' in a && 'constructor' in b)) {
1244 return false;
1245 }
1246 }
1247 // Assume equality for cyclic structures. The algorithm for detecting cyclic
1248 // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
1249
1250 // Initializing stack of traversed objects.
1251 // It's done here since we only need them for objects and arrays comparison.
1252 aStack = aStack || [];
1253 bStack = bStack || [];
1254 var length = aStack.length;
1255 while (length--) {
1256 // Linear search. Performance is inversely proportional to the number of
1257 // unique nested structures.
1258 if (aStack[length] === a) return bStack[length] === b;
1259 }
1260
1261 // Add the first object to the stack of traversed objects.
1262 aStack.push(a);
1263 bStack.push(b);
1264
1265 // Recursively compare objects and arrays.
1266 if (areArrays) {
1267 // Compare array lengths to determine if a deep comparison is necessary.
1268 length = a.length;
1269 if (length !== b.length) return false;
1270 // Deep compare the contents, ignoring non-numeric properties.
1271 while (length--) {
1272 if (!eq(a[length], b[length], aStack, bStack)) return false;
1273 }
1274 } else {
1275 // Deep compare objects.
1276 var keys = _.keys(a), key;
1277 length = keys.length;
1278 // Ensure that both objects contain the same number of properties before comparing deep equality.
1279 if (_.keys(b).length !== length) return false;
1280 while (length--) {
1281 // Deep compare each member
1282 key = keys[length];
1283 if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
1284 }
1285 }
1286 // Remove the first object from the stack of traversed objects.
1287 aStack.pop();
1288 bStack.pop();
1289 return true;
1290 };
1291
1292 // Perform a deep comparison to check if two objects are equal.
1293 _.isEqual = function(a, b) {
1294 return eq(a, b);
1295 };
1296
1297 // Is a given array, string, or object empty?
1298 // An "empty" object has no enumerable own-properties.
1299 _.isEmpty = function(obj) {
1300 if (obj == null) return true;
1301 if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
1302 return _.keys(obj).length === 0;
1303 };
1304
1305 // Is a given value a DOM element?
1306 _.isElement = function(obj) {
1307 return !!(obj && obj.nodeType === 1);
1308 };
1309
1310 // Is a given value an array?
1311 // Delegates to ECMA5's native Array.isArray
1312 _.isArray = nativeIsArray || function(obj) {
1313 return toString.call(obj) === '[object Array]';
1314 };
1315
1316 // Is a given variable an object?
1317 _.isObject = function(obj) {
1318 var type = typeof obj;
1319 return type === 'function' || type === 'object' && !!obj;
1320 };
1321
1322 // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError, isMap, isWeakMap, isSet, isWeakSet.
1323 _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error', 'Symbol', 'Map', 'WeakMap', 'Set', 'WeakSet'], function(name) {
1324 _['is' + name] = function(obj) {
1325 return toString.call(obj) === '[object ' + name + ']';
1326 };
1327 });
1328
1329 // Define a fallback version of the method in browsers (ahem, IE < 9), where
1330 // there isn't any inspectable "Arguments" type.
1331 if (!_.isArguments(arguments)) {
1332 _.isArguments = function(obj) {
1333 return _.has(obj, 'callee');
1334 };
1335 }
1336
1337 // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
1338 // IE 11 (#1621), Safari 8 (#1929), and PhantomJS (#2236).
1339 var nodelist = root.document && root.document.childNodes;
1340 if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelist != 'function') {
1341 _.isFunction = function(obj) {
1342 return typeof obj == 'function' || false;
1343 };
1344 }
1345
1346 // Is a given object a finite number?
1347 _.isFinite = function(obj) {
1348 return !_.isSymbol(obj) && isFinite(obj) && !isNaN(parseFloat(obj));
1349 };
1350
1351 // Is the given value `NaN`?
1352 _.isNaN = function(obj) {
1353 return isNaN(obj) && _.isNumber(obj);
1354 };
1355
1356 // Is a given value a boolean?
1357 _.isBoolean = function(obj) {
1358 return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
1359 };
1360
1361 // Is a given value equal to null?
1362 _.isNull = function(obj) {
1363 return obj === null;
1364 };
1365
1366 // Is a given variable undefined?
1367 _.isUndefined = function(obj) {
1368 return obj === void 0;
1369 };
1370
1371 // Shortcut function for checking if an object has a given property directly
1372 // on itself (in other words, not on a prototype).
1373 _.has = function(obj, key) {
1374 return obj != null && hasOwnProperty.call(obj, key);
1375 };
1376
1377 // Utility Functions
1378 // -----------------
1379
1380 // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
1381 // previous owner. Returns a reference to the Underscore object.
1382 _.noConflict = function() {
1383 root._ = previousUnderscore;
1384 return this;
1385 };
1386
1387 // Keep the identity function around for default iteratees.
1388 _.identity = function(value) {
1389 return value;
1390 };
1391
1392 // Predicate-generating functions. Often useful outside of Underscore.
1393 _.constant = function(value) {
1394 return function() {
1395 return value;
1396 };
1397 };
1398
1399 _.noop = function(){};
1400
1401 _.property = property;
1402
1403 // Generates a function for a given object that returns a given property.
1404 _.propertyOf = function(obj) {
1405 return obj == null ? function(){} : function(key) {
1406 return obj[key];
1407 };
1408 };
1409
1410 // Returns a predicate for checking whether an object has a given set of
1411 // `key:value` pairs.
1412 _.matcher = _.matches = function(attrs) {
1413 attrs = _.extendOwn({}, attrs);
1414 return function(obj) {
1415 return _.isMatch(obj, attrs);
1416 };
1417 };
1418
1419 // Run a function **n** times.
1420 _.times = function(n, iteratee, context) {
1421 var accum = Array(Math.max(0, n));
1422 iteratee = optimizeCb(iteratee, context, 1);
1423 for (var i = 0; i < n; i++) accum[i] = iteratee(i);
1424 return accum;
1425 };
1426
1427 // Return a random integer between min and max (inclusive).
1428 _.random = function(min, max) {
1429 if (max == null) {
1430 max = min;
1431 min = 0;
1432 }
1433 return min + Math.floor(Math.random() * (max - min + 1));
1434 };
1435
1436 // A (possibly faster) way to get the current timestamp as an integer.
1437 _.now = Date.now || function() {
1438 return new Date().getTime();
1439 };
1440
1441 // List of HTML entities for escaping.
1442 var escapeMap = {
1443 '&': '&',
1444 '<': '<',
1445 '>': '>',
1446 '"': '"',
1447 "'": ''',
1448 '`': '`'
1449 };
1450 var unescapeMap = _.invert(escapeMap);
1451
1452 // Functions for escaping and unescaping strings to/from HTML interpolation.
1453 var createEscaper = function(map) {
1454 var escaper = function(match) {
1455 return map[match];
1456 };
1457 // Regexes for identifying a key that needs to be escaped.
1458 var source = '(?:' + _.keys(map).join('|') + ')';
1459 var testRegexp = RegExp(source);
1460 var replaceRegexp = RegExp(source, 'g');
1461 return function(string) {
1462 string = string == null ? '' : '' + string;
1463 return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
1464 };
1465 };
1466 _.escape = createEscaper(escapeMap);
1467 _.unescape = createEscaper(unescapeMap);
1468
1469 // If the value of the named `property` is a function then invoke it with the
1470 // `object` as context; otherwise, return it.
1471 _.result = function(object, prop, fallback) {
1472 var value = object == null ? void 0 : object[prop];
1473 if (value === void 0) {
1474 value = fallback;
1475 }
1476 return _.isFunction(value) ? value.call(object) : value;
1477 };
1478
1479 // Generate a unique integer id (unique within the entire client session).
1480 // Useful for temporary DOM ids.
1481 var idCounter = 0;
1482 _.uniqueId = function(prefix) {
1483 var id = ++idCounter + '';
1484 return prefix ? prefix + id : id;
1485 };
1486
1487 // By default, Underscore uses ERB-style template delimiters, change the
1488 // following template settings to use alternative delimiters.
1489 _.templateSettings = {
1490 evaluate: /<%([\s\S]+?)%>/g,
1491 interpolate: /<%=([\s\S]+?)%>/g,
1492 escape: /<%-([\s\S]+?)%>/g
1493 };
1494
1495 // When customizing `templateSettings`, if you don't want to define an
1496 // interpolation, evaluation or escaping regex, we need one that is
1497 // guaranteed not to match.
1498 var noMatch = /(.)^/;
1499
1500 // Certain characters need to be escaped so that they can be put into a
1501 // string literal.
1502 var escapes = {
1503 "'": "'",
1504 '\\': '\\',
1505 '\r': 'r',
1506 '\n': 'n',
1507 '\u2028': 'u2028',
1508 '\u2029': 'u2029'
1509 };
1510
1511 var escapeRegExp = /\\|'|\r|\n|\u2028|\u2029/g;
1512
1513 var escapeChar = function(match) {
1514 return '\\' + escapes[match];
1515 };
1516
1517 // JavaScript micro-templating, similar to John Resig's implementation.
1518 // Underscore templating handles arbitrary delimiters, preserves whitespace,
1519 // and correctly escapes quotes within interpolated code.
1520 // NB: `oldSettings` only exists for backwards compatibility.
1521 _.template = function(text, settings, oldSettings) {
1522 if (!settings && oldSettings) settings = oldSettings;
1523 settings = _.defaults({}, settings, _.templateSettings);
1524
1525 // Combine delimiters into one regular expression via alternation.
1526 var matcher = RegExp([
1527 (settings.escape || noMatch).source,
1528 (settings.interpolate || noMatch).source,
1529 (settings.evaluate || noMatch).source
1530 ].join('|') + '|$', 'g');
1531
1532 // Compile the template source, escaping string literals appropriately.
1533 var index = 0;
1534 var source = "__p+='";
1535 text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
1536 source += text.slice(index, offset).replace(escapeRegExp, escapeChar);
1537 index = offset + match.length;
1538
1539 if (escape) {
1540 source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
1541 } else if (interpolate) {
1542 source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
1543 } else if (evaluate) {
1544 source += "';\n" + evaluate + "\n__p+='";
1545 }
1546
1547 // Adobe VMs need the match returned to produce the correct offset.
1548 return match;
1549 });
1550 source += "';\n";
1551
1552 // If a variable is not specified, place data values in local scope.
1553 if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
1554
1555 source = "var __t,__p='',__j=Array.prototype.join," +
1556 "print=function(){__p+=__j.call(arguments,'');};\n" +
1557 source + 'return __p;\n';
1558
1559 var render;
1560 try {
1561 render = new Function(settings.variable || 'obj', '_', source);
1562 } catch (e) {
1563 e.source = source;
1564 throw e;
1565 }
1566
1567 var template = function(data) {
1568 return render.call(this, data, _);
1569 };
1570
1571 // Provide the compiled source as a convenience for precompilation.
1572 var argument = settings.variable || 'obj';
1573 template.source = 'function(' + argument + '){\n' + source + '}';
1574
1575 return template;
1576 };
1577
1578 // Add a "chain" function. Start chaining a wrapped Underscore object.
1579 _.chain = function(obj) {
1580 var instance = _(obj);
1581 instance._chain = true;
1582 return instance;
1583 };
1584
1585 // OOP
1586 // ---------------
1587 // If Underscore is called as a function, it returns a wrapped object that
1588 // can be used OO-style. This wrapper holds altered versions of all the
1589 // underscore functions. Wrapped objects may be chained.
1590
1591 // Helper function to continue chaining intermediate results.
1592 var chainResult = function(instance, obj) {
1593 return instance._chain ? _(obj).chain() : obj;
1594 };
1595
1596 // Add your own custom functions to the Underscore object.
1597 _.mixin = function(obj) {
1598 _.each(_.functions(obj), function(name) {
1599 var func = _[name] = obj[name];
1600 _.prototype[name] = function() {
1601 var args = [this._wrapped];
1602 push.apply(args, arguments);
1603 return chainResult(this, func.apply(_, args));
1604 };
1605 });
1606 return _;
1607 };
1608
1609 // Add all of the Underscore functions to the wrapper object.
1610 _.mixin(_);
1611
1612 // Add all mutator Array functions to the wrapper.
1613 _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
1614 var method = ArrayProto[name];
1615 _.prototype[name] = function() {
1616 var obj = this._wrapped;
1617 method.apply(obj, arguments);
1618 if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
1619 return chainResult(this, obj);
1620 };
1621 });
1622
1623 // Add all accessor Array functions to the wrapper.
1624 _.each(['concat', 'join', 'slice'], function(name) {
1625 var method = ArrayProto[name];
1626 _.prototype[name] = function() {
1627 return chainResult(this, method.apply(this._wrapped, arguments));
1628 };
1629 });
1630
1631 // Extracts the result from a wrapped and chained object.
1632 _.prototype.value = function() {
1633 return this._wrapped;
1634 };
1635
1636 // Provide unwrapping proxy for some methods used in engine operations
1637 // such as arithmetic and JSON stringification.
1638 _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
1639
1640 _.prototype.toString = function() {
1641 return '' + this._wrapped;
1642 };
1643
1644 // AMD registration happens at the end for compatibility with AMD loaders
1645 // that may not enforce next-turn semantics on modules. Even though general
1646 // practice for AMD registration is to be anonymous, underscore registers
1647 // as a named module because, like jQuery, it is a base library that is
1648 // popular enough to be bundled in a third party lib, but not be part of
1649 // an AMD load request. Those cases could generate an error when an
1650 // anonymous define() is called outside of a loader request.
1651 if (typeof define == 'function' && define.amd) {
1652 define('underscore', [], function() {
1653 return _;
1654 });
1655 }
1656}());
1657(function (global, factory) {
1658 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
1659 typeof define === 'function' && define.amd ? define(['exports'], factory) :
1660 (factory((global.THREE = {})));
1661}(this, (function (exports) { 'use strict';
1662
1663// Polyfills
1664
1665if ( Number.EPSILON === undefined ) {
1666
1667 Number.EPSILON = Math.pow( 2, - 52 );
1668
1669}
1670
1671if ( Number.isInteger === undefined ) {
1672
1673 // Missing in IE
1674 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger
1675
1676 Number.isInteger = function ( value ) {
1677
1678 return typeof value === 'number' && isFinite( value ) && Math.floor( value ) === value;
1679
1680 };
1681
1682}
1683
1684//
1685
1686if ( Math.sign === undefined ) {
1687
1688 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign
1689
1690 Math.sign = function ( x ) {
1691
1692 return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : + x;
1693
1694 };
1695
1696}
1697
1698if ( 'name' in Function.prototype === false ) {
1699
1700 // Missing in IE
1701 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
1702
1703 Object.defineProperty( Function.prototype, 'name', {
1704
1705 get: function () {
1706
1707 return this.toString().match( /^\s*function\s*([^\(\s]*)/ )[ 1 ];
1708
1709 }
1710
1711 } );
1712
1713}
1714
1715if ( Object.assign === undefined ) {
1716
1717 // Missing in IE
1718 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
1719
1720 ( function () {
1721
1722 Object.assign = function ( target ) {
1723
1724 if ( target === undefined || target === null ) {
1725
1726 throw new TypeError( 'Cannot convert undefined or null to object' );
1727
1728 }
1729
1730 var output = Object( target );
1731
1732 for ( var index = 1; index < arguments.length; index ++ ) {
1733
1734 var source = arguments[ index ];
1735
1736 if ( source !== undefined && source !== null ) {
1737
1738 for ( var nextKey in source ) {
1739
1740 if ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) {
1741
1742 output[ nextKey ] = source[ nextKey ];
1743
1744 }
1745
1746 }
1747
1748 }
1749
1750 }
1751
1752 return output;
1753
1754 };
1755
1756 } )();
1757
1758}
1759
1760/**
1761 * https://github.com/mrdoob/eventdispatcher.js/
1762 */
1763
1764function EventDispatcher() {}
1765
1766Object.assign( EventDispatcher.prototype, {
1767
1768 addEventListener: function ( type, listener ) {
1769
1770 if ( this._listeners === undefined ) this._listeners = {};
1771
1772 var listeners = this._listeners;
1773
1774 if ( listeners[ type ] === undefined ) {
1775
1776 listeners[ type ] = [];
1777
1778 }
1779
1780 if ( listeners[ type ].indexOf( listener ) === - 1 ) {
1781
1782 listeners[ type ].push( listener );
1783
1784 }
1785
1786 },
1787
1788 hasEventListener: function ( type, listener ) {
1789
1790 if ( this._listeners === undefined ) return false;
1791
1792 var listeners = this._listeners;
1793
1794 return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;
1795
1796 },
1797
1798 removeEventListener: function ( type, listener ) {
1799
1800 if ( this._listeners === undefined ) return;
1801
1802 var listeners = this._listeners;
1803 var listenerArray = listeners[ type ];
1804
1805 if ( listenerArray !== undefined ) {
1806
1807 var index = listenerArray.indexOf( listener );
1808
1809 if ( index !== - 1 ) {
1810
1811 listenerArray.splice( index, 1 );
1812
1813 }
1814
1815 }
1816
1817 },
1818
1819 dispatchEvent: function ( event ) {
1820
1821 if ( this._listeners === undefined ) return;
1822
1823 var listeners = this._listeners;
1824 var listenerArray = listeners[ event.type ];
1825
1826 if ( listenerArray !== undefined ) {
1827
1828 event.target = this;
1829
1830 var array = listenerArray.slice( 0 );
1831
1832 for ( var i = 0, l = array.length; i < l; i ++ ) {
1833
1834 array[ i ].call( this, event );
1835
1836 }
1837
1838 }
1839
1840 }
1841
1842} );
1843
1844var REVISION = '89';
1845
1846var CullFaceNone = 0;
1847var CullFaceBack = 1;
1848var CullFaceFront = 2;
1849
1850var FrontFaceDirectionCW = 0;
1851
1852
1853var PCFShadowMap = 1;
1854var PCFSoftShadowMap = 2;
1855var FrontSide = 0;
1856var BackSide = 1;
1857var DoubleSide = 2;
1858var FlatShading = 1;
1859
1860var NoColors = 0;
1861
1862
1863var NoBlending = 0;
1864var NormalBlending = 1;
1865var AdditiveBlending = 2;
1866var SubtractiveBlending = 3;
1867var MultiplyBlending = 4;
1868var CustomBlending = 5;
1869var AddEquation = 100;
1870var SubtractEquation = 101;
1871var ReverseSubtractEquation = 102;
1872var MinEquation = 103;
1873var MaxEquation = 104;
1874var ZeroFactor = 200;
1875var OneFactor = 201;
1876var SrcColorFactor = 202;
1877var OneMinusSrcColorFactor = 203;
1878var SrcAlphaFactor = 204;
1879var OneMinusSrcAlphaFactor = 205;
1880var DstAlphaFactor = 206;
1881var OneMinusDstAlphaFactor = 207;
1882var DstColorFactor = 208;
1883var OneMinusDstColorFactor = 209;
1884var SrcAlphaSaturateFactor = 210;
1885var NeverDepth = 0;
1886var AlwaysDepth = 1;
1887var LessDepth = 2;
1888var LessEqualDepth = 3;
1889var EqualDepth = 4;
1890var GreaterEqualDepth = 5;
1891var GreaterDepth = 6;
1892var NotEqualDepth = 7;
1893var MultiplyOperation = 0;
1894var MixOperation = 1;
1895var AddOperation = 2;
1896var NoToneMapping = 0;
1897var LinearToneMapping = 1;
1898var ReinhardToneMapping = 2;
1899var Uncharted2ToneMapping = 3;
1900var CineonToneMapping = 4;
1901var UVMapping = 300;
1902var CubeReflectionMapping = 301;
1903var CubeRefractionMapping = 302;
1904var EquirectangularReflectionMapping = 303;
1905var EquirectangularRefractionMapping = 304;
1906var SphericalReflectionMapping = 305;
1907var CubeUVReflectionMapping = 306;
1908var CubeUVRefractionMapping = 307;
1909var RepeatWrapping = 1000;
1910var ClampToEdgeWrapping = 1001;
1911var MirroredRepeatWrapping = 1002;
1912var NearestFilter = 1003;
1913var NearestMipMapNearestFilter = 1004;
1914var NearestMipMapLinearFilter = 1005;
1915var LinearFilter = 1006;
1916var LinearMipMapNearestFilter = 1007;
1917var LinearMipMapLinearFilter = 1008;
1918var UnsignedByteType = 1009;
1919var ByteType = 1010;
1920var ShortType = 1011;
1921var UnsignedShortType = 1012;
1922var IntType = 1013;
1923var UnsignedIntType = 1014;
1924var FloatType = 1015;
1925var HalfFloatType = 1016;
1926var UnsignedShort4444Type = 1017;
1927var UnsignedShort5551Type = 1018;
1928var UnsignedShort565Type = 1019;
1929var UnsignedInt248Type = 1020;
1930var AlphaFormat = 1021;
1931var RGBFormat = 1022;
1932var RGBAFormat = 1023;
1933var LuminanceFormat = 1024;
1934var LuminanceAlphaFormat = 1025;
1935
1936var DepthFormat = 1026;
1937var DepthStencilFormat = 1027;
1938var RGB_S3TC_DXT1_Format = 2001;
1939var RGBA_S3TC_DXT1_Format = 2002;
1940var RGBA_S3TC_DXT3_Format = 2003;
1941var RGBA_S3TC_DXT5_Format = 2004;
1942var RGB_PVRTC_4BPPV1_Format = 2100;
1943var RGB_PVRTC_2BPPV1_Format = 2101;
1944var RGBA_PVRTC_4BPPV1_Format = 2102;
1945var RGBA_PVRTC_2BPPV1_Format = 2103;
1946var RGB_ETC1_Format = 2151;
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956var TrianglesDrawMode = 0;
1957var TriangleStripDrawMode = 1;
1958var TriangleFanDrawMode = 2;
1959var LinearEncoding = 3000;
1960var sRGBEncoding = 3001;
1961var GammaEncoding = 3007;
1962var RGBEEncoding = 3002;
1963
1964var RGBM7Encoding = 3004;
1965var RGBM16Encoding = 3005;
1966var RGBDEncoding = 3006;
1967var BasicDepthPacking = 3200;
1968var RGBADepthPacking = 3201;
1969
1970/**
1971 * @author alteredq / http://alteredqualia.com/
1972 * @author mrdoob / http://mrdoob.com/
1973 */
1974
1975var _Math = {
1976
1977 DEG2RAD: Math.PI / 180,
1978 RAD2DEG: 180 / Math.PI,
1979
1980 generateUUID: ( function () {
1981
1982 // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
1983
1984 var lut = [];
1985
1986 for ( var i = 0; i < 256; i ++ ) {
1987
1988 lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 ).toUpperCase();
1989
1990 }
1991
1992 return function () {
1993
1994 var d0 = Math.random() * 0xffffffff | 0;
1995 var d1 = Math.random() * 0xffffffff | 0;
1996 var d2 = Math.random() * 0xffffffff | 0;
1997 var d3 = Math.random() * 0xffffffff | 0;
1998 return lut[ d0 & 0xff ] + lut[ d0 >> 8 & 0xff ] + lut[ d0 >> 16 & 0xff ] + lut[ d0 >> 24 & 0xff ] + '-' +
1999 lut[ d1 & 0xff ] + lut[ d1 >> 8 & 0xff ] + '-' + lut[ d1 >> 16 & 0x0f | 0x40 ] + lut[ d1 >> 24 & 0xff ] + '-' +
2000 lut[ d2 & 0x3f | 0x80 ] + lut[ d2 >> 8 & 0xff ] + '-' + lut[ d2 >> 16 & 0xff ] + lut[ d2 >> 24 & 0xff ] +
2001 lut[ d3 & 0xff ] + lut[ d3 >> 8 & 0xff ] + lut[ d3 >> 16 & 0xff ] + lut[ d3 >> 24 & 0xff ];
2002
2003 };
2004
2005 } )(),
2006
2007 clamp: function ( value, min, max ) {
2008
2009 return Math.max( min, Math.min( max, value ) );
2010
2011 },
2012
2013 // compute euclidian modulo of m % n
2014 // https://en.wikipedia.org/wiki/Modulo_operation
2015
2016 euclideanModulo: function ( n, m ) {
2017
2018 return ( ( n % m ) + m ) % m;
2019
2020 },
2021
2022 // Linear mapping from range <a1, a2> to range <b1, b2>
2023
2024 mapLinear: function ( x, a1, a2, b1, b2 ) {
2025
2026 return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
2027
2028 },
2029
2030 // https://en.wikipedia.org/wiki/Linear_interpolation
2031
2032 lerp: function ( x, y, t ) {
2033
2034 return ( 1 - t ) * x + t * y;
2035
2036 },
2037
2038 // http://en.wikipedia.org/wiki/Smoothstep
2039
2040 smoothstep: function ( x, min, max ) {
2041
2042 if ( x <= min ) return 0;
2043 if ( x >= max ) return 1;
2044
2045 x = ( x - min ) / ( max - min );
2046
2047 return x * x * ( 3 - 2 * x );
2048
2049 },
2050
2051 smootherstep: function ( x, min, max ) {
2052
2053 if ( x <= min ) return 0;
2054 if ( x >= max ) return 1;
2055
2056 x = ( x - min ) / ( max - min );
2057
2058 return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
2059
2060 },
2061
2062 // Random integer from <low, high> interval
2063
2064 randInt: function ( low, high ) {
2065
2066 return low + Math.floor( Math.random() * ( high - low + 1 ) );
2067
2068 },
2069
2070 // Random float from <low, high> interval
2071
2072 randFloat: function ( low, high ) {
2073
2074 return low + Math.random() * ( high - low );
2075
2076 },
2077
2078 // Random float from <-range/2, range/2> interval
2079
2080 randFloatSpread: function ( range ) {
2081
2082 return range * ( 0.5 - Math.random() );
2083
2084 },
2085
2086 degToRad: function ( degrees ) {
2087
2088 return degrees * _Math.DEG2RAD;
2089
2090 },
2091
2092 radToDeg: function ( radians ) {
2093
2094 return radians * _Math.RAD2DEG;
2095
2096 },
2097
2098 isPowerOfTwo: function ( value ) {
2099
2100 return ( value & ( value - 1 ) ) === 0 && value !== 0;
2101
2102 },
2103
2104 ceilPowerOfTwo: function ( value ) {
2105
2106 return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );
2107
2108 },
2109
2110 floorPowerOfTwo: function ( value ) {
2111
2112 return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );
2113
2114 }
2115
2116};
2117
2118/**
2119 * @author mrdoob / http://mrdoob.com/
2120 * @author philogb / http://blog.thejit.org/
2121 * @author egraether / http://egraether.com/
2122 * @author zz85 / http://www.lab4games.net/zz85/blog
2123 */
2124
2125function Vector2( x, y ) {
2126
2127 this.x = x || 0;
2128 this.y = y || 0;
2129
2130}
2131
2132Object.defineProperties( Vector2.prototype, {
2133
2134 "width": {
2135
2136 get: function () {
2137
2138 return this.x;
2139
2140 },
2141
2142 set: function ( value ) {
2143
2144 this.x = value;
2145
2146 }
2147
2148 },
2149
2150 "height": {
2151
2152 get: function () {
2153
2154 return this.y;
2155
2156 },
2157
2158 set: function ( value ) {
2159
2160 this.y = value;
2161
2162 }
2163
2164 }
2165
2166} );
2167
2168Object.assign( Vector2.prototype, {
2169
2170 isVector2: true,
2171
2172 set: function ( x, y ) {
2173
2174 this.x = x;
2175 this.y = y;
2176
2177 return this;
2178
2179 },
2180
2181 setScalar: function ( scalar ) {
2182
2183 this.x = scalar;
2184 this.y = scalar;
2185
2186 return this;
2187
2188 },
2189
2190 setX: function ( x ) {
2191
2192 this.x = x;
2193
2194 return this;
2195
2196 },
2197
2198 setY: function ( y ) {
2199
2200 this.y = y;
2201
2202 return this;
2203
2204 },
2205
2206 setComponent: function ( index, value ) {
2207
2208 switch ( index ) {
2209
2210 case 0: this.x = value; break;
2211 case 1: this.y = value; break;
2212 default: throw new Error( 'index is out of range: ' + index );
2213
2214 }
2215
2216 return this;
2217
2218 },
2219
2220 getComponent: function ( index ) {
2221
2222 switch ( index ) {
2223
2224 case 0: return this.x;
2225 case 1: return this.y;
2226 default: throw new Error( 'index is out of range: ' + index );
2227
2228 }
2229
2230 },
2231
2232 clone: function () {
2233
2234 return new this.constructor( this.x, this.y );
2235
2236 },
2237
2238 copy: function ( v ) {
2239
2240 this.x = v.x;
2241 this.y = v.y;
2242
2243 return this;
2244
2245 },
2246
2247 add: function ( v, w ) {
2248
2249 if ( w !== undefined ) {
2250
2251 console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
2252 return this.addVectors( v, w );
2253
2254 }
2255
2256 this.x += v.x;
2257 this.y += v.y;
2258
2259 return this;
2260
2261 },
2262
2263 addScalar: function ( s ) {
2264
2265 this.x += s;
2266 this.y += s;
2267
2268 return this;
2269
2270 },
2271
2272 addVectors: function ( a, b ) {
2273
2274 this.x = a.x + b.x;
2275 this.y = a.y + b.y;
2276
2277 return this;
2278
2279 },
2280
2281 addScaledVector: function ( v, s ) {
2282
2283 this.x += v.x * s;
2284 this.y += v.y * s;
2285
2286 return this;
2287
2288 },
2289
2290 sub: function ( v, w ) {
2291
2292 if ( w !== undefined ) {
2293
2294 console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
2295 return this.subVectors( v, w );
2296
2297 }
2298
2299 this.x -= v.x;
2300 this.y -= v.y;
2301
2302 return this;
2303
2304 },
2305
2306 subScalar: function ( s ) {
2307
2308 this.x -= s;
2309 this.y -= s;
2310
2311 return this;
2312
2313 },
2314
2315 subVectors: function ( a, b ) {
2316
2317 this.x = a.x - b.x;
2318 this.y = a.y - b.y;
2319
2320 return this;
2321
2322 },
2323
2324 multiply: function ( v ) {
2325
2326 this.x *= v.x;
2327 this.y *= v.y;
2328
2329 return this;
2330
2331 },
2332
2333 multiplyScalar: function ( scalar ) {
2334
2335 this.x *= scalar;
2336 this.y *= scalar;
2337
2338 return this;
2339
2340 },
2341
2342 divide: function ( v ) {
2343
2344 this.x /= v.x;
2345 this.y /= v.y;
2346
2347 return this;
2348
2349 },
2350
2351 divideScalar: function ( scalar ) {
2352
2353 return this.multiplyScalar( 1 / scalar );
2354
2355 },
2356
2357 applyMatrix3: function ( m ) {
2358
2359 var x = this.x, y = this.y;
2360 var e = m.elements;
2361
2362 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ];
2363 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ];
2364
2365 return this;
2366
2367 },
2368
2369 min: function ( v ) {
2370
2371 this.x = Math.min( this.x, v.x );
2372 this.y = Math.min( this.y, v.y );
2373
2374 return this;
2375
2376 },
2377
2378 max: function ( v ) {
2379
2380 this.x = Math.max( this.x, v.x );
2381 this.y = Math.max( this.y, v.y );
2382
2383 return this;
2384
2385 },
2386
2387 clamp: function ( min, max ) {
2388
2389 // assumes min < max, componentwise
2390
2391 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
2392 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
2393
2394 return this;
2395
2396 },
2397
2398 clampScalar: function () {
2399
2400 var min = new Vector2();
2401 var max = new Vector2();
2402
2403 return function clampScalar( minVal, maxVal ) {
2404
2405 min.set( minVal, minVal );
2406 max.set( maxVal, maxVal );
2407
2408 return this.clamp( min, max );
2409
2410 };
2411
2412 }(),
2413
2414 clampLength: function ( min, max ) {
2415
2416 var length = this.length();
2417
2418 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
2419
2420 },
2421
2422 floor: function () {
2423
2424 this.x = Math.floor( this.x );
2425 this.y = Math.floor( this.y );
2426
2427 return this;
2428
2429 },
2430
2431 ceil: function () {
2432
2433 this.x = Math.ceil( this.x );
2434 this.y = Math.ceil( this.y );
2435
2436 return this;
2437
2438 },
2439
2440 round: function () {
2441
2442 this.x = Math.round( this.x );
2443 this.y = Math.round( this.y );
2444
2445 return this;
2446
2447 },
2448
2449 roundToZero: function () {
2450
2451 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
2452 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
2453
2454 return this;
2455
2456 },
2457
2458 negate: function () {
2459
2460 this.x = - this.x;
2461 this.y = - this.y;
2462
2463 return this;
2464
2465 },
2466
2467 dot: function ( v ) {
2468
2469 return this.x * v.x + this.y * v.y;
2470
2471 },
2472
2473 lengthSq: function () {
2474
2475 return this.x * this.x + this.y * this.y;
2476
2477 },
2478
2479 length: function () {
2480
2481 return Math.sqrt( this.x * this.x + this.y * this.y );
2482
2483 },
2484
2485 manhattanLength: function () {
2486
2487 return Math.abs( this.x ) + Math.abs( this.y );
2488
2489 },
2490
2491 normalize: function () {
2492
2493 return this.divideScalar( this.length() || 1 );
2494
2495 },
2496
2497 angle: function () {
2498
2499 // computes the angle in radians with respect to the positive x-axis
2500
2501 var angle = Math.atan2( this.y, this.x );
2502
2503 if ( angle < 0 ) angle += 2 * Math.PI;
2504
2505 return angle;
2506
2507 },
2508
2509 distanceTo: function ( v ) {
2510
2511 return Math.sqrt( this.distanceToSquared( v ) );
2512
2513 },
2514
2515 distanceToSquared: function ( v ) {
2516
2517 var dx = this.x - v.x, dy = this.y - v.y;
2518 return dx * dx + dy * dy;
2519
2520 },
2521
2522 manhattanDistanceTo: function ( v ) {
2523
2524 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );
2525
2526 },
2527
2528 setLength: function ( length ) {
2529
2530 return this.normalize().multiplyScalar( length );
2531
2532 },
2533
2534 lerp: function ( v, alpha ) {
2535
2536 this.x += ( v.x - this.x ) * alpha;
2537 this.y += ( v.y - this.y ) * alpha;
2538
2539 return this;
2540
2541 },
2542
2543 lerpVectors: function ( v1, v2, alpha ) {
2544
2545 return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
2546
2547 },
2548
2549 equals: function ( v ) {
2550
2551 return ( ( v.x === this.x ) && ( v.y === this.y ) );
2552
2553 },
2554
2555 fromArray: function ( array, offset ) {
2556
2557 if ( offset === undefined ) offset = 0;
2558
2559 this.x = array[ offset ];
2560 this.y = array[ offset + 1 ];
2561
2562 return this;
2563
2564 },
2565
2566 toArray: function ( array, offset ) {
2567
2568 if ( array === undefined ) array = [];
2569 if ( offset === undefined ) offset = 0;
2570
2571 array[ offset ] = this.x;
2572 array[ offset + 1 ] = this.y;
2573
2574 return array;
2575
2576 },
2577
2578 fromBufferAttribute: function ( attribute, index, offset ) {
2579
2580 if ( offset !== undefined ) {
2581
2582 console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' );
2583
2584 }
2585
2586 this.x = attribute.getX( index );
2587 this.y = attribute.getY( index );
2588
2589 return this;
2590
2591 },
2592
2593 rotateAround: function ( center, angle ) {
2594
2595 var c = Math.cos( angle ), s = Math.sin( angle );
2596
2597 var x = this.x - center.x;
2598 var y = this.y - center.y;
2599
2600 this.x = x * c - y * s + center.x;
2601 this.y = x * s + y * c + center.y;
2602
2603 return this;
2604
2605 }
2606
2607} );
2608
2609/**
2610 * @author mrdoob / http://mrdoob.com/
2611 * @author supereggbert / http://www.paulbrunt.co.uk/
2612 * @author philogb / http://blog.thejit.org/
2613 * @author jordi_ros / http://plattsoft.com
2614 * @author D1plo1d / http://github.com/D1plo1d
2615 * @author alteredq / http://alteredqualia.com/
2616 * @author mikael emtinger / http://gomo.se/
2617 * @author timknip / http://www.floorplanner.com/
2618 * @author bhouston / http://clara.io
2619 * @author WestLangley / http://github.com/WestLangley
2620 */
2621
2622function Matrix4() {
2623
2624 this.elements = [
2625
2626 1, 0, 0, 0,
2627 0, 1, 0, 0,
2628 0, 0, 1, 0,
2629 0, 0, 0, 1
2630
2631 ];
2632
2633 if ( arguments.length > 0 ) {
2634
2635 console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );
2636
2637 }
2638
2639}
2640
2641Object.assign( Matrix4.prototype, {
2642
2643 isMatrix4: true,
2644
2645 set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
2646
2647 var te = this.elements;
2648
2649 te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;
2650 te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;
2651 te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;
2652 te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;
2653
2654 return this;
2655
2656 },
2657
2658 identity: function () {
2659
2660 this.set(
2661
2662 1, 0, 0, 0,
2663 0, 1, 0, 0,
2664 0, 0, 1, 0,
2665 0, 0, 0, 1
2666
2667 );
2668
2669 return this;
2670
2671 },
2672
2673 clone: function () {
2674
2675 return new Matrix4().fromArray( this.elements );
2676
2677 },
2678
2679 copy: function ( m ) {
2680
2681 var te = this.elements;
2682 var me = m.elements;
2683
2684 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];
2685 te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];
2686 te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];
2687 te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];
2688
2689 return this;
2690
2691 },
2692
2693 copyPosition: function ( m ) {
2694
2695 var te = this.elements, me = m.elements;
2696
2697 te[ 12 ] = me[ 12 ];
2698 te[ 13 ] = me[ 13 ];
2699 te[ 14 ] = me[ 14 ];
2700
2701 return this;
2702
2703 },
2704
2705 extractBasis: function ( xAxis, yAxis, zAxis ) {
2706
2707 xAxis.setFromMatrixColumn( this, 0 );
2708 yAxis.setFromMatrixColumn( this, 1 );
2709 zAxis.setFromMatrixColumn( this, 2 );
2710
2711 return this;
2712
2713 },
2714
2715 makeBasis: function ( xAxis, yAxis, zAxis ) {
2716
2717 this.set(
2718 xAxis.x, yAxis.x, zAxis.x, 0,
2719 xAxis.y, yAxis.y, zAxis.y, 0,
2720 xAxis.z, yAxis.z, zAxis.z, 0,
2721 0, 0, 0, 1
2722 );
2723
2724 return this;
2725
2726 },
2727
2728 extractRotation: function () {
2729
2730 var v1 = new Vector3();
2731
2732 return function extractRotation( m ) {
2733
2734 var te = this.elements;
2735 var me = m.elements;
2736
2737 var scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length();
2738 var scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length();
2739 var scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).length();
2740
2741 te[ 0 ] = me[ 0 ] * scaleX;
2742 te[ 1 ] = me[ 1 ] * scaleX;
2743 te[ 2 ] = me[ 2 ] * scaleX;
2744
2745 te[ 4 ] = me[ 4 ] * scaleY;
2746 te[ 5 ] = me[ 5 ] * scaleY;
2747 te[ 6 ] = me[ 6 ] * scaleY;
2748
2749 te[ 8 ] = me[ 8 ] * scaleZ;
2750 te[ 9 ] = me[ 9 ] * scaleZ;
2751 te[ 10 ] = me[ 10 ] * scaleZ;
2752
2753 return this;
2754
2755 };
2756
2757 }(),
2758
2759 makeRotationFromEuler: function ( euler ) {
2760
2761 if ( ! ( euler && euler.isEuler ) ) {
2762
2763 console.error( 'THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
2764
2765 }
2766
2767 var te = this.elements;
2768
2769 var x = euler.x, y = euler.y, z = euler.z;
2770 var a = Math.cos( x ), b = Math.sin( x );
2771 var c = Math.cos( y ), d = Math.sin( y );
2772 var e = Math.cos( z ), f = Math.sin( z );
2773
2774 if ( euler.order === 'XYZ' ) {
2775
2776 var ae = a * e, af = a * f, be = b * e, bf = b * f;
2777
2778 te[ 0 ] = c * e;
2779 te[ 4 ] = - c * f;
2780 te[ 8 ] = d;
2781
2782 te[ 1 ] = af + be * d;
2783 te[ 5 ] = ae - bf * d;
2784 te[ 9 ] = - b * c;
2785
2786 te[ 2 ] = bf - ae * d;
2787 te[ 6 ] = be + af * d;
2788 te[ 10 ] = a * c;
2789
2790 } else if ( euler.order === 'YXZ' ) {
2791
2792 var ce = c * e, cf = c * f, de = d * e, df = d * f;
2793
2794 te[ 0 ] = ce + df * b;
2795 te[ 4 ] = de * b - cf;
2796 te[ 8 ] = a * d;
2797
2798 te[ 1 ] = a * f;
2799 te[ 5 ] = a * e;
2800 te[ 9 ] = - b;
2801
2802 te[ 2 ] = cf * b - de;
2803 te[ 6 ] = df + ce * b;
2804 te[ 10 ] = a * c;
2805
2806 } else if ( euler.order === 'ZXY' ) {
2807
2808 var ce = c * e, cf = c * f, de = d * e, df = d * f;
2809
2810 te[ 0 ] = ce - df * b;
2811 te[ 4 ] = - a * f;
2812 te[ 8 ] = de + cf * b;
2813
2814 te[ 1 ] = cf + de * b;
2815 te[ 5 ] = a * e;
2816 te[ 9 ] = df - ce * b;
2817
2818 te[ 2 ] = - a * d;
2819 te[ 6 ] = b;
2820 te[ 10 ] = a * c;
2821
2822 } else if ( euler.order === 'ZYX' ) {
2823
2824 var ae = a * e, af = a * f, be = b * e, bf = b * f;
2825
2826 te[ 0 ] = c * e;
2827 te[ 4 ] = be * d - af;
2828 te[ 8 ] = ae * d + bf;
2829
2830 te[ 1 ] = c * f;
2831 te[ 5 ] = bf * d + ae;
2832 te[ 9 ] = af * d - be;
2833
2834 te[ 2 ] = - d;
2835 te[ 6 ] = b * c;
2836 te[ 10 ] = a * c;
2837
2838 } else if ( euler.order === 'YZX' ) {
2839
2840 var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
2841
2842 te[ 0 ] = c * e;
2843 te[ 4 ] = bd - ac * f;
2844 te[ 8 ] = bc * f + ad;
2845
2846 te[ 1 ] = f;
2847 te[ 5 ] = a * e;
2848 te[ 9 ] = - b * e;
2849
2850 te[ 2 ] = - d * e;
2851 te[ 6 ] = ad * f + bc;
2852 te[ 10 ] = ac - bd * f;
2853
2854 } else if ( euler.order === 'XZY' ) {
2855
2856 var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
2857
2858 te[ 0 ] = c * e;
2859 te[ 4 ] = - f;
2860 te[ 8 ] = d * e;
2861
2862 te[ 1 ] = ac * f + bd;
2863 te[ 5 ] = a * e;
2864 te[ 9 ] = ad * f - bc;
2865
2866 te[ 2 ] = bc * f - ad;
2867 te[ 6 ] = b * e;
2868 te[ 10 ] = bd * f + ac;
2869
2870 }
2871
2872 // last column
2873 te[ 3 ] = 0;
2874 te[ 7 ] = 0;
2875 te[ 11 ] = 0;
2876
2877 // bottom row
2878 te[ 12 ] = 0;
2879 te[ 13 ] = 0;
2880 te[ 14 ] = 0;
2881 te[ 15 ] = 1;
2882
2883 return this;
2884
2885 },
2886
2887 makeRotationFromQuaternion: function ( q ) {
2888
2889 var te = this.elements;
2890
2891 var x = q._x, y = q._y, z = q._z, w = q._w;
2892 var x2 = x + x, y2 = y + y, z2 = z + z;
2893 var xx = x * x2, xy = x * y2, xz = x * z2;
2894 var yy = y * y2, yz = y * z2, zz = z * z2;
2895 var wx = w * x2, wy = w * y2, wz = w * z2;
2896
2897 te[ 0 ] = 1 - ( yy + zz );
2898 te[ 4 ] = xy - wz;
2899 te[ 8 ] = xz + wy;
2900
2901 te[ 1 ] = xy + wz;
2902 te[ 5 ] = 1 - ( xx + zz );
2903 te[ 9 ] = yz - wx;
2904
2905 te[ 2 ] = xz - wy;
2906 te[ 6 ] = yz + wx;
2907 te[ 10 ] = 1 - ( xx + yy );
2908
2909 // last column
2910 te[ 3 ] = 0;
2911 te[ 7 ] = 0;
2912 te[ 11 ] = 0;
2913
2914 // bottom row
2915 te[ 12 ] = 0;
2916 te[ 13 ] = 0;
2917 te[ 14 ] = 0;
2918 te[ 15 ] = 1;
2919
2920 return this;
2921
2922 },
2923
2924 lookAt: function () {
2925
2926 var x = new Vector3();
2927 var y = new Vector3();
2928 var z = new Vector3();
2929
2930 return function lookAt( eye, target, up ) {
2931
2932 var te = this.elements;
2933
2934 z.subVectors( eye, target );
2935
2936 if ( z.lengthSq() === 0 ) {
2937
2938 // eye and target are in the same position
2939
2940 z.z = 1;
2941
2942 }
2943
2944 z.normalize();
2945 x.crossVectors( up, z );
2946
2947 if ( x.lengthSq() === 0 ) {
2948
2949 // up and z are parallel
2950
2951 if ( Math.abs( up.z ) === 1 ) {
2952
2953 z.x += 0.0001;
2954
2955 } else {
2956
2957 z.z += 0.0001;
2958
2959 }
2960
2961 z.normalize();
2962 x.crossVectors( up, z );
2963
2964 }
2965
2966 x.normalize();
2967 y.crossVectors( z, x );
2968
2969 te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
2970 te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
2971 te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;
2972
2973 return this;
2974
2975 };
2976
2977 }(),
2978
2979 multiply: function ( m, n ) {
2980
2981 if ( n !== undefined ) {
2982
2983 console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' );
2984 return this.multiplyMatrices( m, n );
2985
2986 }
2987
2988 return this.multiplyMatrices( this, m );
2989
2990 },
2991
2992 premultiply: function ( m ) {
2993
2994 return this.multiplyMatrices( m, this );
2995
2996 },
2997
2998 multiplyMatrices: function ( a, b ) {
2999
3000 var ae = a.elements;
3001 var be = b.elements;
3002 var te = this.elements;
3003
3004 var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];
3005 var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];
3006 var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];
3007 var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];
3008
3009 var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];
3010 var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];
3011 var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];
3012 var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];
3013
3014 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
3015 te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
3016 te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
3017 te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
3018
3019 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
3020 te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
3021 te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
3022 te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
3023
3024 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
3025 te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
3026 te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
3027 te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
3028
3029 te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
3030 te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
3031 te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
3032 te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
3033
3034 return this;
3035
3036 },
3037
3038 multiplyScalar: function ( s ) {
3039
3040 var te = this.elements;
3041
3042 te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;
3043 te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;
3044 te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;
3045 te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;
3046
3047 return this;
3048
3049 },
3050
3051 applyToBufferAttribute: function () {
3052
3053 var v1 = new Vector3();
3054
3055 return function applyToBufferAttribute( attribute ) {
3056
3057 for ( var i = 0, l = attribute.count; i < l; i ++ ) {
3058
3059 v1.x = attribute.getX( i );
3060 v1.y = attribute.getY( i );
3061 v1.z = attribute.getZ( i );
3062
3063 v1.applyMatrix4( this );
3064
3065 attribute.setXYZ( i, v1.x, v1.y, v1.z );
3066
3067 }
3068
3069 return attribute;
3070
3071 };
3072
3073 }(),
3074
3075 determinant: function () {
3076
3077 var te = this.elements;
3078
3079 var n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];
3080 var n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];
3081 var n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];
3082 var n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];
3083
3084 //TODO: make this more efficient
3085 //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
3086
3087 return (
3088 n41 * (
3089 + n14 * n23 * n32
3090 - n13 * n24 * n32
3091 - n14 * n22 * n33
3092 + n12 * n24 * n33
3093 + n13 * n22 * n34
3094 - n12 * n23 * n34
3095 ) +
3096 n42 * (
3097 + n11 * n23 * n34
3098 - n11 * n24 * n33
3099 + n14 * n21 * n33
3100 - n13 * n21 * n34
3101 + n13 * n24 * n31
3102 - n14 * n23 * n31
3103 ) +
3104 n43 * (
3105 + n11 * n24 * n32
3106 - n11 * n22 * n34
3107 - n14 * n21 * n32
3108 + n12 * n21 * n34
3109 + n14 * n22 * n31
3110 - n12 * n24 * n31
3111 ) +
3112 n44 * (
3113 - n13 * n22 * n31
3114 - n11 * n23 * n32
3115 + n11 * n22 * n33
3116 + n13 * n21 * n32
3117 - n12 * n21 * n33
3118 + n12 * n23 * n31
3119 )
3120
3121 );
3122
3123 },
3124
3125 transpose: function () {
3126
3127 var te = this.elements;
3128 var tmp;
3129
3130 tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;
3131 tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;
3132 tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;
3133
3134 tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;
3135 tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;
3136 tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;
3137
3138 return this;
3139
3140 },
3141
3142 setPosition: function ( v ) {
3143
3144 var te = this.elements;
3145
3146 te[ 12 ] = v.x;
3147 te[ 13 ] = v.y;
3148 te[ 14 ] = v.z;
3149
3150 return this;
3151
3152 },
3153
3154 getInverse: function ( m, throwOnDegenerate ) {
3155
3156 // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
3157 var te = this.elements,
3158 me = m.elements,
3159
3160 n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ],
3161 n12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ],
3162 n13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ],
3163 n14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ],
3164
3165 t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
3166 t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
3167 t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
3168 t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
3169
3170 var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
3171
3172 if ( det === 0 ) {
3173
3174 var msg = "THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0";
3175
3176 if ( throwOnDegenerate === true ) {
3177
3178 throw new Error( msg );
3179
3180 } else {
3181
3182 console.warn( msg );
3183
3184 }
3185
3186 return this.identity();
3187
3188 }
3189
3190 var detInv = 1 / det;
3191
3192 te[ 0 ] = t11 * detInv;
3193 te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;
3194 te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;
3195 te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;
3196
3197 te[ 4 ] = t12 * detInv;
3198 te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;
3199 te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;
3200 te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;
3201
3202 te[ 8 ] = t13 * detInv;
3203 te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;
3204 te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;
3205 te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;
3206
3207 te[ 12 ] = t14 * detInv;
3208 te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;
3209 te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;
3210 te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;
3211
3212 return this;
3213
3214 },
3215
3216 scale: function ( v ) {
3217
3218 var te = this.elements;
3219 var x = v.x, y = v.y, z = v.z;
3220
3221 te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;
3222 te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;
3223 te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;
3224 te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;
3225
3226 return this;
3227
3228 },
3229
3230 getMaxScaleOnAxis: function () {
3231
3232 var te = this.elements;
3233
3234 var scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];
3235 var scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];
3236 var scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];
3237
3238 return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );
3239
3240 },
3241
3242 makeTranslation: function ( x, y, z ) {
3243
3244 this.set(
3245
3246 1, 0, 0, x,
3247 0, 1, 0, y,
3248 0, 0, 1, z,
3249 0, 0, 0, 1
3250
3251 );
3252
3253 return this;
3254
3255 },
3256
3257 makeRotationX: function ( theta ) {
3258
3259 var c = Math.cos( theta ), s = Math.sin( theta );
3260
3261 this.set(
3262
3263 1, 0, 0, 0,
3264 0, c, - s, 0,
3265 0, s, c, 0,
3266 0, 0, 0, 1
3267
3268 );
3269
3270 return this;
3271
3272 },
3273
3274 makeRotationY: function ( theta ) {
3275
3276 var c = Math.cos( theta ), s = Math.sin( theta );
3277
3278 this.set(
3279
3280 c, 0, s, 0,
3281 0, 1, 0, 0,
3282 - s, 0, c, 0,
3283 0, 0, 0, 1
3284
3285 );
3286
3287 return this;
3288
3289 },
3290
3291 makeRotationZ: function ( theta ) {
3292
3293 var c = Math.cos( theta ), s = Math.sin( theta );
3294
3295 this.set(
3296
3297 c, - s, 0, 0,
3298 s, c, 0, 0,
3299 0, 0, 1, 0,
3300 0, 0, 0, 1
3301
3302 );
3303
3304 return this;
3305
3306 },
3307
3308 makeRotationAxis: function ( axis, angle ) {
3309
3310 // Based on http://www.gamedev.net/reference/articles/article1199.asp
3311
3312 var c = Math.cos( angle );
3313 var s = Math.sin( angle );
3314 var t = 1 - c;
3315 var x = axis.x, y = axis.y, z = axis.z;
3316 var tx = t * x, ty = t * y;
3317
3318 this.set(
3319
3320 tx * x + c, tx * y - s * z, tx * z + s * y, 0,
3321 tx * y + s * z, ty * y + c, ty * z - s * x, 0,
3322 tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
3323 0, 0, 0, 1
3324
3325 );
3326
3327 return this;
3328
3329 },
3330
3331 makeScale: function ( x, y, z ) {
3332
3333 this.set(
3334
3335 x, 0, 0, 0,
3336 0, y, 0, 0,
3337 0, 0, z, 0,
3338 0, 0, 0, 1
3339
3340 );
3341
3342 return this;
3343
3344 },
3345
3346 makeShear: function ( x, y, z ) {
3347
3348 this.set(
3349
3350 1, y, z, 0,
3351 x, 1, z, 0,
3352 x, y, 1, 0,
3353 0, 0, 0, 1
3354
3355 );
3356
3357 return this;
3358
3359 },
3360
3361 compose: function ( position, quaternion, scale ) {
3362
3363 this.makeRotationFromQuaternion( quaternion );
3364 this.scale( scale );
3365 this.setPosition( position );
3366
3367 return this;
3368
3369 },
3370
3371 decompose: function () {
3372
3373 var vector = new Vector3();
3374 var matrix = new Matrix4();
3375
3376 return function decompose( position, quaternion, scale ) {
3377
3378 var te = this.elements;
3379
3380 var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
3381 var sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
3382 var sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
3383
3384 // if determine is negative, we need to invert one scale
3385 var det = this.determinant();
3386 if ( det < 0 ) sx = - sx;
3387
3388 position.x = te[ 12 ];
3389 position.y = te[ 13 ];
3390 position.z = te[ 14 ];
3391
3392 // scale the rotation part
3393 matrix.copy( this );
3394
3395 var invSX = 1 / sx;
3396 var invSY = 1 / sy;
3397 var invSZ = 1 / sz;
3398
3399 matrix.elements[ 0 ] *= invSX;
3400 matrix.elements[ 1 ] *= invSX;
3401 matrix.elements[ 2 ] *= invSX;
3402
3403 matrix.elements[ 4 ] *= invSY;
3404 matrix.elements[ 5 ] *= invSY;
3405 matrix.elements[ 6 ] *= invSY;
3406
3407 matrix.elements[ 8 ] *= invSZ;
3408 matrix.elements[ 9 ] *= invSZ;
3409 matrix.elements[ 10 ] *= invSZ;
3410
3411 quaternion.setFromRotationMatrix( matrix );
3412
3413 scale.x = sx;
3414 scale.y = sy;
3415 scale.z = sz;
3416
3417 return this;
3418
3419 };
3420
3421 }(),
3422
3423 makePerspective: function ( left, right, top, bottom, near, far ) {
3424
3425 if ( far === undefined ) {
3426
3427 console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' );
3428
3429 }
3430
3431 var te = this.elements;
3432 var x = 2 * near / ( right - left );
3433 var y = 2 * near / ( top - bottom );
3434
3435 var a = ( right + left ) / ( right - left );
3436 var b = ( top + bottom ) / ( top - bottom );
3437 var c = - ( far + near ) / ( far - near );
3438 var d = - 2 * far * near / ( far - near );
3439
3440 te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0;
3441 te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0;
3442 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d;
3443 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0;
3444
3445 return this;
3446
3447 },
3448
3449 makeOrthographic: function ( left, right, top, bottom, near, far ) {
3450
3451 var te = this.elements;
3452 var w = 1.0 / ( right - left );
3453 var h = 1.0 / ( top - bottom );
3454 var p = 1.0 / ( far - near );
3455
3456 var x = ( right + left ) * w;
3457 var y = ( top + bottom ) * h;
3458 var z = ( far + near ) * p;
3459
3460 te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x;
3461 te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y;
3462 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z;
3463 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1;
3464
3465 return this;
3466
3467 },
3468
3469 equals: function ( matrix ) {
3470
3471 var te = this.elements;
3472 var me = matrix.elements;
3473
3474 for ( var i = 0; i < 16; i ++ ) {
3475
3476 if ( te[ i ] !== me[ i ] ) return false;
3477
3478 }
3479
3480 return true;
3481
3482 },
3483
3484 fromArray: function ( array, offset ) {
3485
3486 if ( offset === undefined ) offset = 0;
3487
3488 for ( var i = 0; i < 16; i ++ ) {
3489
3490 this.elements[ i ] = array[ i + offset ];
3491
3492 }
3493
3494 return this;
3495
3496 },
3497
3498 toArray: function ( array, offset ) {
3499
3500 if ( array === undefined ) array = [];
3501 if ( offset === undefined ) offset = 0;
3502
3503 var te = this.elements;
3504
3505 array[ offset ] = te[ 0 ];
3506 array[ offset + 1 ] = te[ 1 ];
3507 array[ offset + 2 ] = te[ 2 ];
3508 array[ offset + 3 ] = te[ 3 ];
3509
3510 array[ offset + 4 ] = te[ 4 ];
3511 array[ offset + 5 ] = te[ 5 ];
3512 array[ offset + 6 ] = te[ 6 ];
3513 array[ offset + 7 ] = te[ 7 ];
3514
3515 array[ offset + 8 ] = te[ 8 ];
3516 array[ offset + 9 ] = te[ 9 ];
3517 array[ offset + 10 ] = te[ 10 ];
3518 array[ offset + 11 ] = te[ 11 ];
3519
3520 array[ offset + 12 ] = te[ 12 ];
3521 array[ offset + 13 ] = te[ 13 ];
3522 array[ offset + 14 ] = te[ 14 ];
3523 array[ offset + 15 ] = te[ 15 ];
3524
3525 return array;
3526
3527 }
3528
3529} );
3530
3531/**
3532 * @author mikael emtinger / http://gomo.se/
3533 * @author alteredq / http://alteredqualia.com/
3534 * @author WestLangley / http://github.com/WestLangley
3535 * @author bhouston / http://clara.io
3536 */
3537
3538function Quaternion( x, y, z, w ) {
3539
3540 this._x = x || 0;
3541 this._y = y || 0;
3542 this._z = z || 0;
3543 this._w = ( w !== undefined ) ? w : 1;
3544
3545}
3546
3547Object.assign( Quaternion, {
3548
3549 slerp: function ( qa, qb, qm, t ) {
3550
3551 return qm.copy( qa ).slerp( qb, t );
3552
3553 },
3554
3555 slerpFlat: function ( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
3556
3557 // fuzz-free, array-based Quaternion SLERP operation
3558
3559 var x0 = src0[ srcOffset0 + 0 ],
3560 y0 = src0[ srcOffset0 + 1 ],
3561 z0 = src0[ srcOffset0 + 2 ],
3562 w0 = src0[ srcOffset0 + 3 ],
3563
3564 x1 = src1[ srcOffset1 + 0 ],
3565 y1 = src1[ srcOffset1 + 1 ],
3566 z1 = src1[ srcOffset1 + 2 ],
3567 w1 = src1[ srcOffset1 + 3 ];
3568
3569 if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
3570
3571 var s = 1 - t,
3572
3573 cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
3574
3575 dir = ( cos >= 0 ? 1 : - 1 ),
3576 sqrSin = 1 - cos * cos;
3577
3578 // Skip the Slerp for tiny steps to avoid numeric problems:
3579 if ( sqrSin > Number.EPSILON ) {
3580
3581 var sin = Math.sqrt( sqrSin ),
3582 len = Math.atan2( sin, cos * dir );
3583
3584 s = Math.sin( s * len ) / sin;
3585 t = Math.sin( t * len ) / sin;
3586
3587 }
3588
3589 var tDir = t * dir;
3590
3591 x0 = x0 * s + x1 * tDir;
3592 y0 = y0 * s + y1 * tDir;
3593 z0 = z0 * s + z1 * tDir;
3594 w0 = w0 * s + w1 * tDir;
3595
3596 // Normalize in case we just did a lerp:
3597 if ( s === 1 - t ) {
3598
3599 var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
3600
3601 x0 *= f;
3602 y0 *= f;
3603 z0 *= f;
3604 w0 *= f;
3605
3606 }
3607
3608 }
3609
3610 dst[ dstOffset ] = x0;
3611 dst[ dstOffset + 1 ] = y0;
3612 dst[ dstOffset + 2 ] = z0;
3613 dst[ dstOffset + 3 ] = w0;
3614
3615 }
3616
3617} );
3618
3619Object.defineProperties( Quaternion.prototype, {
3620
3621 x: {
3622
3623 get: function () {
3624
3625 return this._x;
3626
3627 },
3628
3629 set: function ( value ) {
3630
3631 this._x = value;
3632 this.onChangeCallback();
3633
3634 }
3635
3636 },
3637
3638 y: {
3639
3640 get: function () {
3641
3642 return this._y;
3643
3644 },
3645
3646 set: function ( value ) {
3647
3648 this._y = value;
3649 this.onChangeCallback();
3650
3651 }
3652
3653 },
3654
3655 z: {
3656
3657 get: function () {
3658
3659 return this._z;
3660
3661 },
3662
3663 set: function ( value ) {
3664
3665 this._z = value;
3666 this.onChangeCallback();
3667
3668 }
3669
3670 },
3671
3672 w: {
3673
3674 get: function () {
3675
3676 return this._w;
3677
3678 },
3679
3680 set: function ( value ) {
3681
3682 this._w = value;
3683 this.onChangeCallback();
3684
3685 }
3686
3687 }
3688
3689} );
3690
3691Object.assign( Quaternion.prototype, {
3692
3693 set: function ( x, y, z, w ) {
3694
3695 this._x = x;
3696 this._y = y;
3697 this._z = z;
3698 this._w = w;
3699
3700 this.onChangeCallback();
3701
3702 return this;
3703
3704 },
3705
3706 clone: function () {
3707
3708 return new this.constructor( this._x, this._y, this._z, this._w );
3709
3710 },
3711
3712 copy: function ( quaternion ) {
3713
3714 this._x = quaternion.x;
3715 this._y = quaternion.y;
3716 this._z = quaternion.z;
3717 this._w = quaternion.w;
3718
3719 this.onChangeCallback();
3720
3721 return this;
3722
3723 },
3724
3725 setFromEuler: function ( euler, update ) {
3726
3727 if ( ! ( euler && euler.isEuler ) ) {
3728
3729 throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );
3730
3731 }
3732
3733 var x = euler._x, y = euler._y, z = euler._z, order = euler.order;
3734
3735 // http://www.mathworks.com/matlabcentral/fileexchange/
3736 // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
3737 // content/SpinCalc.m
3738
3739 var cos = Math.cos;
3740 var sin = Math.sin;
3741
3742 var c1 = cos( x / 2 );
3743 var c2 = cos( y / 2 );
3744 var c3 = cos( z / 2 );
3745
3746 var s1 = sin( x / 2 );
3747 var s2 = sin( y / 2 );
3748 var s3 = sin( z / 2 );
3749
3750 if ( order === 'XYZ' ) {
3751
3752 this._x = s1 * c2 * c3 + c1 * s2 * s3;
3753 this._y = c1 * s2 * c3 - s1 * c2 * s3;
3754 this._z = c1 * c2 * s3 + s1 * s2 * c3;
3755 this._w = c1 * c2 * c3 - s1 * s2 * s3;
3756
3757 } else if ( order === 'YXZ' ) {
3758
3759 this._x = s1 * c2 * c3 + c1 * s2 * s3;
3760 this._y = c1 * s2 * c3 - s1 * c2 * s3;
3761 this._z = c1 * c2 * s3 - s1 * s2 * c3;
3762 this._w = c1 * c2 * c3 + s1 * s2 * s3;
3763
3764 } else if ( order === 'ZXY' ) {
3765
3766 this._x = s1 * c2 * c3 - c1 * s2 * s3;
3767 this._y = c1 * s2 * c3 + s1 * c2 * s3;
3768 this._z = c1 * c2 * s3 + s1 * s2 * c3;
3769 this._w = c1 * c2 * c3 - s1 * s2 * s3;
3770
3771 } else if ( order === 'ZYX' ) {
3772
3773 this._x = s1 * c2 * c3 - c1 * s2 * s3;
3774 this._y = c1 * s2 * c3 + s1 * c2 * s3;
3775 this._z = c1 * c2 * s3 - s1 * s2 * c3;
3776 this._w = c1 * c2 * c3 + s1 * s2 * s3;
3777
3778 } else if ( order === 'YZX' ) {
3779
3780 this._x = s1 * c2 * c3 + c1 * s2 * s3;
3781 this._y = c1 * s2 * c3 + s1 * c2 * s3;
3782 this._z = c1 * c2 * s3 - s1 * s2 * c3;
3783 this._w = c1 * c2 * c3 - s1 * s2 * s3;
3784
3785 } else if ( order === 'XZY' ) {
3786
3787 this._x = s1 * c2 * c3 - c1 * s2 * s3;
3788 this._y = c1 * s2 * c3 - s1 * c2 * s3;
3789 this._z = c1 * c2 * s3 + s1 * s2 * c3;
3790 this._w = c1 * c2 * c3 + s1 * s2 * s3;
3791
3792 }
3793
3794 if ( update !== false ) this.onChangeCallback();
3795
3796 return this;
3797
3798 },
3799
3800 setFromAxisAngle: function ( axis, angle ) {
3801
3802 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
3803
3804 // assumes axis is normalized
3805
3806 var halfAngle = angle / 2, s = Math.sin( halfAngle );
3807
3808 this._x = axis.x * s;
3809 this._y = axis.y * s;
3810 this._z = axis.z * s;
3811 this._w = Math.cos( halfAngle );
3812
3813 this.onChangeCallback();
3814
3815 return this;
3816
3817 },
3818
3819 setFromRotationMatrix: function ( m ) {
3820
3821 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
3822
3823 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
3824
3825 var te = m.elements,
3826
3827 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
3828 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
3829 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
3830
3831 trace = m11 + m22 + m33,
3832 s;
3833
3834 if ( trace > 0 ) {
3835
3836 s = 0.5 / Math.sqrt( trace + 1.0 );
3837
3838 this._w = 0.25 / s;
3839 this._x = ( m32 - m23 ) * s;
3840 this._y = ( m13 - m31 ) * s;
3841 this._z = ( m21 - m12 ) * s;
3842
3843 } else if ( m11 > m22 && m11 > m33 ) {
3844
3845 s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
3846
3847 this._w = ( m32 - m23 ) / s;
3848 this._x = 0.25 * s;
3849 this._y = ( m12 + m21 ) / s;
3850 this._z = ( m13 + m31 ) / s;
3851
3852 } else if ( m22 > m33 ) {
3853
3854 s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
3855
3856 this._w = ( m13 - m31 ) / s;
3857 this._x = ( m12 + m21 ) / s;
3858 this._y = 0.25 * s;
3859 this._z = ( m23 + m32 ) / s;
3860
3861 } else {
3862
3863 s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
3864
3865 this._w = ( m21 - m12 ) / s;
3866 this._x = ( m13 + m31 ) / s;
3867 this._y = ( m23 + m32 ) / s;
3868 this._z = 0.25 * s;
3869
3870 }
3871
3872 this.onChangeCallback();
3873
3874 return this;
3875
3876 },
3877
3878 setFromUnitVectors: function () {
3879
3880 // assumes direction vectors vFrom and vTo are normalized
3881
3882 var v1 = new Vector3();
3883 var r;
3884
3885 var EPS = 0.000001;
3886
3887 return function setFromUnitVectors( vFrom, vTo ) {
3888
3889 if ( v1 === undefined ) v1 = new Vector3();
3890
3891 r = vFrom.dot( vTo ) + 1;
3892
3893 if ( r < EPS ) {
3894
3895 r = 0;
3896
3897 if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
3898
3899 v1.set( - vFrom.y, vFrom.x, 0 );
3900
3901 } else {
3902
3903 v1.set( 0, - vFrom.z, vFrom.y );
3904
3905 }
3906
3907 } else {
3908
3909 v1.crossVectors( vFrom, vTo );
3910
3911 }
3912
3913 this._x = v1.x;
3914 this._y = v1.y;
3915 this._z = v1.z;
3916 this._w = r;
3917
3918 return this.normalize();
3919
3920 };
3921
3922 }(),
3923
3924 inverse: function () {
3925
3926 return this.conjugate().normalize();
3927
3928 },
3929
3930 conjugate: function () {
3931
3932 this._x *= - 1;
3933 this._y *= - 1;
3934 this._z *= - 1;
3935
3936 this.onChangeCallback();
3937
3938 return this;
3939
3940 },
3941
3942 dot: function ( v ) {
3943
3944 return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
3945
3946 },
3947
3948 lengthSq: function () {
3949
3950 return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
3951
3952 },
3953
3954 length: function () {
3955
3956 return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
3957
3958 },
3959
3960 normalize: function () {
3961
3962 var l = this.length();
3963
3964 if ( l === 0 ) {
3965
3966 this._x = 0;
3967 this._y = 0;
3968 this._z = 0;
3969 this._w = 1;
3970
3971 } else {
3972
3973 l = 1 / l;
3974
3975 this._x = this._x * l;
3976 this._y = this._y * l;
3977 this._z = this._z * l;
3978 this._w = this._w * l;
3979
3980 }
3981
3982 this.onChangeCallback();
3983
3984 return this;
3985
3986 },
3987
3988 multiply: function ( q, p ) {
3989
3990 if ( p !== undefined ) {
3991
3992 console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
3993 return this.multiplyQuaternions( q, p );
3994
3995 }
3996
3997 return this.multiplyQuaternions( this, q );
3998
3999 },
4000
4001 premultiply: function ( q ) {
4002
4003 return this.multiplyQuaternions( q, this );
4004
4005 },
4006
4007 multiplyQuaternions: function ( a, b ) {
4008
4009 // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
4010
4011 var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
4012 var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
4013
4014 this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
4015 this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
4016 this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
4017 this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
4018
4019 this.onChangeCallback();
4020
4021 return this;
4022
4023 },
4024
4025 slerp: function ( qb, t ) {
4026
4027 if ( t === 0 ) return this;
4028 if ( t === 1 ) return this.copy( qb );
4029
4030 var x = this._x, y = this._y, z = this._z, w = this._w;
4031
4032 // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
4033
4034 var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
4035
4036 if ( cosHalfTheta < 0 ) {
4037
4038 this._w = - qb._w;
4039 this._x = - qb._x;
4040 this._y = - qb._y;
4041 this._z = - qb._z;
4042
4043 cosHalfTheta = - cosHalfTheta;
4044
4045 } else {
4046
4047 this.copy( qb );
4048
4049 }
4050
4051 if ( cosHalfTheta >= 1.0 ) {
4052
4053 this._w = w;
4054 this._x = x;
4055 this._y = y;
4056 this._z = z;
4057
4058 return this;
4059
4060 }
4061
4062 var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
4063
4064 if ( Math.abs( sinHalfTheta ) < 0.001 ) {
4065
4066 this._w = 0.5 * ( w + this._w );
4067 this._x = 0.5 * ( x + this._x );
4068 this._y = 0.5 * ( y + this._y );
4069 this._z = 0.5 * ( z + this._z );
4070
4071 return this;
4072
4073 }
4074
4075 var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
4076 var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
4077 ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
4078
4079 this._w = ( w * ratioA + this._w * ratioB );
4080 this._x = ( x * ratioA + this._x * ratioB );
4081 this._y = ( y * ratioA + this._y * ratioB );
4082 this._z = ( z * ratioA + this._z * ratioB );
4083
4084 this.onChangeCallback();
4085
4086 return this;
4087
4088 },
4089
4090 equals: function ( quaternion ) {
4091
4092 return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
4093
4094 },
4095
4096 fromArray: function ( array, offset ) {
4097
4098 if ( offset === undefined ) offset = 0;
4099
4100 this._x = array[ offset ];
4101 this._y = array[ offset + 1 ];
4102 this._z = array[ offset + 2 ];
4103 this._w = array[ offset + 3 ];
4104
4105 this.onChangeCallback();
4106
4107 return this;
4108
4109 },
4110
4111 toArray: function ( array, offset ) {
4112
4113 if ( array === undefined ) array = [];
4114 if ( offset === undefined ) offset = 0;
4115
4116 array[ offset ] = this._x;
4117 array[ offset + 1 ] = this._y;
4118 array[ offset + 2 ] = this._z;
4119 array[ offset + 3 ] = this._w;
4120
4121 return array;
4122
4123 },
4124
4125 onChange: function ( callback ) {
4126
4127 this.onChangeCallback = callback;
4128
4129 return this;
4130
4131 },
4132
4133 onChangeCallback: function () {}
4134
4135} );
4136
4137/**
4138 * @author mrdoob / http://mrdoob.com/
4139 * @author kile / http://kile.stravaganza.org/
4140 * @author philogb / http://blog.thejit.org/
4141 * @author mikael emtinger / http://gomo.se/
4142 * @author egraether / http://egraether.com/
4143 * @author WestLangley / http://github.com/WestLangley
4144 */
4145
4146function Vector3( x, y, z ) {
4147
4148 this.x = x || 0;
4149 this.y = y || 0;
4150 this.z = z || 0;
4151
4152}
4153
4154Object.assign( Vector3.prototype, {
4155
4156 isVector3: true,
4157
4158 set: function ( x, y, z ) {
4159
4160 this.x = x;
4161 this.y = y;
4162 this.z = z;
4163
4164 return this;
4165
4166 },
4167
4168 setScalar: function ( scalar ) {
4169
4170 this.x = scalar;
4171 this.y = scalar;
4172 this.z = scalar;
4173
4174 return this;
4175
4176 },
4177
4178 setX: function ( x ) {
4179
4180 this.x = x;
4181
4182 return this;
4183
4184 },
4185
4186 setY: function ( y ) {
4187
4188 this.y = y;
4189
4190 return this;
4191
4192 },
4193
4194 setZ: function ( z ) {
4195
4196 this.z = z;
4197
4198 return this;
4199
4200 },
4201
4202 setComponent: function ( index, value ) {
4203
4204 switch ( index ) {
4205
4206 case 0: this.x = value; break;
4207 case 1: this.y = value; break;
4208 case 2: this.z = value; break;
4209 default: throw new Error( 'index is out of range: ' + index );
4210
4211 }
4212
4213 return this;
4214
4215 },
4216
4217 getComponent: function ( index ) {
4218
4219 switch ( index ) {
4220
4221 case 0: return this.x;
4222 case 1: return this.y;
4223 case 2: return this.z;
4224 default: throw new Error( 'index is out of range: ' + index );
4225
4226 }
4227
4228 },
4229
4230 clone: function () {
4231
4232 return new this.constructor( this.x, this.y, this.z );
4233
4234 },
4235
4236 copy: function ( v ) {
4237
4238 this.x = v.x;
4239 this.y = v.y;
4240 this.z = v.z;
4241
4242 return this;
4243
4244 },
4245
4246 add: function ( v, w ) {
4247
4248 if ( w !== undefined ) {
4249
4250 console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
4251 return this.addVectors( v, w );
4252
4253 }
4254
4255 this.x += v.x;
4256 this.y += v.y;
4257 this.z += v.z;
4258
4259 return this;
4260
4261 },
4262
4263 addScalar: function ( s ) {
4264
4265 this.x += s;
4266 this.y += s;
4267 this.z += s;
4268
4269 return this;
4270
4271 },
4272
4273 addVectors: function ( a, b ) {
4274
4275 this.x = a.x + b.x;
4276 this.y = a.y + b.y;
4277 this.z = a.z + b.z;
4278
4279 return this;
4280
4281 },
4282
4283 addScaledVector: function ( v, s ) {
4284
4285 this.x += v.x * s;
4286 this.y += v.y * s;
4287 this.z += v.z * s;
4288
4289 return this;
4290
4291 },
4292
4293 sub: function ( v, w ) {
4294
4295 if ( w !== undefined ) {
4296
4297 console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
4298 return this.subVectors( v, w );
4299
4300 }
4301
4302 this.x -= v.x;
4303 this.y -= v.y;
4304 this.z -= v.z;
4305
4306 return this;
4307
4308 },
4309
4310 subScalar: function ( s ) {
4311
4312 this.x -= s;
4313 this.y -= s;
4314 this.z -= s;
4315
4316 return this;
4317
4318 },
4319
4320 subVectors: function ( a, b ) {
4321
4322 this.x = a.x - b.x;
4323 this.y = a.y - b.y;
4324 this.z = a.z - b.z;
4325
4326 return this;
4327
4328 },
4329
4330 multiply: function ( v, w ) {
4331
4332 if ( w !== undefined ) {
4333
4334 console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
4335 return this.multiplyVectors( v, w );
4336
4337 }
4338
4339 this.x *= v.x;
4340 this.y *= v.y;
4341 this.z *= v.z;
4342
4343 return this;
4344
4345 },
4346
4347 multiplyScalar: function ( scalar ) {
4348
4349 this.x *= scalar;
4350 this.y *= scalar;
4351 this.z *= scalar;
4352
4353 return this;
4354
4355 },
4356
4357 multiplyVectors: function ( a, b ) {
4358
4359 this.x = a.x * b.x;
4360 this.y = a.y * b.y;
4361 this.z = a.z * b.z;
4362
4363 return this;
4364
4365 },
4366
4367 applyEuler: function () {
4368
4369 var quaternion = new Quaternion();
4370
4371 return function applyEuler( euler ) {
4372
4373 if ( ! ( euler && euler.isEuler ) ) {
4374
4375 console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' );
4376
4377 }
4378
4379 return this.applyQuaternion( quaternion.setFromEuler( euler ) );
4380
4381 };
4382
4383 }(),
4384
4385 applyAxisAngle: function () {
4386
4387 var quaternion = new Quaternion();
4388
4389 return function applyAxisAngle( axis, angle ) {
4390
4391 return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );
4392
4393 };
4394
4395 }(),
4396
4397 applyMatrix3: function ( m ) {
4398
4399 var x = this.x, y = this.y, z = this.z;
4400 var e = m.elements;
4401
4402 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
4403 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
4404 this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
4405
4406 return this;
4407
4408 },
4409
4410 applyMatrix4: function ( m ) {
4411
4412 var x = this.x, y = this.y, z = this.z;
4413 var e = m.elements;
4414
4415 var w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );
4416
4417 this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w;
4418 this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w;
4419 this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;
4420
4421 return this;
4422
4423 },
4424
4425 applyQuaternion: function ( q ) {
4426
4427 var x = this.x, y = this.y, z = this.z;
4428 var qx = q.x, qy = q.y, qz = q.z, qw = q.w;
4429
4430 // calculate quat * vector
4431
4432 var ix = qw * x + qy * z - qz * y;
4433 var iy = qw * y + qz * x - qx * z;
4434 var iz = qw * z + qx * y - qy * x;
4435 var iw = - qx * x - qy * y - qz * z;
4436
4437 // calculate result * inverse quat
4438
4439 this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
4440 this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
4441 this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;
4442
4443 return this;
4444
4445 },
4446
4447 project: function () {
4448
4449 var matrix = new Matrix4();
4450
4451 return function project( camera ) {
4452
4453 matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
4454 return this.applyMatrix4( matrix );
4455
4456 };
4457
4458 }(),
4459
4460 unproject: function () {
4461
4462 var matrix = new Matrix4();
4463
4464 return function unproject( camera ) {
4465
4466 matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );
4467 return this.applyMatrix4( matrix );
4468
4469 };
4470
4471 }(),
4472
4473 transformDirection: function ( m ) {
4474
4475 // input: THREE.Matrix4 affine matrix
4476 // vector interpreted as a direction
4477
4478 var x = this.x, y = this.y, z = this.z;
4479 var e = m.elements;
4480
4481 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
4482 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
4483 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
4484
4485 return this.normalize();
4486
4487 },
4488
4489 divide: function ( v ) {
4490
4491 this.x /= v.x;
4492 this.y /= v.y;
4493 this.z /= v.z;
4494
4495 return this;
4496
4497 },
4498
4499 divideScalar: function ( scalar ) {
4500
4501 return this.multiplyScalar( 1 / scalar );
4502
4503 },
4504
4505 min: function ( v ) {
4506
4507 this.x = Math.min( this.x, v.x );
4508 this.y = Math.min( this.y, v.y );
4509 this.z = Math.min( this.z, v.z );
4510
4511 return this;
4512
4513 },
4514
4515 max: function ( v ) {
4516
4517 this.x = Math.max( this.x, v.x );
4518 this.y = Math.max( this.y, v.y );
4519 this.z = Math.max( this.z, v.z );
4520
4521 return this;
4522
4523 },
4524
4525 clamp: function ( min, max ) {
4526
4527 // assumes min < max, componentwise
4528
4529 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
4530 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
4531 this.z = Math.max( min.z, Math.min( max.z, this.z ) );
4532
4533 return this;
4534
4535 },
4536
4537 clampScalar: function () {
4538
4539 var min = new Vector3();
4540 var max = new Vector3();
4541
4542 return function clampScalar( minVal, maxVal ) {
4543
4544 min.set( minVal, minVal, minVal );
4545 max.set( maxVal, maxVal, maxVal );
4546
4547 return this.clamp( min, max );
4548
4549 };
4550
4551 }(),
4552
4553 clampLength: function ( min, max ) {
4554
4555 var length = this.length();
4556
4557 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
4558
4559 },
4560
4561 floor: function () {
4562
4563 this.x = Math.floor( this.x );
4564 this.y = Math.floor( this.y );
4565 this.z = Math.floor( this.z );
4566
4567 return this;
4568
4569 },
4570
4571 ceil: function () {
4572
4573 this.x = Math.ceil( this.x );
4574 this.y = Math.ceil( this.y );
4575 this.z = Math.ceil( this.z );
4576
4577 return this;
4578
4579 },
4580
4581 round: function () {
4582
4583 this.x = Math.round( this.x );
4584 this.y = Math.round( this.y );
4585 this.z = Math.round( this.z );
4586
4587 return this;
4588
4589 },
4590
4591 roundToZero: function () {
4592
4593 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
4594 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
4595 this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
4596
4597 return this;
4598
4599 },
4600
4601 negate: function () {
4602
4603 this.x = - this.x;
4604 this.y = - this.y;
4605 this.z = - this.z;
4606
4607 return this;
4608
4609 },
4610
4611 dot: function ( v ) {
4612
4613 return this.x * v.x + this.y * v.y + this.z * v.z;
4614
4615 },
4616
4617 // TODO lengthSquared?
4618
4619 lengthSq: function () {
4620
4621 return this.x * this.x + this.y * this.y + this.z * this.z;
4622
4623 },
4624
4625 length: function () {
4626
4627 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
4628
4629 },
4630
4631 manhattanLength: function () {
4632
4633 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
4634
4635 },
4636
4637 normalize: function () {
4638
4639 return this.divideScalar( this.length() || 1 );
4640
4641 },
4642
4643 setLength: function ( length ) {
4644
4645 return this.normalize().multiplyScalar( length );
4646
4647 },
4648
4649 lerp: function ( v, alpha ) {
4650
4651 this.x += ( v.x - this.x ) * alpha;
4652 this.y += ( v.y - this.y ) * alpha;
4653 this.z += ( v.z - this.z ) * alpha;
4654
4655 return this;
4656
4657 },
4658
4659 lerpVectors: function ( v1, v2, alpha ) {
4660
4661 return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
4662
4663 },
4664
4665 cross: function ( v, w ) {
4666
4667 if ( w !== undefined ) {
4668
4669 console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
4670 return this.crossVectors( v, w );
4671
4672 }
4673
4674 return this.crossVectors( this, v );
4675
4676 },
4677
4678 crossVectors: function ( a, b ) {
4679
4680 var ax = a.x, ay = a.y, az = a.z;
4681 var bx = b.x, by = b.y, bz = b.z;
4682
4683 this.x = ay * bz - az * by;
4684 this.y = az * bx - ax * bz;
4685 this.z = ax * by - ay * bx;
4686
4687 return this;
4688
4689 },
4690
4691 projectOnVector: function ( vector ) {
4692
4693 var scalar = vector.dot( this ) / vector.lengthSq();
4694
4695 return this.copy( vector ).multiplyScalar( scalar );
4696
4697 },
4698
4699 projectOnPlane: function () {
4700
4701 var v1 = new Vector3();
4702
4703 return function projectOnPlane( planeNormal ) {
4704
4705 v1.copy( this ).projectOnVector( planeNormal );
4706
4707 return this.sub( v1 );
4708
4709 };
4710
4711 }(),
4712
4713 reflect: function () {
4714
4715 // reflect incident vector off plane orthogonal to normal
4716 // normal is assumed to have unit length
4717
4718 var v1 = new Vector3();
4719
4720 return function reflect( normal ) {
4721
4722 return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
4723
4724 };
4725
4726 }(),
4727
4728 angleTo: function ( v ) {
4729
4730 var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) );
4731
4732 // clamp, to handle numerical problems
4733
4734 return Math.acos( _Math.clamp( theta, - 1, 1 ) );
4735
4736 },
4737
4738 distanceTo: function ( v ) {
4739
4740 return Math.sqrt( this.distanceToSquared( v ) );
4741
4742 },
4743
4744 distanceToSquared: function ( v ) {
4745
4746 var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;
4747
4748 return dx * dx + dy * dy + dz * dz;
4749
4750 },
4751
4752 manhattanDistanceTo: function ( v ) {
4753
4754 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );
4755
4756 },
4757
4758 setFromSpherical: function ( s ) {
4759
4760 var sinPhiRadius = Math.sin( s.phi ) * s.radius;
4761
4762 this.x = sinPhiRadius * Math.sin( s.theta );
4763 this.y = Math.cos( s.phi ) * s.radius;
4764 this.z = sinPhiRadius * Math.cos( s.theta );
4765
4766 return this;
4767
4768 },
4769
4770 setFromCylindrical: function ( c ) {
4771
4772 this.x = c.radius * Math.sin( c.theta );
4773 this.y = c.y;
4774 this.z = c.radius * Math.cos( c.theta );
4775
4776 return this;
4777
4778 },
4779
4780 setFromMatrixPosition: function ( m ) {
4781
4782 var e = m.elements;
4783
4784 this.x = e[ 12 ];
4785 this.y = e[ 13 ];
4786 this.z = e[ 14 ];
4787
4788 return this;
4789
4790 },
4791
4792 setFromMatrixScale: function ( m ) {
4793
4794 var sx = this.setFromMatrixColumn( m, 0 ).length();
4795 var sy = this.setFromMatrixColumn( m, 1 ).length();
4796 var sz = this.setFromMatrixColumn( m, 2 ).length();
4797
4798 this.x = sx;
4799 this.y = sy;
4800 this.z = sz;
4801
4802 return this;
4803
4804 },
4805
4806 setFromMatrixColumn: function ( m, index ) {
4807
4808 return this.fromArray( m.elements, index * 4 );
4809
4810 },
4811
4812 equals: function ( v ) {
4813
4814 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
4815
4816 },
4817
4818 fromArray: function ( array, offset ) {
4819
4820 if ( offset === undefined ) offset = 0;
4821
4822 this.x = array[ offset ];
4823 this.y = array[ offset + 1 ];
4824 this.z = array[ offset + 2 ];
4825
4826 return this;
4827
4828 },
4829
4830 toArray: function ( array, offset ) {
4831
4832 if ( array === undefined ) array = [];
4833 if ( offset === undefined ) offset = 0;
4834
4835 array[ offset ] = this.x;
4836 array[ offset + 1 ] = this.y;
4837 array[ offset + 2 ] = this.z;
4838
4839 return array;
4840
4841 },
4842
4843 fromBufferAttribute: function ( attribute, index, offset ) {
4844
4845 if ( offset !== undefined ) {
4846
4847 console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' );
4848
4849 }
4850
4851 this.x = attribute.getX( index );
4852 this.y = attribute.getY( index );
4853 this.z = attribute.getZ( index );
4854
4855 return this;
4856
4857 }
4858
4859} );
4860
4861/**
4862 * @author alteredq / http://alteredqualia.com/
4863 * @author WestLangley / http://github.com/WestLangley
4864 * @author bhouston / http://clara.io
4865 * @author tschw
4866 */
4867
4868function Matrix3() {
4869
4870 this.elements = [
4871
4872 1, 0, 0,
4873 0, 1, 0,
4874 0, 0, 1
4875
4876 ];
4877
4878 if ( arguments.length > 0 ) {
4879
4880 console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );
4881
4882 }
4883
4884}
4885
4886Object.assign( Matrix3.prototype, {
4887
4888 isMatrix3: true,
4889
4890 set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
4891
4892 var te = this.elements;
4893
4894 te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;
4895 te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;
4896 te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;
4897
4898 return this;
4899
4900 },
4901
4902 identity: function () {
4903
4904 this.set(
4905
4906 1, 0, 0,
4907 0, 1, 0,
4908 0, 0, 1
4909
4910 );
4911
4912 return this;
4913
4914 },
4915
4916 clone: function () {
4917
4918 return new this.constructor().fromArray( this.elements );
4919
4920 },
4921
4922 copy: function ( m ) {
4923
4924 var te = this.elements;
4925 var me = m.elements;
4926
4927 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];
4928 te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];
4929 te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];
4930
4931 return this;
4932
4933 },
4934
4935 setFromMatrix4: function ( m ) {
4936
4937 var me = m.elements;
4938
4939 this.set(
4940
4941 me[ 0 ], me[ 4 ], me[ 8 ],
4942 me[ 1 ], me[ 5 ], me[ 9 ],
4943 me[ 2 ], me[ 6 ], me[ 10 ]
4944
4945 );
4946
4947 return this;
4948
4949 },
4950
4951 applyToBufferAttribute: function () {
4952
4953 var v1 = new Vector3();
4954
4955 return function applyToBufferAttribute( attribute ) {
4956
4957 for ( var i = 0, l = attribute.count; i < l; i ++ ) {
4958
4959 v1.x = attribute.getX( i );
4960 v1.y = attribute.getY( i );
4961 v1.z = attribute.getZ( i );
4962
4963 v1.applyMatrix3( this );
4964
4965 attribute.setXYZ( i, v1.x, v1.y, v1.z );
4966
4967 }
4968
4969 return attribute;
4970
4971 };
4972
4973 }(),
4974
4975 multiply: function ( m ) {
4976
4977 return this.multiplyMatrices( this, m );
4978
4979 },
4980
4981 premultiply: function ( m ) {
4982
4983 return this.multiplyMatrices( m, this );
4984
4985 },
4986
4987 multiplyMatrices: function ( a, b ) {
4988
4989 var ae = a.elements;
4990 var be = b.elements;
4991 var te = this.elements;
4992
4993 var a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];
4994 var a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];
4995 var a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];
4996
4997 var b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];
4998 var b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];
4999 var b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];
5000
5001 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;
5002 te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;
5003 te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;
5004
5005 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;
5006 te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;
5007 te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;
5008
5009 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;
5010 te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;
5011 te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;
5012
5013 return this;
5014
5015 },
5016
5017 multiplyScalar: function ( s ) {
5018
5019 var te = this.elements;
5020
5021 te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;
5022 te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;
5023 te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;
5024
5025 return this;
5026
5027 },
5028
5029 determinant: function () {
5030
5031 var te = this.elements;
5032
5033 var a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],
5034 d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
5035 g = te[ 6 ], h = te[ 7 ], i = te[ 8 ];
5036
5037 return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
5038
5039 },
5040
5041 getInverse: function ( matrix, throwOnDegenerate ) {
5042
5043 if ( matrix && matrix.isMatrix4 ) {
5044
5045 console.error( "THREE.Matrix3: .getInverse() no longer takes a Matrix4 argument." );
5046
5047 }
5048
5049 var me = matrix.elements,
5050 te = this.elements,
5051
5052 n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ],
5053 n12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ],
5054 n13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ],
5055
5056 t11 = n33 * n22 - n32 * n23,
5057 t12 = n32 * n13 - n33 * n12,
5058 t13 = n23 * n12 - n22 * n13,
5059
5060 det = n11 * t11 + n21 * t12 + n31 * t13;
5061
5062 if ( det === 0 ) {
5063
5064 var msg = "THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0";
5065
5066 if ( throwOnDegenerate === true ) {
5067
5068 throw new Error( msg );
5069
5070 } else {
5071
5072 console.warn( msg );
5073
5074 }
5075
5076 return this.identity();
5077
5078 }
5079
5080 var detInv = 1 / det;
5081
5082 te[ 0 ] = t11 * detInv;
5083 te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;
5084 te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;
5085
5086 te[ 3 ] = t12 * detInv;
5087 te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;
5088 te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;
5089
5090 te[ 6 ] = t13 * detInv;
5091 te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;
5092 te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;
5093
5094 return this;
5095
5096 },
5097
5098 transpose: function () {
5099
5100 var tmp, m = this.elements;
5101
5102 tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;
5103 tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;
5104 tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;
5105
5106 return this;
5107
5108 },
5109
5110 getNormalMatrix: function ( matrix4 ) {
5111
5112 return this.setFromMatrix4( matrix4 ).getInverse( this ).transpose();
5113
5114 },
5115
5116 transposeIntoArray: function ( r ) {
5117
5118 var m = this.elements;
5119
5120 r[ 0 ] = m[ 0 ];
5121 r[ 1 ] = m[ 3 ];
5122 r[ 2 ] = m[ 6 ];
5123 r[ 3 ] = m[ 1 ];
5124 r[ 4 ] = m[ 4 ];
5125 r[ 5 ] = m[ 7 ];
5126 r[ 6 ] = m[ 2 ];
5127 r[ 7 ] = m[ 5 ];
5128 r[ 8 ] = m[ 8 ];
5129
5130 return this;
5131
5132 },
5133
5134 setUvTransform: function ( tx, ty, sx, sy, rotation, cx, cy ) {
5135
5136 var c = Math.cos( rotation );
5137 var s = Math.sin( rotation );
5138
5139 this.set(
5140 sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx,
5141 - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty,
5142 0, 0, 1
5143 );
5144
5145 },
5146
5147 scale: function ( sx, sy ) {
5148
5149 var te = this.elements;
5150
5151 te[ 0 ] *= sx; te[ 3 ] *= sx; te[ 6 ] *= sx;
5152 te[ 1 ] *= sy; te[ 4 ] *= sy; te[ 7 ] *= sy;
5153
5154 return this;
5155
5156 },
5157
5158 rotate: function ( theta ) {
5159
5160 var c = Math.cos( theta );
5161 var s = Math.sin( theta );
5162
5163 var te = this.elements;
5164
5165 var a11 = te[ 0 ], a12 = te[ 3 ], a13 = te[ 6 ];
5166 var a21 = te[ 1 ], a22 = te[ 4 ], a23 = te[ 7 ];
5167
5168 te[ 0 ] = c * a11 + s * a21;
5169 te[ 3 ] = c * a12 + s * a22;
5170 te[ 6 ] = c * a13 + s * a23;
5171
5172 te[ 1 ] = - s * a11 + c * a21;
5173 te[ 4 ] = - s * a12 + c * a22;
5174 te[ 7 ] = - s * a13 + c * a23;
5175
5176 return this;
5177
5178 },
5179
5180 translate: function ( tx, ty ) {
5181
5182 var te = this.elements;
5183
5184 te[ 0 ] += tx * te[ 2 ]; te[ 3 ] += tx * te[ 5 ]; te[ 6 ] += tx * te[ 8 ];
5185 te[ 1 ] += ty * te[ 2 ]; te[ 4 ] += ty * te[ 5 ]; te[ 7 ] += ty * te[ 8 ];
5186
5187 return this;
5188
5189 },
5190
5191 equals: function ( matrix ) {
5192
5193 var te = this.elements;
5194 var me = matrix.elements;
5195
5196 for ( var i = 0; i < 9; i ++ ) {
5197
5198 if ( te[ i ] !== me[ i ] ) return false;
5199
5200 }
5201
5202 return true;
5203
5204 },
5205
5206 fromArray: function ( array, offset ) {
5207
5208 if ( offset === undefined ) offset = 0;
5209
5210 for ( var i = 0; i < 9; i ++ ) {
5211
5212 this.elements[ i ] = array[ i + offset ];
5213
5214 }
5215
5216 return this;
5217
5218 },
5219
5220 toArray: function ( array, offset ) {
5221
5222 if ( array === undefined ) array = [];
5223 if ( offset === undefined ) offset = 0;
5224
5225 var te = this.elements;
5226
5227 array[ offset ] = te[ 0 ];
5228 array[ offset + 1 ] = te[ 1 ];
5229 array[ offset + 2 ] = te[ 2 ];
5230
5231 array[ offset + 3 ] = te[ 3 ];
5232 array[ offset + 4 ] = te[ 4 ];
5233 array[ offset + 5 ] = te[ 5 ];
5234
5235 array[ offset + 6 ] = te[ 6 ];
5236 array[ offset + 7 ] = te[ 7 ];
5237 array[ offset + 8 ] = te[ 8 ];
5238
5239 return array;
5240
5241 }
5242
5243} );
5244
5245/**
5246 * @author mrdoob / http://mrdoob.com/
5247 * @author alteredq / http://alteredqualia.com/
5248 * @author szimek / https://github.com/szimek/
5249 */
5250
5251var textureId = 0;
5252
5253function Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
5254
5255 Object.defineProperty( this, 'id', { value: textureId ++ } );
5256
5257 this.uuid = _Math.generateUUID();
5258
5259 this.name = '';
5260
5261 this.image = image !== undefined ? image : Texture.DEFAULT_IMAGE;
5262 this.mipmaps = [];
5263
5264 this.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING;
5265
5266 this.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping;
5267 this.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping;
5268
5269 this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
5270 this.minFilter = minFilter !== undefined ? minFilter : LinearMipMapLinearFilter;
5271
5272 this.anisotropy = anisotropy !== undefined ? anisotropy : 1;
5273
5274 this.format = format !== undefined ? format : RGBAFormat;
5275 this.type = type !== undefined ? type : UnsignedByteType;
5276
5277 this.offset = new Vector2( 0, 0 );
5278 this.repeat = new Vector2( 1, 1 );
5279 this.center = new Vector2( 0, 0 );
5280 this.rotation = 0;
5281
5282 this.matrixAutoUpdate = true;
5283 this.matrix = new Matrix3();
5284
5285 this.generateMipmaps = true;
5286 this.premultiplyAlpha = false;
5287 this.flipY = true;
5288 this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
5289
5290 // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
5291 //
5292 // Also changing the encoding after already used by a Material will not automatically make the Material
5293 // update. You need to explicitly call Material.needsUpdate to trigger it to recompile.
5294 this.encoding = encoding !== undefined ? encoding : LinearEncoding;
5295
5296 this.version = 0;
5297 this.onUpdate = null;
5298
5299}
5300
5301Texture.DEFAULT_IMAGE = undefined;
5302Texture.DEFAULT_MAPPING = UVMapping;
5303
5304Texture.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
5305
5306 constructor: Texture,
5307
5308 isTexture: true,
5309
5310 clone: function () {
5311
5312 return new this.constructor().copy( this );
5313
5314 },
5315
5316 copy: function ( source ) {
5317
5318 this.name = source.name;
5319
5320 this.image = source.image;
5321 this.mipmaps = source.mipmaps.slice( 0 );
5322
5323 this.mapping = source.mapping;
5324
5325 this.wrapS = source.wrapS;
5326 this.wrapT = source.wrapT;
5327
5328 this.magFilter = source.magFilter;
5329 this.minFilter = source.minFilter;
5330
5331 this.anisotropy = source.anisotropy;
5332
5333 this.format = source.format;
5334 this.type = source.type;
5335
5336 this.offset.copy( source.offset );
5337 this.repeat.copy( source.repeat );
5338 this.center.copy( source.center );
5339 this.rotation = source.rotation;
5340
5341 this.matrixAutoUpdate = source.matrixAutoUpdate;
5342 this.matrix.copy( source.matrix );
5343
5344 this.generateMipmaps = source.generateMipmaps;
5345 this.premultiplyAlpha = source.premultiplyAlpha;
5346 this.flipY = source.flipY;
5347 this.unpackAlignment = source.unpackAlignment;
5348 this.encoding = source.encoding;
5349
5350 return this;
5351
5352 },
5353
5354 toJSON: function ( meta ) {
5355
5356 var isRootObject = ( meta === undefined || typeof meta === 'string' );
5357
5358 if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) {
5359
5360 return meta.textures[ this.uuid ];
5361
5362 }
5363
5364 function getDataURL( image ) {
5365
5366 var canvas;
5367
5368 if ( image instanceof HTMLCanvasElement ) {
5369
5370 canvas = image;
5371
5372 } else {
5373
5374 canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
5375 canvas.width = image.width;
5376 canvas.height = image.height;
5377
5378 var context = canvas.getContext( '2d' );
5379
5380 if ( image instanceof ImageData ) {
5381
5382 context.putImageData( image, 0, 0 );
5383
5384 } else {
5385
5386 context.drawImage( image, 0, 0, image.width, image.height );
5387
5388 }
5389
5390 }
5391
5392 if ( canvas.width > 2048 || canvas.height > 2048 ) {
5393
5394 return canvas.toDataURL( 'image/jpeg', 0.6 );
5395
5396 } else {
5397
5398 return canvas.toDataURL( 'image/png' );
5399
5400 }
5401
5402 }
5403
5404 var output = {
5405 metadata: {
5406 version: 4.5,
5407 type: 'Texture',
5408 generator: 'Texture.toJSON'
5409 },
5410
5411 uuid: this.uuid,
5412 name: this.name,
5413
5414 mapping: this.mapping,
5415
5416 repeat: [ this.repeat.x, this.repeat.y ],
5417 offset: [ this.offset.x, this.offset.y ],
5418 center: [ this.center.x, this.center.y ],
5419 rotation: this.rotation,
5420
5421 wrap: [ this.wrapS, this.wrapT ],
5422
5423 minFilter: this.minFilter,
5424 magFilter: this.magFilter,
5425 anisotropy: this.anisotropy,
5426
5427 flipY: this.flipY
5428 };
5429
5430 if ( this.image !== undefined ) {
5431
5432 // TODO: Move to THREE.Image
5433
5434 var image = this.image;
5435
5436 if ( image.uuid === undefined ) {
5437
5438 image.uuid = _Math.generateUUID(); // UGH
5439
5440 }
5441
5442 if ( ! isRootObject && meta.images[ image.uuid ] === undefined ) {
5443
5444 meta.images[ image.uuid ] = {
5445 uuid: image.uuid,
5446 url: getDataURL( image )
5447 };
5448
5449 }
5450
5451 output.image = image.uuid;
5452
5453 }
5454
5455 if ( ! isRootObject ) {
5456
5457 meta.textures[ this.uuid ] = output;
5458
5459 }
5460
5461 return output;
5462
5463 },
5464
5465 dispose: function () {
5466
5467 this.dispatchEvent( { type: 'dispose' } );
5468
5469 },
5470
5471 transformUv: function ( uv ) {
5472
5473 if ( this.mapping !== UVMapping ) return;
5474
5475 uv.applyMatrix3( this.matrix );
5476
5477 if ( uv.x < 0 || uv.x > 1 ) {
5478
5479 switch ( this.wrapS ) {
5480
5481 case RepeatWrapping:
5482
5483 uv.x = uv.x - Math.floor( uv.x );
5484 break;
5485
5486 case ClampToEdgeWrapping:
5487
5488 uv.x = uv.x < 0 ? 0 : 1;
5489 break;
5490
5491 case MirroredRepeatWrapping:
5492
5493 if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
5494
5495 uv.x = Math.ceil( uv.x ) - uv.x;
5496
5497 } else {
5498
5499 uv.x = uv.x - Math.floor( uv.x );
5500
5501 }
5502 break;
5503
5504 }
5505
5506 }
5507
5508 if ( uv.y < 0 || uv.y > 1 ) {
5509
5510 switch ( this.wrapT ) {
5511
5512 case RepeatWrapping:
5513
5514 uv.y = uv.y - Math.floor( uv.y );
5515 break;
5516
5517 case ClampToEdgeWrapping:
5518
5519 uv.y = uv.y < 0 ? 0 : 1;
5520 break;
5521
5522 case MirroredRepeatWrapping:
5523
5524 if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
5525
5526 uv.y = Math.ceil( uv.y ) - uv.y;
5527
5528 } else {
5529
5530 uv.y = uv.y - Math.floor( uv.y );
5531
5532 }
5533 break;
5534
5535 }
5536
5537 }
5538
5539 if ( this.flipY ) {
5540
5541 uv.y = 1 - uv.y;
5542
5543 }
5544
5545 }
5546
5547} );
5548
5549Object.defineProperty( Texture.prototype, "needsUpdate", {
5550
5551 set: function ( value ) {
5552
5553 if ( value === true ) this.version ++;
5554
5555 }
5556
5557} );
5558
5559/**
5560 * @author supereggbert / http://www.paulbrunt.co.uk/
5561 * @author philogb / http://blog.thejit.org/
5562 * @author mikael emtinger / http://gomo.se/
5563 * @author egraether / http://egraether.com/
5564 * @author WestLangley / http://github.com/WestLangley
5565 */
5566
5567function Vector4( x, y, z, w ) {
5568
5569 this.x = x || 0;
5570 this.y = y || 0;
5571 this.z = z || 0;
5572 this.w = ( w !== undefined ) ? w : 1;
5573
5574}
5575
5576Object.assign( Vector4.prototype, {
5577
5578 isVector4: true,
5579
5580 set: function ( x, y, z, w ) {
5581
5582 this.x = x;
5583 this.y = y;
5584 this.z = z;
5585 this.w = w;
5586
5587 return this;
5588
5589 },
5590
5591 setScalar: function ( scalar ) {
5592
5593 this.x = scalar;
5594 this.y = scalar;
5595 this.z = scalar;
5596 this.w = scalar;
5597
5598 return this;
5599
5600 },
5601
5602 setX: function ( x ) {
5603
5604 this.x = x;
5605
5606 return this;
5607
5608 },
5609
5610 setY: function ( y ) {
5611
5612 this.y = y;
5613
5614 return this;
5615
5616 },
5617
5618 setZ: function ( z ) {
5619
5620 this.z = z;
5621
5622 return this;
5623
5624 },
5625
5626 setW: function ( w ) {
5627
5628 this.w = w;
5629
5630 return this;
5631
5632 },
5633
5634 setComponent: function ( index, value ) {
5635
5636 switch ( index ) {
5637
5638 case 0: this.x = value; break;
5639 case 1: this.y = value; break;
5640 case 2: this.z = value; break;
5641 case 3: this.w = value; break;
5642 default: throw new Error( 'index is out of range: ' + index );
5643
5644 }
5645
5646 return this;
5647
5648 },
5649
5650 getComponent: function ( index ) {
5651
5652 switch ( index ) {
5653
5654 case 0: return this.x;
5655 case 1: return this.y;
5656 case 2: return this.z;
5657 case 3: return this.w;
5658 default: throw new Error( 'index is out of range: ' + index );
5659
5660 }
5661
5662 },
5663
5664 clone: function () {
5665
5666 return new this.constructor( this.x, this.y, this.z, this.w );
5667
5668 },
5669
5670 copy: function ( v ) {
5671
5672 this.x = v.x;
5673 this.y = v.y;
5674 this.z = v.z;
5675 this.w = ( v.w !== undefined ) ? v.w : 1;
5676
5677 return this;
5678
5679 },
5680
5681 add: function ( v, w ) {
5682
5683 if ( w !== undefined ) {
5684
5685 console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
5686 return this.addVectors( v, w );
5687
5688 }
5689
5690 this.x += v.x;
5691 this.y += v.y;
5692 this.z += v.z;
5693 this.w += v.w;
5694
5695 return this;
5696
5697 },
5698
5699 addScalar: function ( s ) {
5700
5701 this.x += s;
5702 this.y += s;
5703 this.z += s;
5704 this.w += s;
5705
5706 return this;
5707
5708 },
5709
5710 addVectors: function ( a, b ) {
5711
5712 this.x = a.x + b.x;
5713 this.y = a.y + b.y;
5714 this.z = a.z + b.z;
5715 this.w = a.w + b.w;
5716
5717 return this;
5718
5719 },
5720
5721 addScaledVector: function ( v, s ) {
5722
5723 this.x += v.x * s;
5724 this.y += v.y * s;
5725 this.z += v.z * s;
5726 this.w += v.w * s;
5727
5728 return this;
5729
5730 },
5731
5732 sub: function ( v, w ) {
5733
5734 if ( w !== undefined ) {
5735
5736 console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
5737 return this.subVectors( v, w );
5738
5739 }
5740
5741 this.x -= v.x;
5742 this.y -= v.y;
5743 this.z -= v.z;
5744 this.w -= v.w;
5745
5746 return this;
5747
5748 },
5749
5750 subScalar: function ( s ) {
5751
5752 this.x -= s;
5753 this.y -= s;
5754 this.z -= s;
5755 this.w -= s;
5756
5757 return this;
5758
5759 },
5760
5761 subVectors: function ( a, b ) {
5762
5763 this.x = a.x - b.x;
5764 this.y = a.y - b.y;
5765 this.z = a.z - b.z;
5766 this.w = a.w - b.w;
5767
5768 return this;
5769
5770 },
5771
5772 multiplyScalar: function ( scalar ) {
5773
5774 this.x *= scalar;
5775 this.y *= scalar;
5776 this.z *= scalar;
5777 this.w *= scalar;
5778
5779 return this;
5780
5781 },
5782
5783 applyMatrix4: function ( m ) {
5784
5785 var x = this.x, y = this.y, z = this.z, w = this.w;
5786 var e = m.elements;
5787
5788 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;
5789 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;
5790 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;
5791 this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;
5792
5793 return this;
5794
5795 },
5796
5797 divideScalar: function ( scalar ) {
5798
5799 return this.multiplyScalar( 1 / scalar );
5800
5801 },
5802
5803 setAxisAngleFromQuaternion: function ( q ) {
5804
5805 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
5806
5807 // q is assumed to be normalized
5808
5809 this.w = 2 * Math.acos( q.w );
5810
5811 var s = Math.sqrt( 1 - q.w * q.w );
5812
5813 if ( s < 0.0001 ) {
5814
5815 this.x = 1;
5816 this.y = 0;
5817 this.z = 0;
5818
5819 } else {
5820
5821 this.x = q.x / s;
5822 this.y = q.y / s;
5823 this.z = q.z / s;
5824
5825 }
5826
5827 return this;
5828
5829 },
5830
5831 setAxisAngleFromRotationMatrix: function ( m ) {
5832
5833 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
5834
5835 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
5836
5837 var angle, x, y, z, // variables for result
5838 epsilon = 0.01, // margin to allow for rounding errors
5839 epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees
5840
5841 te = m.elements,
5842
5843 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
5844 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
5845 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
5846
5847 if ( ( Math.abs( m12 - m21 ) < epsilon ) &&
5848 ( Math.abs( m13 - m31 ) < epsilon ) &&
5849 ( Math.abs( m23 - m32 ) < epsilon ) ) {
5850
5851 // singularity found
5852 // first check for identity matrix which must have +1 for all terms
5853 // in leading diagonal and zero in other terms
5854
5855 if ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&
5856 ( Math.abs( m13 + m31 ) < epsilon2 ) &&
5857 ( Math.abs( m23 + m32 ) < epsilon2 ) &&
5858 ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {
5859
5860 // this singularity is identity matrix so angle = 0
5861
5862 this.set( 1, 0, 0, 0 );
5863
5864 return this; // zero angle, arbitrary axis
5865
5866 }
5867
5868 // otherwise this singularity is angle = 180
5869
5870 angle = Math.PI;
5871
5872 var xx = ( m11 + 1 ) / 2;
5873 var yy = ( m22 + 1 ) / 2;
5874 var zz = ( m33 + 1 ) / 2;
5875 var xy = ( m12 + m21 ) / 4;
5876 var xz = ( m13 + m31 ) / 4;
5877 var yz = ( m23 + m32 ) / 4;
5878
5879 if ( ( xx > yy ) && ( xx > zz ) ) {
5880
5881 // m11 is the largest diagonal term
5882
5883 if ( xx < epsilon ) {
5884
5885 x = 0;
5886 y = 0.707106781;
5887 z = 0.707106781;
5888
5889 } else {
5890
5891 x = Math.sqrt( xx );
5892 y = xy / x;
5893 z = xz / x;
5894
5895 }
5896
5897 } else if ( yy > zz ) {
5898
5899 // m22 is the largest diagonal term
5900
5901 if ( yy < epsilon ) {
5902
5903 x = 0.707106781;
5904 y = 0;
5905 z = 0.707106781;
5906
5907 } else {
5908
5909 y = Math.sqrt( yy );
5910 x = xy / y;
5911 z = yz / y;
5912
5913 }
5914
5915 } else {
5916
5917 // m33 is the largest diagonal term so base result on this
5918
5919 if ( zz < epsilon ) {
5920
5921 x = 0.707106781;
5922 y = 0.707106781;
5923 z = 0;
5924
5925 } else {
5926
5927 z = Math.sqrt( zz );
5928 x = xz / z;
5929 y = yz / z;
5930
5931 }
5932
5933 }
5934
5935 this.set( x, y, z, angle );
5936
5937 return this; // return 180 deg rotation
5938
5939 }
5940
5941 // as we have reached here there are no singularities so we can handle normally
5942
5943 var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +
5944 ( m13 - m31 ) * ( m13 - m31 ) +
5945 ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize
5946
5947 if ( Math.abs( s ) < 0.001 ) s = 1;
5948
5949 // prevent divide by zero, should not happen if matrix is orthogonal and should be
5950 // caught by singularity test above, but I've left it in just in case
5951
5952 this.x = ( m32 - m23 ) / s;
5953 this.y = ( m13 - m31 ) / s;
5954 this.z = ( m21 - m12 ) / s;
5955 this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );
5956
5957 return this;
5958
5959 },
5960
5961 min: function ( v ) {
5962
5963 this.x = Math.min( this.x, v.x );
5964 this.y = Math.min( this.y, v.y );
5965 this.z = Math.min( this.z, v.z );
5966 this.w = Math.min( this.w, v.w );
5967
5968 return this;
5969
5970 },
5971
5972 max: function ( v ) {
5973
5974 this.x = Math.max( this.x, v.x );
5975 this.y = Math.max( this.y, v.y );
5976 this.z = Math.max( this.z, v.z );
5977 this.w = Math.max( this.w, v.w );
5978
5979 return this;
5980
5981 },
5982
5983 clamp: function ( min, max ) {
5984
5985 // assumes min < max, componentwise
5986
5987 this.x = Math.max( min.x, Math.min( max.x, this.x ) );
5988 this.y = Math.max( min.y, Math.min( max.y, this.y ) );
5989 this.z = Math.max( min.z, Math.min( max.z, this.z ) );
5990 this.w = Math.max( min.w, Math.min( max.w, this.w ) );
5991
5992 return this;
5993
5994 },
5995
5996 clampScalar: function () {
5997
5998 var min, max;
5999
6000 return function clampScalar( minVal, maxVal ) {
6001
6002 if ( min === undefined ) {
6003
6004 min = new Vector4();
6005 max = new Vector4();
6006
6007 }
6008
6009 min.set( minVal, minVal, minVal, minVal );
6010 max.set( maxVal, maxVal, maxVal, maxVal );
6011
6012 return this.clamp( min, max );
6013
6014 };
6015
6016 }(),
6017
6018 clampLength: function ( min, max ) {
6019
6020 var length = this.length();
6021
6022 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );
6023
6024 },
6025
6026 floor: function () {
6027
6028 this.x = Math.floor( this.x );
6029 this.y = Math.floor( this.y );
6030 this.z = Math.floor( this.z );
6031 this.w = Math.floor( this.w );
6032
6033 return this;
6034
6035 },
6036
6037 ceil: function () {
6038
6039 this.x = Math.ceil( this.x );
6040 this.y = Math.ceil( this.y );
6041 this.z = Math.ceil( this.z );
6042 this.w = Math.ceil( this.w );
6043
6044 return this;
6045
6046 },
6047
6048 round: function () {
6049
6050 this.x = Math.round( this.x );
6051 this.y = Math.round( this.y );
6052 this.z = Math.round( this.z );
6053 this.w = Math.round( this.w );
6054
6055 return this;
6056
6057 },
6058
6059 roundToZero: function () {
6060
6061 this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
6062 this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
6063 this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
6064 this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );
6065
6066 return this;
6067
6068 },
6069
6070 negate: function () {
6071
6072 this.x = - this.x;
6073 this.y = - this.y;
6074 this.z = - this.z;
6075 this.w = - this.w;
6076
6077 return this;
6078
6079 },
6080
6081 dot: function ( v ) {
6082
6083 return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
6084
6085 },
6086
6087 lengthSq: function () {
6088
6089 return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
6090
6091 },
6092
6093 length: function () {
6094
6095 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );
6096
6097 },
6098
6099 manhattanLength: function () {
6100
6101 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );
6102
6103 },
6104
6105 normalize: function () {
6106
6107 return this.divideScalar( this.length() || 1 );
6108
6109 },
6110
6111 setLength: function ( length ) {
6112
6113 return this.normalize().multiplyScalar( length );
6114
6115 },
6116
6117 lerp: function ( v, alpha ) {
6118
6119 this.x += ( v.x - this.x ) * alpha;
6120 this.y += ( v.y - this.y ) * alpha;
6121 this.z += ( v.z - this.z ) * alpha;
6122 this.w += ( v.w - this.w ) * alpha;
6123
6124 return this;
6125
6126 },
6127
6128 lerpVectors: function ( v1, v2, alpha ) {
6129
6130 return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
6131
6132 },
6133
6134 equals: function ( v ) {
6135
6136 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );
6137
6138 },
6139
6140 fromArray: function ( array, offset ) {
6141
6142 if ( offset === undefined ) offset = 0;
6143
6144 this.x = array[ offset ];
6145 this.y = array[ offset + 1 ];
6146 this.z = array[ offset + 2 ];
6147 this.w = array[ offset + 3 ];
6148
6149 return this;
6150
6151 },
6152
6153 toArray: function ( array, offset ) {
6154
6155 if ( array === undefined ) array = [];
6156 if ( offset === undefined ) offset = 0;
6157
6158 array[ offset ] = this.x;
6159 array[ offset + 1 ] = this.y;
6160 array[ offset + 2 ] = this.z;
6161 array[ offset + 3 ] = this.w;
6162
6163 return array;
6164
6165 },
6166
6167 fromBufferAttribute: function ( attribute, index, offset ) {
6168
6169 if ( offset !== undefined ) {
6170
6171 console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' );
6172
6173 }
6174
6175 this.x = attribute.getX( index );
6176 this.y = attribute.getY( index );
6177 this.z = attribute.getZ( index );
6178 this.w = attribute.getW( index );
6179
6180 return this;
6181
6182 }
6183
6184} );
6185
6186/**
6187 * @author szimek / https://github.com/szimek/
6188 * @author alteredq / http://alteredqualia.com/
6189 * @author Marius Kintel / https://github.com/kintel
6190 */
6191
6192/*
6193 In options, we can specify:
6194 * Texture parameters for an auto-generated target texture
6195 * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
6196*/
6197function WebGLRenderTarget( width, height, options ) {
6198
6199 this.uuid = _Math.generateUUID();
6200
6201 this.width = width;
6202 this.height = height;
6203
6204 this.scissor = new Vector4( 0, 0, width, height );
6205 this.scissorTest = false;
6206
6207 this.viewport = new Vector4( 0, 0, width, height );
6208
6209 options = options || {};
6210
6211 if ( options.minFilter === undefined ) options.minFilter = LinearFilter;
6212
6213 this.texture = new Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding );
6214
6215 this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
6216 this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true;
6217 this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;
6218
6219}
6220
6221WebGLRenderTarget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
6222
6223 constructor: WebGLRenderTarget,
6224
6225 isWebGLRenderTarget: true,
6226
6227 setSize: function ( width, height ) {
6228
6229 if ( this.width !== width || this.height !== height ) {
6230
6231 this.width = width;
6232 this.height = height;
6233
6234 this.dispose();
6235
6236 }
6237
6238 this.viewport.set( 0, 0, width, height );
6239 this.scissor.set( 0, 0, width, height );
6240
6241 },
6242
6243 clone: function () {
6244
6245 return new this.constructor().copy( this );
6246
6247 },
6248
6249 copy: function ( source ) {
6250
6251 this.width = source.width;
6252 this.height = source.height;
6253
6254 this.viewport.copy( source.viewport );
6255
6256 this.texture = source.texture.clone();
6257
6258 this.depthBuffer = source.depthBuffer;
6259 this.stencilBuffer = source.stencilBuffer;
6260 this.depthTexture = source.depthTexture;
6261
6262 return this;
6263
6264 },
6265
6266 dispose: function () {
6267
6268 this.dispatchEvent( { type: 'dispose' } );
6269
6270 }
6271
6272} );
6273
6274/**
6275 * @author alteredq / http://alteredqualia.com/
6276 */
6277
6278function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) {
6279
6280 Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
6281
6282 this.image = { data: data, width: width, height: height };
6283
6284 this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
6285 this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
6286
6287 this.generateMipmaps = false;
6288 this.flipY = false;
6289 this.unpackAlignment = 1;
6290
6291}
6292
6293DataTexture.prototype = Object.create( Texture.prototype );
6294DataTexture.prototype.constructor = DataTexture;
6295
6296DataTexture.prototype.isDataTexture = true;
6297
6298/**
6299 * @author mrdoob / http://mrdoob.com/
6300 */
6301
6302function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) {
6303
6304 images = images !== undefined ? images : [];
6305 mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
6306
6307 Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding );
6308
6309 this.flipY = false;
6310
6311}
6312
6313CubeTexture.prototype = Object.create( Texture.prototype );
6314CubeTexture.prototype.constructor = CubeTexture;
6315
6316CubeTexture.prototype.isCubeTexture = true;
6317
6318Object.defineProperty( CubeTexture.prototype, 'images', {
6319
6320 get: function () {
6321
6322 return this.image;
6323
6324 },
6325
6326 set: function ( value ) {
6327
6328 this.image = value;
6329
6330 }
6331
6332} );
6333
6334/**
6335 * @author tschw
6336 *
6337 * Uniforms of a program.
6338 * Those form a tree structure with a special top-level container for the root,
6339 * which you get by calling 'new WebGLUniforms( gl, program, renderer )'.
6340 *
6341 *
6342 * Properties of inner nodes including the top-level container:
6343 *
6344 * .seq - array of nested uniforms
6345 * .map - nested uniforms by name
6346 *
6347 *
6348 * Methods of all nodes except the top-level container:
6349 *
6350 * .setValue( gl, value, [renderer] )
6351 *
6352 * uploads a uniform value(s)
6353 * the 'renderer' parameter is needed for sampler uniforms
6354 *
6355 *
6356 * Static methods of the top-level container (renderer factorizations):
6357 *
6358 * .upload( gl, seq, values, renderer )
6359 *
6360 * sets uniforms in 'seq' to 'values[id].value'
6361 *
6362 * .seqWithValue( seq, values ) : filteredSeq
6363 *
6364 * filters 'seq' entries with corresponding entry in values
6365 *
6366 *
6367 * Methods of the top-level container (renderer factorizations):
6368 *
6369 * .setValue( gl, name, value )
6370 *
6371 * sets uniform with name 'name' to 'value'
6372 *
6373 * .set( gl, obj, prop )
6374 *
6375 * sets uniform from object and property with same name than uniform
6376 *
6377 * .setOptional( gl, obj, prop )
6378 *
6379 * like .set for an optional property of the object
6380 *
6381 */
6382
6383var emptyTexture = new Texture();
6384var emptyCubeTexture = new CubeTexture();
6385
6386// --- Base for inner nodes (including the root) ---
6387
6388function UniformContainer() {
6389
6390 this.seq = [];
6391 this.map = {};
6392
6393}
6394
6395// --- Utilities ---
6396
6397// Array Caches (provide typed arrays for temporary by size)
6398
6399var arrayCacheF32 = [];
6400var arrayCacheI32 = [];
6401
6402// Float32Array caches used for uploading Matrix uniforms
6403
6404var mat4array = new Float32Array( 16 );
6405var mat3array = new Float32Array( 9 );
6406
6407// Flattening for arrays of vectors and matrices
6408
6409function flatten( array, nBlocks, blockSize ) {
6410
6411 var firstElem = array[ 0 ];
6412
6413 if ( firstElem <= 0 || firstElem > 0 ) return array;
6414 // unoptimized: ! isNaN( firstElem )
6415 // see http://jacksondunstan.com/articles/983
6416
6417 var n = nBlocks * blockSize,
6418 r = arrayCacheF32[ n ];
6419
6420 if ( r === undefined ) {
6421
6422 r = new Float32Array( n );
6423 arrayCacheF32[ n ] = r;
6424
6425 }
6426
6427 if ( nBlocks !== 0 ) {
6428
6429 firstElem.toArray( r, 0 );
6430
6431 for ( var i = 1, offset = 0; i !== nBlocks; ++ i ) {
6432
6433 offset += blockSize;
6434 array[ i ].toArray( r, offset );
6435
6436 }
6437
6438 }
6439
6440 return r;
6441
6442}
6443
6444// Texture unit allocation
6445
6446function allocTexUnits( renderer, n ) {
6447
6448 var r = arrayCacheI32[ n ];
6449
6450 if ( r === undefined ) {
6451
6452 r = new Int32Array( n );
6453 arrayCacheI32[ n ] = r;
6454
6455 }
6456
6457 for ( var i = 0; i !== n; ++ i )
6458 r[ i ] = renderer.allocTextureUnit();
6459
6460 return r;
6461
6462}
6463
6464// --- Setters ---
6465
6466// Note: Defining these methods externally, because they come in a bunch
6467// and this way their names minify.
6468
6469// Single scalar
6470
6471function setValue1f( gl, v ) {
6472
6473 gl.uniform1f( this.addr, v );
6474
6475}
6476
6477function setValue1i( gl, v ) {
6478
6479 gl.uniform1i( this.addr, v );
6480
6481}
6482
6483// Single float vector (from flat array or THREE.VectorN)
6484
6485function setValue2fv( gl, v ) {
6486
6487 if ( v.x === undefined ) {
6488
6489 gl.uniform2fv( this.addr, v );
6490
6491 } else {
6492
6493 gl.uniform2f( this.addr, v.x, v.y );
6494
6495 }
6496
6497}
6498
6499function setValue3fv( gl, v ) {
6500
6501 if ( v.x !== undefined ) {
6502
6503 gl.uniform3f( this.addr, v.x, v.y, v.z );
6504
6505 } else if ( v.r !== undefined ) {
6506
6507 gl.uniform3f( this.addr, v.r, v.g, v.b );
6508
6509 } else {
6510
6511 gl.uniform3fv( this.addr, v );
6512
6513 }
6514
6515}
6516
6517function setValue4fv( gl, v ) {
6518
6519 if ( v.x === undefined ) {
6520
6521 gl.uniform4fv( this.addr, v );
6522
6523 } else {
6524
6525 gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );
6526
6527 }
6528
6529}
6530
6531// Single matrix (from flat array or MatrixN)
6532
6533function setValue2fm( gl, v ) {
6534
6535 gl.uniformMatrix2fv( this.addr, false, v.elements || v );
6536
6537}
6538
6539function setValue3fm( gl, v ) {
6540
6541 if ( v.elements === undefined ) {
6542
6543 gl.uniformMatrix3fv( this.addr, false, v );
6544
6545 } else {
6546
6547 mat3array.set( v.elements );
6548 gl.uniformMatrix3fv( this.addr, false, mat3array );
6549
6550 }
6551
6552}
6553
6554function setValue4fm( gl, v ) {
6555
6556 if ( v.elements === undefined ) {
6557
6558 gl.uniformMatrix4fv( this.addr, false, v );
6559
6560 } else {
6561
6562 mat4array.set( v.elements );
6563 gl.uniformMatrix4fv( this.addr, false, mat4array );
6564
6565 }
6566
6567}
6568
6569// Single texture (2D / Cube)
6570
6571function setValueT1( gl, v, renderer ) {
6572
6573 var unit = renderer.allocTextureUnit();
6574 gl.uniform1i( this.addr, unit );
6575 renderer.setTexture2D( v || emptyTexture, unit );
6576
6577}
6578
6579function setValueT6( gl, v, renderer ) {
6580
6581 var unit = renderer.allocTextureUnit();
6582 gl.uniform1i( this.addr, unit );
6583 renderer.setTextureCube( v || emptyCubeTexture, unit );
6584
6585}
6586
6587// Integer / Boolean vectors or arrays thereof (always flat arrays)
6588
6589function setValue2iv( gl, v ) {
6590
6591 gl.uniform2iv( this.addr, v );
6592
6593}
6594
6595function setValue3iv( gl, v ) {
6596
6597 gl.uniform3iv( this.addr, v );
6598
6599}
6600
6601function setValue4iv( gl, v ) {
6602
6603 gl.uniform4iv( this.addr, v );
6604
6605}
6606
6607// Helper to pick the right setter for the singular case
6608
6609function getSingularSetter( type ) {
6610
6611 switch ( type ) {
6612
6613 case 0x1406: return setValue1f; // FLOAT
6614 case 0x8b50: return setValue2fv; // _VEC2
6615 case 0x8b51: return setValue3fv; // _VEC3
6616 case 0x8b52: return setValue4fv; // _VEC4
6617
6618 case 0x8b5a: return setValue2fm; // _MAT2
6619 case 0x8b5b: return setValue3fm; // _MAT3
6620 case 0x8b5c: return setValue4fm; // _MAT4
6621
6622 case 0x8b5e: case 0x8d66: return setValueT1; // SAMPLER_2D, SAMPLER_EXTERNAL_OES
6623 case 0x8b60: return setValueT6; // SAMPLER_CUBE
6624
6625 case 0x1404: case 0x8b56: return setValue1i; // INT, BOOL
6626 case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
6627 case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
6628 case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4
6629
6630 }
6631
6632}
6633
6634// Array of scalars
6635
6636function setValue1fv( gl, v ) {
6637
6638 gl.uniform1fv( this.addr, v );
6639
6640}
6641function setValue1iv( gl, v ) {
6642
6643 gl.uniform1iv( this.addr, v );
6644
6645}
6646
6647// Array of vectors (flat or from THREE classes)
6648
6649function setValueV2a( gl, v ) {
6650
6651 gl.uniform2fv( this.addr, flatten( v, this.size, 2 ) );
6652
6653}
6654
6655function setValueV3a( gl, v ) {
6656
6657 gl.uniform3fv( this.addr, flatten( v, this.size, 3 ) );
6658
6659}
6660
6661function setValueV4a( gl, v ) {
6662
6663 gl.uniform4fv( this.addr, flatten( v, this.size, 4 ) );
6664
6665}
6666
6667// Array of matrices (flat or from THREE clases)
6668
6669function setValueM2a( gl, v ) {
6670
6671 gl.uniformMatrix2fv( this.addr, false, flatten( v, this.size, 4 ) );
6672
6673}
6674
6675function setValueM3a( gl, v ) {
6676
6677 gl.uniformMatrix3fv( this.addr, false, flatten( v, this.size, 9 ) );
6678
6679}
6680
6681function setValueM4a( gl, v ) {
6682
6683 gl.uniformMatrix4fv( this.addr, false, flatten( v, this.size, 16 ) );
6684
6685}
6686
6687// Array of textures (2D / Cube)
6688
6689function setValueT1a( gl, v, renderer ) {
6690
6691 var n = v.length,
6692 units = allocTexUnits( renderer, n );
6693
6694 gl.uniform1iv( this.addr, units );
6695
6696 for ( var i = 0; i !== n; ++ i ) {
6697
6698 renderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] );
6699
6700 }
6701
6702}
6703
6704function setValueT6a( gl, v, renderer ) {
6705
6706 var n = v.length,
6707 units = allocTexUnits( renderer, n );
6708
6709 gl.uniform1iv( this.addr, units );
6710
6711 for ( var i = 0; i !== n; ++ i ) {
6712
6713 renderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );
6714
6715 }
6716
6717}
6718
6719// Helper to pick the right setter for a pure (bottom-level) array
6720
6721function getPureArraySetter( type ) {
6722
6723 switch ( type ) {
6724
6725 case 0x1406: return setValue1fv; // FLOAT
6726 case 0x8b50: return setValueV2a; // _VEC2
6727 case 0x8b51: return setValueV3a; // _VEC3
6728 case 0x8b52: return setValueV4a; // _VEC4
6729
6730 case 0x8b5a: return setValueM2a; // _MAT2
6731 case 0x8b5b: return setValueM3a; // _MAT3
6732 case 0x8b5c: return setValueM4a; // _MAT4
6733
6734 case 0x8b5e: return setValueT1a; // SAMPLER_2D
6735 case 0x8b60: return setValueT6a; // SAMPLER_CUBE
6736
6737 case 0x1404: case 0x8b56: return setValue1iv; // INT, BOOL
6738 case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2
6739 case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3
6740 case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4
6741
6742 }
6743
6744}
6745
6746// --- Uniform Classes ---
6747
6748function SingleUniform( id, activeInfo, addr ) {
6749
6750 this.id = id;
6751 this.addr = addr;
6752 this.setValue = getSingularSetter( activeInfo.type );
6753
6754 // this.path = activeInfo.name; // DEBUG
6755
6756}
6757
6758function PureArrayUniform( id, activeInfo, addr ) {
6759
6760 this.id = id;
6761 this.addr = addr;
6762 this.size = activeInfo.size;
6763 this.setValue = getPureArraySetter( activeInfo.type );
6764
6765 // this.path = activeInfo.name; // DEBUG
6766
6767}
6768
6769function StructuredUniform( id ) {
6770
6771 this.id = id;
6772
6773 UniformContainer.call( this ); // mix-in
6774
6775}
6776
6777StructuredUniform.prototype.setValue = function ( gl, value ) {
6778
6779 // Note: Don't need an extra 'renderer' parameter, since samplers
6780 // are not allowed in structured uniforms.
6781
6782 var seq = this.seq;
6783
6784 for ( var i = 0, n = seq.length; i !== n; ++ i ) {
6785
6786 var u = seq[ i ];
6787 u.setValue( gl, value[ u.id ] );
6788
6789 }
6790
6791};
6792
6793// --- Top-level ---
6794
6795// Parser - builds up the property tree from the path strings
6796
6797var RePathPart = /([\w\d_]+)(\])?(\[|\.)?/g;
6798
6799// extracts
6800// - the identifier (member name or array index)
6801// - followed by an optional right bracket (found when array index)
6802// - followed by an optional left bracket or dot (type of subscript)
6803//
6804// Note: These portions can be read in a non-overlapping fashion and
6805// allow straightforward parsing of the hierarchy that WebGL encodes
6806// in the uniform names.
6807
6808function addUniform( container, uniformObject ) {
6809
6810 container.seq.push( uniformObject );
6811 container.map[ uniformObject.id ] = uniformObject;
6812
6813}
6814
6815function parseUniform( activeInfo, addr, container ) {
6816
6817 var path = activeInfo.name,
6818 pathLength = path.length;
6819
6820 // reset RegExp object, because of the early exit of a previous run
6821 RePathPart.lastIndex = 0;
6822
6823 for ( ; ; ) {
6824
6825 var match = RePathPart.exec( path ),
6826 matchEnd = RePathPart.lastIndex,
6827
6828 id = match[ 1 ],
6829 idIsIndex = match[ 2 ] === ']',
6830 subscript = match[ 3 ];
6831
6832 if ( idIsIndex ) id = id | 0; // convert to integer
6833
6834 if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {
6835
6836 // bare name or "pure" bottom-level array "[0]" suffix
6837
6838 addUniform( container, subscript === undefined ?
6839 new SingleUniform( id, activeInfo, addr ) :
6840 new PureArrayUniform( id, activeInfo, addr ) );
6841
6842 break;
6843
6844 } else {
6845
6846 // step into inner node / create it in case it doesn't exist
6847
6848 var map = container.map, next = map[ id ];
6849
6850 if ( next === undefined ) {
6851
6852 next = new StructuredUniform( id );
6853 addUniform( container, next );
6854
6855 }
6856
6857 container = next;
6858
6859 }
6860
6861 }
6862
6863}
6864
6865// Root Container
6866
6867function WebGLUniforms( gl, program, renderer ) {
6868
6869 UniformContainer.call( this );
6870
6871 this.renderer = renderer;
6872
6873 var n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
6874
6875 for ( var i = 0; i < n; ++ i ) {
6876
6877 var info = gl.getActiveUniform( program, i ),
6878 path = info.name,
6879 addr = gl.getUniformLocation( program, path );
6880
6881 parseUniform( info, addr, this );
6882
6883 }
6884
6885}
6886
6887WebGLUniforms.prototype.setValue = function ( gl, name, value ) {
6888
6889 var u = this.map[ name ];
6890
6891 if ( u !== undefined ) u.setValue( gl, value, this.renderer );
6892
6893};
6894
6895WebGLUniforms.prototype.setOptional = function ( gl, object, name ) {
6896
6897 var v = object[ name ];
6898
6899 if ( v !== undefined ) this.setValue( gl, name, v );
6900
6901};
6902
6903
6904// Static interface
6905
6906WebGLUniforms.upload = function ( gl, seq, values, renderer ) {
6907
6908 for ( var i = 0, n = seq.length; i !== n; ++ i ) {
6909
6910 var u = seq[ i ],
6911 v = values[ u.id ];
6912
6913 if ( v.needsUpdate !== false ) {
6914
6915 // note: always updating when .needsUpdate is undefined
6916 u.setValue( gl, v.value, renderer );
6917
6918 }
6919
6920 }
6921
6922};
6923
6924WebGLUniforms.seqWithValue = function ( seq, values ) {
6925
6926 var r = [];
6927
6928 for ( var i = 0, n = seq.length; i !== n; ++ i ) {
6929
6930 var u = seq[ i ];
6931 if ( u.id in values ) r.push( u );
6932
6933 }
6934
6935 return r;
6936
6937};
6938
6939/**
6940 * @author mrdoob / http://mrdoob.com/
6941 */
6942
6943var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
6944 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
6945 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
6946 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
6947 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
6948 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
6949 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
6950 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
6951 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
6952 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
6953 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
6954 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
6955 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
6956 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
6957 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
6958 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
6959 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
6960 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
6961 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
6962 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
6963 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
6964 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
6965 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
6966 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
6967
6968function Color( r, g, b ) {
6969
6970 if ( g === undefined && b === undefined ) {
6971
6972 // r is THREE.Color, hex or string
6973 return this.set( r );
6974
6975 }
6976
6977 return this.setRGB( r, g, b );
6978
6979}
6980
6981Object.assign( Color.prototype, {
6982
6983 isColor: true,
6984
6985 r: 1, g: 1, b: 1,
6986
6987 set: function ( value ) {
6988
6989 if ( value && value.isColor ) {
6990
6991 this.copy( value );
6992
6993 } else if ( typeof value === 'number' ) {
6994
6995 this.setHex( value );
6996
6997 } else if ( typeof value === 'string' ) {
6998
6999 this.setStyle( value );
7000
7001 }
7002
7003 return this;
7004
7005 },
7006
7007 setScalar: function ( scalar ) {
7008
7009 this.r = scalar;
7010 this.g = scalar;
7011 this.b = scalar;
7012
7013 return this;
7014
7015 },
7016
7017 setHex: function ( hex ) {
7018
7019 hex = Math.floor( hex );
7020
7021 this.r = ( hex >> 16 & 255 ) / 255;
7022 this.g = ( hex >> 8 & 255 ) / 255;
7023 this.b = ( hex & 255 ) / 255;
7024
7025 return this;
7026
7027 },
7028
7029 setRGB: function ( r, g, b ) {
7030
7031 this.r = r;
7032 this.g = g;
7033 this.b = b;
7034
7035 return this;
7036
7037 },
7038
7039 setHSL: function () {
7040
7041 function hue2rgb( p, q, t ) {
7042
7043 if ( t < 0 ) t += 1;
7044 if ( t > 1 ) t -= 1;
7045 if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
7046 if ( t < 1 / 2 ) return q;
7047 if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
7048 return p;
7049
7050 }
7051
7052 return function setHSL( h, s, l ) {
7053
7054 // h,s,l ranges are in 0.0 - 1.0
7055 h = _Math.euclideanModulo( h, 1 );
7056 s = _Math.clamp( s, 0, 1 );
7057 l = _Math.clamp( l, 0, 1 );
7058
7059 if ( s === 0 ) {
7060
7061 this.r = this.g = this.b = l;
7062
7063 } else {
7064
7065 var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
7066 var q = ( 2 * l ) - p;
7067
7068 this.r = hue2rgb( q, p, h + 1 / 3 );
7069 this.g = hue2rgb( q, p, h );
7070 this.b = hue2rgb( q, p, h - 1 / 3 );
7071
7072 }
7073
7074 return this;
7075
7076 };
7077
7078 }(),
7079
7080 setStyle: function ( style ) {
7081
7082 function handleAlpha( string ) {
7083
7084 if ( string === undefined ) return;
7085
7086 if ( parseFloat( string ) < 1 ) {
7087
7088 console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
7089
7090 }
7091
7092 }
7093
7094
7095 var m;
7096
7097 if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) {
7098
7099 // rgb / hsl
7100
7101 var color;
7102 var name = m[ 1 ];
7103 var components = m[ 2 ];
7104
7105 switch ( name ) {
7106
7107 case 'rgb':
7108 case 'rgba':
7109
7110 if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
7111
7112 // rgb(255,0,0) rgba(255,0,0,0.5)
7113 this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;
7114 this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
7115 this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
7116
7117 handleAlpha( color[ 5 ] );
7118
7119 return this;
7120
7121 }
7122
7123 if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
7124
7125 // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
7126 this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;
7127 this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
7128 this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
7129
7130 handleAlpha( color[ 5 ] );
7131
7132 return this;
7133
7134 }
7135
7136 break;
7137
7138 case 'hsl':
7139 case 'hsla':
7140
7141 if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
7142
7143 // hsl(120,50%,50%) hsla(120,50%,50%,0.5)
7144 var h = parseFloat( color[ 1 ] ) / 360;
7145 var s = parseInt( color[ 2 ], 10 ) / 100;
7146 var l = parseInt( color[ 3 ], 10 ) / 100;
7147
7148 handleAlpha( color[ 5 ] );
7149
7150 return this.setHSL( h, s, l );
7151
7152 }
7153
7154 break;
7155
7156 }
7157
7158 } else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) {
7159
7160 // hex color
7161
7162 var hex = m[ 1 ];
7163 var size = hex.length;
7164
7165 if ( size === 3 ) {
7166
7167 // #ff0
7168 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;
7169 this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
7170 this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
7171
7172 return this;
7173
7174 } else if ( size === 6 ) {
7175
7176 // #ff0000
7177 this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;
7178 this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
7179 this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;
7180
7181 return this;
7182
7183 }
7184
7185 }
7186
7187 if ( style && style.length > 0 ) {
7188
7189 // color keywords
7190 var hex = ColorKeywords[ style ];
7191
7192 if ( hex !== undefined ) {
7193
7194 // red
7195 this.setHex( hex );
7196
7197 } else {
7198
7199 // unknown color
7200 console.warn( 'THREE.Color: Unknown color ' + style );
7201
7202 }
7203
7204 }
7205
7206 return this;
7207
7208 },
7209
7210 clone: function () {
7211
7212 return new this.constructor( this.r, this.g, this.b );
7213
7214 },
7215
7216 copy: function ( color ) {
7217
7218 this.r = color.r;
7219 this.g = color.g;
7220 this.b = color.b;
7221
7222 return this;
7223
7224 },
7225
7226 copyGammaToLinear: function ( color, gammaFactor ) {
7227
7228 if ( gammaFactor === undefined ) gammaFactor = 2.0;
7229
7230 this.r = Math.pow( color.r, gammaFactor );
7231 this.g = Math.pow( color.g, gammaFactor );
7232 this.b = Math.pow( color.b, gammaFactor );
7233
7234 return this;
7235
7236 },
7237
7238 copyLinearToGamma: function ( color, gammaFactor ) {
7239
7240 if ( gammaFactor === undefined ) gammaFactor = 2.0;
7241
7242 var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;
7243
7244 this.r = Math.pow( color.r, safeInverse );
7245 this.g = Math.pow( color.g, safeInverse );
7246 this.b = Math.pow( color.b, safeInverse );
7247
7248 return this;
7249
7250 },
7251
7252 convertGammaToLinear: function () {
7253
7254 var r = this.r, g = this.g, b = this.b;
7255
7256 this.r = r * r;
7257 this.g = g * g;
7258 this.b = b * b;
7259
7260 return this;
7261
7262 },
7263
7264 convertLinearToGamma: function () {
7265
7266 this.r = Math.sqrt( this.r );
7267 this.g = Math.sqrt( this.g );
7268 this.b = Math.sqrt( this.b );
7269
7270 return this;
7271
7272 },
7273
7274 getHex: function () {
7275
7276 return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;
7277
7278 },
7279
7280 getHexString: function () {
7281
7282 return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );
7283
7284 },
7285
7286 getHSL: function ( optionalTarget ) {
7287
7288 // h,s,l ranges are in 0.0 - 1.0
7289
7290 var hsl = optionalTarget || { h: 0, s: 0, l: 0 };
7291
7292 var r = this.r, g = this.g, b = this.b;
7293
7294 var max = Math.max( r, g, b );
7295 var min = Math.min( r, g, b );
7296
7297 var hue, saturation;
7298 var lightness = ( min + max ) / 2.0;
7299
7300 if ( min === max ) {
7301
7302 hue = 0;
7303 saturation = 0;
7304
7305 } else {
7306
7307 var delta = max - min;
7308
7309 saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
7310
7311 switch ( max ) {
7312
7313 case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
7314 case g: hue = ( b - r ) / delta + 2; break;
7315 case b: hue = ( r - g ) / delta + 4; break;
7316
7317 }
7318
7319 hue /= 6;
7320
7321 }
7322
7323 hsl.h = hue;
7324 hsl.s = saturation;
7325 hsl.l = lightness;
7326
7327 return hsl;
7328
7329 },
7330
7331 getStyle: function () {
7332
7333 return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';
7334
7335 },
7336
7337 offsetHSL: function ( h, s, l ) {
7338
7339 var hsl = this.getHSL();
7340
7341 hsl.h += h; hsl.s += s; hsl.l += l;
7342
7343 this.setHSL( hsl.h, hsl.s, hsl.l );
7344
7345 return this;
7346
7347 },
7348
7349 add: function ( color ) {
7350
7351 this.r += color.r;
7352 this.g += color.g;
7353 this.b += color.b;
7354
7355 return this;
7356
7357 },
7358
7359 addColors: function ( color1, color2 ) {
7360
7361 this.r = color1.r + color2.r;
7362 this.g = color1.g + color2.g;
7363 this.b = color1.b + color2.b;
7364
7365 return this;
7366
7367 },
7368
7369 addScalar: function ( s ) {
7370
7371 this.r += s;
7372 this.g += s;
7373 this.b += s;
7374
7375 return this;
7376
7377 },
7378
7379 sub: function ( color ) {
7380
7381 this.r = Math.max( 0, this.r - color.r );
7382 this.g = Math.max( 0, this.g - color.g );
7383 this.b = Math.max( 0, this.b - color.b );
7384
7385 return this;
7386
7387 },
7388
7389 multiply: function ( color ) {
7390
7391 this.r *= color.r;
7392 this.g *= color.g;
7393 this.b *= color.b;
7394
7395 return this;
7396
7397 },
7398
7399 multiplyScalar: function ( s ) {
7400
7401 this.r *= s;
7402 this.g *= s;
7403 this.b *= s;
7404
7405 return this;
7406
7407 },
7408
7409 lerp: function ( color, alpha ) {
7410
7411 this.r += ( color.r - this.r ) * alpha;
7412 this.g += ( color.g - this.g ) * alpha;
7413 this.b += ( color.b - this.b ) * alpha;
7414
7415 return this;
7416
7417 },
7418
7419 equals: function ( c ) {
7420
7421 return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
7422
7423 },
7424
7425 fromArray: function ( array, offset ) {
7426
7427 if ( offset === undefined ) offset = 0;
7428
7429 this.r = array[ offset ];
7430 this.g = array[ offset + 1 ];
7431 this.b = array[ offset + 2 ];
7432
7433 return this;
7434
7435 },
7436
7437 toArray: function ( array, offset ) {
7438
7439 if ( array === undefined ) array = [];
7440 if ( offset === undefined ) offset = 0;
7441
7442 array[ offset ] = this.r;
7443 array[ offset + 1 ] = this.g;
7444 array[ offset + 2 ] = this.b;
7445
7446 return array;
7447
7448 },
7449
7450 toJSON: function () {
7451
7452 return this.getHex();
7453
7454 }
7455
7456} );
7457
7458/**
7459 * Uniforms library for shared webgl shaders
7460 */
7461
7462var UniformsLib = {
7463
7464 common: {
7465
7466 diffuse: { value: new Color( 0xeeeeee ) },
7467 opacity: { value: 1.0 },
7468
7469 map: { value: null },
7470 uvTransform: { value: new Matrix3() },
7471
7472 alphaMap: { value: null },
7473
7474 },
7475
7476 specularmap: {
7477
7478 specularMap: { value: null },
7479
7480 },
7481
7482 envmap: {
7483
7484 envMap: { value: null },
7485 flipEnvMap: { value: - 1 },
7486 reflectivity: { value: 1.0 },
7487 refractionRatio: { value: 0.98 }
7488
7489 },
7490
7491 aomap: {
7492
7493 aoMap: { value: null },
7494 aoMapIntensity: { value: 1 }
7495
7496 },
7497
7498 lightmap: {
7499
7500 lightMap: { value: null },
7501 lightMapIntensity: { value: 1 }
7502
7503 },
7504
7505 emissivemap: {
7506
7507 emissiveMap: { value: null }
7508
7509 },
7510
7511 bumpmap: {
7512
7513 bumpMap: { value: null },
7514 bumpScale: { value: 1 }
7515
7516 },
7517
7518 normalmap: {
7519
7520 normalMap: { value: null },
7521 normalScale: { value: new Vector2( 1, 1 ) }
7522
7523 },
7524
7525 displacementmap: {
7526
7527 displacementMap: { value: null },
7528 displacementScale: { value: 1 },
7529 displacementBias: { value: 0 }
7530
7531 },
7532
7533 roughnessmap: {
7534
7535 roughnessMap: { value: null }
7536
7537 },
7538
7539 metalnessmap: {
7540
7541 metalnessMap: { value: null }
7542
7543 },
7544
7545 gradientmap: {
7546
7547 gradientMap: { value: null }
7548
7549 },
7550
7551 fog: {
7552
7553 fogDensity: { value: 0.00025 },
7554 fogNear: { value: 1 },
7555 fogFar: { value: 2000 },
7556 fogColor: { value: new Color( 0xffffff ) }
7557
7558 },
7559
7560 lights: {
7561
7562 ambientLightColor: { value: [] },
7563
7564 directionalLights: { value: [], properties: {
7565 direction: {},
7566 color: {},
7567
7568 shadow: {},
7569 shadowBias: {},
7570 shadowRadius: {},
7571 shadowMapSize: {}
7572 } },
7573
7574 directionalShadowMap: { value: [] },
7575 directionalShadowMatrix: { value: [] },
7576
7577 spotLights: { value: [], properties: {
7578 color: {},
7579 position: {},
7580 direction: {},
7581 distance: {},
7582 coneCos: {},
7583 penumbraCos: {},
7584 decay: {},
7585
7586 shadow: {},
7587 shadowBias: {},
7588 shadowRadius: {},
7589 shadowMapSize: {}
7590 } },
7591
7592 spotShadowMap: { value: [] },
7593 spotShadowMatrix: { value: [] },
7594
7595 pointLights: { value: [], properties: {
7596 color: {},
7597 position: {},
7598 decay: {},
7599 distance: {},
7600
7601 shadow: {},
7602 shadowBias: {},
7603 shadowRadius: {},
7604 shadowMapSize: {},
7605 shadowCameraNear: {},
7606 shadowCameraFar: {}
7607 } },
7608
7609 pointShadowMap: { value: [] },
7610 pointShadowMatrix: { value: [] },
7611
7612 hemisphereLights: { value: [], properties: {
7613 direction: {},
7614 skyColor: {},
7615 groundColor: {}
7616 } },
7617
7618 // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src
7619 rectAreaLights: { value: [], properties: {
7620 color: {},
7621 position: {},
7622 width: {},
7623 height: {}
7624 } }
7625
7626 },
7627
7628 points: {
7629
7630 diffuse: { value: new Color( 0xeeeeee ) },
7631 opacity: { value: 1.0 },
7632 size: { value: 1.0 },
7633 scale: { value: 1.0 },
7634 map: { value: null },
7635 uvTransform: { value: new Matrix3() }
7636
7637 }
7638
7639};
7640
7641/**
7642 * Uniform Utilities
7643 */
7644
7645var UniformsUtils = {
7646
7647 merge: function ( uniforms ) {
7648
7649 var merged = {};
7650
7651 for ( var u = 0; u < uniforms.length; u ++ ) {
7652
7653 var tmp = this.clone( uniforms[ u ] );
7654
7655 for ( var p in tmp ) {
7656
7657 merged[ p ] = tmp[ p ];
7658
7659 }
7660
7661 }
7662
7663 return merged;
7664
7665 },
7666
7667 clone: function ( uniforms_src ) {
7668
7669 var uniforms_dst = {};
7670
7671 for ( var u in uniforms_src ) {
7672
7673 uniforms_dst[ u ] = {};
7674
7675 for ( var p in uniforms_src[ u ] ) {
7676
7677 var parameter_src = uniforms_src[ u ][ p ];
7678
7679 if ( parameter_src && ( parameter_src.isColor ||
7680 parameter_src.isMatrix3 || parameter_src.isMatrix4 ||
7681 parameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 ||
7682 parameter_src.isTexture ) ) {
7683
7684 uniforms_dst[ u ][ p ] = parameter_src.clone();
7685
7686 } else if ( Array.isArray( parameter_src ) ) {
7687
7688 uniforms_dst[ u ][ p ] = parameter_src.slice();
7689
7690 } else {
7691
7692 uniforms_dst[ u ][ p ] = parameter_src;
7693
7694 }
7695
7696 }
7697
7698 }
7699
7700 return uniforms_dst;
7701
7702 }
7703
7704};
7705
7706var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif\n";
7707
7708var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif\n";
7709
7710var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif\n";
7711
7712var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif\n";
7713
7714var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
7715
7716var begin_vertex = "\nvec3 transformed = vec3( position );\n";
7717
7718var beginnormal_vertex = "\nvec3 objectNormal = vec3( normal );\n";
7719
7720var bsdfs = "float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\tif( decayExponent > 0.0 ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\treturn distanceFalloff * maxDistanceCutoffFactor;\n#else\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n#endif\n\t}\n\treturn 1.0;\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat theta = acos( dot( N, V ) );\n\tvec2 uv = vec2(\n\t\tsqrt( saturate( roughness ) ),\n\t\tsaturate( theta / ( 0.5 * PI ) ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.86267 + (0.49788 + 0.01436 * y ) * y;\n\tfloat b = 3.45068 + (4.18814 + y) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = (x > 0.0) ? v : 0.5 * inversesqrt( 1.0 - x * x ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tvec3 result = vec3( LTC_ClippedSphereFormFactor( vectorFormFactor ) );\n\treturn result;\n}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n";
7721
7722var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n";
7723
7724var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {\n\t\tvec4 plane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t\t\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {\n\t\t\tvec4 plane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t\n\t#endif\n#endif\n";
7725
7726var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif\n";
7727
7728var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\n#endif\n";
7729
7730var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n";
7731
7732var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif";
7733
7734var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n";
7735
7736var color_pars_vertex = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif";
7737
7738var color_vertex = "#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif";
7739
7740var common = "#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat linearToRelativeLuminance( const in vec3 color ) {\n\tvec3 weights = vec3( 0.2126, 0.7152, 0.0722 );\n\treturn dot( weights, color.rgb );\n}\n";
7741
7742var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_textureSize (1024.0)\nint getFaceFromDirection(vec3 direction) {\n\tvec3 absDirection = abs(direction);\n\tint face = -1;\n\tif( absDirection.x > absDirection.z ) {\n\t\tif(absDirection.x > absDirection.y )\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\telse {\n\t\tif(absDirection.z > absDirection.y )\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\treturn face;\n}\n#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0)\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\n\tfloat dxRoughness = dFdx(roughness);\n\tfloat dyRoughness = dFdy(roughness);\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\n\tfloat mipLevel = 0.5 * log2(d);\n\treturn vec2(floor(mipLevel), fract(mipLevel));\n}\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\n\tbool bRes = mipLevel == 0.0;\n\tscale = bRes && (scale < a) ? a : scale;\n\tvec3 r;\n\tvec2 offset;\n\tint face = getFaceFromDirection(direction);\n\tfloat rcpPowScale = 1.0 / powScale;\n\tif( face == 0) {\n\t\tr = vec3(direction.x, -direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 1) {\n\t\tr = vec3(direction.y, direction.x, direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 2) {\n\t\tr = vec3(direction.z, direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 3) {\n\t\tr = vec3(direction.x, direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse if( face == 4) {\n\t\tr = vec3(direction.y, direction.x, -direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse {\n\t\tr = vec3(direction.z, -direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\tr = normalize(r);\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\n\tvec2 base = offset + vec2( texelOffset );\n\treturn base + s * ( scale - 2.0 * texelOffset );\n}\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\nvec4 textureCubeUV(vec3 reflectedDirection, float roughness ) {\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\n\tfloat r1 = floor(roughnessVal);\n\tfloat r2 = r1 + 1.0;\n\tfloat t = fract(roughnessVal);\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\n\tfloat s = mipInfo.y;\n\tfloat level0 = mipInfo.x;\n\tfloat level1 = level0 + 1.0;\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\n\tvec4 result = mix(color10, color20, t);\n\treturn vec4(result.rgb, 1.0);\n}\n#endif\n";
7743
7744var defaultnormal_vertex = "vec3 transformedNormal = normalMatrix * objectNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n";
7745
7746var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n";
7747
7748var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n";
7749
7750var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif\n";
7751
7752var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n";
7753
7754var encodings_fragment = " gl_FragColor = linearToOutputTexel( gl_FragColor );\n";
7755
7756var encodings_pars_fragment = "\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.xyz * value.w * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.x, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = min( floor( D ) / 255.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\n\tXp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract(Le);\n\tvResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\n\treturn vec4( max(vRGB, 0.0), 1.0 );\n}\n";
7757
7758var envmap_fragment = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\treflectVec = normalize( reflectVec );\n\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\treflectVec = normalize( reflectVec );\n\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\tenvColor = envMapTexelToLinear( envColor );\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif\n";
7759
7760var envmap_pars_fragment = "#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntensity;\n#endif\n#ifdef USE_ENVMAP\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\n\t\tvarying vec3 vWorldPosition;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif\n";
7761
7762var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif\n";
7763
7764var envmap_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif\n";
7765
7766var fog_vertex = "\n#ifdef USE_FOG\nfogDepth = -mvPosition.z;\n#endif";
7767
7768var fog_pars_vertex = "#ifdef USE_FOG\n varying float fogDepth;\n#endif\n";
7769
7770var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif\n";
7771
7772var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif\n";
7773
7774var gradientmap_pars_fragment = "#ifdef TOON\n\tuniform sampler2D gradientMap;\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\t\tfloat dotNL = dot( normal, lightDirection );\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t\t#ifdef USE_GRADIENTMAP\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\n\t\t#else\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t\t#endif\n\t}\n#endif\n";
7775
7776var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n";
7777
7778var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
7779
7780var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif\n";
7781
7782var lights_pars = "uniform vec3 ambientLightColor;\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t\tfloat shadowCameraNear;\n\t\tfloat shadowCameraFar;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltcMat;\tuniform sampler2D ltcMag;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif\n#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( queryVec, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar + 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\tvec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif\n";
7783
7784var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n";
7785
7786var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifdef TOON\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#else\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\t\tvec3 irradiance = dotNL * directLight.color;\n\t#endif\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)\n";
7787
7788var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\n#ifdef STANDARD\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.clearCoat = saturate( clearCoat );\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\n#endif\n";
7789
7790var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n\t#ifndef STANDARD\n\t\tfloat clearCoat;\n\t\tfloat clearCoatRoughness;\n\t#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos - halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos + halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos + halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos - halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tfloat norm = texture2D( ltcMag, uv ).a;\n\t\tvec4 t = texture2D( ltcMat, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( 1, 0, t.y ),\n\t\t\tvec3( 0, t.z, 0 ),\n\t\t\tvec3( t.w, 0, t.x )\n\t\t);\n\t\treflectedLight.directSpecular += lightColor * material.specularColor * norm * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifndef STANDARD\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\t#ifndef STANDARD\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifndef STANDARD\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\tfloat dotNL = dotNV;\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\n\t#ifndef STANDARD\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\n#define Material_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.specularRoughness )\n#define Material_ClearCoat_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}\n";
7791
7792var lights_template = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = normalize( vViewPosition );\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#ifdef USE_LIGHTMAP\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, 8 );\n\t#endif\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tvec3 radiance = getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), 8 );\n\t#ifndef STANDARD\n\t\tvec3 clearCoatRadiance = getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), 8 );\n\t#else\n\t\tvec3 clearCoatRadiance = vec3( 0.0 );\n\t#endif\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\n#endif\n";
7793
7794var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif";
7795
7796var logdepthbuf_pars_fragment = "#ifdef USE_LOGDEPTHBUF\n\tuniform float logDepthBufFC;\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n#endif\n";
7797
7798var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#endif\n\tuniform float logDepthBufFC;\n#endif";
7799
7800var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t#else\n\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\tgl_Position.z *= gl_Position.w;\n\t#endif\n#endif\n";
7801
7802var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n";
7803
7804var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n";
7805
7806var map_particle_fragment = "#ifdef USE_MAP\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n";
7807
7808var map_particle_pars_fragment = "#ifdef USE_MAP\n\tuniform mat3 uvTransform;\n\tuniform sampler2D map;\n#endif\n";
7809
7810var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif\n";
7811
7812var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
7813
7814var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n#endif\n";
7815
7816var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif";
7817
7818var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\t#endif\n#endif\n";
7819
7820var normal_fragment = "#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n#endif\n#ifdef USE_NORMALMAP\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n";
7821
7822var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n\t\tvec3 N = normalize( surf_norm );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = normalScale * mapN.xy;\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif\n";
7823
7824var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}\n";
7825
7826var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n";
7827
7828var project_vertex = "vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\n";
7829
7830var dithering_fragment = "#if defined( DITHERING )\n gl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif\n";
7831
7832var dithering_pars_fragment = "#if defined( DITHERING )\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif\n";
7833
7834var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif\n";
7835
7836var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
7837
7838var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\n\t\tvec2 f = fract( uv * size + 0.5 );\n\t\tfloat a = mix( lb, lt, f.y );\n\t\tfloat b = mix( rb, rt, f.y );\n\t\tfloat c = mix( a, b, f.x );\n\t\treturn c;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tshadow = (\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif\n";
7839
7840var shadowmap_pars_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n#endif\n";
7841
7842var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif\n";
7843
7844var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tDirectionalLight directionalLight;\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tSpotLight spotLight;\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tPointLight pointLight;\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}\n";
7845
7846var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif";
7847
7848var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif\n";
7849
7850var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif\n";
7851
7852var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n#endif\n";
7853
7854var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif";
7855
7856var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
7857
7858var tonemapping_fragment = "#if defined( TONE_MAPPING )\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n";
7859
7860var tonemapping_pars_fragment = "#ifndef saturate\n\t#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\n";
7861
7862var uv_pars_fragment = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n#endif";
7863
7864var uv_pars_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\n";
7865
7866var uv_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif";
7867
7868var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif";
7869
7870var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif";
7871
7872var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif";
7873
7874var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n#endif\n";
7875
7876var cube_frag = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldPosition;\nvoid main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );\n\tgl_FragColor.a *= opacity;\n}\n";
7877
7878var cube_vert = "varying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}\n";
7879
7880var depth_frag = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <logdepthbuf_fragment>\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}\n";
7881
7882var depth_vert = "#include <common>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n}\n";
7883
7884var distanceRGBA_frag = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main () {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}\n";
7885
7886var distanceRGBA_vert = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include <common>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\tvWorldPosition = worldPosition.xyz;\n}\n";
7887
7888var equirect_frag = "uniform sampler2D tEquirect;\nvarying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvec3 direction = normalize( vWorldPosition );\n\tvec2 sampleUV;\n\tsampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}\n";
7889
7890var equirect_vert = "varying vec3 vWorldPosition;\n#include <common>\nvoid main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}\n";
7891
7892var linedashed_frag = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <color_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
7893
7894var linedashed_vert = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <color_vertex>\n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}\n";
7895
7896var meshbasic_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include <aomap_fragment>\n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
7897
7898var meshbasic_vert = "#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_ENVMAP\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <envmap_vertex>\n\t#include <fog_vertex>\n}\n";
7899
7900var meshlambert_frag = "uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <bsdfs>\n#include <lights_pars>\n#include <fog_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\t#include <emissivemap_fragment>\n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#include <lightmap_fragment>\n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}\n";
7901
7902var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <envmap_pars_vertex>\n#include <bsdfs>\n#include <lights_pars>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <lights_lambert_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
7903
7904var meshphong_frag = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <gradientmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars>\n#include <lights_phong_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <specularmap_fragment>\n\t#include <normal_fragment>\n\t#include <emissivemap_fragment>\n\t#include <lights_phong_fragment>\n\t#include <lights_template>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}\n";
7905
7906var meshphong_vert = "#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
7907
7908var meshphysical_frag = "#define PHYSICAL\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifndef STANDARD\n\tuniform float clearCoat;\n\tuniform float clearCoatRoughness;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <uv2_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <cube_uv_reflection_fragment>\n#include <lights_pars>\n#include <lights_physical_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <roughnessmap_pars_fragment>\n#include <metalnessmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <roughnessmap_fragment>\n\t#include <metalnessmap_fragment>\n\t#include <normal_fragment>\n\t#include <emissivemap_fragment>\n\t#include <lights_physical_fragment>\n\t#include <lights_template>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}\n";
7909
7910var meshphysical_vert = "#define PHYSICAL\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <uv_pars_vertex>\n#include <uv2_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <uv2_vertex>\n\t#include <color_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
7911
7912var normal_frag = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <packing>\n#include <uv_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\nvoid main() {\n\t#include <logdepthbuf_fragment>\n\t#include <normal_fragment>\n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}\n";
7913
7914var normal_vert = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}\n";
7915
7916var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <color_pars_fragment>\n#include <map_particle_pars_fragment>\n#include <fog_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_particle_fragment>\n\t#include <color_fragment>\n\t#include <alphatest_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include <premultiplied_alpha_fragment>\n\t#include <tonemapping_fragment>\n\t#include <encodings_fragment>\n\t#include <fog_fragment>\n}\n";
7917
7918var points_vert = "uniform float size;\nuniform float scale;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <color_vertex>\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\t#ifdef USE_SIZEATTENUATION\n\t\tgl_PointSize = size * ( scale / - mvPosition.z );\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
7919
7920var shadow_frag = "uniform vec3 color;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include <fog_fragment>\n}\n";
7921
7922var shadow_vert = "#include <fog_pars_vertex>\n#include <shadowmap_pars_vertex>\nvoid main() {\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}\n";
7923
7924var ShaderChunk = {
7925 alphamap_fragment: alphamap_fragment,
7926 alphamap_pars_fragment: alphamap_pars_fragment,
7927 alphatest_fragment: alphatest_fragment,
7928 aomap_fragment: aomap_fragment,
7929 aomap_pars_fragment: aomap_pars_fragment,
7930 begin_vertex: begin_vertex,
7931 beginnormal_vertex: beginnormal_vertex,
7932 bsdfs: bsdfs,
7933 bumpmap_pars_fragment: bumpmap_pars_fragment,
7934 clipping_planes_fragment: clipping_planes_fragment,
7935 clipping_planes_pars_fragment: clipping_planes_pars_fragment,
7936 clipping_planes_pars_vertex: clipping_planes_pars_vertex,
7937 clipping_planes_vertex: clipping_planes_vertex,
7938 color_fragment: color_fragment,
7939 color_pars_fragment: color_pars_fragment,
7940 color_pars_vertex: color_pars_vertex,
7941 color_vertex: color_vertex,
7942 common: common,
7943 cube_uv_reflection_fragment: cube_uv_reflection_fragment,
7944 defaultnormal_vertex: defaultnormal_vertex,
7945 displacementmap_pars_vertex: displacementmap_pars_vertex,
7946 displacementmap_vertex: displacementmap_vertex,
7947 emissivemap_fragment: emissivemap_fragment,
7948 emissivemap_pars_fragment: emissivemap_pars_fragment,
7949 encodings_fragment: encodings_fragment,
7950 encodings_pars_fragment: encodings_pars_fragment,
7951 envmap_fragment: envmap_fragment,
7952 envmap_pars_fragment: envmap_pars_fragment,
7953 envmap_pars_vertex: envmap_pars_vertex,
7954 envmap_vertex: envmap_vertex,
7955 fog_vertex: fog_vertex,
7956 fog_pars_vertex: fog_pars_vertex,
7957 fog_fragment: fog_fragment,
7958 fog_pars_fragment: fog_pars_fragment,
7959 gradientmap_pars_fragment: gradientmap_pars_fragment,
7960 lightmap_fragment: lightmap_fragment,
7961 lightmap_pars_fragment: lightmap_pars_fragment,
7962 lights_lambert_vertex: lights_lambert_vertex,
7963 lights_pars: lights_pars,
7964 lights_phong_fragment: lights_phong_fragment,
7965 lights_phong_pars_fragment: lights_phong_pars_fragment,
7966 lights_physical_fragment: lights_physical_fragment,
7967 lights_physical_pars_fragment: lights_physical_pars_fragment,
7968 lights_template: lights_template,
7969 logdepthbuf_fragment: logdepthbuf_fragment,
7970 logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
7971 logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
7972 logdepthbuf_vertex: logdepthbuf_vertex,
7973 map_fragment: map_fragment,
7974 map_pars_fragment: map_pars_fragment,
7975 map_particle_fragment: map_particle_fragment,
7976 map_particle_pars_fragment: map_particle_pars_fragment,
7977 metalnessmap_fragment: metalnessmap_fragment,
7978 metalnessmap_pars_fragment: metalnessmap_pars_fragment,
7979 morphnormal_vertex: morphnormal_vertex,
7980 morphtarget_pars_vertex: morphtarget_pars_vertex,
7981 morphtarget_vertex: morphtarget_vertex,
7982 normal_fragment: normal_fragment,
7983 normalmap_pars_fragment: normalmap_pars_fragment,
7984 packing: packing,
7985 premultiplied_alpha_fragment: premultiplied_alpha_fragment,
7986 project_vertex: project_vertex,
7987 dithering_fragment: dithering_fragment,
7988 dithering_pars_fragment: dithering_pars_fragment,
7989 roughnessmap_fragment: roughnessmap_fragment,
7990 roughnessmap_pars_fragment: roughnessmap_pars_fragment,
7991 shadowmap_pars_fragment: shadowmap_pars_fragment,
7992 shadowmap_pars_vertex: shadowmap_pars_vertex,
7993 shadowmap_vertex: shadowmap_vertex,
7994 shadowmask_pars_fragment: shadowmask_pars_fragment,
7995 skinbase_vertex: skinbase_vertex,
7996 skinning_pars_vertex: skinning_pars_vertex,
7997 skinning_vertex: skinning_vertex,
7998 skinnormal_vertex: skinnormal_vertex,
7999 specularmap_fragment: specularmap_fragment,
8000 specularmap_pars_fragment: specularmap_pars_fragment,
8001 tonemapping_fragment: tonemapping_fragment,
8002 tonemapping_pars_fragment: tonemapping_pars_fragment,
8003 uv_pars_fragment: uv_pars_fragment,
8004 uv_pars_vertex: uv_pars_vertex,
8005 uv_vertex: uv_vertex,
8006 uv2_pars_fragment: uv2_pars_fragment,
8007 uv2_pars_vertex: uv2_pars_vertex,
8008 uv2_vertex: uv2_vertex,
8009 worldpos_vertex: worldpos_vertex,
8010
8011 cube_frag: cube_frag,
8012 cube_vert: cube_vert,
8013 depth_frag: depth_frag,
8014 depth_vert: depth_vert,
8015 distanceRGBA_frag: distanceRGBA_frag,
8016 distanceRGBA_vert: distanceRGBA_vert,
8017 equirect_frag: equirect_frag,
8018 equirect_vert: equirect_vert,
8019 linedashed_frag: linedashed_frag,
8020 linedashed_vert: linedashed_vert,
8021 meshbasic_frag: meshbasic_frag,
8022 meshbasic_vert: meshbasic_vert,
8023 meshlambert_frag: meshlambert_frag,
8024 meshlambert_vert: meshlambert_vert,
8025 meshphong_frag: meshphong_frag,
8026 meshphong_vert: meshphong_vert,
8027 meshphysical_frag: meshphysical_frag,
8028 meshphysical_vert: meshphysical_vert,
8029 normal_frag: normal_frag,
8030 normal_vert: normal_vert,
8031 points_frag: points_frag,
8032 points_vert: points_vert,
8033 shadow_frag: shadow_frag,
8034 shadow_vert: shadow_vert
8035};
8036
8037/**
8038 * @author alteredq / http://alteredqualia.com/
8039 * @author mrdoob / http://mrdoob.com/
8040 * @author mikael emtinger / http://gomo.se/
8041 */
8042
8043var ShaderLib = {
8044
8045 basic: {
8046
8047 uniforms: UniformsUtils.merge( [
8048 UniformsLib.common,
8049 UniformsLib.specularmap,
8050 UniformsLib.envmap,
8051 UniformsLib.aomap,
8052 UniformsLib.lightmap,
8053 UniformsLib.fog
8054 ] ),
8055
8056 vertexShader: ShaderChunk.meshbasic_vert,
8057 fragmentShader: ShaderChunk.meshbasic_frag
8058
8059 },
8060
8061 lambert: {
8062
8063 uniforms: UniformsUtils.merge( [
8064 UniformsLib.common,
8065 UniformsLib.specularmap,
8066 UniformsLib.envmap,
8067 UniformsLib.aomap,
8068 UniformsLib.lightmap,
8069 UniformsLib.emissivemap,
8070 UniformsLib.fog,
8071 UniformsLib.lights,
8072 {
8073 emissive: { value: new Color( 0x000000 ) }
8074 }
8075 ] ),
8076
8077 vertexShader: ShaderChunk.meshlambert_vert,
8078 fragmentShader: ShaderChunk.meshlambert_frag
8079
8080 },
8081
8082 phong: {
8083
8084 uniforms: UniformsUtils.merge( [
8085 UniformsLib.common,
8086 UniformsLib.specularmap,
8087 UniformsLib.envmap,
8088 UniformsLib.aomap,
8089 UniformsLib.lightmap,
8090 UniformsLib.emissivemap,
8091 UniformsLib.bumpmap,
8092 UniformsLib.normalmap,
8093 UniformsLib.displacementmap,
8094 UniformsLib.gradientmap,
8095 UniformsLib.fog,
8096 UniformsLib.lights,
8097 {
8098 emissive: { value: new Color( 0x000000 ) },
8099 specular: { value: new Color( 0x111111 ) },
8100 shininess: { value: 30 }
8101 }
8102 ] ),
8103
8104 vertexShader: ShaderChunk.meshphong_vert,
8105 fragmentShader: ShaderChunk.meshphong_frag
8106
8107 },
8108
8109 standard: {
8110
8111 uniforms: UniformsUtils.merge( [
8112 UniformsLib.common,
8113 UniformsLib.envmap,
8114 UniformsLib.aomap,
8115 UniformsLib.lightmap,
8116 UniformsLib.emissivemap,
8117 UniformsLib.bumpmap,
8118 UniformsLib.normalmap,
8119 UniformsLib.displacementmap,
8120 UniformsLib.roughnessmap,
8121 UniformsLib.metalnessmap,
8122 UniformsLib.fog,
8123 UniformsLib.lights,
8124 {
8125 emissive: { value: new Color( 0x000000 ) },
8126 roughness: { value: 0.5 },
8127 metalness: { value: 0.5 },
8128 envMapIntensity: { value: 1 } // temporary
8129 }
8130 ] ),
8131
8132 vertexShader: ShaderChunk.meshphysical_vert,
8133 fragmentShader: ShaderChunk.meshphysical_frag
8134
8135 },
8136
8137 points: {
8138
8139 uniforms: UniformsUtils.merge( [
8140 UniformsLib.points,
8141 UniformsLib.fog
8142 ] ),
8143
8144 vertexShader: ShaderChunk.points_vert,
8145 fragmentShader: ShaderChunk.points_frag
8146
8147 },
8148
8149 dashed: {
8150
8151 uniforms: UniformsUtils.merge( [
8152 UniformsLib.common,
8153 UniformsLib.fog,
8154 {
8155 scale: { value: 1 },
8156 dashSize: { value: 1 },
8157 totalSize: { value: 2 }
8158 }
8159 ] ),
8160
8161 vertexShader: ShaderChunk.linedashed_vert,
8162 fragmentShader: ShaderChunk.linedashed_frag
8163
8164 },
8165
8166 depth: {
8167
8168 uniforms: UniformsUtils.merge( [
8169 UniformsLib.common,
8170 UniformsLib.displacementmap
8171 ] ),
8172
8173 vertexShader: ShaderChunk.depth_vert,
8174 fragmentShader: ShaderChunk.depth_frag
8175
8176 },
8177
8178 normal: {
8179
8180 uniforms: UniformsUtils.merge( [
8181 UniformsLib.common,
8182 UniformsLib.bumpmap,
8183 UniformsLib.normalmap,
8184 UniformsLib.displacementmap,
8185 {
8186 opacity: { value: 1.0 }
8187 }
8188 ] ),
8189
8190 vertexShader: ShaderChunk.normal_vert,
8191 fragmentShader: ShaderChunk.normal_frag
8192
8193 },
8194
8195 /* -------------------------------------------------------------------------
8196 // Cube map shader
8197 ------------------------------------------------------------------------- */
8198
8199 cube: {
8200
8201 uniforms: {
8202 tCube: { value: null },
8203 tFlip: { value: - 1 },
8204 opacity: { value: 1.0 }
8205 },
8206
8207 vertexShader: ShaderChunk.cube_vert,
8208 fragmentShader: ShaderChunk.cube_frag
8209
8210 },
8211
8212 equirect: {
8213
8214 uniforms: {
8215 tEquirect: { value: null },
8216 },
8217
8218 vertexShader: ShaderChunk.equirect_vert,
8219 fragmentShader: ShaderChunk.equirect_frag
8220
8221 },
8222
8223 distanceRGBA: {
8224
8225 uniforms: UniformsUtils.merge( [
8226 UniformsLib.common,
8227 UniformsLib.displacementmap,
8228 {
8229 referencePosition: { value: new Vector3() },
8230 nearDistance: { value: 1 },
8231 farDistance: { value: 1000 }
8232 }
8233 ] ),
8234
8235 vertexShader: ShaderChunk.distanceRGBA_vert,
8236 fragmentShader: ShaderChunk.distanceRGBA_frag
8237
8238 },
8239
8240 shadow: {
8241
8242 uniforms: UniformsUtils.merge( [
8243 UniformsLib.lights,
8244 UniformsLib.fog,
8245 {
8246 color: { value: new Color( 0x00000 ) },
8247 opacity: { value: 1.0 }
8248 },
8249 ] ),
8250
8251 vertexShader: ShaderChunk.shadow_vert,
8252 fragmentShader: ShaderChunk.shadow_frag
8253
8254 }
8255
8256};
8257
8258ShaderLib.physical = {
8259
8260 uniforms: UniformsUtils.merge( [
8261 ShaderLib.standard.uniforms,
8262 {
8263 clearCoat: { value: 0 },
8264 clearCoatRoughness: { value: 0 }
8265 }
8266 ] ),
8267
8268 vertexShader: ShaderChunk.meshphysical_vert,
8269 fragmentShader: ShaderChunk.meshphysical_frag
8270
8271};
8272
8273/**
8274 * @author bhouston / http://clara.io
8275 */
8276
8277function Box2( min, max ) {
8278
8279 this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity );
8280 this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity );
8281
8282}
8283
8284Object.assign( Box2.prototype, {
8285
8286 set: function ( min, max ) {
8287
8288 this.min.copy( min );
8289 this.max.copy( max );
8290
8291 return this;
8292
8293 },
8294
8295 setFromPoints: function ( points ) {
8296
8297 this.makeEmpty();
8298
8299 for ( var i = 0, il = points.length; i < il; i ++ ) {
8300
8301 this.expandByPoint( points[ i ] );
8302
8303 }
8304
8305 return this;
8306
8307 },
8308
8309 setFromCenterAndSize: function () {
8310
8311 var v1 = new Vector2();
8312
8313 return function setFromCenterAndSize( center, size ) {
8314
8315 var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
8316 this.min.copy( center ).sub( halfSize );
8317 this.max.copy( center ).add( halfSize );
8318
8319 return this;
8320
8321 };
8322
8323 }(),
8324
8325 clone: function () {
8326
8327 return new this.constructor().copy( this );
8328
8329 },
8330
8331 copy: function ( box ) {
8332
8333 this.min.copy( box.min );
8334 this.max.copy( box.max );
8335
8336 return this;
8337
8338 },
8339
8340 makeEmpty: function () {
8341
8342 this.min.x = this.min.y = + Infinity;
8343 this.max.x = this.max.y = - Infinity;
8344
8345 return this;
8346
8347 },
8348
8349 isEmpty: function () {
8350
8351 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
8352
8353 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );
8354
8355 },
8356
8357 getCenter: function ( optionalTarget ) {
8358
8359 var result = optionalTarget || new Vector2();
8360 return this.isEmpty() ? result.set( 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
8361
8362 },
8363
8364 getSize: function ( optionalTarget ) {
8365
8366 var result = optionalTarget || new Vector2();
8367 return this.isEmpty() ? result.set( 0, 0 ) : result.subVectors( this.max, this.min );
8368
8369 },
8370
8371 expandByPoint: function ( point ) {
8372
8373 this.min.min( point );
8374 this.max.max( point );
8375
8376 return this;
8377
8378 },
8379
8380 expandByVector: function ( vector ) {
8381
8382 this.min.sub( vector );
8383 this.max.add( vector );
8384
8385 return this;
8386
8387 },
8388
8389 expandByScalar: function ( scalar ) {
8390
8391 this.min.addScalar( - scalar );
8392 this.max.addScalar( scalar );
8393
8394 return this;
8395
8396 },
8397
8398 containsPoint: function ( point ) {
8399
8400 return point.x < this.min.x || point.x > this.max.x ||
8401 point.y < this.min.y || point.y > this.max.y ? false : true;
8402
8403 },
8404
8405 containsBox: function ( box ) {
8406
8407 return this.min.x <= box.min.x && box.max.x <= this.max.x &&
8408 this.min.y <= box.min.y && box.max.y <= this.max.y;
8409
8410 },
8411
8412 getParameter: function ( point, optionalTarget ) {
8413
8414 // This can potentially have a divide by zero if the box
8415 // has a size dimension of 0.
8416
8417 var result = optionalTarget || new Vector2();
8418
8419 return result.set(
8420 ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
8421 ( point.y - this.min.y ) / ( this.max.y - this.min.y )
8422 );
8423
8424 },
8425
8426 intersectsBox: function ( box ) {
8427
8428 // using 4 splitting planes to rule out intersections
8429
8430 return box.max.x < this.min.x || box.min.x > this.max.x ||
8431 box.max.y < this.min.y || box.min.y > this.max.y ? false : true;
8432
8433 },
8434
8435 clampPoint: function ( point, optionalTarget ) {
8436
8437 var result = optionalTarget || new Vector2();
8438 return result.copy( point ).clamp( this.min, this.max );
8439
8440 },
8441
8442 distanceToPoint: function () {
8443
8444 var v1 = new Vector2();
8445
8446 return function distanceToPoint( point ) {
8447
8448 var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
8449 return clampedPoint.sub( point ).length();
8450
8451 };
8452
8453 }(),
8454
8455 intersect: function ( box ) {
8456
8457 this.min.max( box.min );
8458 this.max.min( box.max );
8459
8460 return this;
8461
8462 },
8463
8464 union: function ( box ) {
8465
8466 this.min.min( box.min );
8467 this.max.max( box.max );
8468
8469 return this;
8470
8471 },
8472
8473 translate: function ( offset ) {
8474
8475 this.min.add( offset );
8476 this.max.add( offset );
8477
8478 return this;
8479
8480 },
8481
8482 equals: function ( box ) {
8483
8484 return box.min.equals( this.min ) && box.max.equals( this.max );
8485
8486 }
8487
8488} );
8489
8490/**
8491 * @author mikael emtinger / http://gomo.se/
8492 * @author alteredq / http://alteredqualia.com/
8493 */
8494
8495function WebGLFlareRenderer( renderer, gl, state, textures, capabilities ) {
8496
8497 var vertexBuffer, elementBuffer;
8498 var shader, program, attributes, uniforms;
8499
8500 var tempTexture, occlusionTexture;
8501
8502 function init() {
8503
8504 var vertices = new Float32Array( [
8505 - 1, - 1, 0, 0,
8506 1, - 1, 1, 0,
8507 1, 1, 1, 1,
8508 - 1, 1, 0, 1
8509 ] );
8510
8511 var faces = new Uint16Array( [
8512 0, 1, 2,
8513 0, 2, 3
8514 ] );
8515
8516 // buffers
8517
8518 vertexBuffer = gl.createBuffer();
8519 elementBuffer = gl.createBuffer();
8520
8521 gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
8522 gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );
8523
8524 gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
8525 gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );
8526
8527 // textures
8528
8529 tempTexture = gl.createTexture();
8530 occlusionTexture = gl.createTexture();
8531
8532 state.bindTexture( gl.TEXTURE_2D, tempTexture );
8533 gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, 16, 16, 0, gl.RGB, gl.UNSIGNED_BYTE, null );
8534 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );
8535 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );
8536 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
8537 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
8538
8539 state.bindTexture( gl.TEXTURE_2D, occlusionTexture );
8540 gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null );
8541 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );
8542 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );
8543 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
8544 gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
8545
8546 shader = {
8547
8548 vertexShader: [
8549
8550 'uniform lowp int renderType;',
8551
8552 'uniform vec3 screenPosition;',
8553 'uniform vec2 scale;',
8554 'uniform float rotation;',
8555
8556 'uniform sampler2D occlusionMap;',
8557
8558 'attribute vec2 position;',
8559 'attribute vec2 uv;',
8560
8561 'varying vec2 vUV;',
8562 'varying float vVisibility;',
8563
8564 'void main() {',
8565
8566 ' vUV = uv;',
8567
8568 ' vec2 pos = position;',
8569
8570 ' if ( renderType == 2 ) {',
8571
8572 ' vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );',
8573 ' visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );',
8574 ' visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );',
8575 ' visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );',
8576 ' visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );',
8577 ' visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );',
8578 ' visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );',
8579 ' visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );',
8580 ' visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );',
8581
8582 ' vVisibility = visibility.r / 9.0;',
8583 ' vVisibility *= 1.0 - visibility.g / 9.0;',
8584 ' vVisibility *= visibility.b / 9.0;',
8585 ' vVisibility *= 1.0 - visibility.a / 9.0;',
8586
8587 ' pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;',
8588 ' pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;',
8589
8590 ' }',
8591
8592 ' gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );',
8593
8594 '}'
8595
8596 ].join( '\n' ),
8597
8598 fragmentShader: [
8599
8600 'uniform lowp int renderType;',
8601
8602 'uniform sampler2D map;',
8603 'uniform float opacity;',
8604 'uniform vec3 color;',
8605
8606 'varying vec2 vUV;',
8607 'varying float vVisibility;',
8608
8609 'void main() {',
8610
8611 // pink square
8612
8613 ' if ( renderType == 0 ) {',
8614
8615 ' gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );',
8616
8617 // restore
8618
8619 ' } else if ( renderType == 1 ) {',
8620
8621 ' gl_FragColor = texture2D( map, vUV );',
8622
8623 // flare
8624
8625 ' } else {',
8626
8627 ' vec4 texture = texture2D( map, vUV );',
8628 ' texture.a *= opacity * vVisibility;',
8629 ' gl_FragColor = texture;',
8630 ' gl_FragColor.rgb *= color;',
8631
8632 ' }',
8633
8634 '}'
8635
8636 ].join( '\n' )
8637
8638 };
8639
8640 program = createProgram( shader );
8641
8642 attributes = {
8643 vertex: gl.getAttribLocation( program, 'position' ),
8644 uv: gl.getAttribLocation( program, 'uv' )
8645 };
8646
8647 uniforms = {
8648 renderType: gl.getUniformLocation( program, 'renderType' ),
8649 map: gl.getUniformLocation( program, 'map' ),
8650 occlusionMap: gl.getUniformLocation( program, 'occlusionMap' ),
8651 opacity: gl.getUniformLocation( program, 'opacity' ),
8652 color: gl.getUniformLocation( program, 'color' ),
8653 scale: gl.getUniformLocation( program, 'scale' ),
8654 rotation: gl.getUniformLocation( program, 'rotation' ),
8655 screenPosition: gl.getUniformLocation( program, 'screenPosition' )
8656 };
8657
8658 }
8659
8660 /*
8661 * Render lens flares
8662 * Method: renders 16x16 0xff00ff-colored points scattered over the light source area,
8663 * reads these back and calculates occlusion.
8664 */
8665
8666 this.render = function ( flares, scene, camera, viewport ) {
8667
8668 if ( flares.length === 0 ) return;
8669
8670 var tempPosition = new Vector3();
8671
8672 var invAspect = viewport.w / viewport.z,
8673 halfViewportWidth = viewport.z * 0.5,
8674 halfViewportHeight = viewport.w * 0.5;
8675
8676 var size = 16 / viewport.w,
8677 scale = new Vector2( size * invAspect, size );
8678
8679 var screenPosition = new Vector3( 1, 1, 0 ),
8680 screenPositionPixels = new Vector2( 1, 1 );
8681
8682 var validArea = new Box2();
8683
8684 validArea.min.set( viewport.x, viewport.y );
8685 validArea.max.set( viewport.x + ( viewport.z - 16 ), viewport.y + ( viewport.w - 16 ) );
8686
8687 if ( program === undefined ) {
8688
8689 init();
8690
8691 }
8692
8693 state.useProgram( program );
8694
8695 state.initAttributes();
8696 state.enableAttribute( attributes.vertex );
8697 state.enableAttribute( attributes.uv );
8698 state.disableUnusedAttributes();
8699
8700 // loop through all lens flares to update their occlusion and positions
8701 // setup gl and common used attribs/uniforms
8702
8703 gl.uniform1i( uniforms.occlusionMap, 0 );
8704 gl.uniform1i( uniforms.map, 1 );
8705
8706 gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
8707 gl.vertexAttribPointer( attributes.vertex, 2, gl.FLOAT, false, 2 * 8, 0 );
8708 gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );
8709
8710 gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
8711
8712 state.disable( gl.CULL_FACE );
8713 state.buffers.depth.setMask( false );
8714
8715 for ( var i = 0, l = flares.length; i < l; i ++ ) {
8716
8717 size = 16 / viewport.w;
8718 scale.set( size * invAspect, size );
8719
8720 // calc object screen position
8721
8722 var flare = flares[ i ];
8723
8724 tempPosition.set( flare.matrixWorld.elements[ 12 ], flare.matrixWorld.elements[ 13 ], flare.matrixWorld.elements[ 14 ] );
8725
8726 tempPosition.applyMatrix4( camera.matrixWorldInverse );
8727 tempPosition.applyMatrix4( camera.projectionMatrix );
8728
8729 // setup arrays for gl programs
8730
8731 screenPosition.copy( tempPosition );
8732
8733 // horizontal and vertical coordinate of the lower left corner of the pixels to copy
8734
8735 screenPositionPixels.x = viewport.x + ( screenPosition.x * halfViewportWidth ) + halfViewportWidth - 8;
8736 screenPositionPixels.y = viewport.y + ( screenPosition.y * halfViewportHeight ) + halfViewportHeight - 8;
8737
8738 // screen cull
8739
8740 if ( validArea.containsPoint( screenPositionPixels ) === true ) {
8741
8742 // save current RGB to temp texture
8743
8744 state.activeTexture( gl.TEXTURE0 );
8745 state.bindTexture( gl.TEXTURE_2D, null );
8746 state.activeTexture( gl.TEXTURE1 );
8747 state.bindTexture( gl.TEXTURE_2D, tempTexture );
8748 gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 );
8749
8750
8751 // render pink quad
8752
8753 gl.uniform1i( uniforms.renderType, 0 );
8754 gl.uniform2f( uniforms.scale, scale.x, scale.y );
8755 gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );
8756
8757 state.disable( gl.BLEND );
8758 state.enable( gl.DEPTH_TEST );
8759
8760 gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
8761
8762
8763 // copy result to occlusionMap
8764
8765 state.activeTexture( gl.TEXTURE0 );
8766 state.bindTexture( gl.TEXTURE_2D, occlusionTexture );
8767 gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x, screenPositionPixels.y, 16, 16, 0 );
8768
8769
8770 // restore graphics
8771
8772 gl.uniform1i( uniforms.renderType, 1 );
8773 state.disable( gl.DEPTH_TEST );
8774
8775 state.activeTexture( gl.TEXTURE1 );
8776 state.bindTexture( gl.TEXTURE_2D, tempTexture );
8777 gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
8778
8779
8780 // update object positions
8781
8782 flare.positionScreen.copy( screenPosition );
8783
8784 if ( flare.customUpdateCallback ) {
8785
8786 flare.customUpdateCallback( flare );
8787
8788 } else {
8789
8790 flare.updateLensFlares();
8791
8792 }
8793
8794 // render flares
8795
8796 gl.uniform1i( uniforms.renderType, 2 );
8797 state.enable( gl.BLEND );
8798
8799 for ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) {
8800
8801 var sprite = flare.lensFlares[ j ];
8802
8803 if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) {
8804
8805 screenPosition.x = sprite.x;
8806 screenPosition.y = sprite.y;
8807 screenPosition.z = sprite.z;
8808
8809 size = sprite.size * sprite.scale / viewport.w;
8810
8811 scale.x = size * invAspect;
8812 scale.y = size;
8813
8814 gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );
8815 gl.uniform2f( uniforms.scale, scale.x, scale.y );
8816 gl.uniform1f( uniforms.rotation, sprite.rotation );
8817
8818 gl.uniform1f( uniforms.opacity, sprite.opacity );
8819 gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b );
8820
8821 state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst );
8822
8823 textures.setTexture2D( sprite.texture, 1 );
8824
8825 gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
8826
8827 }
8828
8829 }
8830
8831 }
8832
8833 }
8834
8835 // restore gl
8836
8837 state.enable( gl.CULL_FACE );
8838 state.enable( gl.DEPTH_TEST );
8839 state.buffers.depth.setMask( true );
8840
8841 state.reset();
8842
8843 };
8844
8845 function createProgram( shader ) {
8846
8847 var program = gl.createProgram();
8848
8849 var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
8850 var vertexShader = gl.createShader( gl.VERTEX_SHADER );
8851
8852 var prefix = 'precision ' + capabilities.precision + ' float;\n';
8853
8854 gl.shaderSource( fragmentShader, prefix + shader.fragmentShader );
8855 gl.shaderSource( vertexShader, prefix + shader.vertexShader );
8856
8857 gl.compileShader( fragmentShader );
8858 gl.compileShader( vertexShader );
8859
8860 gl.attachShader( program, fragmentShader );
8861 gl.attachShader( program, vertexShader );
8862
8863 gl.linkProgram( program );
8864
8865 return program;
8866
8867 }
8868
8869}
8870
8871/**
8872 * @author mrdoob / http://mrdoob.com/
8873 */
8874
8875function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
8876
8877 Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
8878
8879 this.needsUpdate = true;
8880
8881}
8882
8883CanvasTexture.prototype = Object.create( Texture.prototype );
8884CanvasTexture.prototype.constructor = CanvasTexture;
8885
8886/**
8887 * @author mikael emtinger / http://gomo.se/
8888 * @author alteredq / http://alteredqualia.com/
8889 */
8890
8891function WebGLSpriteRenderer( renderer, gl, state, textures, capabilities ) {
8892
8893 var vertexBuffer, elementBuffer;
8894 var program, attributes, uniforms;
8895
8896 var texture;
8897
8898 // decompose matrixWorld
8899
8900 var spritePosition = new Vector3();
8901 var spriteRotation = new Quaternion();
8902 var spriteScale = new Vector3();
8903
8904 function init() {
8905
8906 var vertices = new Float32Array( [
8907 - 0.5, - 0.5, 0, 0,
8908 0.5, - 0.5, 1, 0,
8909 0.5, 0.5, 1, 1,
8910 - 0.5, 0.5, 0, 1
8911 ] );
8912
8913 var faces = new Uint16Array( [
8914 0, 1, 2,
8915 0, 2, 3
8916 ] );
8917
8918 vertexBuffer = gl.createBuffer();
8919 elementBuffer = gl.createBuffer();
8920
8921 gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
8922 gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );
8923
8924 gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
8925 gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );
8926
8927 program = createProgram();
8928
8929 attributes = {
8930 position: gl.getAttribLocation( program, 'position' ),
8931 uv: gl.getAttribLocation( program, 'uv' )
8932 };
8933
8934 uniforms = {
8935 uvOffset: gl.getUniformLocation( program, 'uvOffset' ),
8936 uvScale: gl.getUniformLocation( program, 'uvScale' ),
8937
8938 rotation: gl.getUniformLocation( program, 'rotation' ),
8939 scale: gl.getUniformLocation( program, 'scale' ),
8940
8941 color: gl.getUniformLocation( program, 'color' ),
8942 map: gl.getUniformLocation( program, 'map' ),
8943 opacity: gl.getUniformLocation( program, 'opacity' ),
8944
8945 modelViewMatrix: gl.getUniformLocation( program, 'modelViewMatrix' ),
8946 projectionMatrix: gl.getUniformLocation( program, 'projectionMatrix' ),
8947
8948 fogType: gl.getUniformLocation( program, 'fogType' ),
8949 fogDensity: gl.getUniformLocation( program, 'fogDensity' ),
8950 fogNear: gl.getUniformLocation( program, 'fogNear' ),
8951 fogFar: gl.getUniformLocation( program, 'fogFar' ),
8952 fogColor: gl.getUniformLocation( program, 'fogColor' ),
8953 fogDepth: gl.getUniformLocation( program, 'fogDepth' ),
8954
8955 alphaTest: gl.getUniformLocation( program, 'alphaTest' )
8956 };
8957
8958 var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
8959 canvas.width = 8;
8960 canvas.height = 8;
8961
8962 var context = canvas.getContext( '2d' );
8963 context.fillStyle = 'white';
8964 context.fillRect( 0, 0, 8, 8 );
8965
8966 texture = new CanvasTexture( canvas );
8967
8968 }
8969
8970 this.render = function ( sprites, scene, camera ) {
8971
8972 if ( sprites.length === 0 ) return;
8973
8974 // setup gl
8975
8976 if ( program === undefined ) {
8977
8978 init();
8979
8980 }
8981
8982 state.useProgram( program );
8983
8984 state.initAttributes();
8985 state.enableAttribute( attributes.position );
8986 state.enableAttribute( attributes.uv );
8987 state.disableUnusedAttributes();
8988
8989 state.disable( gl.CULL_FACE );
8990 state.enable( gl.BLEND );
8991
8992 gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
8993 gl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 );
8994 gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );
8995
8996 gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
8997
8998 gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements );
8999
9000 state.activeTexture( gl.TEXTURE0 );
9001 gl.uniform1i( uniforms.map, 0 );
9002
9003 var oldFogType = 0;
9004 var sceneFogType = 0;
9005 var fog = scene.fog;
9006
9007 if ( fog ) {
9008
9009 gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b );
9010
9011 if ( fog.isFog ) {
9012
9013 gl.uniform1f( uniforms.fogNear, fog.near );
9014 gl.uniform1f( uniforms.fogFar, fog.far );
9015
9016 gl.uniform1i( uniforms.fogType, 1 );
9017 oldFogType = 1;
9018 sceneFogType = 1;
9019
9020 } else if ( fog.isFogExp2 ) {
9021
9022 gl.uniform1f( uniforms.fogDensity, fog.density );
9023
9024 gl.uniform1i( uniforms.fogType, 2 );
9025 oldFogType = 2;
9026 sceneFogType = 2;
9027
9028 }
9029
9030 } else {
9031
9032 gl.uniform1i( uniforms.fogType, 0 );
9033 oldFogType = 0;
9034 sceneFogType = 0;
9035
9036 }
9037
9038
9039 // update positions and sort
9040
9041 for ( var i = 0, l = sprites.length; i < l; i ++ ) {
9042
9043 var sprite = sprites[ i ];
9044
9045 sprite.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld );
9046 sprite.z = - sprite.modelViewMatrix.elements[ 14 ];
9047
9048 }
9049
9050 sprites.sort( painterSortStable );
9051
9052 // render all sprites
9053
9054 var scale = [];
9055
9056 for ( var i = 0, l = sprites.length; i < l; i ++ ) {
9057
9058 var sprite = sprites[ i ];
9059 var material = sprite.material;
9060
9061 if ( material.visible === false ) continue;
9062
9063 sprite.onBeforeRender( renderer, scene, camera, undefined, material, undefined );
9064
9065 gl.uniform1f( uniforms.alphaTest, material.alphaTest );
9066 gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite.modelViewMatrix.elements );
9067
9068 sprite.matrixWorld.decompose( spritePosition, spriteRotation, spriteScale );
9069
9070 scale[ 0 ] = spriteScale.x;
9071 scale[ 1 ] = spriteScale.y;
9072
9073 var fogType = 0;
9074
9075 if ( scene.fog && material.fog ) {
9076
9077 fogType = sceneFogType;
9078
9079 }
9080
9081 if ( oldFogType !== fogType ) {
9082
9083 gl.uniform1i( uniforms.fogType, fogType );
9084 oldFogType = fogType;
9085
9086 }
9087
9088 if ( material.map !== null ) {
9089
9090 gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y );
9091 gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y );
9092
9093 } else {
9094
9095 gl.uniform2f( uniforms.uvOffset, 0, 0 );
9096 gl.uniform2f( uniforms.uvScale, 1, 1 );
9097
9098 }
9099
9100 gl.uniform1f( uniforms.opacity, material.opacity );
9101 gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b );
9102
9103 gl.uniform1f( uniforms.rotation, material.rotation );
9104 gl.uniform2fv( uniforms.scale, scale );
9105
9106 state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha );
9107 state.buffers.depth.setTest( material.depthTest );
9108 state.buffers.depth.setMask( material.depthWrite );
9109 state.buffers.color.setMask( material.colorWrite );
9110
9111 textures.setTexture2D( material.map || texture, 0 );
9112
9113 gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
9114
9115 sprite.onAfterRender( renderer, scene, camera, undefined, material, undefined );
9116
9117 }
9118
9119 // restore gl
9120
9121 state.enable( gl.CULL_FACE );
9122
9123 state.reset();
9124
9125 };
9126
9127 function createProgram() {
9128
9129 var program = gl.createProgram();
9130
9131 var vertexShader = gl.createShader( gl.VERTEX_SHADER );
9132 var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
9133
9134 gl.shaderSource( vertexShader, [
9135
9136 'precision ' + capabilities.precision + ' float;',
9137
9138 '#define SHADER_NAME ' + 'SpriteMaterial',
9139
9140 'uniform mat4 modelViewMatrix;',
9141 'uniform mat4 projectionMatrix;',
9142 'uniform float rotation;',
9143 'uniform vec2 scale;',
9144 'uniform vec2 uvOffset;',
9145 'uniform vec2 uvScale;',
9146
9147 'attribute vec2 position;',
9148 'attribute vec2 uv;',
9149
9150 'varying vec2 vUV;',
9151 'varying float fogDepth;',
9152
9153 'void main() {',
9154
9155 ' vUV = uvOffset + uv * uvScale;',
9156
9157 ' vec2 alignedPosition = position * scale;',
9158
9159 ' vec2 rotatedPosition;',
9160 ' rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;',
9161 ' rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;',
9162
9163 ' vec4 mvPosition;',
9164
9165 ' mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );',
9166 ' mvPosition.xy += rotatedPosition;',
9167
9168 ' gl_Position = projectionMatrix * mvPosition;',
9169
9170 ' fogDepth = - mvPosition.z;',
9171
9172 '}'
9173
9174 ].join( '\n' ) );
9175
9176 gl.shaderSource( fragmentShader, [
9177
9178 'precision ' + capabilities.precision + ' float;',
9179
9180 '#define SHADER_NAME ' + 'SpriteMaterial',
9181
9182 'uniform vec3 color;',
9183 'uniform sampler2D map;',
9184 'uniform float opacity;',
9185
9186 'uniform int fogType;',
9187 'uniform vec3 fogColor;',
9188 'uniform float fogDensity;',
9189 'uniform float fogNear;',
9190 'uniform float fogFar;',
9191 'uniform float alphaTest;',
9192
9193 'varying vec2 vUV;',
9194 'varying float fogDepth;',
9195
9196 'void main() {',
9197
9198 ' vec4 texture = texture2D( map, vUV );',
9199
9200 ' gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );',
9201
9202 ' if ( gl_FragColor.a < alphaTest ) discard;',
9203
9204 ' if ( fogType > 0 ) {',
9205
9206 ' float fogFactor = 0.0;',
9207
9208 ' if ( fogType == 1 ) {',
9209
9210 ' fogFactor = smoothstep( fogNear, fogFar, fogDepth );',
9211
9212 ' } else {',
9213
9214 ' const float LOG2 = 1.442695;',
9215 ' fogFactor = exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 );',
9216 ' fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );',
9217
9218 ' }',
9219
9220 ' gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );',
9221
9222 ' }',
9223
9224 '}'
9225
9226 ].join( '\n' ) );
9227
9228 gl.compileShader( vertexShader );
9229 gl.compileShader( fragmentShader );
9230
9231 gl.attachShader( program, vertexShader );
9232 gl.attachShader( program, fragmentShader );
9233
9234 gl.linkProgram( program );
9235
9236 return program;
9237
9238 }
9239
9240 function painterSortStable( a, b ) {
9241
9242 if ( a.renderOrder !== b.renderOrder ) {
9243
9244 return a.renderOrder - b.renderOrder;
9245
9246 } else if ( a.z !== b.z ) {
9247
9248 return b.z - a.z;
9249
9250 } else {
9251
9252 return b.id - a.id;
9253
9254 }
9255
9256 }
9257
9258}
9259
9260/**
9261 * @author mrdoob / http://mrdoob.com/
9262 * @author alteredq / http://alteredqualia.com/
9263 */
9264
9265var materialId = 0;
9266
9267function Material() {
9268
9269 Object.defineProperty( this, 'id', { value: materialId ++ } );
9270
9271 this.uuid = _Math.generateUUID();
9272
9273 this.name = '';
9274 this.type = 'Material';
9275
9276 this.fog = true;
9277 this.lights = true;
9278
9279 this.blending = NormalBlending;
9280 this.side = FrontSide;
9281 this.flatShading = false;
9282 this.vertexColors = NoColors; // THREE.NoColors, THREE.VertexColors, THREE.FaceColors
9283
9284 this.opacity = 1;
9285 this.transparent = false;
9286
9287 this.blendSrc = SrcAlphaFactor;
9288 this.blendDst = OneMinusSrcAlphaFactor;
9289 this.blendEquation = AddEquation;
9290 this.blendSrcAlpha = null;
9291 this.blendDstAlpha = null;
9292 this.blendEquationAlpha = null;
9293
9294 this.depthFunc = LessEqualDepth;
9295 this.depthTest = true;
9296 this.depthWrite = true;
9297
9298 this.clippingPlanes = null;
9299 this.clipIntersection = false;
9300 this.clipShadows = false;
9301
9302 this.colorWrite = true;
9303
9304 this.precision = null; // override the renderer's default precision for this material
9305
9306 this.polygonOffset = false;
9307 this.polygonOffsetFactor = 0;
9308 this.polygonOffsetUnits = 0;
9309
9310 this.dithering = false;
9311
9312 this.alphaTest = 0;
9313 this.premultipliedAlpha = false;
9314
9315 this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer
9316
9317 this.visible = true;
9318
9319 this.userData = {};
9320
9321 this.needsUpdate = true;
9322
9323}
9324
9325Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
9326
9327 constructor: Material,
9328
9329 isMaterial: true,
9330
9331 onBeforeCompile: function () {},
9332
9333 setValues: function ( values ) {
9334
9335 if ( values === undefined ) return;
9336
9337 for ( var key in values ) {
9338
9339 var newValue = values[ key ];
9340
9341 if ( newValue === undefined ) {
9342
9343 console.warn( "THREE.Material: '" + key + "' parameter is undefined." );
9344 continue;
9345
9346 }
9347
9348 // for backward compatability if shading is set in the constructor
9349 if ( key === 'shading' ) {
9350
9351 console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' );
9352 this.flatShading = ( newValue === FlatShading ) ? true : false;
9353 continue;
9354
9355 }
9356
9357 var currentValue = this[ key ];
9358
9359 if ( currentValue === undefined ) {
9360
9361 console.warn( "THREE." + this.type + ": '" + key + "' is not a property of this material." );
9362 continue;
9363
9364 }
9365
9366 if ( currentValue && currentValue.isColor ) {
9367
9368 currentValue.set( newValue );
9369
9370 } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {
9371
9372 currentValue.copy( newValue );
9373
9374 } else if ( key === 'overdraw' ) {
9375
9376 // ensure overdraw is backwards-compatible with legacy boolean type
9377 this[ key ] = Number( newValue );
9378
9379 } else {
9380
9381 this[ key ] = newValue;
9382
9383 }
9384
9385 }
9386
9387 },
9388
9389 toJSON: function ( meta ) {
9390
9391 var isRoot = ( meta === undefined || typeof meta === 'string' );
9392
9393 if ( isRoot ) {
9394
9395 meta = {
9396 textures: {},
9397 images: {}
9398 };
9399
9400 }
9401
9402 var data = {
9403 metadata: {
9404 version: 4.5,
9405 type: 'Material',
9406 generator: 'Material.toJSON'
9407 }
9408 };
9409
9410 // standard Material serialization
9411 data.uuid = this.uuid;
9412 data.type = this.type;
9413
9414 if ( this.name !== '' ) data.name = this.name;
9415
9416 if ( this.color && this.color.isColor ) data.color = this.color.getHex();
9417
9418 if ( this.roughness !== undefined ) data.roughness = this.roughness;
9419 if ( this.metalness !== undefined ) data.metalness = this.metalness;
9420
9421 if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
9422 if ( this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;
9423
9424 if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
9425 if ( this.shininess !== undefined ) data.shininess = this.shininess;
9426 if ( this.clearCoat !== undefined ) data.clearCoat = this.clearCoat;
9427 if ( this.clearCoatRoughness !== undefined ) data.clearCoatRoughness = this.clearCoatRoughness;
9428
9429 if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
9430 if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
9431 if ( this.lightMap && this.lightMap.isTexture ) data.lightMap = this.lightMap.toJSON( meta ).uuid;
9432 if ( this.bumpMap && this.bumpMap.isTexture ) {
9433
9434 data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
9435 data.bumpScale = this.bumpScale;
9436
9437 }
9438 if ( this.normalMap && this.normalMap.isTexture ) {
9439
9440 data.normalMap = this.normalMap.toJSON( meta ).uuid;
9441 data.normalScale = this.normalScale.toArray();
9442
9443 }
9444 if ( this.displacementMap && this.displacementMap.isTexture ) {
9445
9446 data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
9447 data.displacementScale = this.displacementScale;
9448 data.displacementBias = this.displacementBias;
9449
9450 }
9451 if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
9452 if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;
9453
9454 if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
9455 if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
9456
9457 if ( this.envMap && this.envMap.isTexture ) {
9458
9459 data.envMap = this.envMap.toJSON( meta ).uuid;
9460 data.reflectivity = this.reflectivity; // Scale behind envMap
9461
9462 }
9463
9464 if ( this.gradientMap && this.gradientMap.isTexture ) {
9465
9466 data.gradientMap = this.gradientMap.toJSON( meta ).uuid;
9467
9468 }
9469
9470 if ( this.size !== undefined ) data.size = this.size;
9471 if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
9472
9473 if ( this.blending !== NormalBlending ) data.blending = this.blending;
9474 if ( this.flatShading === true ) data.flatShading = this.flatShading;
9475 if ( this.side !== FrontSide ) data.side = this.side;
9476 if ( this.vertexColors !== NoColors ) data.vertexColors = this.vertexColors;
9477
9478 if ( this.opacity < 1 ) data.opacity = this.opacity;
9479 if ( this.transparent === true ) data.transparent = this.transparent;
9480
9481 data.depthFunc = this.depthFunc;
9482 data.depthTest = this.depthTest;
9483 data.depthWrite = this.depthWrite;
9484
9485 // rotation (SpriteMaterial)
9486 if ( this.rotation !== 0 ) data.rotation = this.rotation;
9487
9488 if ( this.linewidth !== 1 ) data.linewidth = this.linewidth;
9489 if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
9490 if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
9491 if ( this.scale !== undefined ) data.scale = this.scale;
9492
9493 if ( this.dithering === true ) data.dithering = true;
9494
9495 if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
9496 if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;
9497
9498 if ( this.wireframe === true ) data.wireframe = this.wireframe;
9499 if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
9500 if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
9501 if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
9502
9503 if ( this.morphTargets === true ) data.morphTargets = true;
9504 if ( this.skinning === true ) data.skinning = true;
9505
9506 if ( this.visible === false ) data.visible = false;
9507 if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
9508
9509 // TODO: Copied from Object3D.toJSON
9510
9511 function extractFromCache( cache ) {
9512
9513 var values = [];
9514
9515 for ( var key in cache ) {
9516
9517 var data = cache[ key ];
9518 delete data.metadata;
9519 values.push( data );
9520
9521 }
9522
9523 return values;
9524
9525 }
9526
9527 if ( isRoot ) {
9528
9529 var textures = extractFromCache( meta.textures );
9530 var images = extractFromCache( meta.images );
9531
9532 if ( textures.length > 0 ) data.textures = textures;
9533 if ( images.length > 0 ) data.images = images;
9534
9535 }
9536
9537 return data;
9538
9539 },
9540
9541 clone: function () {
9542
9543 return new this.constructor().copy( this );
9544
9545 },
9546
9547 copy: function ( source ) {
9548
9549 this.name = source.name;
9550
9551 this.fog = source.fog;
9552 this.lights = source.lights;
9553
9554 this.blending = source.blending;
9555 this.side = source.side;
9556 this.flatShading = source.flatShading;
9557 this.vertexColors = source.vertexColors;
9558
9559 this.opacity = source.opacity;
9560 this.transparent = source.transparent;
9561
9562 this.blendSrc = source.blendSrc;
9563 this.blendDst = source.blendDst;
9564 this.blendEquation = source.blendEquation;
9565 this.blendSrcAlpha = source.blendSrcAlpha;
9566 this.blendDstAlpha = source.blendDstAlpha;
9567 this.blendEquationAlpha = source.blendEquationAlpha;
9568
9569 this.depthFunc = source.depthFunc;
9570 this.depthTest = source.depthTest;
9571 this.depthWrite = source.depthWrite;
9572
9573 this.colorWrite = source.colorWrite;
9574
9575 this.precision = source.precision;
9576
9577 this.polygonOffset = source.polygonOffset;
9578 this.polygonOffsetFactor = source.polygonOffsetFactor;
9579 this.polygonOffsetUnits = source.polygonOffsetUnits;
9580
9581 this.dithering = source.dithering;
9582
9583 this.alphaTest = source.alphaTest;
9584 this.premultipliedAlpha = source.premultipliedAlpha;
9585
9586 this.overdraw = source.overdraw;
9587
9588 this.visible = source.visible;
9589 this.userData = JSON.parse( JSON.stringify( source.userData ) );
9590
9591 this.clipShadows = source.clipShadows;
9592 this.clipIntersection = source.clipIntersection;
9593
9594 var srcPlanes = source.clippingPlanes,
9595 dstPlanes = null;
9596
9597 if ( srcPlanes !== null ) {
9598
9599 var n = srcPlanes.length;
9600 dstPlanes = new Array( n );
9601
9602 for ( var i = 0; i !== n; ++ i )
9603 dstPlanes[ i ] = srcPlanes[ i ].clone();
9604
9605 }
9606
9607 this.clippingPlanes = dstPlanes;
9608
9609 return this;
9610
9611 },
9612
9613 dispose: function () {
9614
9615 this.dispatchEvent( { type: 'dispose' } );
9616
9617 }
9618
9619} );
9620
9621/**
9622 * @author mrdoob / http://mrdoob.com/
9623 * @author alteredq / http://alteredqualia.com/
9624 * @author bhouston / https://clara.io
9625 * @author WestLangley / http://github.com/WestLangley
9626 *
9627 * parameters = {
9628 *
9629 * opacity: <float>,
9630 *
9631 * map: new THREE.Texture( <Image> ),
9632 *
9633 * alphaMap: new THREE.Texture( <Image> ),
9634 *
9635 * displacementMap: new THREE.Texture( <Image> ),
9636 * displacementScale: <float>,
9637 * displacementBias: <float>,
9638 *
9639 * wireframe: <boolean>,
9640 * wireframeLinewidth: <float>
9641 * }
9642 */
9643
9644function MeshDepthMaterial( parameters ) {
9645
9646 Material.call( this );
9647
9648 this.type = 'MeshDepthMaterial';
9649
9650 this.depthPacking = BasicDepthPacking;
9651
9652 this.skinning = false;
9653 this.morphTargets = false;
9654
9655 this.map = null;
9656
9657 this.alphaMap = null;
9658
9659 this.displacementMap = null;
9660 this.displacementScale = 1;
9661 this.displacementBias = 0;
9662
9663 this.wireframe = false;
9664 this.wireframeLinewidth = 1;
9665
9666 this.fog = false;
9667 this.lights = false;
9668
9669 this.setValues( parameters );
9670
9671}
9672
9673MeshDepthMaterial.prototype = Object.create( Material.prototype );
9674MeshDepthMaterial.prototype.constructor = MeshDepthMaterial;
9675
9676MeshDepthMaterial.prototype.isMeshDepthMaterial = true;
9677
9678MeshDepthMaterial.prototype.copy = function ( source ) {
9679
9680 Material.prototype.copy.call( this, source );
9681
9682 this.depthPacking = source.depthPacking;
9683
9684 this.skinning = source.skinning;
9685 this.morphTargets = source.morphTargets;
9686
9687 this.map = source.map;
9688
9689 this.alphaMap = source.alphaMap;
9690
9691 this.displacementMap = source.displacementMap;
9692 this.displacementScale = source.displacementScale;
9693 this.displacementBias = source.displacementBias;
9694
9695 this.wireframe = source.wireframe;
9696 this.wireframeLinewidth = source.wireframeLinewidth;
9697
9698 return this;
9699
9700};
9701
9702/**
9703 * @author WestLangley / http://github.com/WestLangley
9704 *
9705 * parameters = {
9706 *
9707 * referencePosition: <float>,
9708 * nearDistance: <float>,
9709 * farDistance: <float>,
9710 *
9711 * skinning: <bool>,
9712 * morphTargets: <bool>,
9713 *
9714 * map: new THREE.Texture( <Image> ),
9715 *
9716 * alphaMap: new THREE.Texture( <Image> ),
9717 *
9718 * displacementMap: new THREE.Texture( <Image> ),
9719 * displacementScale: <float>,
9720 * displacementBias: <float>
9721 *
9722 * }
9723 */
9724
9725function MeshDistanceMaterial( parameters ) {
9726
9727 Material.call( this );
9728
9729 this.type = 'MeshDistanceMaterial';
9730
9731 this.referencePosition = new Vector3();
9732 this.nearDistance = 1;
9733 this.farDistance = 1000;
9734
9735 this.skinning = false;
9736 this.morphTargets = false;
9737
9738 this.map = null;
9739
9740 this.alphaMap = null;
9741
9742 this.displacementMap = null;
9743 this.displacementScale = 1;
9744 this.displacementBias = 0;
9745
9746 this.fog = false;
9747 this.lights = false;
9748
9749 this.setValues( parameters );
9750
9751}
9752
9753MeshDistanceMaterial.prototype = Object.create( Material.prototype );
9754MeshDistanceMaterial.prototype.constructor = MeshDistanceMaterial;
9755
9756MeshDistanceMaterial.prototype.isMeshDistanceMaterial = true;
9757
9758MeshDistanceMaterial.prototype.copy = function ( source ) {
9759
9760 Material.prototype.copy.call( this, source );
9761
9762 this.referencePosition.copy( source.referencePosition );
9763 this.nearDistance = source.nearDistance;
9764 this.farDistance = source.farDistance;
9765
9766 this.skinning = source.skinning;
9767 this.morphTargets = source.morphTargets;
9768
9769 this.map = source.map;
9770
9771 this.alphaMap = source.alphaMap;
9772
9773 this.displacementMap = source.displacementMap;
9774 this.displacementScale = source.displacementScale;
9775 this.displacementBias = source.displacementBias;
9776
9777 return this;
9778
9779};
9780
9781/**
9782 * @author bhouston / http://clara.io
9783 * @author WestLangley / http://github.com/WestLangley
9784 */
9785
9786function Box3( min, max ) {
9787
9788 this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity );
9789 this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity );
9790
9791}
9792
9793Object.assign( Box3.prototype, {
9794
9795 isBox3: true,
9796
9797 set: function ( min, max ) {
9798
9799 this.min.copy( min );
9800 this.max.copy( max );
9801
9802 return this;
9803
9804 },
9805
9806 setFromArray: function ( array ) {
9807
9808 var minX = + Infinity;
9809 var minY = + Infinity;
9810 var minZ = + Infinity;
9811
9812 var maxX = - Infinity;
9813 var maxY = - Infinity;
9814 var maxZ = - Infinity;
9815
9816 for ( var i = 0, l = array.length; i < l; i += 3 ) {
9817
9818 var x = array[ i ];
9819 var y = array[ i + 1 ];
9820 var z = array[ i + 2 ];
9821
9822 if ( x < minX ) minX = x;
9823 if ( y < minY ) minY = y;
9824 if ( z < minZ ) minZ = z;
9825
9826 if ( x > maxX ) maxX = x;
9827 if ( y > maxY ) maxY = y;
9828 if ( z > maxZ ) maxZ = z;
9829
9830 }
9831
9832 this.min.set( minX, minY, minZ );
9833 this.max.set( maxX, maxY, maxZ );
9834
9835 return this;
9836
9837 },
9838
9839 setFromBufferAttribute: function ( attribute ) {
9840
9841 var minX = + Infinity;
9842 var minY = + Infinity;
9843 var minZ = + Infinity;
9844
9845 var maxX = - Infinity;
9846 var maxY = - Infinity;
9847 var maxZ = - Infinity;
9848
9849 for ( var i = 0, l = attribute.count; i < l; i ++ ) {
9850
9851 var x = attribute.getX( i );
9852 var y = attribute.getY( i );
9853 var z = attribute.getZ( i );
9854
9855 if ( x < minX ) minX = x;
9856 if ( y < minY ) minY = y;
9857 if ( z < minZ ) minZ = z;
9858
9859 if ( x > maxX ) maxX = x;
9860 if ( y > maxY ) maxY = y;
9861 if ( z > maxZ ) maxZ = z;
9862
9863 }
9864
9865 this.min.set( minX, minY, minZ );
9866 this.max.set( maxX, maxY, maxZ );
9867
9868 return this;
9869
9870 },
9871
9872 setFromPoints: function ( points ) {
9873
9874 this.makeEmpty();
9875
9876 for ( var i = 0, il = points.length; i < il; i ++ ) {
9877
9878 this.expandByPoint( points[ i ] );
9879
9880 }
9881
9882 return this;
9883
9884 },
9885
9886 setFromCenterAndSize: function () {
9887
9888 var v1 = new Vector3();
9889
9890 return function setFromCenterAndSize( center, size ) {
9891
9892 var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
9893
9894 this.min.copy( center ).sub( halfSize );
9895 this.max.copy( center ).add( halfSize );
9896
9897 return this;
9898
9899 };
9900
9901 }(),
9902
9903 setFromObject: function ( object ) {
9904
9905 this.makeEmpty();
9906
9907 return this.expandByObject( object );
9908
9909 },
9910
9911 clone: function () {
9912
9913 return new this.constructor().copy( this );
9914
9915 },
9916
9917 copy: function ( box ) {
9918
9919 this.min.copy( box.min );
9920 this.max.copy( box.max );
9921
9922 return this;
9923
9924 },
9925
9926 makeEmpty: function () {
9927
9928 this.min.x = this.min.y = this.min.z = + Infinity;
9929 this.max.x = this.max.y = this.max.z = - Infinity;
9930
9931 return this;
9932
9933 },
9934
9935 isEmpty: function () {
9936
9937 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
9938
9939 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );
9940
9941 },
9942
9943 getCenter: function ( optionalTarget ) {
9944
9945 var result = optionalTarget || new Vector3();
9946 return this.isEmpty() ? result.set( 0, 0, 0 ) : result.addVectors( this.min, this.max ).multiplyScalar( 0.5 );
9947
9948 },
9949
9950 getSize: function ( optionalTarget ) {
9951
9952 var result = optionalTarget || new Vector3();
9953 return this.isEmpty() ? result.set( 0, 0, 0 ) : result.subVectors( this.max, this.min );
9954
9955 },
9956
9957 expandByPoint: function ( point ) {
9958
9959 this.min.min( point );
9960 this.max.max( point );
9961
9962 return this;
9963
9964 },
9965
9966 expandByVector: function ( vector ) {
9967
9968 this.min.sub( vector );
9969 this.max.add( vector );
9970
9971 return this;
9972
9973 },
9974
9975 expandByScalar: function ( scalar ) {
9976
9977 this.min.addScalar( - scalar );
9978 this.max.addScalar( scalar );
9979
9980 return this;
9981
9982 },
9983
9984 expandByObject: function () {
9985
9986 // Computes the world-axis-aligned bounding box of an object (including its children),
9987 // accounting for both the object's, and children's, world transforms
9988
9989 var scope, i, l;
9990
9991 var v1 = new Vector3();
9992
9993 function traverse( node ) {
9994
9995 var geometry = node.geometry;
9996
9997 if ( geometry !== undefined ) {
9998
9999 if ( geometry.isGeometry ) {
10000
10001 var vertices = geometry.vertices;
10002
10003 for ( i = 0, l = vertices.length; i < l; i ++ ) {
10004
10005 v1.copy( vertices[ i ] );
10006 v1.applyMatrix4( node.matrixWorld );
10007
10008 scope.expandByPoint( v1 );
10009
10010 }
10011
10012 } else if ( geometry.isBufferGeometry ) {
10013
10014 var attribute = geometry.attributes.position;
10015
10016 if ( attribute !== undefined ) {
10017
10018 for ( i = 0, l = attribute.count; i < l; i ++ ) {
10019
10020 v1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld );
10021
10022 scope.expandByPoint( v1 );
10023
10024 }
10025
10026 }
10027
10028 }
10029
10030 }
10031
10032 }
10033
10034 return function expandByObject( object ) {
10035
10036 scope = this;
10037
10038 object.updateMatrixWorld( true );
10039
10040 object.traverse( traverse );
10041
10042 return this;
10043
10044 };
10045
10046 }(),
10047
10048 containsPoint: function ( point ) {
10049
10050 return point.x < this.min.x || point.x > this.max.x ||
10051 point.y < this.min.y || point.y > this.max.y ||
10052 point.z < this.min.z || point.z > this.max.z ? false : true;
10053
10054 },
10055
10056 containsBox: function ( box ) {
10057
10058 return this.min.x <= box.min.x && box.max.x <= this.max.x &&
10059 this.min.y <= box.min.y && box.max.y <= this.max.y &&
10060 this.min.z <= box.min.z && box.max.z <= this.max.z;
10061
10062 },
10063
10064 getParameter: function ( point, optionalTarget ) {
10065
10066 // This can potentially have a divide by zero if the box
10067 // has a size dimension of 0.
10068
10069 var result = optionalTarget || new Vector3();
10070
10071 return result.set(
10072 ( point.x - this.min.x ) / ( this.max.x - this.min.x ),
10073 ( point.y - this.min.y ) / ( this.max.y - this.min.y ),
10074 ( point.z - this.min.z ) / ( this.max.z - this.min.z )
10075 );
10076
10077 },
10078
10079 intersectsBox: function ( box ) {
10080
10081 // using 6 splitting planes to rule out intersections.
10082 return box.max.x < this.min.x || box.min.x > this.max.x ||
10083 box.max.y < this.min.y || box.min.y > this.max.y ||
10084 box.max.z < this.min.z || box.min.z > this.max.z ? false : true;
10085
10086 },
10087
10088 intersectsSphere: ( function () {
10089
10090 var closestPoint = new Vector3();
10091
10092 return function intersectsSphere( sphere ) {
10093
10094 // Find the point on the AABB closest to the sphere center.
10095 this.clampPoint( sphere.center, closestPoint );
10096
10097 // If that point is inside the sphere, the AABB and sphere intersect.
10098 return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
10099
10100 };
10101
10102 } )(),
10103
10104 intersectsPlane: function ( plane ) {
10105
10106 // We compute the minimum and maximum dot product values. If those values
10107 // are on the same side (back or front) of the plane, then there is no intersection.
10108
10109 var min, max;
10110
10111 if ( plane.normal.x > 0 ) {
10112
10113 min = plane.normal.x * this.min.x;
10114 max = plane.normal.x * this.max.x;
10115
10116 } else {
10117
10118 min = plane.normal.x * this.max.x;
10119 max = plane.normal.x * this.min.x;
10120
10121 }
10122
10123 if ( plane.normal.y > 0 ) {
10124
10125 min += plane.normal.y * this.min.y;
10126 max += plane.normal.y * this.max.y;
10127
10128 } else {
10129
10130 min += plane.normal.y * this.max.y;
10131 max += plane.normal.y * this.min.y;
10132
10133 }
10134
10135 if ( plane.normal.z > 0 ) {
10136
10137 min += plane.normal.z * this.min.z;
10138 max += plane.normal.z * this.max.z;
10139
10140 } else {
10141
10142 min += plane.normal.z * this.max.z;
10143 max += plane.normal.z * this.min.z;
10144
10145 }
10146
10147 return ( min <= plane.constant && max >= plane.constant );
10148
10149 },
10150
10151 clampPoint: function ( point, optionalTarget ) {
10152
10153 var result = optionalTarget || new Vector3();
10154 return result.copy( point ).clamp( this.min, this.max );
10155
10156 },
10157
10158 distanceToPoint: function () {
10159
10160 var v1 = new Vector3();
10161
10162 return function distanceToPoint( point ) {
10163
10164 var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
10165 return clampedPoint.sub( point ).length();
10166
10167 };
10168
10169 }(),
10170
10171 getBoundingSphere: function () {
10172
10173 var v1 = new Vector3();
10174
10175 return function getBoundingSphere( optionalTarget ) {
10176
10177 var result = optionalTarget || new Sphere();
10178
10179 this.getCenter( result.center );
10180
10181 result.radius = this.getSize( v1 ).length() * 0.5;
10182
10183 return result;
10184
10185 };
10186
10187 }(),
10188
10189 intersect: function ( box ) {
10190
10191 this.min.max( box.min );
10192 this.max.min( box.max );
10193
10194 // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.
10195 if ( this.isEmpty() ) this.makeEmpty();
10196
10197 return this;
10198
10199 },
10200
10201 union: function ( box ) {
10202
10203 this.min.min( box.min );
10204 this.max.max( box.max );
10205
10206 return this;
10207
10208 },
10209
10210 applyMatrix4: function () {
10211
10212 var points = [
10213 new Vector3(),
10214 new Vector3(),
10215 new Vector3(),
10216 new Vector3(),
10217 new Vector3(),
10218 new Vector3(),
10219 new Vector3(),
10220 new Vector3()
10221 ];
10222
10223 return function applyMatrix4( matrix ) {
10224
10225 // transform of empty box is an empty box.
10226 if ( this.isEmpty() ) return this;
10227
10228 // NOTE: I am using a binary pattern to specify all 2^3 combinations below
10229 points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
10230 points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
10231 points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
10232 points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
10233 points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
10234 points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
10235 points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
10236 points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111
10237
10238 this.setFromPoints( points );
10239
10240 return this;
10241
10242 };
10243
10244 }(),
10245
10246 translate: function ( offset ) {
10247
10248 this.min.add( offset );
10249 this.max.add( offset );
10250
10251 return this;
10252
10253 },
10254
10255 equals: function ( box ) {
10256
10257 return box.min.equals( this.min ) && box.max.equals( this.max );
10258
10259 }
10260
10261} );
10262
10263/**
10264 * @author bhouston / http://clara.io
10265 * @author mrdoob / http://mrdoob.com/
10266 */
10267
10268function Sphere( center, radius ) {
10269
10270 this.center = ( center !== undefined ) ? center : new Vector3();
10271 this.radius = ( radius !== undefined ) ? radius : 0;
10272
10273}
10274
10275Object.assign( Sphere.prototype, {
10276
10277 set: function ( center, radius ) {
10278
10279 this.center.copy( center );
10280 this.radius = radius;
10281
10282 return this;
10283
10284 },
10285
10286 setFromPoints: function () {
10287
10288 var box = new Box3();
10289
10290 return function setFromPoints( points, optionalCenter ) {
10291
10292 var center = this.center;
10293
10294 if ( optionalCenter !== undefined ) {
10295
10296 center.copy( optionalCenter );
10297
10298 } else {
10299
10300 box.setFromPoints( points ).getCenter( center );
10301
10302 }
10303
10304 var maxRadiusSq = 0;
10305
10306 for ( var i = 0, il = points.length; i < il; i ++ ) {
10307
10308 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );
10309
10310 }
10311
10312 this.radius = Math.sqrt( maxRadiusSq );
10313
10314 return this;
10315
10316 };
10317
10318 }(),
10319
10320 clone: function () {
10321
10322 return new this.constructor().copy( this );
10323
10324 },
10325
10326 copy: function ( sphere ) {
10327
10328 this.center.copy( sphere.center );
10329 this.radius = sphere.radius;
10330
10331 return this;
10332
10333 },
10334
10335 empty: function () {
10336
10337 return ( this.radius <= 0 );
10338
10339 },
10340
10341 containsPoint: function ( point ) {
10342
10343 return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );
10344
10345 },
10346
10347 distanceToPoint: function ( point ) {
10348
10349 return ( point.distanceTo( this.center ) - this.radius );
10350
10351 },
10352
10353 intersectsSphere: function ( sphere ) {
10354
10355 var radiusSum = this.radius + sphere.radius;
10356
10357 return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );
10358
10359 },
10360
10361 intersectsBox: function ( box ) {
10362
10363 return box.intersectsSphere( this );
10364
10365 },
10366
10367 intersectsPlane: function ( plane ) {
10368
10369 return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;
10370
10371 },
10372
10373 clampPoint: function ( point, optionalTarget ) {
10374
10375 var deltaLengthSq = this.center.distanceToSquared( point );
10376
10377 var result = optionalTarget || new Vector3();
10378
10379 result.copy( point );
10380
10381 if ( deltaLengthSq > ( this.radius * this.radius ) ) {
10382
10383 result.sub( this.center ).normalize();
10384 result.multiplyScalar( this.radius ).add( this.center );
10385
10386 }
10387
10388 return result;
10389
10390 },
10391
10392 getBoundingBox: function ( optionalTarget ) {
10393
10394 var box = optionalTarget || new Box3();
10395
10396 box.set( this.center, this.center );
10397 box.expandByScalar( this.radius );
10398
10399 return box;
10400
10401 },
10402
10403 applyMatrix4: function ( matrix ) {
10404
10405 this.center.applyMatrix4( matrix );
10406 this.radius = this.radius * matrix.getMaxScaleOnAxis();
10407
10408 return this;
10409
10410 },
10411
10412 translate: function ( offset ) {
10413
10414 this.center.add( offset );
10415
10416 return this;
10417
10418 },
10419
10420 equals: function ( sphere ) {
10421
10422 return sphere.center.equals( this.center ) && ( sphere.radius === this.radius );
10423
10424 }
10425
10426} );
10427
10428/**
10429 * @author bhouston / http://clara.io
10430 */
10431
10432function Plane( normal, constant ) {
10433
10434 // normal is assumed to be normalized
10435
10436 this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 );
10437 this.constant = ( constant !== undefined ) ? constant : 0;
10438
10439}
10440
10441Object.assign( Plane.prototype, {
10442
10443 set: function ( normal, constant ) {
10444
10445 this.normal.copy( normal );
10446 this.constant = constant;
10447
10448 return this;
10449
10450 },
10451
10452 setComponents: function ( x, y, z, w ) {
10453
10454 this.normal.set( x, y, z );
10455 this.constant = w;
10456
10457 return this;
10458
10459 },
10460
10461 setFromNormalAndCoplanarPoint: function ( normal, point ) {
10462
10463 this.normal.copy( normal );
10464 this.constant = - point.dot( this.normal );
10465
10466 return this;
10467
10468 },
10469
10470 setFromCoplanarPoints: function () {
10471
10472 var v1 = new Vector3();
10473 var v2 = new Vector3();
10474
10475 return function setFromCoplanarPoints( a, b, c ) {
10476
10477 var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize();
10478
10479 // Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
10480
10481 this.setFromNormalAndCoplanarPoint( normal, a );
10482
10483 return this;
10484
10485 };
10486
10487 }(),
10488
10489 clone: function () {
10490
10491 return new this.constructor().copy( this );
10492
10493 },
10494
10495 copy: function ( plane ) {
10496
10497 this.normal.copy( plane.normal );
10498 this.constant = plane.constant;
10499
10500 return this;
10501
10502 },
10503
10504 normalize: function () {
10505
10506 // Note: will lead to a divide by zero if the plane is invalid.
10507
10508 var inverseNormalLength = 1.0 / this.normal.length();
10509 this.normal.multiplyScalar( inverseNormalLength );
10510 this.constant *= inverseNormalLength;
10511
10512 return this;
10513
10514 },
10515
10516 negate: function () {
10517
10518 this.constant *= - 1;
10519 this.normal.negate();
10520
10521 return this;
10522
10523 },
10524
10525 distanceToPoint: function ( point ) {
10526
10527 return this.normal.dot( point ) + this.constant;
10528
10529 },
10530
10531 distanceToSphere: function ( sphere ) {
10532
10533 return this.distanceToPoint( sphere.center ) - sphere.radius;
10534
10535 },
10536
10537 projectPoint: function ( point, optionalTarget ) {
10538
10539 var result = optionalTarget || new Vector3();
10540
10541 return result.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point );
10542
10543 },
10544
10545 intersectLine: function () {
10546
10547 var v1 = new Vector3();
10548
10549 return function intersectLine( line, optionalTarget ) {
10550
10551 var result = optionalTarget || new Vector3();
10552
10553 var direction = line.delta( v1 );
10554
10555 var denominator = this.normal.dot( direction );
10556
10557 if ( denominator === 0 ) {
10558
10559 // line is coplanar, return origin
10560 if ( this.distanceToPoint( line.start ) === 0 ) {
10561
10562 return result.copy( line.start );
10563
10564 }
10565
10566 // Unsure if this is the correct method to handle this case.
10567 return undefined;
10568
10569 }
10570
10571 var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
10572
10573 if ( t < 0 || t > 1 ) {
10574
10575 return undefined;
10576
10577 }
10578
10579 return result.copy( direction ).multiplyScalar( t ).add( line.start );
10580
10581 };
10582
10583 }(),
10584
10585 intersectsLine: function ( line ) {
10586
10587 // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
10588
10589 var startSign = this.distanceToPoint( line.start );
10590 var endSign = this.distanceToPoint( line.end );
10591
10592 return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );
10593
10594 },
10595
10596 intersectsBox: function ( box ) {
10597
10598 return box.intersectsPlane( this );
10599
10600 },
10601
10602 intersectsSphere: function ( sphere ) {
10603
10604 return sphere.intersectsPlane( this );
10605
10606 },
10607
10608 coplanarPoint: function ( optionalTarget ) {
10609
10610 var result = optionalTarget || new Vector3();
10611
10612 return result.copy( this.normal ).multiplyScalar( - this.constant );
10613
10614 },
10615
10616 applyMatrix4: function () {
10617
10618 var v1 = new Vector3();
10619 var m1 = new Matrix3();
10620
10621 return function applyMatrix4( matrix, optionalNormalMatrix ) {
10622
10623 var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix );
10624
10625 var referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix );
10626
10627 var normal = this.normal.applyMatrix3( normalMatrix ).normalize();
10628
10629 this.constant = - referencePoint.dot( normal );
10630
10631 return this;
10632
10633 };
10634
10635 }(),
10636
10637 translate: function ( offset ) {
10638
10639 this.constant -= offset.dot( this.normal );
10640
10641 return this;
10642
10643 },
10644
10645 equals: function ( plane ) {
10646
10647 return plane.normal.equals( this.normal ) && ( plane.constant === this.constant );
10648
10649 }
10650
10651} );
10652
10653/**
10654 * @author mrdoob / http://mrdoob.com/
10655 * @author alteredq / http://alteredqualia.com/
10656 * @author bhouston / http://clara.io
10657 */
10658
10659function Frustum( p0, p1, p2, p3, p4, p5 ) {
10660
10661 this.planes = [
10662
10663 ( p0 !== undefined ) ? p0 : new Plane(),
10664 ( p1 !== undefined ) ? p1 : new Plane(),
10665 ( p2 !== undefined ) ? p2 : new Plane(),
10666 ( p3 !== undefined ) ? p3 : new Plane(),
10667 ( p4 !== undefined ) ? p4 : new Plane(),
10668 ( p5 !== undefined ) ? p5 : new Plane()
10669
10670 ];
10671
10672}
10673
10674Object.assign( Frustum.prototype, {
10675
10676 set: function ( p0, p1, p2, p3, p4, p5 ) {
10677
10678 var planes = this.planes;
10679
10680 planes[ 0 ].copy( p0 );
10681 planes[ 1 ].copy( p1 );
10682 planes[ 2 ].copy( p2 );
10683 planes[ 3 ].copy( p3 );
10684 planes[ 4 ].copy( p4 );
10685 planes[ 5 ].copy( p5 );
10686
10687 return this;
10688
10689 },
10690
10691 clone: function () {
10692
10693 return new this.constructor().copy( this );
10694
10695 },
10696
10697 copy: function ( frustum ) {
10698
10699 var planes = this.planes;
10700
10701 for ( var i = 0; i < 6; i ++ ) {
10702
10703 planes[ i ].copy( frustum.planes[ i ] );
10704
10705 }
10706
10707 return this;
10708
10709 },
10710
10711 setFromMatrix: function ( m ) {
10712
10713 var planes = this.planes;
10714 var me = m.elements;
10715 var me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
10716 var me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
10717 var me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
10718 var me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
10719
10720 planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
10721 planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
10722 planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
10723 planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
10724 planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
10725 planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();
10726
10727 return this;
10728
10729 },
10730
10731 intersectsObject: function () {
10732
10733 var sphere = new Sphere();
10734
10735 return function intersectsObject( object ) {
10736
10737 var geometry = object.geometry;
10738
10739 if ( geometry.boundingSphere === null )
10740 geometry.computeBoundingSphere();
10741
10742 sphere.copy( geometry.boundingSphere )
10743 .applyMatrix4( object.matrixWorld );
10744
10745 return this.intersectsSphere( sphere );
10746
10747 };
10748
10749 }(),
10750
10751 intersectsSprite: function () {
10752
10753 var sphere = new Sphere();
10754
10755 return function intersectsSprite( sprite ) {
10756
10757 sphere.center.set( 0, 0, 0 );
10758 sphere.radius = 0.7071067811865476;
10759 sphere.applyMatrix4( sprite.matrixWorld );
10760
10761 return this.intersectsSphere( sphere );
10762
10763 };
10764
10765 }(),
10766
10767 intersectsSphere: function ( sphere ) {
10768
10769 var planes = this.planes;
10770 var center = sphere.center;
10771 var negRadius = - sphere.radius;
10772
10773 for ( var i = 0; i < 6; i ++ ) {
10774
10775 var distance = planes[ i ].distanceToPoint( center );
10776
10777 if ( distance < negRadius ) {
10778
10779 return false;
10780
10781 }
10782
10783 }
10784
10785 return true;
10786
10787 },
10788
10789 intersectsBox: function () {
10790
10791 var p1 = new Vector3(),
10792 p2 = new Vector3();
10793
10794 return function intersectsBox( box ) {
10795
10796 var planes = this.planes;
10797
10798 for ( var i = 0; i < 6; i ++ ) {
10799
10800 var plane = planes[ i ];
10801
10802 p1.x = plane.normal.x > 0 ? box.min.x : box.max.x;
10803 p2.x = plane.normal.x > 0 ? box.max.x : box.min.x;
10804 p1.y = plane.normal.y > 0 ? box.min.y : box.max.y;
10805 p2.y = plane.normal.y > 0 ? box.max.y : box.min.y;
10806 p1.z = plane.normal.z > 0 ? box.min.z : box.max.z;
10807 p2.z = plane.normal.z > 0 ? box.max.z : box.min.z;
10808
10809 var d1 = plane.distanceToPoint( p1 );
10810 var d2 = plane.distanceToPoint( p2 );
10811
10812 // if both outside plane, no intersection
10813
10814 if ( d1 < 0 && d2 < 0 ) {
10815
10816 return false;
10817
10818 }
10819
10820 }
10821
10822 return true;
10823
10824 };
10825
10826 }(),
10827
10828 containsPoint: function ( point ) {
10829
10830 var planes = this.planes;
10831
10832 for ( var i = 0; i < 6; i ++ ) {
10833
10834 if ( planes[ i ].distanceToPoint( point ) < 0 ) {
10835
10836 return false;
10837
10838 }
10839
10840 }
10841
10842 return true;
10843
10844 }
10845
10846} );
10847
10848/**
10849 * @author alteredq / http://alteredqualia.com/
10850 * @author mrdoob / http://mrdoob.com/
10851 */
10852
10853function WebGLShadowMap( _renderer, _objects, maxTextureSize ) {
10854
10855 var _frustum = new Frustum(),
10856 _projScreenMatrix = new Matrix4(),
10857
10858 _shadowMapSize = new Vector2(),
10859 _maxShadowMapSize = new Vector2( maxTextureSize, maxTextureSize ),
10860
10861 _lookTarget = new Vector3(),
10862 _lightPositionWorld = new Vector3(),
10863
10864 _MorphingFlag = 1,
10865 _SkinningFlag = 2,
10866
10867 _NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1,
10868
10869 _depthMaterials = new Array( _NumberOfMaterialVariants ),
10870 _distanceMaterials = new Array( _NumberOfMaterialVariants ),
10871
10872 _materialCache = {};
10873
10874 var cubeDirections = [
10875 new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
10876 new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
10877 ];
10878
10879 var cubeUps = [
10880 new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
10881 new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 )
10882 ];
10883
10884 var cube2DViewPorts = [
10885 new Vector4(), new Vector4(), new Vector4(),
10886 new Vector4(), new Vector4(), new Vector4()
10887 ];
10888
10889 // init
10890
10891 for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) {
10892
10893 var useMorphing = ( i & _MorphingFlag ) !== 0;
10894 var useSkinning = ( i & _SkinningFlag ) !== 0;
10895
10896 var depthMaterial = new MeshDepthMaterial( {
10897
10898 depthPacking: RGBADepthPacking,
10899
10900 morphTargets: useMorphing,
10901 skinning: useSkinning
10902
10903 } );
10904
10905 _depthMaterials[ i ] = depthMaterial;
10906
10907 //
10908
10909 var distanceMaterial = new MeshDistanceMaterial( {
10910
10911 morphTargets: useMorphing,
10912 skinning: useSkinning
10913
10914 } );
10915
10916 _distanceMaterials[ i ] = distanceMaterial;
10917
10918 }
10919
10920 //
10921
10922 var scope = this;
10923
10924 this.enabled = false;
10925
10926 this.autoUpdate = true;
10927 this.needsUpdate = false;
10928
10929 this.type = PCFShadowMap;
10930
10931 this.renderReverseSided = true;
10932 this.renderSingleSided = true;
10933
10934 this.render = function ( lights, scene, camera ) {
10935
10936 if ( scope.enabled === false ) return;
10937 if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;
10938
10939 if ( lights.length === 0 ) return;
10940
10941 // TODO Clean up (needed in case of contextlost)
10942 var _gl = _renderer.context;
10943 var _state = _renderer.state;
10944
10945 // Set GL state for depth map.
10946 _state.disable( _gl.BLEND );
10947 _state.buffers.color.setClear( 1, 1, 1, 1 );
10948 _state.buffers.depth.setTest( true );
10949 _state.setScissorTest( false );
10950
10951 // render depth map
10952
10953 var faceCount;
10954
10955 for ( var i = 0, il = lights.length; i < il; i ++ ) {
10956
10957 var light = lights[ i ];
10958 var shadow = light.shadow;
10959 var isPointLight = light && light.isPointLight;
10960
10961 if ( shadow === undefined ) {
10962
10963 console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
10964 continue;
10965
10966 }
10967
10968 var shadowCamera = shadow.camera;
10969
10970 _shadowMapSize.copy( shadow.mapSize );
10971 _shadowMapSize.min( _maxShadowMapSize );
10972
10973 if ( isPointLight ) {
10974
10975 var vpWidth = _shadowMapSize.x;
10976 var vpHeight = _shadowMapSize.y;
10977
10978 // These viewports map a cube-map onto a 2D texture with the
10979 // following orientation:
10980 //
10981 // xzXZ
10982 // y Y
10983 //
10984 // X - Positive x direction
10985 // x - Negative x direction
10986 // Y - Positive y direction
10987 // y - Negative y direction
10988 // Z - Positive z direction
10989 // z - Negative z direction
10990
10991 // positive X
10992 cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight );
10993 // negative X
10994 cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight );
10995 // positive Z
10996 cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight );
10997 // negative Z
10998 cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight );
10999 // positive Y
11000 cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight );
11001 // negative Y
11002 cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight );
11003
11004 _shadowMapSize.x *= 4.0;
11005 _shadowMapSize.y *= 2.0;
11006
11007 }
11008
11009 if ( shadow.map === null ) {
11010
11011 var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };
11012
11013 shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
11014 shadow.map.texture.name = light.name + ".shadowMap";
11015
11016 shadowCamera.updateProjectionMatrix();
11017
11018 }
11019
11020 if ( shadow.isSpotLightShadow ) {
11021
11022 shadow.update( light );
11023
11024 }
11025
11026 var shadowMap = shadow.map;
11027 var shadowMatrix = shadow.matrix;
11028
11029 _lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
11030 shadowCamera.position.copy( _lightPositionWorld );
11031
11032 if ( isPointLight ) {
11033
11034 faceCount = 6;
11035
11036 // for point lights we set the shadow matrix to be a translation-only matrix
11037 // equal to inverse of the light's position
11038
11039 shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z );
11040
11041 } else {
11042
11043 faceCount = 1;
11044
11045 _lookTarget.setFromMatrixPosition( light.target.matrixWorld );
11046 shadowCamera.lookAt( _lookTarget );
11047 shadowCamera.updateMatrixWorld();
11048
11049 // compute shadow matrix
11050
11051 shadowMatrix.set(
11052 0.5, 0.0, 0.0, 0.5,
11053 0.0, 0.5, 0.0, 0.5,
11054 0.0, 0.0, 0.5, 0.5,
11055 0.0, 0.0, 0.0, 1.0
11056 );
11057
11058 shadowMatrix.multiply( shadowCamera.projectionMatrix );
11059 shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
11060
11061 }
11062
11063 _renderer.setRenderTarget( shadowMap );
11064 _renderer.clear();
11065
11066 // render shadow map for each cube face (if omni-directional) or
11067 // run a single pass if not
11068
11069 for ( var face = 0; face < faceCount; face ++ ) {
11070
11071 if ( isPointLight ) {
11072
11073 _lookTarget.copy( shadowCamera.position );
11074 _lookTarget.add( cubeDirections[ face ] );
11075 shadowCamera.up.copy( cubeUps[ face ] );
11076 shadowCamera.lookAt( _lookTarget );
11077 shadowCamera.updateMatrixWorld();
11078
11079 var vpDimensions = cube2DViewPorts[ face ];
11080 _state.viewport( vpDimensions );
11081
11082 }
11083
11084 // update camera matrices and frustum
11085
11086 _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
11087 _frustum.setFromMatrix( _projScreenMatrix );
11088
11089 // set object matrices & frustum culling
11090
11091 renderObject( scene, camera, shadowCamera, isPointLight );
11092
11093 }
11094
11095 }
11096
11097 scope.needsUpdate = false;
11098
11099 };
11100
11101 function getDepthMaterial( object, material, isPointLight, lightPositionWorld, shadowCameraNear, shadowCameraFar ) {
11102
11103 var geometry = object.geometry;
11104
11105 var result = null;
11106
11107 var materialVariants = _depthMaterials;
11108 var customMaterial = object.customDepthMaterial;
11109
11110 if ( isPointLight ) {
11111
11112 materialVariants = _distanceMaterials;
11113 customMaterial = object.customDistanceMaterial;
11114
11115 }
11116
11117 if ( ! customMaterial ) {
11118
11119 var useMorphing = false;
11120
11121 if ( material.morphTargets ) {
11122
11123 if ( geometry && geometry.isBufferGeometry ) {
11124
11125 useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0;
11126
11127 } else if ( geometry && geometry.isGeometry ) {
11128
11129 useMorphing = geometry.morphTargets && geometry.morphTargets.length > 0;
11130
11131 }
11132
11133 }
11134
11135 if ( object.isSkinnedMesh && material.skinning === false ) {
11136
11137 console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object );
11138
11139 }
11140
11141 var useSkinning = object.isSkinnedMesh && material.skinning;
11142
11143 var variantIndex = 0;
11144
11145 if ( useMorphing ) variantIndex |= _MorphingFlag;
11146 if ( useSkinning ) variantIndex |= _SkinningFlag;
11147
11148 result = materialVariants[ variantIndex ];
11149
11150 } else {
11151
11152 result = customMaterial;
11153
11154 }
11155
11156 if ( _renderer.localClippingEnabled &&
11157 material.clipShadows === true &&
11158 material.clippingPlanes.length !== 0 ) {
11159
11160 // in this case we need a unique material instance reflecting the
11161 // appropriate state
11162
11163 var keyA = result.uuid, keyB = material.uuid;
11164
11165 var materialsForVariant = _materialCache[ keyA ];
11166
11167 if ( materialsForVariant === undefined ) {
11168
11169 materialsForVariant = {};
11170 _materialCache[ keyA ] = materialsForVariant;
11171
11172 }
11173
11174 var cachedMaterial = materialsForVariant[ keyB ];
11175
11176 if ( cachedMaterial === undefined ) {
11177
11178 cachedMaterial = result.clone();
11179 materialsForVariant[ keyB ] = cachedMaterial;
11180
11181 }
11182
11183 result = cachedMaterial;
11184
11185 }
11186
11187 result.visible = material.visible;
11188 result.wireframe = material.wireframe;
11189
11190 var side = material.side;
11191
11192 if ( scope.renderSingleSided && side == DoubleSide ) {
11193
11194 side = FrontSide;
11195
11196 }
11197
11198 if ( scope.renderReverseSided ) {
11199
11200 if ( side === FrontSide ) side = BackSide;
11201 else if ( side === BackSide ) side = FrontSide;
11202
11203 }
11204
11205 result.side = side;
11206
11207 result.clipShadows = material.clipShadows;
11208 result.clippingPlanes = material.clippingPlanes;
11209 result.clipIntersection = material.clipIntersection;
11210
11211 result.wireframeLinewidth = material.wireframeLinewidth;
11212 result.linewidth = material.linewidth;
11213
11214 if ( isPointLight && result.isMeshDistanceMaterial ) {
11215
11216 result.referencePosition.copy( lightPositionWorld );
11217 result.nearDistance = shadowCameraNear;
11218 result.farDistance = shadowCameraFar;
11219
11220 }
11221
11222 return result;
11223
11224 }
11225
11226 function renderObject( object, camera, shadowCamera, isPointLight ) {
11227
11228 if ( object.visible === false ) return;
11229
11230 var visible = object.layers.test( camera.layers );
11231
11232 if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {
11233
11234 if ( object.castShadow && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {
11235
11236 object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
11237
11238 var geometry = _objects.update( object );
11239 var material = object.material;
11240
11241 if ( Array.isArray( material ) ) {
11242
11243 var groups = geometry.groups;
11244
11245 for ( var k = 0, kl = groups.length; k < kl; k ++ ) {
11246
11247 var group = groups[ k ];
11248 var groupMaterial = material[ group.materialIndex ];
11249
11250 if ( groupMaterial && groupMaterial.visible ) {
11251
11252 var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );
11253 _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );
11254
11255 }
11256
11257 }
11258
11259 } else if ( material.visible ) {
11260
11261 var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );
11262 _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );
11263
11264 }
11265
11266 }
11267
11268 }
11269
11270 var children = object.children;
11271
11272 for ( var i = 0, l = children.length; i < l; i ++ ) {
11273
11274 renderObject( children[ i ], camera, shadowCamera, isPointLight );
11275
11276 }
11277
11278 }
11279
11280}
11281
11282/**
11283 * @author mrdoob / http://mrdoob.com/
11284 */
11285
11286function WebGLAttributes( gl ) {
11287
11288 var buffers = {};
11289
11290 function createBuffer( attribute, bufferType ) {
11291
11292 var array = attribute.array;
11293 var usage = attribute.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW;
11294
11295 var buffer = gl.createBuffer();
11296
11297 gl.bindBuffer( bufferType, buffer );
11298 gl.bufferData( bufferType, array, usage );
11299
11300 attribute.onUploadCallback();
11301
11302 var type = gl.FLOAT;
11303
11304 if ( array instanceof Float32Array ) {
11305
11306 type = gl.FLOAT;
11307
11308 } else if ( array instanceof Float64Array ) {
11309
11310 console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' );
11311
11312 } else if ( array instanceof Uint16Array ) {
11313
11314 type = gl.UNSIGNED_SHORT;
11315
11316 } else if ( array instanceof Int16Array ) {
11317
11318 type = gl.SHORT;
11319
11320 } else if ( array instanceof Uint32Array ) {
11321
11322 type = gl.UNSIGNED_INT;
11323
11324 } else if ( array instanceof Int32Array ) {
11325
11326 type = gl.INT;
11327
11328 } else if ( array instanceof Int8Array ) {
11329
11330 type = gl.BYTE;
11331
11332 } else if ( array instanceof Uint8Array ) {
11333
11334 type = gl.UNSIGNED_BYTE;
11335
11336 }
11337
11338 return {
11339 buffer: buffer,
11340 type: type,
11341 bytesPerElement: array.BYTES_PER_ELEMENT,
11342 version: attribute.version
11343 };
11344
11345 }
11346
11347 function updateBuffer( buffer, attribute, bufferType ) {
11348
11349 var array = attribute.array;
11350 var updateRange = attribute.updateRange;
11351
11352 gl.bindBuffer( bufferType, buffer );
11353
11354 if ( attribute.dynamic === false ) {
11355
11356 gl.bufferData( bufferType, array, gl.STATIC_DRAW );
11357
11358 } else if ( updateRange.count === - 1 ) {
11359
11360 // Not using update ranges
11361
11362 gl.bufferSubData( bufferType, 0, array );
11363
11364 } else if ( updateRange.count === 0 ) {
11365
11366 console.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' );
11367
11368 } else {
11369
11370 gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
11371 array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );
11372
11373 updateRange.count = - 1; // reset range
11374
11375 }
11376
11377 }
11378
11379 //
11380
11381 function get( attribute ) {
11382
11383 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
11384
11385 return buffers[ attribute.uuid ];
11386
11387 }
11388
11389 function remove( attribute ) {
11390
11391 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
11392
11393 var data = buffers[ attribute.uuid ];
11394
11395 if ( data ) {
11396
11397 gl.deleteBuffer( data.buffer );
11398
11399 delete buffers[ attribute.uuid ];
11400
11401 }
11402
11403 }
11404
11405 function update( attribute, bufferType ) {
11406
11407 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
11408
11409 var data = buffers[ attribute.uuid ];
11410
11411 if ( data === undefined ) {
11412
11413 buffers[ attribute.uuid ] = createBuffer( attribute, bufferType );
11414
11415 } else if ( data.version < attribute.version ) {
11416
11417 updateBuffer( data.buffer, attribute, bufferType );
11418
11419 data.version = attribute.version;
11420
11421 }
11422
11423 }
11424
11425 return {
11426
11427 get: get,
11428 remove: remove,
11429 update: update
11430
11431 };
11432
11433}
11434
11435/**
11436 * @author mrdoob / http://mrdoob.com/
11437 * @author WestLangley / http://github.com/WestLangley
11438 * @author bhouston / http://clara.io
11439 */
11440
11441function Euler( x, y, z, order ) {
11442
11443 this._x = x || 0;
11444 this._y = y || 0;
11445 this._z = z || 0;
11446 this._order = order || Euler.DefaultOrder;
11447
11448}
11449
11450Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];
11451
11452Euler.DefaultOrder = 'XYZ';
11453
11454Object.defineProperties( Euler.prototype, {
11455
11456 x: {
11457
11458 get: function () {
11459
11460 return this._x;
11461
11462 },
11463
11464 set: function ( value ) {
11465
11466 this._x = value;
11467 this.onChangeCallback();
11468
11469 }
11470
11471 },
11472
11473 y: {
11474
11475 get: function () {
11476
11477 return this._y;
11478
11479 },
11480
11481 set: function ( value ) {
11482
11483 this._y = value;
11484 this.onChangeCallback();
11485
11486 }
11487
11488 },
11489
11490 z: {
11491
11492 get: function () {
11493
11494 return this._z;
11495
11496 },
11497
11498 set: function ( value ) {
11499
11500 this._z = value;
11501 this.onChangeCallback();
11502
11503 }
11504
11505 },
11506
11507 order: {
11508
11509 get: function () {
11510
11511 return this._order;
11512
11513 },
11514
11515 set: function ( value ) {
11516
11517 this._order = value;
11518 this.onChangeCallback();
11519
11520 }
11521
11522 }
11523
11524} );
11525
11526Object.assign( Euler.prototype, {
11527
11528 isEuler: true,
11529
11530 set: function ( x, y, z, order ) {
11531
11532 this._x = x;
11533 this._y = y;
11534 this._z = z;
11535 this._order = order || this._order;
11536
11537 this.onChangeCallback();
11538
11539 return this;
11540
11541 },
11542
11543 clone: function () {
11544
11545 return new this.constructor( this._x, this._y, this._z, this._order );
11546
11547 },
11548
11549 copy: function ( euler ) {
11550
11551 this._x = euler._x;
11552 this._y = euler._y;
11553 this._z = euler._z;
11554 this._order = euler._order;
11555
11556 this.onChangeCallback();
11557
11558 return this;
11559
11560 },
11561
11562 setFromRotationMatrix: function ( m, order, update ) {
11563
11564 var clamp = _Math.clamp;
11565
11566 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
11567
11568 var te = m.elements;
11569 var m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
11570 var m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
11571 var m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
11572
11573 order = order || this._order;
11574
11575 if ( order === 'XYZ' ) {
11576
11577 this._y = Math.asin( clamp( m13, - 1, 1 ) );
11578
11579 if ( Math.abs( m13 ) < 0.99999 ) {
11580
11581 this._x = Math.atan2( - m23, m33 );
11582 this._z = Math.atan2( - m12, m11 );
11583
11584 } else {
11585
11586 this._x = Math.atan2( m32, m22 );
11587 this._z = 0;
11588
11589 }
11590
11591 } else if ( order === 'YXZ' ) {
11592
11593 this._x = Math.asin( - clamp( m23, - 1, 1 ) );
11594
11595 if ( Math.abs( m23 ) < 0.99999 ) {
11596
11597 this._y = Math.atan2( m13, m33 );
11598 this._z = Math.atan2( m21, m22 );
11599
11600 } else {
11601
11602 this._y = Math.atan2( - m31, m11 );
11603 this._z = 0;
11604
11605 }
11606
11607 } else if ( order === 'ZXY' ) {
11608
11609 this._x = Math.asin( clamp( m32, - 1, 1 ) );
11610
11611 if ( Math.abs( m32 ) < 0.99999 ) {
11612
11613 this._y = Math.atan2( - m31, m33 );
11614 this._z = Math.atan2( - m12, m22 );
11615
11616 } else {
11617
11618 this._y = 0;
11619 this._z = Math.atan2( m21, m11 );
11620
11621 }
11622
11623 } else if ( order === 'ZYX' ) {
11624
11625 this._y = Math.asin( - clamp( m31, - 1, 1 ) );
11626
11627 if ( Math.abs( m31 ) < 0.99999 ) {
11628
11629 this._x = Math.atan2( m32, m33 );
11630 this._z = Math.atan2( m21, m11 );
11631
11632 } else {
11633
11634 this._x = 0;
11635 this._z = Math.atan2( - m12, m22 );
11636
11637 }
11638
11639 } else if ( order === 'YZX' ) {
11640
11641 this._z = Math.asin( clamp( m21, - 1, 1 ) );
11642
11643 if ( Math.abs( m21 ) < 0.99999 ) {
11644
11645 this._x = Math.atan2( - m23, m22 );
11646 this._y = Math.atan2( - m31, m11 );
11647
11648 } else {
11649
11650 this._x = 0;
11651 this._y = Math.atan2( m13, m33 );
11652
11653 }
11654
11655 } else if ( order === 'XZY' ) {
11656
11657 this._z = Math.asin( - clamp( m12, - 1, 1 ) );
11658
11659 if ( Math.abs( m12 ) < 0.99999 ) {
11660
11661 this._x = Math.atan2( m32, m22 );
11662 this._y = Math.atan2( m13, m11 );
11663
11664 } else {
11665
11666 this._x = Math.atan2( - m23, m33 );
11667 this._y = 0;
11668
11669 }
11670
11671 } else {
11672
11673 console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order );
11674
11675 }
11676
11677 this._order = order;
11678
11679 if ( update !== false ) this.onChangeCallback();
11680
11681 return this;
11682
11683 },
11684
11685 setFromQuaternion: function () {
11686
11687 var matrix = new Matrix4();
11688
11689 return function setFromQuaternion( q, order, update ) {
11690
11691 matrix.makeRotationFromQuaternion( q );
11692
11693 return this.setFromRotationMatrix( matrix, order, update );
11694
11695 };
11696
11697 }(),
11698
11699 setFromVector3: function ( v, order ) {
11700
11701 return this.set( v.x, v.y, v.z, order || this._order );
11702
11703 },
11704
11705 reorder: function () {
11706
11707 // WARNING: this discards revolution information -bhouston
11708
11709 var q = new Quaternion();
11710
11711 return function reorder( newOrder ) {
11712
11713 q.setFromEuler( this );
11714
11715 return this.setFromQuaternion( q, newOrder );
11716
11717 };
11718
11719 }(),
11720
11721 equals: function ( euler ) {
11722
11723 return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
11724
11725 },
11726
11727 fromArray: function ( array ) {
11728
11729 this._x = array[ 0 ];
11730 this._y = array[ 1 ];
11731 this._z = array[ 2 ];
11732 if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
11733
11734 this.onChangeCallback();
11735
11736 return this;
11737
11738 },
11739
11740 toArray: function ( array, offset ) {
11741
11742 if ( array === undefined ) array = [];
11743 if ( offset === undefined ) offset = 0;
11744
11745 array[ offset ] = this._x;
11746 array[ offset + 1 ] = this._y;
11747 array[ offset + 2 ] = this._z;
11748 array[ offset + 3 ] = this._order;
11749
11750 return array;
11751
11752 },
11753
11754 toVector3: function ( optionalResult ) {
11755
11756 if ( optionalResult ) {
11757
11758 return optionalResult.set( this._x, this._y, this._z );
11759
11760 } else {
11761
11762 return new Vector3( this._x, this._y, this._z );
11763
11764 }
11765
11766 },
11767
11768 onChange: function ( callback ) {
11769
11770 this.onChangeCallback = callback;
11771
11772 return this;
11773
11774 },
11775
11776 onChangeCallback: function () {}
11777
11778} );
11779
11780/**
11781 * @author mrdoob / http://mrdoob.com/
11782 */
11783
11784function Layers() {
11785
11786 this.mask = 1 | 0;
11787
11788}
11789
11790Object.assign( Layers.prototype, {
11791
11792 set: function ( channel ) {
11793
11794 this.mask = 1 << channel | 0;
11795
11796 },
11797
11798 enable: function ( channel ) {
11799
11800 this.mask |= 1 << channel | 0;
11801
11802 },
11803
11804 toggle: function ( channel ) {
11805
11806 this.mask ^= 1 << channel | 0;
11807
11808 },
11809
11810 disable: function ( channel ) {
11811
11812 this.mask &= ~ ( 1 << channel | 0 );
11813
11814 },
11815
11816 test: function ( layers ) {
11817
11818 return ( this.mask & layers.mask ) !== 0;
11819
11820 }
11821
11822} );
11823
11824/**
11825 * @author mrdoob / http://mrdoob.com/
11826 * @author mikael emtinger / http://gomo.se/
11827 * @author alteredq / http://alteredqualia.com/
11828 * @author WestLangley / http://github.com/WestLangley
11829 * @author elephantatwork / www.elephantatwork.ch
11830 */
11831
11832var object3DId = 0;
11833
11834function Object3D() {
11835
11836 Object.defineProperty( this, 'id', { value: object3DId ++ } );
11837
11838 this.uuid = _Math.generateUUID();
11839
11840 this.name = '';
11841 this.type = 'Object3D';
11842
11843 this.parent = null;
11844 this.children = [];
11845
11846 this.up = Object3D.DefaultUp.clone();
11847
11848 var position = new Vector3();
11849 var rotation = new Euler();
11850 var quaternion = new Quaternion();
11851 var scale = new Vector3( 1, 1, 1 );
11852
11853 function onRotationChange() {
11854
11855 quaternion.setFromEuler( rotation, false );
11856
11857 }
11858
11859 function onQuaternionChange() {
11860
11861 rotation.setFromQuaternion( quaternion, undefined, false );
11862
11863 }
11864
11865 rotation.onChange( onRotationChange );
11866 quaternion.onChange( onQuaternionChange );
11867
11868 Object.defineProperties( this, {
11869 position: {
11870 enumerable: true,
11871 value: position
11872 },
11873 rotation: {
11874 enumerable: true,
11875 value: rotation
11876 },
11877 quaternion: {
11878 enumerable: true,
11879 value: quaternion
11880 },
11881 scale: {
11882 enumerable: true,
11883 value: scale
11884 },
11885 modelViewMatrix: {
11886 value: new Matrix4()
11887 },
11888 normalMatrix: {
11889 value: new Matrix3()
11890 }
11891 } );
11892
11893 this.matrix = new Matrix4();
11894 this.matrixWorld = new Matrix4();
11895
11896 this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
11897 this.matrixWorldNeedsUpdate = false;
11898
11899 this.layers = new Layers();
11900 this.visible = true;
11901
11902 this.castShadow = false;
11903 this.receiveShadow = false;
11904
11905 this.frustumCulled = true;
11906 this.renderOrder = 0;
11907
11908 this.userData = {};
11909
11910}
11911
11912Object3D.DefaultUp = new Vector3( 0, 1, 0 );
11913Object3D.DefaultMatrixAutoUpdate = true;
11914
11915Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
11916
11917 constructor: Object3D,
11918
11919 isObject3D: true,
11920
11921 onBeforeRender: function () {},
11922 onAfterRender: function () {},
11923
11924 applyMatrix: function ( matrix ) {
11925
11926 this.matrix.multiplyMatrices( matrix, this.matrix );
11927
11928 this.matrix.decompose( this.position, this.quaternion, this.scale );
11929
11930 },
11931
11932 applyQuaternion: function ( q ) {
11933
11934 this.quaternion.premultiply( q );
11935
11936 return this;
11937
11938 },
11939
11940 setRotationFromAxisAngle: function ( axis, angle ) {
11941
11942 // assumes axis is normalized
11943
11944 this.quaternion.setFromAxisAngle( axis, angle );
11945
11946 },
11947
11948 setRotationFromEuler: function ( euler ) {
11949
11950 this.quaternion.setFromEuler( euler, true );
11951
11952 },
11953
11954 setRotationFromMatrix: function ( m ) {
11955
11956 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
11957
11958 this.quaternion.setFromRotationMatrix( m );
11959
11960 },
11961
11962 setRotationFromQuaternion: function ( q ) {
11963
11964 // assumes q is normalized
11965
11966 this.quaternion.copy( q );
11967
11968 },
11969
11970 rotateOnAxis: function () {
11971
11972 // rotate object on axis in object space
11973 // axis is assumed to be normalized
11974
11975 var q1 = new Quaternion();
11976
11977 return function rotateOnAxis( axis, angle ) {
11978
11979 q1.setFromAxisAngle( axis, angle );
11980
11981 this.quaternion.multiply( q1 );
11982
11983 return this;
11984
11985 };
11986
11987 }(),
11988
11989 rotateOnWorldAxis: function () {
11990
11991 // rotate object on axis in world space
11992 // axis is assumed to be normalized
11993 // method assumes no rotated parent
11994
11995 var q1 = new Quaternion();
11996
11997 return function rotateOnWorldAxis( axis, angle ) {
11998
11999 q1.setFromAxisAngle( axis, angle );
12000
12001 this.quaternion.premultiply( q1 );
12002
12003 return this;
12004
12005 };
12006
12007 }(),
12008
12009 rotateX: function () {
12010
12011 var v1 = new Vector3( 1, 0, 0 );
12012
12013 return function rotateX( angle ) {
12014
12015 return this.rotateOnAxis( v1, angle );
12016
12017 };
12018
12019 }(),
12020
12021 rotateY: function () {
12022
12023 var v1 = new Vector3( 0, 1, 0 );
12024
12025 return function rotateY( angle ) {
12026
12027 return this.rotateOnAxis( v1, angle );
12028
12029 };
12030
12031 }(),
12032
12033 rotateZ: function () {
12034
12035 var v1 = new Vector3( 0, 0, 1 );
12036
12037 return function rotateZ( angle ) {
12038
12039 return this.rotateOnAxis( v1, angle );
12040
12041 };
12042
12043 }(),
12044
12045 translateOnAxis: function () {
12046
12047 // translate object by distance along axis in object space
12048 // axis is assumed to be normalized
12049
12050 var v1 = new Vector3();
12051
12052 return function translateOnAxis( axis, distance ) {
12053
12054 v1.copy( axis ).applyQuaternion( this.quaternion );
12055
12056 this.position.add( v1.multiplyScalar( distance ) );
12057
12058 return this;
12059
12060 };
12061
12062 }(),
12063
12064 translateX: function () {
12065
12066 var v1 = new Vector3( 1, 0, 0 );
12067
12068 return function translateX( distance ) {
12069
12070 return this.translateOnAxis( v1, distance );
12071
12072 };
12073
12074 }(),
12075
12076 translateY: function () {
12077
12078 var v1 = new Vector3( 0, 1, 0 );
12079
12080 return function translateY( distance ) {
12081
12082 return this.translateOnAxis( v1, distance );
12083
12084 };
12085
12086 }(),
12087
12088 translateZ: function () {
12089
12090 var v1 = new Vector3( 0, 0, 1 );
12091
12092 return function translateZ( distance ) {
12093
12094 return this.translateOnAxis( v1, distance );
12095
12096 };
12097
12098 }(),
12099
12100 localToWorld: function ( vector ) {
12101
12102 return vector.applyMatrix4( this.matrixWorld );
12103
12104 },
12105
12106 worldToLocal: function () {
12107
12108 var m1 = new Matrix4();
12109
12110 return function worldToLocal( vector ) {
12111
12112 return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) );
12113
12114 };
12115
12116 }(),
12117
12118 lookAt: function () {
12119
12120 // This method does not support objects with rotated and/or translated parent(s)
12121
12122 var m1 = new Matrix4();
12123 var vector = new Vector3();
12124
12125 return function lookAt( x, y, z ) {
12126
12127 if ( x.isVector3 ) {
12128
12129 vector.copy( x );
12130
12131 } else {
12132
12133 vector.set( x, y, z );
12134
12135 }
12136
12137 if ( this.isCamera ) {
12138
12139 m1.lookAt( this.position, vector, this.up );
12140
12141 } else {
12142
12143 m1.lookAt( vector, this.position, this.up );
12144
12145 }
12146
12147 this.quaternion.setFromRotationMatrix( m1 );
12148
12149 };
12150
12151 }(),
12152
12153 add: function ( object ) {
12154
12155 if ( arguments.length > 1 ) {
12156
12157 for ( var i = 0; i < arguments.length; i ++ ) {
12158
12159 this.add( arguments[ i ] );
12160
12161 }
12162
12163 return this;
12164
12165 }
12166
12167 if ( object === this ) {
12168
12169 console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object );
12170 return this;
12171
12172 }
12173
12174 if ( ( object && object.isObject3D ) ) {
12175
12176 if ( object.parent !== null ) {
12177
12178 object.parent.remove( object );
12179
12180 }
12181
12182 object.parent = this;
12183 object.dispatchEvent( { type: 'added' } );
12184
12185 this.children.push( object );
12186
12187 } else {
12188
12189 console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object );
12190
12191 }
12192
12193 return this;
12194
12195 },
12196
12197 remove: function ( object ) {
12198
12199 if ( arguments.length > 1 ) {
12200
12201 for ( var i = 0; i < arguments.length; i ++ ) {
12202
12203 this.remove( arguments[ i ] );
12204
12205 }
12206
12207 return this;
12208
12209 }
12210
12211 var index = this.children.indexOf( object );
12212
12213 if ( index !== - 1 ) {
12214
12215 object.parent = null;
12216
12217 object.dispatchEvent( { type: 'removed' } );
12218
12219 this.children.splice( index, 1 );
12220
12221 }
12222
12223 return this;
12224
12225 },
12226
12227 getObjectById: function ( id ) {
12228
12229 return this.getObjectByProperty( 'id', id );
12230
12231 },
12232
12233 getObjectByName: function ( name ) {
12234
12235 return this.getObjectByProperty( 'name', name );
12236
12237 },
12238
12239 getObjectByProperty: function ( name, value ) {
12240
12241 if ( this[ name ] === value ) return this;
12242
12243 for ( var i = 0, l = this.children.length; i < l; i ++ ) {
12244
12245 var child = this.children[ i ];
12246 var object = child.getObjectByProperty( name, value );
12247
12248 if ( object !== undefined ) {
12249
12250 return object;
12251
12252 }
12253
12254 }
12255
12256 return undefined;
12257
12258 },
12259
12260 getWorldPosition: function ( optionalTarget ) {
12261
12262 var result = optionalTarget || new Vector3();
12263
12264 this.updateMatrixWorld( true );
12265
12266 return result.setFromMatrixPosition( this.matrixWorld );
12267
12268 },
12269
12270 getWorldQuaternion: function () {
12271
12272 var position = new Vector3();
12273 var scale = new Vector3();
12274
12275 return function getWorldQuaternion( optionalTarget ) {
12276
12277 var result = optionalTarget || new Quaternion();
12278
12279 this.updateMatrixWorld( true );
12280
12281 this.matrixWorld.decompose( position, result, scale );
12282
12283 return result;
12284
12285 };
12286
12287 }(),
12288
12289 getWorldRotation: function () {
12290
12291 var quaternion = new Quaternion();
12292
12293 return function getWorldRotation( optionalTarget ) {
12294
12295 var result = optionalTarget || new Euler();
12296
12297 this.getWorldQuaternion( quaternion );
12298
12299 return result.setFromQuaternion( quaternion, this.rotation.order, false );
12300
12301 };
12302
12303 }(),
12304
12305 getWorldScale: function () {
12306
12307 var position = new Vector3();
12308 var quaternion = new Quaternion();
12309
12310 return function getWorldScale( optionalTarget ) {
12311
12312 var result = optionalTarget || new Vector3();
12313
12314 this.updateMatrixWorld( true );
12315
12316 this.matrixWorld.decompose( position, quaternion, result );
12317
12318 return result;
12319
12320 };
12321
12322 }(),
12323
12324 getWorldDirection: function () {
12325
12326 var quaternion = new Quaternion();
12327
12328 return function getWorldDirection( optionalTarget ) {
12329
12330 var result = optionalTarget || new Vector3();
12331
12332 this.getWorldQuaternion( quaternion );
12333
12334 return result.set( 0, 0, 1 ).applyQuaternion( quaternion );
12335
12336 };
12337
12338 }(),
12339
12340 raycast: function () {},
12341
12342 traverse: function ( callback ) {
12343
12344 callback( this );
12345
12346 var children = this.children;
12347
12348 for ( var i = 0, l = children.length; i < l; i ++ ) {
12349
12350 children[ i ].traverse( callback );
12351
12352 }
12353
12354 },
12355
12356 traverseVisible: function ( callback ) {
12357
12358 if ( this.visible === false ) return;
12359
12360 callback( this );
12361
12362 var children = this.children;
12363
12364 for ( var i = 0, l = children.length; i < l; i ++ ) {
12365
12366 children[ i ].traverseVisible( callback );
12367
12368 }
12369
12370 },
12371
12372 traverseAncestors: function ( callback ) {
12373
12374 var parent = this.parent;
12375
12376 if ( parent !== null ) {
12377
12378 callback( parent );
12379
12380 parent.traverseAncestors( callback );
12381
12382 }
12383
12384 },
12385
12386 updateMatrix: function () {
12387
12388 this.matrix.compose( this.position, this.quaternion, this.scale );
12389
12390 this.matrixWorldNeedsUpdate = true;
12391
12392 },
12393
12394 updateMatrixWorld: function ( force ) {
12395
12396 if ( this.matrixAutoUpdate ) this.updateMatrix();
12397
12398 if ( this.matrixWorldNeedsUpdate || force ) {
12399
12400 if ( this.parent === null ) {
12401
12402 this.matrixWorld.copy( this.matrix );
12403
12404 } else {
12405
12406 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
12407
12408 }
12409
12410 this.matrixWorldNeedsUpdate = false;
12411
12412 force = true;
12413
12414 }
12415
12416 // update children
12417
12418 var children = this.children;
12419
12420 for ( var i = 0, l = children.length; i < l; i ++ ) {
12421
12422 children[ i ].updateMatrixWorld( force );
12423
12424 }
12425
12426 },
12427
12428 toJSON: function ( meta ) {
12429
12430 // meta is a string when called from JSON.stringify
12431 var isRootObject = ( meta === undefined || typeof meta === 'string' );
12432
12433 var output = {};
12434
12435 // meta is a hash used to collect geometries, materials.
12436 // not providing it implies that this is the root object
12437 // being serialized.
12438 if ( isRootObject ) {
12439
12440 // initialize meta obj
12441 meta = {
12442 geometries: {},
12443 materials: {},
12444 textures: {},
12445 images: {},
12446 shapes: {}
12447 };
12448
12449 output.metadata = {
12450 version: 4.5,
12451 type: 'Object',
12452 generator: 'Object3D.toJSON'
12453 };
12454
12455 }
12456
12457 // standard Object3D serialization
12458
12459 var object = {};
12460
12461 object.uuid = this.uuid;
12462 object.type = this.type;
12463
12464 if ( this.name !== '' ) object.name = this.name;
12465 if ( this.castShadow === true ) object.castShadow = true;
12466 if ( this.receiveShadow === true ) object.receiveShadow = true;
12467 if ( this.visible === false ) object.visible = false;
12468 if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;
12469
12470 object.matrix = this.matrix.toArray();
12471
12472 //
12473
12474 function serialize( library, element ) {
12475
12476 if ( library[ element.uuid ] === undefined ) {
12477
12478 library[ element.uuid ] = element.toJSON( meta );
12479
12480 }
12481
12482 return element.uuid;
12483
12484 }
12485
12486 if ( this.geometry !== undefined ) {
12487
12488 object.geometry = serialize( meta.geometries, this.geometry );
12489
12490 var parameters = this.geometry.parameters;
12491
12492 if ( parameters !== undefined && parameters.shapes !== undefined ) {
12493
12494 var shapes = parameters.shapes;
12495
12496 if ( Array.isArray( shapes ) ) {
12497
12498 for ( var i = 0, l = shapes.length; i < l; i ++ ) {
12499
12500 var shape = shapes[ i ];
12501
12502 serialize( meta.shapes, shape );
12503
12504 }
12505
12506 } else {
12507
12508 serialize( meta.shapes, shapes );
12509
12510 }
12511
12512 }
12513
12514 }
12515
12516 if ( this.material !== undefined ) {
12517
12518 if ( Array.isArray( this.material ) ) {
12519
12520 var uuids = [];
12521
12522 for ( var i = 0, l = this.material.length; i < l; i ++ ) {
12523
12524 uuids.push( serialize( meta.materials, this.material[ i ] ) );
12525
12526 }
12527
12528 object.material = uuids;
12529
12530 } else {
12531
12532 object.material = serialize( meta.materials, this.material );
12533
12534 }
12535
12536 }
12537
12538 //
12539
12540 if ( this.children.length > 0 ) {
12541
12542 object.children = [];
12543
12544 for ( var i = 0; i < this.children.length; i ++ ) {
12545
12546 object.children.push( this.children[ i ].toJSON( meta ).object );
12547
12548 }
12549
12550 }
12551
12552 if ( isRootObject ) {
12553
12554 var geometries = extractFromCache( meta.geometries );
12555 var materials = extractFromCache( meta.materials );
12556 var textures = extractFromCache( meta.textures );
12557 var images = extractFromCache( meta.images );
12558 var shapes = extractFromCache( meta.shapes );
12559
12560 if ( geometries.length > 0 ) output.geometries = geometries;
12561 if ( materials.length > 0 ) output.materials = materials;
12562 if ( textures.length > 0 ) output.textures = textures;
12563 if ( images.length > 0 ) output.images = images;
12564 if ( shapes.length > 0 ) output.shapes = shapes;
12565
12566 }
12567
12568 output.object = object;
12569
12570 return output;
12571
12572 // extract data from the cache hash
12573 // remove metadata on each item
12574 // and return as array
12575 function extractFromCache( cache ) {
12576
12577 var values = [];
12578 for ( var key in cache ) {
12579
12580 var data = cache[ key ];
12581 delete data.metadata;
12582 values.push( data );
12583
12584 }
12585 return values;
12586
12587 }
12588
12589 },
12590
12591 clone: function ( recursive ) {
12592
12593 return new this.constructor().copy( this, recursive );
12594
12595 },
12596
12597 copy: function ( source, recursive ) {
12598
12599 if ( recursive === undefined ) recursive = true;
12600
12601 this.name = source.name;
12602
12603 this.up.copy( source.up );
12604
12605 this.position.copy( source.position );
12606 this.quaternion.copy( source.quaternion );
12607 this.scale.copy( source.scale );
12608
12609 this.matrix.copy( source.matrix );
12610 this.matrixWorld.copy( source.matrixWorld );
12611
12612 this.matrixAutoUpdate = source.matrixAutoUpdate;
12613 this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
12614
12615 this.layers.mask = source.layers.mask;
12616 this.visible = source.visible;
12617
12618 this.castShadow = source.castShadow;
12619 this.receiveShadow = source.receiveShadow;
12620
12621 this.frustumCulled = source.frustumCulled;
12622 this.renderOrder = source.renderOrder;
12623
12624 this.userData = JSON.parse( JSON.stringify( source.userData ) );
12625
12626 if ( recursive === true ) {
12627
12628 for ( var i = 0; i < source.children.length; i ++ ) {
12629
12630 var child = source.children[ i ];
12631 this.add( child.clone() );
12632
12633 }
12634
12635 }
12636
12637 return this;
12638
12639 }
12640
12641} );
12642
12643/**
12644 * @author mrdoob / http://mrdoob.com/
12645 * @author mikael emtinger / http://gomo.se/
12646 * @author WestLangley / http://github.com/WestLangley
12647*/
12648
12649function Camera() {
12650
12651 Object3D.call( this );
12652
12653 this.type = 'Camera';
12654
12655 this.matrixWorldInverse = new Matrix4();
12656 this.projectionMatrix = new Matrix4();
12657
12658}
12659
12660Camera.prototype = Object.assign( Object.create( Object3D.prototype ), {
12661
12662 constructor: Camera,
12663
12664 isCamera: true,
12665
12666 copy: function ( source, recursive ) {
12667
12668 Object3D.prototype.copy.call( this, source, recursive );
12669
12670 this.matrixWorldInverse.copy( source.matrixWorldInverse );
12671 this.projectionMatrix.copy( source.projectionMatrix );
12672
12673 return this;
12674
12675 },
12676
12677 getWorldDirection: function () {
12678
12679 var quaternion = new Quaternion();
12680
12681 return function getWorldDirection( optionalTarget ) {
12682
12683 var result = optionalTarget || new Vector3();
12684
12685 this.getWorldQuaternion( quaternion );
12686
12687 return result.set( 0, 0, - 1 ).applyQuaternion( quaternion );
12688
12689 };
12690
12691 }(),
12692
12693 updateMatrixWorld: function ( force ) {
12694
12695 Object3D.prototype.updateMatrixWorld.call( this, force );
12696
12697 this.matrixWorldInverse.getInverse( this.matrixWorld );
12698
12699 },
12700
12701 clone: function () {
12702
12703 return new this.constructor().copy( this );
12704
12705 }
12706
12707} );
12708
12709/**
12710 * @author alteredq / http://alteredqualia.com/
12711 * @author arose / http://github.com/arose
12712 */
12713
12714function OrthographicCamera( left, right, top, bottom, near, far ) {
12715
12716 Camera.call( this );
12717
12718 this.type = 'OrthographicCamera';
12719
12720 this.zoom = 1;
12721 this.view = null;
12722
12723 this.left = left;
12724 this.right = right;
12725 this.top = top;
12726 this.bottom = bottom;
12727
12728 this.near = ( near !== undefined ) ? near : 0.1;
12729 this.far = ( far !== undefined ) ? far : 2000;
12730
12731 this.updateProjectionMatrix();
12732
12733}
12734
12735OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), {
12736
12737 constructor: OrthographicCamera,
12738
12739 isOrthographicCamera: true,
12740
12741 copy: function ( source, recursive ) {
12742
12743 Camera.prototype.copy.call( this, source, recursive );
12744
12745 this.left = source.left;
12746 this.right = source.right;
12747 this.top = source.top;
12748 this.bottom = source.bottom;
12749 this.near = source.near;
12750 this.far = source.far;
12751
12752 this.zoom = source.zoom;
12753 this.view = source.view === null ? null : Object.assign( {}, source.view );
12754
12755 return this;
12756
12757 },
12758
12759 setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {
12760
12761 if ( this.view === null ) {
12762
12763 this.view = {
12764 enabled: true,
12765 fullWidth: 1,
12766 fullHeight: 1,
12767 offsetX: 0,
12768 offsetY: 0,
12769 width: 1,
12770 height: 1
12771 };
12772
12773 }
12774
12775 this.view.enabled = true;
12776 this.view.fullWidth = fullWidth;
12777 this.view.fullHeight = fullHeight;
12778 this.view.offsetX = x;
12779 this.view.offsetY = y;
12780 this.view.width = width;
12781 this.view.height = height;
12782
12783 this.updateProjectionMatrix();
12784
12785 },
12786
12787 clearViewOffset: function () {
12788
12789 if ( this.view !== null ) {
12790
12791 this.view.enabled = false;
12792
12793 }
12794
12795 this.updateProjectionMatrix();
12796
12797 },
12798
12799 updateProjectionMatrix: function () {
12800
12801 var dx = ( this.right - this.left ) / ( 2 * this.zoom );
12802 var dy = ( this.top - this.bottom ) / ( 2 * this.zoom );
12803 var cx = ( this.right + this.left ) / 2;
12804 var cy = ( this.top + this.bottom ) / 2;
12805
12806 var left = cx - dx;
12807 var right = cx + dx;
12808 var top = cy + dy;
12809 var bottom = cy - dy;
12810
12811 if ( this.view !== null && this.view.enabled ) {
12812
12813 var zoomW = this.zoom / ( this.view.width / this.view.fullWidth );
12814 var zoomH = this.zoom / ( this.view.height / this.view.fullHeight );
12815 var scaleW = ( this.right - this.left ) / this.view.width;
12816 var scaleH = ( this.top - this.bottom ) / this.view.height;
12817
12818 left += scaleW * ( this.view.offsetX / zoomW );
12819 right = left + scaleW * ( this.view.width / zoomW );
12820 top -= scaleH * ( this.view.offsetY / zoomH );
12821 bottom = top - scaleH * ( this.view.height / zoomH );
12822
12823 }
12824
12825 this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far );
12826
12827 },
12828
12829 toJSON: function ( meta ) {
12830
12831 var data = Object3D.prototype.toJSON.call( this, meta );
12832
12833 data.object.zoom = this.zoom;
12834 data.object.left = this.left;
12835 data.object.right = this.right;
12836 data.object.top = this.top;
12837 data.object.bottom = this.bottom;
12838 data.object.near = this.near;
12839 data.object.far = this.far;
12840
12841 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
12842
12843 return data;
12844
12845 }
12846
12847} );
12848
12849/**
12850 * @author mrdoob / http://mrdoob.com/
12851 * @author alteredq / http://alteredqualia.com/
12852 */
12853
12854function Face3( a, b, c, normal, color, materialIndex ) {
12855
12856 this.a = a;
12857 this.b = b;
12858 this.c = c;
12859
12860 this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3();
12861 this.vertexNormals = Array.isArray( normal ) ? normal : [];
12862
12863 this.color = ( color && color.isColor ) ? color : new Color();
12864 this.vertexColors = Array.isArray( color ) ? color : [];
12865
12866 this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
12867
12868}
12869
12870Object.assign( Face3.prototype, {
12871
12872 clone: function () {
12873
12874 return new this.constructor().copy( this );
12875
12876 },
12877
12878 copy: function ( source ) {
12879
12880 this.a = source.a;
12881 this.b = source.b;
12882 this.c = source.c;
12883
12884 this.normal.copy( source.normal );
12885 this.color.copy( source.color );
12886
12887 this.materialIndex = source.materialIndex;
12888
12889 for ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) {
12890
12891 this.vertexNormals[ i ] = source.vertexNormals[ i ].clone();
12892
12893 }
12894
12895 for ( var i = 0, il = source.vertexColors.length; i < il; i ++ ) {
12896
12897 this.vertexColors[ i ] = source.vertexColors[ i ].clone();
12898
12899 }
12900
12901 return this;
12902
12903 }
12904
12905} );
12906
12907/**
12908 * @author mrdoob / http://mrdoob.com/
12909 * @author kile / http://kile.stravaganza.org/
12910 * @author alteredq / http://alteredqualia.com/
12911 * @author mikael emtinger / http://gomo.se/
12912 * @author zz85 / http://www.lab4games.net/zz85/blog
12913 * @author bhouston / http://clara.io
12914 */
12915
12916var geometryId = 0; // Geometry uses even numbers as Id
12917
12918function Geometry() {
12919
12920 Object.defineProperty( this, 'id', { value: geometryId += 2 } );
12921
12922 this.uuid = _Math.generateUUID();
12923
12924 this.name = '';
12925 this.type = 'Geometry';
12926
12927 this.vertices = [];
12928 this.colors = [];
12929 this.faces = [];
12930 this.faceVertexUvs = [[]];
12931
12932 this.morphTargets = [];
12933 this.morphNormals = [];
12934
12935 this.skinWeights = [];
12936 this.skinIndices = [];
12937
12938 this.lineDistances = [];
12939
12940 this.boundingBox = null;
12941 this.boundingSphere = null;
12942
12943 // update flags
12944
12945 this.elementsNeedUpdate = false;
12946 this.verticesNeedUpdate = false;
12947 this.uvsNeedUpdate = false;
12948 this.normalsNeedUpdate = false;
12949 this.colorsNeedUpdate = false;
12950 this.lineDistancesNeedUpdate = false;
12951 this.groupsNeedUpdate = false;
12952
12953}
12954
12955Geometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
12956
12957 constructor: Geometry,
12958
12959 isGeometry: true,
12960
12961 applyMatrix: function ( matrix ) {
12962
12963 var normalMatrix = new Matrix3().getNormalMatrix( matrix );
12964
12965 for ( var i = 0, il = this.vertices.length; i < il; i ++ ) {
12966
12967 var vertex = this.vertices[ i ];
12968 vertex.applyMatrix4( matrix );
12969
12970 }
12971
12972 for ( var i = 0, il = this.faces.length; i < il; i ++ ) {
12973
12974 var face = this.faces[ i ];
12975 face.normal.applyMatrix3( normalMatrix ).normalize();
12976
12977 for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {
12978
12979 face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize();
12980
12981 }
12982
12983 }
12984
12985 if ( this.boundingBox !== null ) {
12986
12987 this.computeBoundingBox();
12988
12989 }
12990
12991 if ( this.boundingSphere !== null ) {
12992
12993 this.computeBoundingSphere();
12994
12995 }
12996
12997 this.verticesNeedUpdate = true;
12998 this.normalsNeedUpdate = true;
12999
13000 return this;
13001
13002 },
13003
13004 rotateX: function () {
13005
13006 // rotate geometry around world x-axis
13007
13008 var m1 = new Matrix4();
13009
13010 return function rotateX( angle ) {
13011
13012 m1.makeRotationX( angle );
13013
13014 this.applyMatrix( m1 );
13015
13016 return this;
13017
13018 };
13019
13020 }(),
13021
13022 rotateY: function () {
13023
13024 // rotate geometry around world y-axis
13025
13026 var m1 = new Matrix4();
13027
13028 return function rotateY( angle ) {
13029
13030 m1.makeRotationY( angle );
13031
13032 this.applyMatrix( m1 );
13033
13034 return this;
13035
13036 };
13037
13038 }(),
13039
13040 rotateZ: function () {
13041
13042 // rotate geometry around world z-axis
13043
13044 var m1 = new Matrix4();
13045
13046 return function rotateZ( angle ) {
13047
13048 m1.makeRotationZ( angle );
13049
13050 this.applyMatrix( m1 );
13051
13052 return this;
13053
13054 };
13055
13056 }(),
13057
13058 translate: function () {
13059
13060 // translate geometry
13061
13062 var m1 = new Matrix4();
13063
13064 return function translate( x, y, z ) {
13065
13066 m1.makeTranslation( x, y, z );
13067
13068 this.applyMatrix( m1 );
13069
13070 return this;
13071
13072 };
13073
13074 }(),
13075
13076 scale: function () {
13077
13078 // scale geometry
13079
13080 var m1 = new Matrix4();
13081
13082 return function scale( x, y, z ) {
13083
13084 m1.makeScale( x, y, z );
13085
13086 this.applyMatrix( m1 );
13087
13088 return this;
13089
13090 };
13091
13092 }(),
13093
13094 lookAt: function () {
13095
13096 var obj = new Object3D();
13097
13098 return function lookAt( vector ) {
13099
13100 obj.lookAt( vector );
13101
13102 obj.updateMatrix();
13103
13104 this.applyMatrix( obj.matrix );
13105
13106 };
13107
13108 }(),
13109
13110 fromBufferGeometry: function ( geometry ) {
13111
13112 var scope = this;
13113
13114 var indices = geometry.index !== null ? geometry.index.array : undefined;
13115 var attributes = geometry.attributes;
13116
13117 var positions = attributes.position.array;
13118 var normals = attributes.normal !== undefined ? attributes.normal.array : undefined;
13119 var colors = attributes.color !== undefined ? attributes.color.array : undefined;
13120 var uvs = attributes.uv !== undefined ? attributes.uv.array : undefined;
13121 var uvs2 = attributes.uv2 !== undefined ? attributes.uv2.array : undefined;
13122
13123 if ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = [];
13124
13125 var tempNormals = [];
13126 var tempUVs = [];
13127 var tempUVs2 = [];
13128
13129 for ( var i = 0, j = 0; i < positions.length; i += 3, j += 2 ) {
13130
13131 scope.vertices.push( new Vector3( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ) );
13132
13133 if ( normals !== undefined ) {
13134
13135 tempNormals.push( new Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) );
13136
13137 }
13138
13139 if ( colors !== undefined ) {
13140
13141 scope.colors.push( new Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) );
13142
13143 }
13144
13145 if ( uvs !== undefined ) {
13146
13147 tempUVs.push( new Vector2( uvs[ j ], uvs[ j + 1 ] ) );
13148
13149 }
13150
13151 if ( uvs2 !== undefined ) {
13152
13153 tempUVs2.push( new Vector2( uvs2[ j ], uvs2[ j + 1 ] ) );
13154
13155 }
13156
13157 }
13158
13159 function addFace( a, b, c, materialIndex ) {
13160
13161 var vertexNormals = normals !== undefined ? [ tempNormals[ a ].clone(), tempNormals[ b ].clone(), tempNormals[ c ].clone() ] : [];
13162 var vertexColors = colors !== undefined ? [ scope.colors[ a ].clone(), scope.colors[ b ].clone(), scope.colors[ c ].clone() ] : [];
13163
13164 var face = new Face3( a, b, c, vertexNormals, vertexColors, materialIndex );
13165
13166 scope.faces.push( face );
13167
13168 if ( uvs !== undefined ) {
13169
13170 scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ].clone(), tempUVs[ b ].clone(), tempUVs[ c ].clone() ] );
13171
13172 }
13173
13174 if ( uvs2 !== undefined ) {
13175
13176 scope.faceVertexUvs[ 1 ].push( [ tempUVs2[ a ].clone(), tempUVs2[ b ].clone(), tempUVs2[ c ].clone() ] );
13177
13178 }
13179
13180 }
13181
13182 var groups = geometry.groups;
13183
13184 if ( groups.length > 0 ) {
13185
13186 for ( var i = 0; i < groups.length; i ++ ) {
13187
13188 var group = groups[ i ];
13189
13190 var start = group.start;
13191 var count = group.count;
13192
13193 for ( var j = start, jl = start + count; j < jl; j += 3 ) {
13194
13195 if ( indices !== undefined ) {
13196
13197 addFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ], group.materialIndex );
13198
13199 } else {
13200
13201 addFace( j, j + 1, j + 2, group.materialIndex );
13202
13203 }
13204
13205 }
13206
13207 }
13208
13209 } else {
13210
13211 if ( indices !== undefined ) {
13212
13213 for ( var i = 0; i < indices.length; i += 3 ) {
13214
13215 addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
13216
13217 }
13218
13219 } else {
13220
13221 for ( var i = 0; i < positions.length / 3; i += 3 ) {
13222
13223 addFace( i, i + 1, i + 2 );
13224
13225 }
13226
13227 }
13228
13229 }
13230
13231 this.computeFaceNormals();
13232
13233 if ( geometry.boundingBox !== null ) {
13234
13235 this.boundingBox = geometry.boundingBox.clone();
13236
13237 }
13238
13239 if ( geometry.boundingSphere !== null ) {
13240
13241 this.boundingSphere = geometry.boundingSphere.clone();
13242
13243 }
13244
13245 return this;
13246
13247 },
13248
13249 center: function () {
13250
13251 this.computeBoundingBox();
13252
13253 var offset = this.boundingBox.getCenter().negate();
13254
13255 this.translate( offset.x, offset.y, offset.z );
13256
13257 return offset;
13258
13259 },
13260
13261 normalize: function () {
13262
13263 this.computeBoundingSphere();
13264
13265 var center = this.boundingSphere.center;
13266 var radius = this.boundingSphere.radius;
13267
13268 var s = radius === 0 ? 1 : 1.0 / radius;
13269
13270 var matrix = new Matrix4();
13271 matrix.set(
13272 s, 0, 0, - s * center.x,
13273 0, s, 0, - s * center.y,
13274 0, 0, s, - s * center.z,
13275 0, 0, 0, 1
13276 );
13277
13278 this.applyMatrix( matrix );
13279
13280 return this;
13281
13282 },
13283
13284 computeFaceNormals: function () {
13285
13286 var cb = new Vector3(), ab = new Vector3();
13287
13288 for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) {
13289
13290 var face = this.faces[ f ];
13291
13292 var vA = this.vertices[ face.a ];
13293 var vB = this.vertices[ face.b ];
13294 var vC = this.vertices[ face.c ];
13295
13296 cb.subVectors( vC, vB );
13297 ab.subVectors( vA, vB );
13298 cb.cross( ab );
13299
13300 cb.normalize();
13301
13302 face.normal.copy( cb );
13303
13304 }
13305
13306 },
13307
13308 computeVertexNormals: function ( areaWeighted ) {
13309
13310 if ( areaWeighted === undefined ) areaWeighted = true;
13311
13312 var v, vl, f, fl, face, vertices;
13313
13314 vertices = new Array( this.vertices.length );
13315
13316 for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
13317
13318 vertices[ v ] = new Vector3();
13319
13320 }
13321
13322 if ( areaWeighted ) {
13323
13324 // vertex normals weighted by triangle areas
13325 // http://www.iquilezles.org/www/articles/normals/normals.htm
13326
13327 var vA, vB, vC;
13328 var cb = new Vector3(), ab = new Vector3();
13329
13330 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
13331
13332 face = this.faces[ f ];
13333
13334 vA = this.vertices[ face.a ];
13335 vB = this.vertices[ face.b ];
13336 vC = this.vertices[ face.c ];
13337
13338 cb.subVectors( vC, vB );
13339 ab.subVectors( vA, vB );
13340 cb.cross( ab );
13341
13342 vertices[ face.a ].add( cb );
13343 vertices[ face.b ].add( cb );
13344 vertices[ face.c ].add( cb );
13345
13346 }
13347
13348 } else {
13349
13350 this.computeFaceNormals();
13351
13352 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
13353
13354 face = this.faces[ f ];
13355
13356 vertices[ face.a ].add( face.normal );
13357 vertices[ face.b ].add( face.normal );
13358 vertices[ face.c ].add( face.normal );
13359
13360 }
13361
13362 }
13363
13364 for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
13365
13366 vertices[ v ].normalize();
13367
13368 }
13369
13370 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
13371
13372 face = this.faces[ f ];
13373
13374 var vertexNormals = face.vertexNormals;
13375
13376 if ( vertexNormals.length === 3 ) {
13377
13378 vertexNormals[ 0 ].copy( vertices[ face.a ] );
13379 vertexNormals[ 1 ].copy( vertices[ face.b ] );
13380 vertexNormals[ 2 ].copy( vertices[ face.c ] );
13381
13382 } else {
13383
13384 vertexNormals[ 0 ] = vertices[ face.a ].clone();
13385 vertexNormals[ 1 ] = vertices[ face.b ].clone();
13386 vertexNormals[ 2 ] = vertices[ face.c ].clone();
13387
13388 }
13389
13390 }
13391
13392 if ( this.faces.length > 0 ) {
13393
13394 this.normalsNeedUpdate = true;
13395
13396 }
13397
13398 },
13399
13400 computeFlatVertexNormals: function () {
13401
13402 var f, fl, face;
13403
13404 this.computeFaceNormals();
13405
13406 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
13407
13408 face = this.faces[ f ];
13409
13410 var vertexNormals = face.vertexNormals;
13411
13412 if ( vertexNormals.length === 3 ) {
13413
13414 vertexNormals[ 0 ].copy( face.normal );
13415 vertexNormals[ 1 ].copy( face.normal );
13416 vertexNormals[ 2 ].copy( face.normal );
13417
13418 } else {
13419
13420 vertexNormals[ 0 ] = face.normal.clone();
13421 vertexNormals[ 1 ] = face.normal.clone();
13422 vertexNormals[ 2 ] = face.normal.clone();
13423
13424 }
13425
13426 }
13427
13428 if ( this.faces.length > 0 ) {
13429
13430 this.normalsNeedUpdate = true;
13431
13432 }
13433
13434 },
13435
13436 computeMorphNormals: function () {
13437
13438 var i, il, f, fl, face;
13439
13440 // save original normals
13441 // - create temp variables on first access
13442 // otherwise just copy (for faster repeated calls)
13443
13444 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
13445
13446 face = this.faces[ f ];
13447
13448 if ( ! face.__originalFaceNormal ) {
13449
13450 face.__originalFaceNormal = face.normal.clone();
13451
13452 } else {
13453
13454 face.__originalFaceNormal.copy( face.normal );
13455
13456 }
13457
13458 if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = [];
13459
13460 for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) {
13461
13462 if ( ! face.__originalVertexNormals[ i ] ) {
13463
13464 face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone();
13465
13466 } else {
13467
13468 face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] );
13469
13470 }
13471
13472 }
13473
13474 }
13475
13476 // use temp geometry to compute face and vertex normals for each morph
13477
13478 var tmpGeo = new Geometry();
13479 tmpGeo.faces = this.faces;
13480
13481 for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) {
13482
13483 // create on first access
13484
13485 if ( ! this.morphNormals[ i ] ) {
13486
13487 this.morphNormals[ i ] = {};
13488 this.morphNormals[ i ].faceNormals = [];
13489 this.morphNormals[ i ].vertexNormals = [];
13490
13491 var dstNormalsFace = this.morphNormals[ i ].faceNormals;
13492 var dstNormalsVertex = this.morphNormals[ i ].vertexNormals;
13493
13494 var faceNormal, vertexNormals;
13495
13496 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
13497
13498 faceNormal = new Vector3();
13499 vertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() };
13500
13501 dstNormalsFace.push( faceNormal );
13502 dstNormalsVertex.push( vertexNormals );
13503
13504 }
13505
13506 }
13507
13508 var morphNormals = this.morphNormals[ i ];
13509
13510 // set vertices to morph target
13511
13512 tmpGeo.vertices = this.morphTargets[ i ].vertices;
13513
13514 // compute morph normals
13515
13516 tmpGeo.computeFaceNormals();
13517 tmpGeo.computeVertexNormals();
13518
13519 // store morph normals
13520
13521 var faceNormal, vertexNormals;
13522
13523 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
13524
13525 face = this.faces[ f ];
13526
13527 faceNormal = morphNormals.faceNormals[ f ];
13528 vertexNormals = morphNormals.vertexNormals[ f ];
13529
13530 faceNormal.copy( face.normal );
13531
13532 vertexNormals.a.copy( face.vertexNormals[ 0 ] );
13533 vertexNormals.b.copy( face.vertexNormals[ 1 ] );
13534 vertexNormals.c.copy( face.vertexNormals[ 2 ] );
13535
13536 }
13537
13538 }
13539
13540 // restore original normals
13541
13542 for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
13543
13544 face = this.faces[ f ];
13545
13546 face.normal = face.__originalFaceNormal;
13547 face.vertexNormals = face.__originalVertexNormals;
13548
13549 }
13550
13551 },
13552
13553 computeLineDistances: function () {
13554
13555 var d = 0;
13556 var vertices = this.vertices;
13557
13558 for ( var i = 0, il = vertices.length; i < il; i ++ ) {
13559
13560 if ( i > 0 ) {
13561
13562 d += vertices[ i ].distanceTo( vertices[ i - 1 ] );
13563
13564 }
13565
13566 this.lineDistances[ i ] = d;
13567
13568 }
13569
13570 },
13571
13572 computeBoundingBox: function () {
13573
13574 if ( this.boundingBox === null ) {
13575
13576 this.boundingBox = new Box3();
13577
13578 }
13579
13580 this.boundingBox.setFromPoints( this.vertices );
13581
13582 },
13583
13584 computeBoundingSphere: function () {
13585
13586 if ( this.boundingSphere === null ) {
13587
13588 this.boundingSphere = new Sphere();
13589
13590 }
13591
13592 this.boundingSphere.setFromPoints( this.vertices );
13593
13594 },
13595
13596 merge: function ( geometry, matrix, materialIndexOffset ) {
13597
13598 if ( ! ( geometry && geometry.isGeometry ) ) {
13599
13600 console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry );
13601 return;
13602
13603 }
13604
13605 var normalMatrix,
13606 vertexOffset = this.vertices.length,
13607 vertices1 = this.vertices,
13608 vertices2 = geometry.vertices,
13609 faces1 = this.faces,
13610 faces2 = geometry.faces,
13611 uvs1 = this.faceVertexUvs[ 0 ],
13612 uvs2 = geometry.faceVertexUvs[ 0 ],
13613 colors1 = this.colors,
13614 colors2 = geometry.colors;
13615
13616 if ( materialIndexOffset === undefined ) materialIndexOffset = 0;
13617
13618 if ( matrix !== undefined ) {
13619
13620 normalMatrix = new Matrix3().getNormalMatrix( matrix );
13621
13622 }
13623
13624 // vertices
13625
13626 for ( var i = 0, il = vertices2.length; i < il; i ++ ) {
13627
13628 var vertex = vertices2[ i ];
13629
13630 var vertexCopy = vertex.clone();
13631
13632 if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix );
13633
13634 vertices1.push( vertexCopy );
13635
13636 }
13637
13638 // colors
13639
13640 for ( var i = 0, il = colors2.length; i < il; i ++ ) {
13641
13642 colors1.push( colors2[ i ].clone() );
13643
13644 }
13645
13646 // faces
13647
13648 for ( i = 0, il = faces2.length; i < il; i ++ ) {
13649
13650 var face = faces2[ i ], faceCopy, normal, color,
13651 faceVertexNormals = face.vertexNormals,
13652 faceVertexColors = face.vertexColors;
13653
13654 faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
13655 faceCopy.normal.copy( face.normal );
13656
13657 if ( normalMatrix !== undefined ) {
13658
13659 faceCopy.normal.applyMatrix3( normalMatrix ).normalize();
13660
13661 }
13662
13663 for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {
13664
13665 normal = faceVertexNormals[ j ].clone();
13666
13667 if ( normalMatrix !== undefined ) {
13668
13669 normal.applyMatrix3( normalMatrix ).normalize();
13670
13671 }
13672
13673 faceCopy.vertexNormals.push( normal );
13674
13675 }
13676
13677 faceCopy.color.copy( face.color );
13678
13679 for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {
13680
13681 color = faceVertexColors[ j ];
13682 faceCopy.vertexColors.push( color.clone() );
13683
13684 }
13685
13686 faceCopy.materialIndex = face.materialIndex + materialIndexOffset;
13687
13688 faces1.push( faceCopy );
13689
13690 }
13691
13692 // uvs
13693
13694 for ( i = 0, il = uvs2.length; i < il; i ++ ) {
13695
13696 var uv = uvs2[ i ], uvCopy = [];
13697
13698 if ( uv === undefined ) {
13699
13700 continue;
13701
13702 }
13703
13704 for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
13705
13706 uvCopy.push( uv[ j ].clone() );
13707
13708 }
13709
13710 uvs1.push( uvCopy );
13711
13712 }
13713
13714 },
13715
13716 mergeMesh: function ( mesh ) {
13717
13718 if ( ! ( mesh && mesh.isMesh ) ) {
13719
13720 console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh );
13721 return;
13722
13723 }
13724
13725 mesh.matrixAutoUpdate && mesh.updateMatrix();
13726
13727 this.merge( mesh.geometry, mesh.matrix );
13728
13729 },
13730
13731 /*
13732 * Checks for duplicate vertices with hashmap.
13733 * Duplicated vertices are removed
13734 * and faces' vertices are updated.
13735 */
13736
13737 mergeVertices: function () {
13738
13739 var verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique)
13740 var unique = [], changes = [];
13741
13742 var v, key;
13743 var precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001
13744 var precision = Math.pow( 10, precisionPoints );
13745 var i, il, face;
13746 var indices, j, jl;
13747
13748 for ( i = 0, il = this.vertices.length; i < il; i ++ ) {
13749
13750 v = this.vertices[ i ];
13751 key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision );
13752
13753 if ( verticesMap[ key ] === undefined ) {
13754
13755 verticesMap[ key ] = i;
13756 unique.push( this.vertices[ i ] );
13757 changes[ i ] = unique.length - 1;
13758
13759 } else {
13760
13761 //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]);
13762 changes[ i ] = changes[ verticesMap[ key ] ];
13763
13764 }
13765
13766 }
13767
13768
13769 // if faces are completely degenerate after merging vertices, we
13770 // have to remove them from the geometry.
13771 var faceIndicesToRemove = [];
13772
13773 for ( i = 0, il = this.faces.length; i < il; i ++ ) {
13774
13775 face = this.faces[ i ];
13776
13777 face.a = changes[ face.a ];
13778 face.b = changes[ face.b ];
13779 face.c = changes[ face.c ];
13780
13781 indices = [ face.a, face.b, face.c ];
13782
13783 // if any duplicate vertices are found in a Face3
13784 // we have to remove the face as nothing can be saved
13785 for ( var n = 0; n < 3; n ++ ) {
13786
13787 if ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) {
13788
13789 faceIndicesToRemove.push( i );
13790 break;
13791
13792 }
13793
13794 }
13795
13796 }
13797
13798 for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) {
13799
13800 var idx = faceIndicesToRemove[ i ];
13801
13802 this.faces.splice( idx, 1 );
13803
13804 for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {
13805
13806 this.faceVertexUvs[ j ].splice( idx, 1 );
13807
13808 }
13809
13810 }
13811
13812 // Use unique set of vertices
13813
13814 var diff = this.vertices.length - unique.length;
13815 this.vertices = unique;
13816 return diff;
13817
13818 },
13819
13820 setFromPoints: function ( points ) {
13821
13822 this.vertices = [];
13823
13824 for ( var i = 0, l = points.length; i < l; i ++ ) {
13825
13826 var point = points[ i ];
13827 this.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) );
13828
13829 }
13830
13831 return this;
13832
13833 },
13834
13835 sortFacesByMaterialIndex: function () {
13836
13837 var faces = this.faces;
13838 var length = faces.length;
13839
13840 // tag faces
13841
13842 for ( var i = 0; i < length; i ++ ) {
13843
13844 faces[ i ]._id = i;
13845
13846 }
13847
13848 // sort faces
13849
13850 function materialIndexSort( a, b ) {
13851
13852 return a.materialIndex - b.materialIndex;
13853
13854 }
13855
13856 faces.sort( materialIndexSort );
13857
13858 // sort uvs
13859
13860 var uvs1 = this.faceVertexUvs[ 0 ];
13861 var uvs2 = this.faceVertexUvs[ 1 ];
13862
13863 var newUvs1, newUvs2;
13864
13865 if ( uvs1 && uvs1.length === length ) newUvs1 = [];
13866 if ( uvs2 && uvs2.length === length ) newUvs2 = [];
13867
13868 for ( var i = 0; i < length; i ++ ) {
13869
13870 var id = faces[ i ]._id;
13871
13872 if ( newUvs1 ) newUvs1.push( uvs1[ id ] );
13873 if ( newUvs2 ) newUvs2.push( uvs2[ id ] );
13874
13875 }
13876
13877 if ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1;
13878 if ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2;
13879
13880 },
13881
13882 toJSON: function () {
13883
13884 var data = {
13885 metadata: {
13886 version: 4.5,
13887 type: 'Geometry',
13888 generator: 'Geometry.toJSON'
13889 }
13890 };
13891
13892 // standard Geometry serialization
13893
13894 data.uuid = this.uuid;
13895 data.type = this.type;
13896 if ( this.name !== '' ) data.name = this.name;
13897
13898 if ( this.parameters !== undefined ) {
13899
13900 var parameters = this.parameters;
13901
13902 for ( var key in parameters ) {
13903
13904 if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
13905
13906 }
13907
13908 return data;
13909
13910 }
13911
13912 var vertices = [];
13913
13914 for ( var i = 0; i < this.vertices.length; i ++ ) {
13915
13916 var vertex = this.vertices[ i ];
13917 vertices.push( vertex.x, vertex.y, vertex.z );
13918
13919 }
13920
13921 var faces = [];
13922 var normals = [];
13923 var normalsHash = {};
13924 var colors = [];
13925 var colorsHash = {};
13926 var uvs = [];
13927 var uvsHash = {};
13928
13929 for ( var i = 0; i < this.faces.length; i ++ ) {
13930
13931 var face = this.faces[ i ];
13932
13933 var hasMaterial = true;
13934 var hasFaceUv = false; // deprecated
13935 var hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined;
13936 var hasFaceNormal = face.normal.length() > 0;
13937 var hasFaceVertexNormal = face.vertexNormals.length > 0;
13938 var hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1;
13939 var hasFaceVertexColor = face.vertexColors.length > 0;
13940
13941 var faceType = 0;
13942
13943 faceType = setBit( faceType, 0, 0 ); // isQuad
13944 faceType = setBit( faceType, 1, hasMaterial );
13945 faceType = setBit( faceType, 2, hasFaceUv );
13946 faceType = setBit( faceType, 3, hasFaceVertexUv );
13947 faceType = setBit( faceType, 4, hasFaceNormal );
13948 faceType = setBit( faceType, 5, hasFaceVertexNormal );
13949 faceType = setBit( faceType, 6, hasFaceColor );
13950 faceType = setBit( faceType, 7, hasFaceVertexColor );
13951
13952 faces.push( faceType );
13953 faces.push( face.a, face.b, face.c );
13954 faces.push( face.materialIndex );
13955
13956 if ( hasFaceVertexUv ) {
13957
13958 var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ];
13959
13960 faces.push(
13961 getUvIndex( faceVertexUvs[ 0 ] ),
13962 getUvIndex( faceVertexUvs[ 1 ] ),
13963 getUvIndex( faceVertexUvs[ 2 ] )
13964 );
13965
13966 }
13967
13968 if ( hasFaceNormal ) {
13969
13970 faces.push( getNormalIndex( face.normal ) );
13971
13972 }
13973
13974 if ( hasFaceVertexNormal ) {
13975
13976 var vertexNormals = face.vertexNormals;
13977
13978 faces.push(
13979 getNormalIndex( vertexNormals[ 0 ] ),
13980 getNormalIndex( vertexNormals[ 1 ] ),
13981 getNormalIndex( vertexNormals[ 2 ] )
13982 );
13983
13984 }
13985
13986 if ( hasFaceColor ) {
13987
13988 faces.push( getColorIndex( face.color ) );
13989
13990 }
13991
13992 if ( hasFaceVertexColor ) {
13993
13994 var vertexColors = face.vertexColors;
13995
13996 faces.push(
13997 getColorIndex( vertexColors[ 0 ] ),
13998 getColorIndex( vertexColors[ 1 ] ),
13999 getColorIndex( vertexColors[ 2 ] )
14000 );
14001
14002 }
14003
14004 }
14005
14006 function setBit( value, position, enabled ) {
14007
14008 return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) );
14009
14010 }
14011
14012 function getNormalIndex( normal ) {
14013
14014 var hash = normal.x.toString() + normal.y.toString() + normal.z.toString();
14015
14016 if ( normalsHash[ hash ] !== undefined ) {
14017
14018 return normalsHash[ hash ];
14019
14020 }
14021
14022 normalsHash[ hash ] = normals.length / 3;
14023 normals.push( normal.x, normal.y, normal.z );
14024
14025 return normalsHash[ hash ];
14026
14027 }
14028
14029 function getColorIndex( color ) {
14030
14031 var hash = color.r.toString() + color.g.toString() + color.b.toString();
14032
14033 if ( colorsHash[ hash ] !== undefined ) {
14034
14035 return colorsHash[ hash ];
14036
14037 }
14038
14039 colorsHash[ hash ] = colors.length;
14040 colors.push( color.getHex() );
14041
14042 return colorsHash[ hash ];
14043
14044 }
14045
14046 function getUvIndex( uv ) {
14047
14048 var hash = uv.x.toString() + uv.y.toString();
14049
14050 if ( uvsHash[ hash ] !== undefined ) {
14051
14052 return uvsHash[ hash ];
14053
14054 }
14055
14056 uvsHash[ hash ] = uvs.length / 2;
14057 uvs.push( uv.x, uv.y );
14058
14059 return uvsHash[ hash ];
14060
14061 }
14062
14063 data.data = {};
14064
14065 data.data.vertices = vertices;
14066 data.data.normals = normals;
14067 if ( colors.length > 0 ) data.data.colors = colors;
14068 if ( uvs.length > 0 ) data.data.uvs = [ uvs ]; // temporal backward compatibility
14069 data.data.faces = faces;
14070
14071 return data;
14072
14073 },
14074
14075 clone: function () {
14076
14077 /*
14078 // Handle primitives
14079
14080 var parameters = this.parameters;
14081
14082 if ( parameters !== undefined ) {
14083
14084 var values = [];
14085
14086 for ( var key in parameters ) {
14087
14088 values.push( parameters[ key ] );
14089
14090 }
14091
14092 var geometry = Object.create( this.constructor.prototype );
14093 this.constructor.apply( geometry, values );
14094 return geometry;
14095
14096 }
14097
14098 return new this.constructor().copy( this );
14099 */
14100
14101 return new Geometry().copy( this );
14102
14103 },
14104
14105 copy: function ( source ) {
14106
14107 var i, il, j, jl, k, kl;
14108
14109 // reset
14110
14111 this.vertices = [];
14112 this.colors = [];
14113 this.faces = [];
14114 this.faceVertexUvs = [[]];
14115 this.morphTargets = [];
14116 this.morphNormals = [];
14117 this.skinWeights = [];
14118 this.skinIndices = [];
14119 this.lineDistances = [];
14120 this.boundingBox = null;
14121 this.boundingSphere = null;
14122
14123 // name
14124
14125 this.name = source.name;
14126
14127 // vertices
14128
14129 var vertices = source.vertices;
14130
14131 for ( i = 0, il = vertices.length; i < il; i ++ ) {
14132
14133 this.vertices.push( vertices[ i ].clone() );
14134
14135 }
14136
14137 // colors
14138
14139 var colors = source.colors;
14140
14141 for ( i = 0, il = colors.length; i < il; i ++ ) {
14142
14143 this.colors.push( colors[ i ].clone() );
14144
14145 }
14146
14147 // faces
14148
14149 var faces = source.faces;
14150
14151 for ( i = 0, il = faces.length; i < il; i ++ ) {
14152
14153 this.faces.push( faces[ i ].clone() );
14154
14155 }
14156
14157 // face vertex uvs
14158
14159 for ( i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) {
14160
14161 var faceVertexUvs = source.faceVertexUvs[ i ];
14162
14163 if ( this.faceVertexUvs[ i ] === undefined ) {
14164
14165 this.faceVertexUvs[ i ] = [];
14166
14167 }
14168
14169 for ( j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) {
14170
14171 var uvs = faceVertexUvs[ j ], uvsCopy = [];
14172
14173 for ( k = 0, kl = uvs.length; k < kl; k ++ ) {
14174
14175 var uv = uvs[ k ];
14176
14177 uvsCopy.push( uv.clone() );
14178
14179 }
14180
14181 this.faceVertexUvs[ i ].push( uvsCopy );
14182
14183 }
14184
14185 }
14186
14187 // morph targets
14188
14189 var morphTargets = source.morphTargets;
14190
14191 for ( i = 0, il = morphTargets.length; i < il; i ++ ) {
14192
14193 var morphTarget = {};
14194 morphTarget.name = morphTargets[ i ].name;
14195
14196 // vertices
14197
14198 if ( morphTargets[ i ].vertices !== undefined ) {
14199
14200 morphTarget.vertices = [];
14201
14202 for ( j = 0, jl = morphTargets[ i ].vertices.length; j < jl; j ++ ) {
14203
14204 morphTarget.vertices.push( morphTargets[ i ].vertices[ j ].clone() );
14205
14206 }
14207
14208 }
14209
14210 // normals
14211
14212 if ( morphTargets[ i ].normals !== undefined ) {
14213
14214 morphTarget.normals = [];
14215
14216 for ( j = 0, jl = morphTargets[ i ].normals.length; j < jl; j ++ ) {
14217
14218 morphTarget.normals.push( morphTargets[ i ].normals[ j ].clone() );
14219
14220 }
14221
14222 }
14223
14224 this.morphTargets.push( morphTarget );
14225
14226 }
14227
14228 // morph normals
14229
14230 var morphNormals = source.morphNormals;
14231
14232 for ( i = 0, il = morphNormals.length; i < il; i ++ ) {
14233
14234 var morphNormal = {};
14235
14236 // vertex normals
14237
14238 if ( morphNormals[ i ].vertexNormals !== undefined ) {
14239
14240 morphNormal.vertexNormals = [];
14241
14242 for ( j = 0, jl = morphNormals[ i ].vertexNormals.length; j < jl; j ++ ) {
14243
14244 var srcVertexNormal = morphNormals[ i ].vertexNormals[ j ];
14245 var destVertexNormal = {};
14246
14247 destVertexNormal.a = srcVertexNormal.a.clone();
14248 destVertexNormal.b = srcVertexNormal.b.clone();
14249 destVertexNormal.c = srcVertexNormal.c.clone();
14250
14251 morphNormal.vertexNormals.push( destVertexNormal );
14252
14253 }
14254
14255 }
14256
14257 // face normals
14258
14259 if ( morphNormals[ i ].faceNormals !== undefined ) {
14260
14261 morphNormal.faceNormals = [];
14262
14263 for ( j = 0, jl = morphNormals[ i ].faceNormals.length; j < jl; j ++ ) {
14264
14265 morphNormal.faceNormals.push( morphNormals[ i ].faceNormals[ j ].clone() );
14266
14267 }
14268
14269 }
14270
14271 this.morphNormals.push( morphNormal );
14272
14273 }
14274
14275 // skin weights
14276
14277 var skinWeights = source.skinWeights;
14278
14279 for ( i = 0, il = skinWeights.length; i < il; i ++ ) {
14280
14281 this.skinWeights.push( skinWeights[ i ].clone() );
14282
14283 }
14284
14285 // skin indices
14286
14287 var skinIndices = source.skinIndices;
14288
14289 for ( i = 0, il = skinIndices.length; i < il; i ++ ) {
14290
14291 this.skinIndices.push( skinIndices[ i ].clone() );
14292
14293 }
14294
14295 // line distances
14296
14297 var lineDistances = source.lineDistances;
14298
14299 for ( i = 0, il = lineDistances.length; i < il; i ++ ) {
14300
14301 this.lineDistances.push( lineDistances[ i ] );
14302
14303 }
14304
14305 // bounding box
14306
14307 var boundingBox = source.boundingBox;
14308
14309 if ( boundingBox !== null ) {
14310
14311 this.boundingBox = boundingBox.clone();
14312
14313 }
14314
14315 // bounding sphere
14316
14317 var boundingSphere = source.boundingSphere;
14318
14319 if ( boundingSphere !== null ) {
14320
14321 this.boundingSphere = boundingSphere.clone();
14322
14323 }
14324
14325 // update flags
14326
14327 this.elementsNeedUpdate = source.elementsNeedUpdate;
14328 this.verticesNeedUpdate = source.verticesNeedUpdate;
14329 this.uvsNeedUpdate = source.uvsNeedUpdate;
14330 this.normalsNeedUpdate = source.normalsNeedUpdate;
14331 this.colorsNeedUpdate = source.colorsNeedUpdate;
14332 this.lineDistancesNeedUpdate = source.lineDistancesNeedUpdate;
14333 this.groupsNeedUpdate = source.groupsNeedUpdate;
14334
14335 return this;
14336
14337 },
14338
14339 dispose: function () {
14340
14341 this.dispatchEvent( { type: 'dispose' } );
14342
14343 }
14344
14345} );
14346
14347/**
14348 * @author mrdoob / http://mrdoob.com/
14349 */
14350
14351function BufferAttribute( array, itemSize, normalized ) {
14352
14353 if ( Array.isArray( array ) ) {
14354
14355 throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
14356
14357 }
14358
14359 this.uuid = _Math.generateUUID();
14360 this.name = '';
14361
14362 this.array = array;
14363 this.itemSize = itemSize;
14364 this.count = array !== undefined ? array.length / itemSize : 0;
14365 this.normalized = normalized === true;
14366
14367 this.dynamic = false;
14368 this.updateRange = { offset: 0, count: - 1 };
14369
14370 this.onUploadCallback = function () {};
14371
14372 this.version = 0;
14373
14374}
14375
14376Object.defineProperty( BufferAttribute.prototype, 'needsUpdate', {
14377
14378 set: function ( value ) {
14379
14380 if ( value === true ) this.version ++;
14381
14382 }
14383
14384} );
14385
14386Object.assign( BufferAttribute.prototype, {
14387
14388 isBufferAttribute: true,
14389
14390 setArray: function ( array ) {
14391
14392 if ( Array.isArray( array ) ) {
14393
14394 throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
14395
14396 }
14397
14398 this.count = array !== undefined ? array.length / this.itemSize : 0;
14399 this.array = array;
14400
14401 },
14402
14403 setDynamic: function ( value ) {
14404
14405 this.dynamic = value;
14406
14407 return this;
14408
14409 },
14410
14411 copy: function ( source ) {
14412
14413 this.array = new source.array.constructor( source.array );
14414 this.itemSize = source.itemSize;
14415 this.count = source.count;
14416 this.normalized = source.normalized;
14417
14418 this.dynamic = source.dynamic;
14419
14420 return this;
14421
14422 },
14423
14424 copyAt: function ( index1, attribute, index2 ) {
14425
14426 index1 *= this.itemSize;
14427 index2 *= attribute.itemSize;
14428
14429 for ( var i = 0, l = this.itemSize; i < l; i ++ ) {
14430
14431 this.array[ index1 + i ] = attribute.array[ index2 + i ];
14432
14433 }
14434
14435 return this;
14436
14437 },
14438
14439 copyArray: function ( array ) {
14440
14441 this.array.set( array );
14442
14443 return this;
14444
14445 },
14446
14447 copyColorsArray: function ( colors ) {
14448
14449 var array = this.array, offset = 0;
14450
14451 for ( var i = 0, l = colors.length; i < l; i ++ ) {
14452
14453 var color = colors[ i ];
14454
14455 if ( color === undefined ) {
14456
14457 console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i );
14458 color = new Color();
14459
14460 }
14461
14462 array[ offset ++ ] = color.r;
14463 array[ offset ++ ] = color.g;
14464 array[ offset ++ ] = color.b;
14465
14466 }
14467
14468 return this;
14469
14470 },
14471
14472 copyIndicesArray: function ( indices ) {
14473
14474 var array = this.array, offset = 0;
14475
14476 for ( var i = 0, l = indices.length; i < l; i ++ ) {
14477
14478 var index = indices[ i ];
14479
14480 array[ offset ++ ] = index.a;
14481 array[ offset ++ ] = index.b;
14482 array[ offset ++ ] = index.c;
14483
14484 }
14485
14486 return this;
14487
14488 },
14489
14490 copyVector2sArray: function ( vectors ) {
14491
14492 var array = this.array, offset = 0;
14493
14494 for ( var i = 0, l = vectors.length; i < l; i ++ ) {
14495
14496 var vector = vectors[ i ];
14497
14498 if ( vector === undefined ) {
14499
14500 console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i );
14501 vector = new Vector2();
14502
14503 }
14504
14505 array[ offset ++ ] = vector.x;
14506 array[ offset ++ ] = vector.y;
14507
14508 }
14509
14510 return this;
14511
14512 },
14513
14514 copyVector3sArray: function ( vectors ) {
14515
14516 var array = this.array, offset = 0;
14517
14518 for ( var i = 0, l = vectors.length; i < l; i ++ ) {
14519
14520 var vector = vectors[ i ];
14521
14522 if ( vector === undefined ) {
14523
14524 console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i );
14525 vector = new Vector3();
14526
14527 }
14528
14529 array[ offset ++ ] = vector.x;
14530 array[ offset ++ ] = vector.y;
14531 array[ offset ++ ] = vector.z;
14532
14533 }
14534
14535 return this;
14536
14537 },
14538
14539 copyVector4sArray: function ( vectors ) {
14540
14541 var array = this.array, offset = 0;
14542
14543 for ( var i = 0, l = vectors.length; i < l; i ++ ) {
14544
14545 var vector = vectors[ i ];
14546
14547 if ( vector === undefined ) {
14548
14549 console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i );
14550 vector = new Vector4();
14551
14552 }
14553
14554 array[ offset ++ ] = vector.x;
14555 array[ offset ++ ] = vector.y;
14556 array[ offset ++ ] = vector.z;
14557 array[ offset ++ ] = vector.w;
14558
14559 }
14560
14561 return this;
14562
14563 },
14564
14565 set: function ( value, offset ) {
14566
14567 if ( offset === undefined ) offset = 0;
14568
14569 this.array.set( value, offset );
14570
14571 return this;
14572
14573 },
14574
14575 getX: function ( index ) {
14576
14577 return this.array[ index * this.itemSize ];
14578
14579 },
14580
14581 setX: function ( index, x ) {
14582
14583 this.array[ index * this.itemSize ] = x;
14584
14585 return this;
14586
14587 },
14588
14589 getY: function ( index ) {
14590
14591 return this.array[ index * this.itemSize + 1 ];
14592
14593 },
14594
14595 setY: function ( index, y ) {
14596
14597 this.array[ index * this.itemSize + 1 ] = y;
14598
14599 return this;
14600
14601 },
14602
14603 getZ: function ( index ) {
14604
14605 return this.array[ index * this.itemSize + 2 ];
14606
14607 },
14608
14609 setZ: function ( index, z ) {
14610
14611 this.array[ index * this.itemSize + 2 ] = z;
14612
14613 return this;
14614
14615 },
14616
14617 getW: function ( index ) {
14618
14619 return this.array[ index * this.itemSize + 3 ];
14620
14621 },
14622
14623 setW: function ( index, w ) {
14624
14625 this.array[ index * this.itemSize + 3 ] = w;
14626
14627 return this;
14628
14629 },
14630
14631 setXY: function ( index, x, y ) {
14632
14633 index *= this.itemSize;
14634
14635 this.array[ index + 0 ] = x;
14636 this.array[ index + 1 ] = y;
14637
14638 return this;
14639
14640 },
14641
14642 setXYZ: function ( index, x, y, z ) {
14643
14644 index *= this.itemSize;
14645
14646 this.array[ index + 0 ] = x;
14647 this.array[ index + 1 ] = y;
14648 this.array[ index + 2 ] = z;
14649
14650 return this;
14651
14652 },
14653
14654 setXYZW: function ( index, x, y, z, w ) {
14655
14656 index *= this.itemSize;
14657
14658 this.array[ index + 0 ] = x;
14659 this.array[ index + 1 ] = y;
14660 this.array[ index + 2 ] = z;
14661 this.array[ index + 3 ] = w;
14662
14663 return this;
14664
14665 },
14666
14667 onUpload: function ( callback ) {
14668
14669 this.onUploadCallback = callback;
14670
14671 return this;
14672
14673 },
14674
14675 clone: function () {
14676
14677 return new this.constructor( this.array, this.itemSize ).copy( this );
14678
14679 }
14680
14681} );
14682
14683//
14684
14685function Int8BufferAttribute( array, itemSize, normalized ) {
14686
14687 BufferAttribute.call( this, new Int8Array( array ), itemSize, normalized );
14688
14689}
14690
14691Int8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14692Int8BufferAttribute.prototype.constructor = Int8BufferAttribute;
14693
14694
14695function Uint8BufferAttribute( array, itemSize, normalized ) {
14696
14697 BufferAttribute.call( this, new Uint8Array( array ), itemSize, normalized );
14698
14699}
14700
14701Uint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14702Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute;
14703
14704
14705function Uint8ClampedBufferAttribute( array, itemSize, normalized ) {
14706
14707 BufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize, normalized );
14708
14709}
14710
14711Uint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14712Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute;
14713
14714
14715function Int16BufferAttribute( array, itemSize, normalized ) {
14716
14717 BufferAttribute.call( this, new Int16Array( array ), itemSize, normalized );
14718
14719}
14720
14721Int16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14722Int16BufferAttribute.prototype.constructor = Int16BufferAttribute;
14723
14724
14725function Uint16BufferAttribute( array, itemSize, normalized ) {
14726
14727 BufferAttribute.call( this, new Uint16Array( array ), itemSize, normalized );
14728
14729}
14730
14731Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14732Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute;
14733
14734
14735function Int32BufferAttribute( array, itemSize, normalized ) {
14736
14737 BufferAttribute.call( this, new Int32Array( array ), itemSize, normalized );
14738
14739}
14740
14741Int32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14742Int32BufferAttribute.prototype.constructor = Int32BufferAttribute;
14743
14744
14745function Uint32BufferAttribute( array, itemSize, normalized ) {
14746
14747 BufferAttribute.call( this, new Uint32Array( array ), itemSize, normalized );
14748
14749}
14750
14751Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14752Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute;
14753
14754
14755function Float32BufferAttribute( array, itemSize, normalized ) {
14756
14757 BufferAttribute.call( this, new Float32Array( array ), itemSize, normalized );
14758
14759}
14760
14761Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14762Float32BufferAttribute.prototype.constructor = Float32BufferAttribute;
14763
14764
14765function Float64BufferAttribute( array, itemSize, normalized ) {
14766
14767 BufferAttribute.call( this, new Float64Array( array ), itemSize, normalized );
14768
14769}
14770
14771Float64BufferAttribute.prototype = Object.create( BufferAttribute.prototype );
14772Float64BufferAttribute.prototype.constructor = Float64BufferAttribute;
14773
14774/**
14775 * @author mrdoob / http://mrdoob.com/
14776 */
14777
14778function DirectGeometry() {
14779
14780 this.indices = [];
14781 this.vertices = [];
14782 this.normals = [];
14783 this.colors = [];
14784 this.uvs = [];
14785 this.uvs2 = [];
14786
14787 this.groups = [];
14788
14789 this.morphTargets = {};
14790
14791 this.skinWeights = [];
14792 this.skinIndices = [];
14793
14794 // this.lineDistances = [];
14795
14796 this.boundingBox = null;
14797 this.boundingSphere = null;
14798
14799 // update flags
14800
14801 this.verticesNeedUpdate = false;
14802 this.normalsNeedUpdate = false;
14803 this.colorsNeedUpdate = false;
14804 this.uvsNeedUpdate = false;
14805 this.groupsNeedUpdate = false;
14806
14807}
14808
14809Object.assign( DirectGeometry.prototype, {
14810
14811 computeGroups: function ( geometry ) {
14812
14813 var group;
14814 var groups = [];
14815 var materialIndex = undefined;
14816
14817 var faces = geometry.faces;
14818
14819 for ( var i = 0; i < faces.length; i ++ ) {
14820
14821 var face = faces[ i ];
14822
14823 // materials
14824
14825 if ( face.materialIndex !== materialIndex ) {
14826
14827 materialIndex = face.materialIndex;
14828
14829 if ( group !== undefined ) {
14830
14831 group.count = ( i * 3 ) - group.start;
14832 groups.push( group );
14833
14834 }
14835
14836 group = {
14837 start: i * 3,
14838 materialIndex: materialIndex
14839 };
14840
14841 }
14842
14843 }
14844
14845 if ( group !== undefined ) {
14846
14847 group.count = ( i * 3 ) - group.start;
14848 groups.push( group );
14849
14850 }
14851
14852 this.groups = groups;
14853
14854 },
14855
14856 fromGeometry: function ( geometry ) {
14857
14858 var faces = geometry.faces;
14859 var vertices = geometry.vertices;
14860 var faceVertexUvs = geometry.faceVertexUvs;
14861
14862 var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;
14863 var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;
14864
14865 // morphs
14866
14867 var morphTargets = geometry.morphTargets;
14868 var morphTargetsLength = morphTargets.length;
14869
14870 var morphTargetsPosition;
14871
14872 if ( morphTargetsLength > 0 ) {
14873
14874 morphTargetsPosition = [];
14875
14876 for ( var i = 0; i < morphTargetsLength; i ++ ) {
14877
14878 morphTargetsPosition[ i ] = [];
14879
14880 }
14881
14882 this.morphTargets.position = morphTargetsPosition;
14883
14884 }
14885
14886 var morphNormals = geometry.morphNormals;
14887 var morphNormalsLength = morphNormals.length;
14888
14889 var morphTargetsNormal;
14890
14891 if ( morphNormalsLength > 0 ) {
14892
14893 morphTargetsNormal = [];
14894
14895 for ( var i = 0; i < morphNormalsLength; i ++ ) {
14896
14897 morphTargetsNormal[ i ] = [];
14898
14899 }
14900
14901 this.morphTargets.normal = morphTargetsNormal;
14902
14903 }
14904
14905 // skins
14906
14907 var skinIndices = geometry.skinIndices;
14908 var skinWeights = geometry.skinWeights;
14909
14910 var hasSkinIndices = skinIndices.length === vertices.length;
14911 var hasSkinWeights = skinWeights.length === vertices.length;
14912
14913 //
14914
14915 for ( var i = 0; i < faces.length; i ++ ) {
14916
14917 var face = faces[ i ];
14918
14919 this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] );
14920
14921 var vertexNormals = face.vertexNormals;
14922
14923 if ( vertexNormals.length === 3 ) {
14924
14925 this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] );
14926
14927 } else {
14928
14929 var normal = face.normal;
14930
14931 this.normals.push( normal, normal, normal );
14932
14933 }
14934
14935 var vertexColors = face.vertexColors;
14936
14937 if ( vertexColors.length === 3 ) {
14938
14939 this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] );
14940
14941 } else {
14942
14943 var color = face.color;
14944
14945 this.colors.push( color, color, color );
14946
14947 }
14948
14949 if ( hasFaceVertexUv === true ) {
14950
14951 var vertexUvs = faceVertexUvs[ 0 ][ i ];
14952
14953 if ( vertexUvs !== undefined ) {
14954
14955 this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );
14956
14957 } else {
14958
14959 console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i );
14960
14961 this.uvs.push( new Vector2(), new Vector2(), new Vector2() );
14962
14963 }
14964
14965 }
14966
14967 if ( hasFaceVertexUv2 === true ) {
14968
14969 var vertexUvs = faceVertexUvs[ 1 ][ i ];
14970
14971 if ( vertexUvs !== undefined ) {
14972
14973 this.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] );
14974
14975 } else {
14976
14977 console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i );
14978
14979 this.uvs2.push( new Vector2(), new Vector2(), new Vector2() );
14980
14981 }
14982
14983 }
14984
14985 // morphs
14986
14987 for ( var j = 0; j < morphTargetsLength; j ++ ) {
14988
14989 var morphTarget = morphTargets[ j ].vertices;
14990
14991 morphTargetsPosition[ j ].push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] );
14992
14993 }
14994
14995 for ( var j = 0; j < morphNormalsLength; j ++ ) {
14996
14997 var morphNormal = morphNormals[ j ].vertexNormals[ i ];
14998
14999 morphTargetsNormal[ j ].push( morphNormal.a, morphNormal.b, morphNormal.c );
15000
15001 }
15002
15003 // skins
15004
15005 if ( hasSkinIndices ) {
15006
15007 this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] );
15008
15009 }
15010
15011 if ( hasSkinWeights ) {
15012
15013 this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] );
15014
15015 }
15016
15017 }
15018
15019 this.computeGroups( geometry );
15020
15021 this.verticesNeedUpdate = geometry.verticesNeedUpdate;
15022 this.normalsNeedUpdate = geometry.normalsNeedUpdate;
15023 this.colorsNeedUpdate = geometry.colorsNeedUpdate;
15024 this.uvsNeedUpdate = geometry.uvsNeedUpdate;
15025 this.groupsNeedUpdate = geometry.groupsNeedUpdate;
15026
15027 return this;
15028
15029 }
15030
15031} );
15032
15033/**
15034 * @author mrdoob / http://mrdoob.com/
15035 */
15036
15037function arrayMax( array ) {
15038
15039 if ( array.length === 0 ) return - Infinity;
15040
15041 var max = array[ 0 ];
15042
15043 for ( var i = 1, l = array.length; i < l; ++ i ) {
15044
15045 if ( array[ i ] > max ) max = array[ i ];
15046
15047 }
15048
15049 return max;
15050
15051}
15052
15053/**
15054 * @author alteredq / http://alteredqualia.com/
15055 * @author mrdoob / http://mrdoob.com/
15056 */
15057
15058var bufferGeometryId = 1; // BufferGeometry uses odd numbers as Id
15059
15060function BufferGeometry() {
15061
15062 Object.defineProperty( this, 'id', { value: bufferGeometryId += 2 } );
15063
15064 this.uuid = _Math.generateUUID();
15065
15066 this.name = '';
15067 this.type = 'BufferGeometry';
15068
15069 this.index = null;
15070 this.attributes = {};
15071
15072 this.morphAttributes = {};
15073
15074 this.groups = [];
15075
15076 this.boundingBox = null;
15077 this.boundingSphere = null;
15078
15079 this.drawRange = { start: 0, count: Infinity };
15080
15081}
15082
15083BufferGeometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), {
15084
15085 constructor: BufferGeometry,
15086
15087 isBufferGeometry: true,
15088
15089 getIndex: function () {
15090
15091 return this.index;
15092
15093 },
15094
15095 setIndex: function ( index ) {
15096
15097 if ( Array.isArray( index ) ) {
15098
15099 this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );
15100
15101 } else {
15102
15103 this.index = index;
15104
15105 }
15106
15107 },
15108
15109 addAttribute: function ( name, attribute ) {
15110
15111 if ( ! ( attribute && attribute.isBufferAttribute ) && ! ( attribute && attribute.isInterleavedBufferAttribute ) ) {
15112
15113 console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
15114
15115 this.addAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) );
15116
15117 return;
15118
15119 }
15120
15121 if ( name === 'index' ) {
15122
15123 console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' );
15124 this.setIndex( attribute );
15125
15126 return;
15127
15128 }
15129
15130 this.attributes[ name ] = attribute;
15131
15132 return this;
15133
15134 },
15135
15136 getAttribute: function ( name ) {
15137
15138 return this.attributes[ name ];
15139
15140 },
15141
15142 removeAttribute: function ( name ) {
15143
15144 delete this.attributes[ name ];
15145
15146 return this;
15147
15148 },
15149
15150 addGroup: function ( start, count, materialIndex ) {
15151
15152 this.groups.push( {
15153
15154 start: start,
15155 count: count,
15156 materialIndex: materialIndex !== undefined ? materialIndex : 0
15157
15158 } );
15159
15160 },
15161
15162 clearGroups: function () {
15163
15164 this.groups = [];
15165
15166 },
15167
15168 setDrawRange: function ( start, count ) {
15169
15170 this.drawRange.start = start;
15171 this.drawRange.count = count;
15172
15173 },
15174
15175 applyMatrix: function ( matrix ) {
15176
15177 var position = this.attributes.position;
15178
15179 if ( position !== undefined ) {
15180
15181 matrix.applyToBufferAttribute( position );
15182 position.needsUpdate = true;
15183
15184 }
15185
15186 var normal = this.attributes.normal;
15187
15188 if ( normal !== undefined ) {
15189
15190 var normalMatrix = new Matrix3().getNormalMatrix( matrix );
15191
15192 normalMatrix.applyToBufferAttribute( normal );
15193 normal.needsUpdate = true;
15194
15195 }
15196
15197 if ( this.boundingBox !== null ) {
15198
15199 this.computeBoundingBox();
15200
15201 }
15202
15203 if ( this.boundingSphere !== null ) {
15204
15205 this.computeBoundingSphere();
15206
15207 }
15208
15209 return this;
15210
15211 },
15212
15213 rotateX: function () {
15214
15215 // rotate geometry around world x-axis
15216
15217 var m1 = new Matrix4();
15218
15219 return function rotateX( angle ) {
15220
15221 m1.makeRotationX( angle );
15222
15223 this.applyMatrix( m1 );
15224
15225 return this;
15226
15227 };
15228
15229 }(),
15230
15231 rotateY: function () {
15232
15233 // rotate geometry around world y-axis
15234
15235 var m1 = new Matrix4();
15236
15237 return function rotateY( angle ) {
15238
15239 m1.makeRotationY( angle );
15240
15241 this.applyMatrix( m1 );
15242
15243 return this;
15244
15245 };
15246
15247 }(),
15248
15249 rotateZ: function () {
15250
15251 // rotate geometry around world z-axis
15252
15253 var m1 = new Matrix4();
15254
15255 return function rotateZ( angle ) {
15256
15257 m1.makeRotationZ( angle );
15258
15259 this.applyMatrix( m1 );
15260
15261 return this;
15262
15263 };
15264
15265 }(),
15266
15267 translate: function () {
15268
15269 // translate geometry
15270
15271 var m1 = new Matrix4();
15272
15273 return function translate( x, y, z ) {
15274
15275 m1.makeTranslation( x, y, z );
15276
15277 this.applyMatrix( m1 );
15278
15279 return this;
15280
15281 };
15282
15283 }(),
15284
15285 scale: function () {
15286
15287 // scale geometry
15288
15289 var m1 = new Matrix4();
15290
15291 return function scale( x, y, z ) {
15292
15293 m1.makeScale( x, y, z );
15294
15295 this.applyMatrix( m1 );
15296
15297 return this;
15298
15299 };
15300
15301 }(),
15302
15303 lookAt: function () {
15304
15305 var obj = new Object3D();
15306
15307 return function lookAt( vector ) {
15308
15309 obj.lookAt( vector );
15310
15311 obj.updateMatrix();
15312
15313 this.applyMatrix( obj.matrix );
15314
15315 };
15316
15317 }(),
15318
15319 center: function () {
15320
15321 this.computeBoundingBox();
15322
15323 var offset = this.boundingBox.getCenter().negate();
15324
15325 this.translate( offset.x, offset.y, offset.z );
15326
15327 return offset;
15328
15329 },
15330
15331 setFromObject: function ( object ) {
15332
15333 // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this );
15334
15335 var geometry = object.geometry;
15336
15337 if ( object.isPoints || object.isLine ) {
15338
15339 var positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 );
15340 var colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 );
15341
15342 this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) );
15343 this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) );
15344
15345 if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) {
15346
15347 var lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 );
15348
15349 this.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) );
15350
15351 }
15352
15353 if ( geometry.boundingSphere !== null ) {
15354
15355 this.boundingSphere = geometry.boundingSphere.clone();
15356
15357 }
15358
15359 if ( geometry.boundingBox !== null ) {
15360
15361 this.boundingBox = geometry.boundingBox.clone();
15362
15363 }
15364
15365 } else if ( object.isMesh ) {
15366
15367 if ( geometry && geometry.isGeometry ) {
15368
15369 this.fromGeometry( geometry );
15370
15371 }
15372
15373 }
15374
15375 return this;
15376
15377 },
15378
15379 setFromPoints: function ( points ) {
15380
15381 var position = [];
15382
15383 for ( var i = 0, l = points.length; i < l; i ++ ) {
15384
15385 var point = points[ i ];
15386 position.push( point.x, point.y, point.z || 0 );
15387
15388 }
15389
15390 this.addAttribute( 'position', new Float32BufferAttribute( position, 3 ) );
15391
15392 return this;
15393
15394 },
15395
15396 updateFromObject: function ( object ) {
15397
15398 var geometry = object.geometry;
15399
15400 if ( object.isMesh ) {
15401
15402 var direct = geometry.__directGeometry;
15403
15404 if ( geometry.elementsNeedUpdate === true ) {
15405
15406 direct = undefined;
15407 geometry.elementsNeedUpdate = false;
15408
15409 }
15410
15411 if ( direct === undefined ) {
15412
15413 return this.fromGeometry( geometry );
15414
15415 }
15416
15417 direct.verticesNeedUpdate = geometry.verticesNeedUpdate;
15418 direct.normalsNeedUpdate = geometry.normalsNeedUpdate;
15419 direct.colorsNeedUpdate = geometry.colorsNeedUpdate;
15420 direct.uvsNeedUpdate = geometry.uvsNeedUpdate;
15421 direct.groupsNeedUpdate = geometry.groupsNeedUpdate;
15422
15423 geometry.verticesNeedUpdate = false;
15424 geometry.normalsNeedUpdate = false;
15425 geometry.colorsNeedUpdate = false;
15426 geometry.uvsNeedUpdate = false;
15427 geometry.groupsNeedUpdate = false;
15428
15429 geometry = direct;
15430
15431 }
15432
15433 var attribute;
15434
15435 if ( geometry.verticesNeedUpdate === true ) {
15436
15437 attribute = this.attributes.position;
15438
15439 if ( attribute !== undefined ) {
15440
15441 attribute.copyVector3sArray( geometry.vertices );
15442 attribute.needsUpdate = true;
15443
15444 }
15445
15446 geometry.verticesNeedUpdate = false;
15447
15448 }
15449
15450 if ( geometry.normalsNeedUpdate === true ) {
15451
15452 attribute = this.attributes.normal;
15453
15454 if ( attribute !== undefined ) {
15455
15456 attribute.copyVector3sArray( geometry.normals );
15457 attribute.needsUpdate = true;
15458
15459 }
15460
15461 geometry.normalsNeedUpdate = false;
15462
15463 }
15464
15465 if ( geometry.colorsNeedUpdate === true ) {
15466
15467 attribute = this.attributes.color;
15468
15469 if ( attribute !== undefined ) {
15470
15471 attribute.copyColorsArray( geometry.colors );
15472 attribute.needsUpdate = true;
15473
15474 }
15475
15476 geometry.colorsNeedUpdate = false;
15477
15478 }
15479
15480 if ( geometry.uvsNeedUpdate ) {
15481
15482 attribute = this.attributes.uv;
15483
15484 if ( attribute !== undefined ) {
15485
15486 attribute.copyVector2sArray( geometry.uvs );
15487 attribute.needsUpdate = true;
15488
15489 }
15490
15491 geometry.uvsNeedUpdate = false;
15492
15493 }
15494
15495 if ( geometry.lineDistancesNeedUpdate ) {
15496
15497 attribute = this.attributes.lineDistance;
15498
15499 if ( attribute !== undefined ) {
15500
15501 attribute.copyArray( geometry.lineDistances );
15502 attribute.needsUpdate = true;
15503
15504 }
15505
15506 geometry.lineDistancesNeedUpdate = false;
15507
15508 }
15509
15510 if ( geometry.groupsNeedUpdate ) {
15511
15512 geometry.computeGroups( object.geometry );
15513 this.groups = geometry.groups;
15514
15515 geometry.groupsNeedUpdate = false;
15516
15517 }
15518
15519 return this;
15520
15521 },
15522
15523 fromGeometry: function ( geometry ) {
15524
15525 geometry.__directGeometry = new DirectGeometry().fromGeometry( geometry );
15526
15527 return this.fromDirectGeometry( geometry.__directGeometry );
15528
15529 },
15530
15531 fromDirectGeometry: function ( geometry ) {
15532
15533 var positions = new Float32Array( geometry.vertices.length * 3 );
15534 this.addAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );
15535
15536 if ( geometry.normals.length > 0 ) {
15537
15538 var normals = new Float32Array( geometry.normals.length * 3 );
15539 this.addAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) );
15540
15541 }
15542
15543 if ( geometry.colors.length > 0 ) {
15544
15545 var colors = new Float32Array( geometry.colors.length * 3 );
15546 this.addAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) );
15547
15548 }
15549
15550 if ( geometry.uvs.length > 0 ) {
15551
15552 var uvs = new Float32Array( geometry.uvs.length * 2 );
15553 this.addAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) );
15554
15555 }
15556
15557 if ( geometry.uvs2.length > 0 ) {
15558
15559 var uvs2 = new Float32Array( geometry.uvs2.length * 2 );
15560 this.addAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) );
15561
15562 }
15563
15564 if ( geometry.indices.length > 0 ) {
15565
15566 var TypeArray = arrayMax( geometry.indices ) > 65535 ? Uint32Array : Uint16Array;
15567 var indices = new TypeArray( geometry.indices.length * 3 );
15568 this.setIndex( new BufferAttribute( indices, 1 ).copyIndicesArray( geometry.indices ) );
15569
15570 }
15571
15572 // groups
15573
15574 this.groups = geometry.groups;
15575
15576 // morphs
15577
15578 for ( var name in geometry.morphTargets ) {
15579
15580 var array = [];
15581 var morphTargets = geometry.morphTargets[ name ];
15582
15583 for ( var i = 0, l = morphTargets.length; i < l; i ++ ) {
15584
15585 var morphTarget = morphTargets[ i ];
15586
15587 var attribute = new Float32BufferAttribute( morphTarget.length * 3, 3 );
15588
15589 array.push( attribute.copyVector3sArray( morphTarget ) );
15590
15591 }
15592
15593 this.morphAttributes[ name ] = array;
15594
15595 }
15596
15597 // skinning
15598
15599 if ( geometry.skinIndices.length > 0 ) {
15600
15601 var skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 );
15602 this.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) );
15603
15604 }
15605
15606 if ( geometry.skinWeights.length > 0 ) {
15607
15608 var skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 );
15609 this.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) );
15610
15611 }
15612
15613 //
15614
15615 if ( geometry.boundingSphere !== null ) {
15616
15617 this.boundingSphere = geometry.boundingSphere.clone();
15618
15619 }
15620
15621 if ( geometry.boundingBox !== null ) {
15622
15623 this.boundingBox = geometry.boundingBox.clone();
15624
15625 }
15626
15627 return this;
15628
15629 },
15630
15631 computeBoundingBox: function () {
15632
15633 if ( this.boundingBox === null ) {
15634
15635 this.boundingBox = new Box3();
15636
15637 }
15638
15639 var position = this.attributes.position;
15640
15641 if ( position !== undefined ) {
15642
15643 this.boundingBox.setFromBufferAttribute( position );
15644
15645 } else {
15646
15647 this.boundingBox.makeEmpty();
15648
15649 }
15650
15651 if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
15652
15653 console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this );
15654
15655 }
15656
15657 },
15658
15659 computeBoundingSphere: function () {
15660
15661 var box = new Box3();
15662 var vector = new Vector3();
15663
15664 return function computeBoundingSphere() {
15665
15666 if ( this.boundingSphere === null ) {
15667
15668 this.boundingSphere = new Sphere();
15669
15670 }
15671
15672 var position = this.attributes.position;
15673
15674 if ( position ) {
15675
15676 var center = this.boundingSphere.center;
15677
15678 box.setFromBufferAttribute( position );
15679 box.getCenter( center );
15680
15681 // hoping to find a boundingSphere with a radius smaller than the
15682 // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
15683
15684 var maxRadiusSq = 0;
15685
15686 for ( var i = 0, il = position.count; i < il; i ++ ) {
15687
15688 vector.x = position.getX( i );
15689 vector.y = position.getY( i );
15690 vector.z = position.getZ( i );
15691 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
15692
15693 }
15694
15695 this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
15696
15697 if ( isNaN( this.boundingSphere.radius ) ) {
15698
15699 console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this );
15700
15701 }
15702
15703 }
15704
15705 };
15706
15707 }(),
15708
15709 computeFaceNormals: function () {
15710
15711 // backwards compatibility
15712
15713 },
15714
15715 computeVertexNormals: function () {
15716
15717 var index = this.index;
15718 var attributes = this.attributes;
15719 var groups = this.groups;
15720
15721 if ( attributes.position ) {
15722
15723 var positions = attributes.position.array;
15724
15725 if ( attributes.normal === undefined ) {
15726
15727 this.addAttribute( 'normal', new BufferAttribute( new Float32Array( positions.length ), 3 ) );
15728
15729 } else {
15730
15731 // reset existing normals to zero
15732
15733 var array = attributes.normal.array;
15734
15735 for ( var i = 0, il = array.length; i < il; i ++ ) {
15736
15737 array[ i ] = 0;
15738
15739 }
15740
15741 }
15742
15743 var normals = attributes.normal.array;
15744
15745 var vA, vB, vC;
15746 var pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
15747 var cb = new Vector3(), ab = new Vector3();
15748
15749 // indexed elements
15750
15751 if ( index ) {
15752
15753 var indices = index.array;
15754
15755 if ( groups.length === 0 ) {
15756
15757 this.addGroup( 0, indices.length );
15758
15759 }
15760
15761 for ( var j = 0, jl = groups.length; j < jl; ++ j ) {
15762
15763 var group = groups[ j ];
15764
15765 var start = group.start;
15766 var count = group.count;
15767
15768 for ( var i = start, il = start + count; i < il; i += 3 ) {
15769
15770 vA = indices[ i + 0 ] * 3;
15771 vB = indices[ i + 1 ] * 3;
15772 vC = indices[ i + 2 ] * 3;
15773
15774 pA.fromArray( positions, vA );
15775 pB.fromArray( positions, vB );
15776 pC.fromArray( positions, vC );
15777
15778 cb.subVectors( pC, pB );
15779 ab.subVectors( pA, pB );
15780 cb.cross( ab );
15781
15782 normals[ vA ] += cb.x;
15783 normals[ vA + 1 ] += cb.y;
15784 normals[ vA + 2 ] += cb.z;
15785
15786 normals[ vB ] += cb.x;
15787 normals[ vB + 1 ] += cb.y;
15788 normals[ vB + 2 ] += cb.z;
15789
15790 normals[ vC ] += cb.x;
15791 normals[ vC + 1 ] += cb.y;
15792 normals[ vC + 2 ] += cb.z;
15793
15794 }
15795
15796 }
15797
15798 } else {
15799
15800 // non-indexed elements (unconnected triangle soup)
15801
15802 for ( var i = 0, il = positions.length; i < il; i += 9 ) {
15803
15804 pA.fromArray( positions, i );
15805 pB.fromArray( positions, i + 3 );
15806 pC.fromArray( positions, i + 6 );
15807
15808 cb.subVectors( pC, pB );
15809 ab.subVectors( pA, pB );
15810 cb.cross( ab );
15811
15812 normals[ i ] = cb.x;
15813 normals[ i + 1 ] = cb.y;
15814 normals[ i + 2 ] = cb.z;
15815
15816 normals[ i + 3 ] = cb.x;
15817 normals[ i + 4 ] = cb.y;
15818 normals[ i + 5 ] = cb.z;
15819
15820 normals[ i + 6 ] = cb.x;
15821 normals[ i + 7 ] = cb.y;
15822 normals[ i + 8 ] = cb.z;
15823
15824 }
15825
15826 }
15827
15828 this.normalizeNormals();
15829
15830 attributes.normal.needsUpdate = true;
15831
15832 }
15833
15834 },
15835
15836 merge: function ( geometry, offset ) {
15837
15838 if ( ! ( geometry && geometry.isBufferGeometry ) ) {
15839
15840 console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
15841 return;
15842
15843 }
15844
15845 if ( offset === undefined ) offset = 0;
15846
15847 var attributes = this.attributes;
15848
15849 for ( var key in attributes ) {
15850
15851 if ( geometry.attributes[ key ] === undefined ) continue;
15852
15853 var attribute1 = attributes[ key ];
15854 var attributeArray1 = attribute1.array;
15855
15856 var attribute2 = geometry.attributes[ key ];
15857 var attributeArray2 = attribute2.array;
15858
15859 var attributeSize = attribute2.itemSize;
15860
15861 for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) {
15862
15863 attributeArray1[ j ] = attributeArray2[ i ];
15864
15865 }
15866
15867 }
15868
15869 return this;
15870
15871 },
15872
15873 normalizeNormals: function () {
15874
15875 var vector = new Vector3();
15876
15877 return function normalizeNormals() {
15878
15879 var normals = this.attributes.normal;
15880
15881 for ( var i = 0, il = normals.count; i < il; i ++ ) {
15882
15883 vector.x = normals.getX( i );
15884 vector.y = normals.getY( i );
15885 vector.z = normals.getZ( i );
15886
15887 vector.normalize();
15888
15889 normals.setXYZ( i, vector.x, vector.y, vector.z );
15890
15891 }
15892
15893 };
15894
15895 }(),
15896
15897 toNonIndexed: function () {
15898
15899 if ( this.index === null ) {
15900
15901 console.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' );
15902 return this;
15903
15904 }
15905
15906 var geometry2 = new BufferGeometry();
15907
15908 var indices = this.index.array;
15909 var attributes = this.attributes;
15910
15911 for ( var name in attributes ) {
15912
15913 var attribute = attributes[ name ];
15914
15915 var array = attribute.array;
15916 var itemSize = attribute.itemSize;
15917
15918 var array2 = new array.constructor( indices.length * itemSize );
15919
15920 var index = 0, index2 = 0;
15921
15922 for ( var i = 0, l = indices.length; i < l; i ++ ) {
15923
15924 index = indices[ i ] * itemSize;
15925
15926 for ( var j = 0; j < itemSize; j ++ ) {
15927
15928 array2[ index2 ++ ] = array[ index ++ ];
15929
15930 }
15931
15932 }
15933
15934 geometry2.addAttribute( name, new BufferAttribute( array2, itemSize ) );
15935
15936 }
15937
15938 return geometry2;
15939
15940 },
15941
15942 toJSON: function () {
15943
15944 var data = {
15945 metadata: {
15946 version: 4.5,
15947 type: 'BufferGeometry',
15948 generator: 'BufferGeometry.toJSON'
15949 }
15950 };
15951
15952 // standard BufferGeometry serialization
15953
15954 data.uuid = this.uuid;
15955 data.type = this.type;
15956 if ( this.name !== '' ) data.name = this.name;
15957
15958 if ( this.parameters !== undefined ) {
15959
15960 var parameters = this.parameters;
15961
15962 for ( var key in parameters ) {
15963
15964 if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];
15965
15966 }
15967
15968 return data;
15969
15970 }
15971
15972 data.data = { attributes: {} };
15973
15974 var index = this.index;
15975
15976 if ( index !== null ) {
15977
15978 var array = Array.prototype.slice.call( index.array );
15979
15980 data.data.index = {
15981 type: index.array.constructor.name,
15982 array: array
15983 };
15984
15985 }
15986
15987 var attributes = this.attributes;
15988
15989 for ( var key in attributes ) {
15990
15991 var attribute = attributes[ key ];
15992
15993 var array = Array.prototype.slice.call( attribute.array );
15994
15995 data.data.attributes[ key ] = {
15996 itemSize: attribute.itemSize,
15997 type: attribute.array.constructor.name,
15998 array: array,
15999 normalized: attribute.normalized
16000 };
16001
16002 }
16003
16004 var groups = this.groups;
16005
16006 if ( groups.length > 0 ) {
16007
16008 data.data.groups = JSON.parse( JSON.stringify( groups ) );
16009
16010 }
16011
16012 var boundingSphere = this.boundingSphere;
16013
16014 if ( boundingSphere !== null ) {
16015
16016 data.data.boundingSphere = {
16017 center: boundingSphere.center.toArray(),
16018 radius: boundingSphere.radius
16019 };
16020
16021 }
16022
16023 return data;
16024
16025 },
16026
16027 clone: function () {
16028
16029 /*
16030 // Handle primitives
16031
16032 var parameters = this.parameters;
16033
16034 if ( parameters !== undefined ) {
16035
16036 var values = [];
16037
16038 for ( var key in parameters ) {
16039
16040 values.push( parameters[ key ] );
16041
16042 }
16043
16044 var geometry = Object.create( this.constructor.prototype );
16045 this.constructor.apply( geometry, values );
16046 return geometry;
16047
16048 }
16049
16050 return new this.constructor().copy( this );
16051 */
16052
16053 return new BufferGeometry().copy( this );
16054
16055 },
16056
16057 copy: function ( source ) {
16058
16059 var name, i, l;
16060
16061 // reset
16062
16063 this.index = null;
16064 this.attributes = {};
16065 this.morphAttributes = {};
16066 this.groups = [];
16067 this.boundingBox = null;
16068 this.boundingSphere = null;
16069
16070 // name
16071
16072 this.name = source.name;
16073
16074 // index
16075
16076 var index = source.index;
16077
16078 if ( index !== null ) {
16079
16080 this.setIndex( index.clone() );
16081
16082 }
16083
16084 // attributes
16085
16086 var attributes = source.attributes;
16087
16088 for ( name in attributes ) {
16089
16090 var attribute = attributes[ name ];
16091 this.addAttribute( name, attribute.clone() );
16092
16093 }
16094
16095 // morph attributes
16096
16097 var morphAttributes = source.morphAttributes;
16098
16099 for ( name in morphAttributes ) {
16100
16101 var array = [];
16102 var morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes
16103
16104 for ( i = 0, l = morphAttribute.length; i < l; i ++ ) {
16105
16106 array.push( morphAttribute[ i ].clone() );
16107
16108 }
16109
16110 this.morphAttributes[ name ] = array;
16111
16112 }
16113
16114 // groups
16115
16116 var groups = source.groups;
16117
16118 for ( i = 0, l = groups.length; i < l; i ++ ) {
16119
16120 var group = groups[ i ];
16121 this.addGroup( group.start, group.count, group.materialIndex );
16122
16123 }
16124
16125 // bounding box
16126
16127 var boundingBox = source.boundingBox;
16128
16129 if ( boundingBox !== null ) {
16130
16131 this.boundingBox = boundingBox.clone();
16132
16133 }
16134
16135 // bounding sphere
16136
16137 var boundingSphere = source.boundingSphere;
16138
16139 if ( boundingSphere !== null ) {
16140
16141 this.boundingSphere = boundingSphere.clone();
16142
16143 }
16144
16145 // draw range
16146
16147 this.drawRange.start = source.drawRange.start;
16148 this.drawRange.count = source.drawRange.count;
16149
16150 return this;
16151
16152 },
16153
16154 dispose: function () {
16155
16156 this.dispatchEvent( { type: 'dispose' } );
16157
16158 }
16159
16160} );
16161
16162/**
16163 * @author mrdoob / http://mrdoob.com/
16164 * @author Mugen87 / https://github.com/Mugen87
16165 */
16166
16167// BoxGeometry
16168
16169function BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {
16170
16171 Geometry.call( this );
16172
16173 this.type = 'BoxGeometry';
16174
16175 this.parameters = {
16176 width: width,
16177 height: height,
16178 depth: depth,
16179 widthSegments: widthSegments,
16180 heightSegments: heightSegments,
16181 depthSegments: depthSegments
16182 };
16183
16184 this.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) );
16185 this.mergeVertices();
16186
16187}
16188
16189BoxGeometry.prototype = Object.create( Geometry.prototype );
16190BoxGeometry.prototype.constructor = BoxGeometry;
16191
16192// BoxBufferGeometry
16193
16194function BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) {
16195
16196 BufferGeometry.call( this );
16197
16198 this.type = 'BoxBufferGeometry';
16199
16200 this.parameters = {
16201 width: width,
16202 height: height,
16203 depth: depth,
16204 widthSegments: widthSegments,
16205 heightSegments: heightSegments,
16206 depthSegments: depthSegments
16207 };
16208
16209 var scope = this;
16210
16211 width = width || 1;
16212 height = height || 1;
16213 depth = depth || 1;
16214
16215 // segments
16216
16217 widthSegments = Math.floor( widthSegments ) || 1;
16218 heightSegments = Math.floor( heightSegments ) || 1;
16219 depthSegments = Math.floor( depthSegments ) || 1;
16220
16221 // buffers
16222
16223 var indices = [];
16224 var vertices = [];
16225 var normals = [];
16226 var uvs = [];
16227
16228 // helper variables
16229
16230 var numberOfVertices = 0;
16231 var groupStart = 0;
16232
16233 // build each side of the box geometry
16234
16235 buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px
16236 buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx
16237 buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py
16238 buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny
16239 buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz
16240 buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz
16241
16242 // build geometry
16243
16244 this.setIndex( indices );
16245 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
16246 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
16247 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
16248
16249 function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {
16250
16251 var segmentWidth = width / gridX;
16252 var segmentHeight = height / gridY;
16253
16254 var widthHalf = width / 2;
16255 var heightHalf = height / 2;
16256 var depthHalf = depth / 2;
16257
16258 var gridX1 = gridX + 1;
16259 var gridY1 = gridY + 1;
16260
16261 var vertexCounter = 0;
16262 var groupCount = 0;
16263
16264 var ix, iy;
16265
16266 var vector = new Vector3();
16267
16268 // generate vertices, normals and uvs
16269
16270 for ( iy = 0; iy < gridY1; iy ++ ) {
16271
16272 var y = iy * segmentHeight - heightHalf;
16273
16274 for ( ix = 0; ix < gridX1; ix ++ ) {
16275
16276 var x = ix * segmentWidth - widthHalf;
16277
16278 // set values to correct vector component
16279
16280 vector[ u ] = x * udir;
16281 vector[ v ] = y * vdir;
16282 vector[ w ] = depthHalf;
16283
16284 // now apply vector to vertex buffer
16285
16286 vertices.push( vector.x, vector.y, vector.z );
16287
16288 // set values to correct vector component
16289
16290 vector[ u ] = 0;
16291 vector[ v ] = 0;
16292 vector[ w ] = depth > 0 ? 1 : - 1;
16293
16294 // now apply vector to normal buffer
16295
16296 normals.push( vector.x, vector.y, vector.z );
16297
16298 // uvs
16299
16300 uvs.push( ix / gridX );
16301 uvs.push( 1 - ( iy / gridY ) );
16302
16303 // counters
16304
16305 vertexCounter += 1;
16306
16307 }
16308
16309 }
16310
16311 // indices
16312
16313 // 1. you need three indices to draw a single face
16314 // 2. a single segment consists of two faces
16315 // 3. so we need to generate six (2*3) indices per segment
16316
16317 for ( iy = 0; iy < gridY; iy ++ ) {
16318
16319 for ( ix = 0; ix < gridX; ix ++ ) {
16320
16321 var a = numberOfVertices + ix + gridX1 * iy;
16322 var b = numberOfVertices + ix + gridX1 * ( iy + 1 );
16323 var c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
16324 var d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
16325
16326 // faces
16327
16328 indices.push( a, b, d );
16329 indices.push( b, c, d );
16330
16331 // increase counter
16332
16333 groupCount += 6;
16334
16335 }
16336
16337 }
16338
16339 // add a group to the geometry. this will ensure multi material support
16340
16341 scope.addGroup( groupStart, groupCount, materialIndex );
16342
16343 // calculate new start value for groups
16344
16345 groupStart += groupCount;
16346
16347 // update total number of vertices
16348
16349 numberOfVertices += vertexCounter;
16350
16351 }
16352
16353}
16354
16355BoxBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
16356BoxBufferGeometry.prototype.constructor = BoxBufferGeometry;
16357
16358/**
16359 * @author mrdoob / http://mrdoob.com/
16360 * @author Mugen87 / https://github.com/Mugen87
16361 */
16362
16363// PlaneGeometry
16364
16365function PlaneGeometry( width, height, widthSegments, heightSegments ) {
16366
16367 Geometry.call( this );
16368
16369 this.type = 'PlaneGeometry';
16370
16371 this.parameters = {
16372 width: width,
16373 height: height,
16374 widthSegments: widthSegments,
16375 heightSegments: heightSegments
16376 };
16377
16378 this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) );
16379 this.mergeVertices();
16380
16381}
16382
16383PlaneGeometry.prototype = Object.create( Geometry.prototype );
16384PlaneGeometry.prototype.constructor = PlaneGeometry;
16385
16386// PlaneBufferGeometry
16387
16388function PlaneBufferGeometry( width, height, widthSegments, heightSegments ) {
16389
16390 BufferGeometry.call( this );
16391
16392 this.type = 'PlaneBufferGeometry';
16393
16394 this.parameters = {
16395 width: width,
16396 height: height,
16397 widthSegments: widthSegments,
16398 heightSegments: heightSegments
16399 };
16400
16401 width = width || 1;
16402 height = height || 1;
16403
16404 var width_half = width / 2;
16405 var height_half = height / 2;
16406
16407 var gridX = Math.floor( widthSegments ) || 1;
16408 var gridY = Math.floor( heightSegments ) || 1;
16409
16410 var gridX1 = gridX + 1;
16411 var gridY1 = gridY + 1;
16412
16413 var segment_width = width / gridX;
16414 var segment_height = height / gridY;
16415
16416 var ix, iy;
16417
16418 // buffers
16419
16420 var indices = [];
16421 var vertices = [];
16422 var normals = [];
16423 var uvs = [];
16424
16425 // generate vertices, normals and uvs
16426
16427 for ( iy = 0; iy < gridY1; iy ++ ) {
16428
16429 var y = iy * segment_height - height_half;
16430
16431 for ( ix = 0; ix < gridX1; ix ++ ) {
16432
16433 var x = ix * segment_width - width_half;
16434
16435 vertices.push( x, - y, 0 );
16436
16437 normals.push( 0, 0, 1 );
16438
16439 uvs.push( ix / gridX );
16440 uvs.push( 1 - ( iy / gridY ) );
16441
16442 }
16443
16444 }
16445
16446 // indices
16447
16448 for ( iy = 0; iy < gridY; iy ++ ) {
16449
16450 for ( ix = 0; ix < gridX; ix ++ ) {
16451
16452 var a = ix + gridX1 * iy;
16453 var b = ix + gridX1 * ( iy + 1 );
16454 var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
16455 var d = ( ix + 1 ) + gridX1 * iy;
16456
16457 // faces
16458
16459 indices.push( a, b, d );
16460 indices.push( b, c, d );
16461
16462 }
16463
16464 }
16465
16466 // build geometry
16467
16468 this.setIndex( indices );
16469 this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
16470 this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
16471 this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
16472
16473}
16474
16475PlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
16476PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry;
16477
16478/**
16479 * @author mrdoob / http://mrdoob.com/
16480 * @author alteredq / http://alteredqualia.com/
16481 *
16482 * parameters = {
16483 * color: <hex>,
16484 * opacity: <float>,
16485 * map: new THREE.Texture( <Image> ),
16486 *
16487 * lightMap: new THREE.Texture( <Image> ),
16488 * lightMapIntensity: <float>
16489 *
16490 * aoMap: new THREE.Texture( <Image> ),
16491 * aoMapIntensity: <float>
16492 *
16493 * specularMap: new THREE.Texture( <Image> ),
16494 *
16495 * alphaMap: new THREE.Texture( <Image> ),
16496 *
16497 * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
16498 * combine: THREE.Multiply,
16499 * reflectivity: <float>,
16500 * refractionRatio: <float>,
16501 *
16502 * depthTest: <bool>,
16503 * depthWrite: <bool>,
16504 *
16505 * wireframe: <boolean>,
16506 * wireframeLinewidth: <float>,
16507 *
16508 * skinning: <bool>,
16509 * morphTargets: <bool>
16510 * }
16511 */
16512
16513function MeshBasicMaterial( parameters ) {
16514
16515 Material.call( this );
16516
16517 this.type = 'MeshBasicMaterial';
16518
16519 this.color = new Color( 0xffffff ); // emissive
16520
16521 this.map = null;
16522
16523 this.lightMap = null;
16524 this.lightMapIntensity = 1.0;
16525
16526 this.aoMap = null;
16527 this.aoMapIntensity = 1.0;
16528
16529 this.specularMap = null;
16530
16531 this.alphaMap = null;
16532
16533 this.envMap = null;
16534 this.combine = MultiplyOperation;
16535 this.reflectivity = 1;
16536 this.refractionRatio = 0.98;
16537
16538 this.wireframe = false;
16539 this.wireframeLinewidth = 1;
16540 this.wireframeLinecap = 'round';
16541 this.wireframeLinejoin = 'round';
16542
16543 this.skinning = false;
16544 this.morphTargets = false;
16545
16546 this.lights = false;
16547
16548 this.setValues( parameters );
16549
16550}
16551
16552MeshBasicMaterial.prototype = Object.create( Material.prototype );
16553MeshBasicMaterial.prototype.constructor = MeshBasicMaterial;
16554
16555MeshBasicMaterial.prototype.isMeshBasicMaterial = true;
16556
16557MeshBasicMaterial.prototype.copy = function ( source ) {
16558
16559 Material.prototype.copy.call( this, source );
16560
16561 this.color.copy( source.color );
16562
16563 this.map = source.map;
16564
16565 this.lightMap = source.lightMap;
16566 this.lightMapIntensity = source.lightMapIntensity;
16567
16568 this.aoMap = source.aoMap;
16569 this.aoMapIntensity = source.aoMapIntensity;
16570
16571 this.specularMap = source.specularMap;
16572
16573 this.alphaMap = source.alphaMap;
16574
16575 this.envMap = source.envMap;
16576 this.combine = source.combine;
16577 this.reflectivity = source.reflectivity;
16578 this.refractionRatio = source.refractionRatio;
16579
16580 this.wireframe = source.wireframe;
16581 this.wireframeLinewidth = source.wireframeLinewidth;
16582 this.wireframeLinecap = source.wireframeLinecap;
16583 this.wireframeLinejoin = source.wireframeLinejoin;
16584
16585 this.skinning = source.skinning;
16586 this.morphTargets = source.morphTargets;
16587
16588 return this;
16589
16590};
16591
16592/**
16593 * @author alteredq / http://alteredqualia.com/
16594 *
16595 * parameters = {
16596 * defines: { "label" : "value" },
16597 * uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } },
16598 *
16599 * fragmentShader: <string>,
16600 * vertexShader: <string>,
16601 *
16602 * wireframe: <boolean>,
16603 * wireframeLinewidth: <float>,
16604 *
16605 * lights: <bool>,
16606 *
16607 * skinning: <bool>,
16608 * morphTargets: <bool>,
16609 * morphNormals: <bool>
16610 * }
16611 */
16612
16613function ShaderMaterial( parameters ) {
16614
16615 Material.call( this );
16616
16617 this.type = 'ShaderMaterial';
16618
16619 this.defines = {};
16620 this.uniforms = {};
16621
16622 this.vertexShader = 'void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}';
16623 this.fragmentShader = 'void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}';
16624
16625 this.linewidth = 1;
16626
16627 this.wireframe = false;
16628 this.wireframeLinewidth = 1;
16629
16630 this.fog = false; // set to use scene fog
16631 this.lights = false; // set to use scene lights
16632 this.clipping = false; // set to use user-defined clipping planes
16633
16634 this.skinning = false; // set to use skinning attribute streams
16635 this.morphTargets = false; // set to use morph targets
16636 this.morphNormals = false; // set to use morph normals
16637
16638 this.extensions = {
16639 derivatives: false, // set to use derivatives
16640 fragDepth: false, // set to use fragment depth values
16641 drawBuffers: false, // set to use draw buffers
16642 shaderTextureLOD: false // set to use shader texture LOD
16643 };
16644
16645 // When rendered geometry doesn't include these attributes but the material does,
16646 // use these default values in WebGL. This avoids errors when buffer data is missing.
16647 this.defaultAttributeValues = {
16648 'color': [ 1, 1, 1 ],
16649 'uv': [ 0, 0 ],
16650 'uv2': [ 0, 0 ]
16651 };
16652
16653 this.index0AttributeName = undefined;
16654
16655 if ( parameters !== undefined ) {
16656
16657 if ( parameters.attributes !== undefined ) {
16658
16659 console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' );
16660
16661 }
16662
16663 this.setValues( parameters );
16664
16665 }
16666
16667}
16668
16669ShaderMaterial.prototype = Object.create( Material.prototype );
16670ShaderMaterial.prototype.constructor = ShaderMaterial;
16671
16672ShaderMaterial.prototype.isShaderMaterial = true;
16673
16674ShaderMaterial.prototype.copy = function ( source ) {
16675
16676 Material.prototype.copy.call( this, source );
16677
16678 this.fragmentShader = source.fragmentShader;
16679 this.vertexShader = source.vertexShader;
16680
16681 this.uniforms = UniformsUtils.clone( source.uniforms );
16682
16683 this.defines = source.defines;
16684
16685 this.wireframe = source.wireframe;
16686 this.wireframeLinewidth = source.wireframeLinewidth;
16687
16688 this.lights = source.lights;
16689 this.clipping = source.clipping;
16690
16691 this.skinning = source.skinning;
16692
16693 this.morphTargets = source.morphTargets;
16694 this.morphNormals = source.morphNormals;
16695
16696 this.extensions = source.extensions;
16697
16698 return this;
16699
16700};
16701
16702ShaderMaterial.prototype.toJSON = function ( meta ) {
16703
16704 var data = Material.prototype.toJSON.call( this, meta );
16705
16706 data.uniforms = this.uniforms;
16707 data.vertexShader = this.vertexShader;
16708 data.fragmentShader = this.fragmentShader;
16709
16710 return data;
16711
16712};
16713
16714/**
16715 * @author bhouston / http://clara.io
16716 */
16717
16718function Ray( origin, direction ) {
16719
16720 this.origin = ( origin !== undefined ) ? origin : new Vector3();
16721 this.direction = ( direction !== undefined ) ? direction : new Vector3();
16722
16723}
16724
16725Object.assign( Ray.prototype, {
16726
16727 set: function ( origin, direction ) {
16728
16729 this.origin.copy( origin );
16730 this.direction.copy( direction );
16731
16732 return this;
16733
16734 },
16735
16736 clone: function () {
16737
16738 return new this.constructor().copy( this );
16739
16740 },
16741
16742 copy: function ( ray ) {
16743
16744 this.origin.copy( ray.origin );
16745 this.direction.copy( ray.direction );
16746
16747 return this;
16748
16749 },
16750
16751 at: function ( t, optionalTarget ) {
16752
16753 var result = optionalTarget || new Vector3();
16754
16755 return result.copy( this.direction ).multiplyScalar( t ).add( this.origin );
16756
16757 },
16758
16759 lookAt: function ( v ) {
16760
16761 this.direction.copy( v ).sub( this.origin ).normalize();
16762
16763 return this;
16764
16765 },
16766
16767 recast: function () {
16768
16769 var v1 = new Vector3();
16770
16771 return function recast( t ) {
16772
16773 this.origin.copy( this.at( t, v1 ) );
16774
16775 return this;
16776
16777 };
16778
16779 }(),
16780
16781 closestPointToPoint: function ( point, optionalTarget ) {
16782
16783 var result = optionalTarget || new Vector3();
16784 result.subVectors( point, this.origin );
16785 var directionDistance = result.dot( this.direction );
16786
16787 if ( directionDistance < 0 ) {
16788
16789 return result.copy( this.origin );
16790
16791 }
16792
16793 return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
16794
16795 },
16796
16797 distanceToPoint: function ( point ) {
16798
16799 return Math.sqrt( this.distanceSqToPoint( point ) );
16800
16801 },
16802
16803 distanceSqToPoint: function () {
16804
16805 var v1 = new Vector3();
16806
16807 return function distanceSqToPoint( point ) {
16808
16809 var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );
16810
16811 // point behind the ray
16812
16813 if ( directionDistance < 0 ) {
16814
16815 return this.origin.distanceToSquared( point );
16816
16817 }
16818
16819 v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
16820
16821 return v1.distanceToSquared( point );
16822
16823 };
16824
16825 }(),
16826
16827 distanceSqToSegment: function () {
16828
16829 var segCenter = new Vector3();
16830 var segDir = new Vector3();
16831 var diff = new Vector3();
16832
16833 return function distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
16834
16835 // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
16836 // It returns the min distance between the ray and the segment
16837 // defined by v0 and v1
16838 // It can also set two optional targets :
16839 // - The closest point on the ray
16840 // - The closest point on the segment
16841
16842 segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
16843 segDir.copy( v1 ).sub( v0 ).normalize();
16844 diff.copy( this.origin ).sub( segCenter );
16845
16846 var segExtent = v0.distanceTo( v1 ) * 0.5;
16847 var a01 = - this.direction.dot( segDir );
16848 var b0 = diff.dot( this.direction );
16849 var b1 = - diff.dot( segDir );
16850 var c = diff.lengthSq();
16851 var det = Math.abs( 1 - a01 * a01 );
16852 var s0, s1, sqrDist, extDet;
16853
16854 if ( det > 0 ) {
16855
16856 // The ray and segment are not parallel.
16857
16858 s0 = a01 * b1 - b0;
16859 s1 = a01 * b0 - b1;
16860 extDet = segExtent * det;
16861
16862 if ( s0 >= 0 ) {
16863
16864 if ( s1 >= - extDet ) {
16865
16866 if ( s1 <= extDet ) {
16867
16868 // region 0
16869 // Minimum at interior points of ray and segment.
16870
16871 var invDet = 1 / det;
16872 s0 *= invDet;
16873 s1 *= invDet;
16874 sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
16875
16876 } else {
16877
16878 // region 1
16879
16880 s1 = segExtent;
16881 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
16882 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
16883
16884 }
16885
16886 } else {
16887
16888 // region 5
16889
16890 s1 = - segExtent;
16891 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
16892 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
16893
16894 }
16895
16896 } else {
16897
16898 if ( s1 <= - extDet ) {
16899
16900 // region 4
16901
16902 s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
16903 s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
16904 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
16905
16906 } else if ( s1 <= extDet ) {
16907
16908 // region 3
16909
16910 s0 = 0;
16911 s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
16912 sqrDist = s1 * ( s1 + 2 * b1 ) + c;
16913
16914 } else {
16915
16916 // region 2
16917
16918 s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
16919 s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
16920 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
16921
16922 }
16923
16924 }
16925
16926 } else {
16927
16928 // Ray and segment are parallel.
16929
16930 s1 = ( a01 > 0 ) ? - segExtent : segExtent;
16931 s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
16932 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
16933
16934 }
16935
16936 if ( optionalPointOnRay ) {
16937
16938 optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );
16939
16940 }
16941
16942 if ( optionalPointOnSegment ) {
16943
16944 optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter );
16945
16946 }
16947
16948 return sqrDist;
16949
16950 };
16951
16952 }(),
16953
16954 intersectSphere: function () {
16955
16956 var v1 = new Vector3();
16957
16958 return function intersectSphere( sphere, optionalTarget ) {
16959
16960 v1.subVectors( sphere.center, this.origin );
16961 var tca = v1.dot( this.direction );
16962 var d2 = v1.dot( v1 ) - tca * tca;
16963 var radius2 = sphere.radius * sphere.radius;
16964
16965 if ( d2 > radius2 ) return null;
16966
16967 var thc = Math.sqrt( radius2 - d2 );
16968
16969 // t0 = first intersect point - entrance on front of sphere
16970 var t0 = tca - thc;
16971
16972 // t1 = second intersect point - exit point on back of sphere
16973 var t1 = tca + thc;
16974
16975 // test to see if both t0 and t1 are behind the ray - if so, return null
16976 if ( t0 < 0 && t1 < 0 ) return null;
16977
16978 // test to see if t0 is behind the ray:
16979 // if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
16980 // in order to always return an intersect point that is in front of the ray.
16981 if ( t0 < 0 ) return this.at( t1, optionalTarget );
16982
16983 // else t0 is in front of the ray, so return the first collision point scaled by t0
16984 return this.at( t0, optionalTarget );
16985
16986 };
16987
16988 }(),
16989
16990 intersectsSphere: function ( sphere ) {
16991
16992 return this.distanceToPoint( sphere.center ) <= sphere.radius;
16993
16994 },
16995
16996 distanceToPlane: function ( plane ) {
16997
16998 var denominator = plane.normal.dot( this.direction );
16999
17000 if ( denominator === 0 ) {
17001
17002 // line is coplanar, return origin
17003 if ( plane.distanceToPoint( this.origin ) === 0 ) {
17004
17005 return 0;
17006
17007 }
17008
17009 // Null is preferable to undefined since undefined means.... it is undefined
17010
17011 return null;
17012
17013 }
17014
17015 var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;
17016
17017 // Return if the ray never intersects the plane
17018
17019 return t >= 0 ? t : null;
17020
17021 },
17022
17023 intersectPlane: function ( plane, optionalTarget ) {
17024
17025 var t = this.distanceToPlane( plane );
17026
17027 if ( t === null ) {
17028
17029 return null;
17030
17031 }
17032
17033 return this.at( t, optionalTarget );
17034
17035 },
17036
17037 intersectsPlane: function ( plane ) {
17038
17039 // check if the ray lies on the plane first
17040
17041 var distToPoint = plane.distanceToPoint( this.origin );
17042
17043 if ( distToPoint === 0 ) {
17044
17045 return true;
17046
17047 }
17048
17049 var denominator = plane.normal.dot( this.direction );
17050
17051 if ( denominator * distToPoint < 0 ) {
17052
17053 return true;
17054
17055 }
17056
17057 // ray origin is behind the plane (and is pointing behind it)
17058
17059 return false;
17060
17061 },
17062
17063 intersectBox: function ( box, optionalTarget ) {
17064
17065 var tmin, tmax, tymin, tymax, tzmin, tzmax;
17066
17067 var invdirx = 1 / this.direction.x,
17068 invdiry = 1 / this.direction.y,
17069 invdirz = 1 / this.direction.z;
17070
17071 var origin = this.origin;
17072
17073 if ( invdirx >= 0 ) {
17074
17075 tmin = ( box.min.x - origin.x ) * invdirx;
17076 tmax = ( box.max.x - origin.x ) * invdirx;
17077
17078 } else {
17079
17080 tmin = ( box.max.x - origin.x ) * invdirx;
17081 tmax = ( box.min.x - origin.x ) * invdirx;
17082
17083 }
17084
17085 if ( invdiry >= 0 ) {
17086
17087 tymin = ( box.min.y - origin.y ) * invdiry;
17088 tymax = ( box.max.y - origin.y ) * invdiry;
17089
17090 } else {
17091
17092 tymin = ( box.max.y - origin.y ) * invdiry;
17093 tymax = ( box.min.y - origin.y ) * invdiry;
17094
17095 }
17096
17097 if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;
17098
17099 // These lines also handle the case where tmin or tmax is NaN
17100 // (result of 0 * Infinity). x !== x returns true if x is NaN
17101
17102 if ( tymin > tmin || tmin !== tmin ) tmin = tymin;
17103
17104 if ( tymax < tmax || tmax !== tmax ) tmax = tymax;
17105
17106 if ( invdirz >= 0 ) {
17107
17108 tzmin = ( box.min.z - origin.z ) * invdirz;
17109 tzmax = ( box.max.z - origin.z ) * invdirz;
17110
17111 } else {
17112
17113 tzmin = ( box.max.z - origin.z ) * invdirz;
17114 tzmax = ( box.min.z - origin.z ) * invdirz;
17115
17116 }
17117
17118 if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;
17119
17120 if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;
17121
17122 if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;
17123
17124 //return point closest to the ray (positive side)
17125
17126 if ( tmax < 0 ) return null;
17127
17128 return this.at( tmin >= 0 ? tmin : tmax, optionalTarget );
17129
17130 },
17131
17132 intersectsBox: ( function () {
17133
17134 var v = new Vector3();
17135
17136 return function intersectsBox( box ) {
17137
17138 return this.intersectBox( box, v ) !== null;
17139
17140 };
17141
17142 } )(),
17143
17144 intersectTriangle: function () {
17145
17146 // Compute the offset origin, edges, and normal.
17147 var diff = new Vector3();
17148 var edge1 = new Vector3();
17149 var edge2 = new Vector3();
17150 var normal = new Vector3();
17151
17152 return function intersectTriangle( a, b, c, backfaceCulling, optionalTarget ) {
17153
17154 // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
17155
17156 edge1.subVectors( b, a );
17157 edge2.subVectors( c, a );
17158 normal.crossVectors( edge1, edge2 );
17159
17160 // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
17161 // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
17162 // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
17163 // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
17164 // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
17165 var DdN = this.direction.dot( normal );
17166 var sign;
17167
17168 if ( DdN > 0 ) {
17169
17170 if ( backfaceCulling ) return null;
17171 sign = 1;
17172
17173 } else if ( DdN < 0 ) {
17174
17175 sign = - 1;
17176 DdN = - DdN;
17177
17178 } else {
17179
17180 return null;
17181
17182 }
17183
17184 diff.subVectors( this.origin, a );
17185 var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) );
17186
17187 // b1 < 0, no intersection
17188 if ( DdQxE2 < 0 ) {
17189
17190 return null;
17191
17192 }
17193
17194 var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) );
17195
17196 // b2 < 0, no intersection
17197 if ( DdE1xQ < 0 ) {
17198
17199 return null;
17200
17201 }
17202
17203 // b1+b2 > 1, no intersection
17204 if ( DdQxE2 + DdE1xQ > DdN ) {
17205
17206 return null;
17207
17208 }
17209
17210 // Line intersects triangle, check if ray does.
17211 var QdN = - sign * diff.dot( normal );
17212
17213 // t < 0, no intersection
17214 if ( QdN < 0 ) {
17215
17216 return null;
17217
17218 }
17219
17220 // Ray intersects triangle.
17221 return this.at( QdN / DdN, optionalTarget );
17222
17223 };
17224
17225 }(),
17226
17227 applyMatrix4: function ( matrix4 ) {
17228
17229 this.origin.applyMatrix4( matrix4 );
17230 this.direction.transformDirection( matrix4 );
17231
17232 return this;
17233
17234 },
17235
17236 equals: function ( ray ) {
17237
17238 return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
17239
17240 }
17241
17242} );
17243
17244/**
17245 * @author bhouston / http://clara.io
17246 */
17247
17248function Line3( start, end ) {
17249
17250 this.start = ( start !== undefined ) ? start : new Vector3();
17251 this.end = ( end !== undefined ) ? end : new Vector3();
17252
17253}
17254
17255Object.assign( Line3.prototype, {
17256
17257 set: function ( start, end ) {
17258
17259 this.start.copy( start );
17260 this.end.copy( end );
17261
17262 return this;
17263
17264 },
17265
17266 clone: function () {
17267
17268 return new this.constructor().copy( this );
17269
17270 },
17271
17272 copy: function ( line ) {
17273
17274 this.start.copy( line.start );
17275 this.end.copy( line.end );
17276
17277 return this;
17278
17279 },
17280
17281 getCenter: function ( optionalTarget ) {
17282
17283 var result = optionalTarget || new Vector3();
17284 return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 );
17285
17286 },
17287
17288 delta: function ( optionalTarget ) {
17289
17290 var result = optionalTarget || new Vector3();
17291 return result.subVectors( this.end, this.start );
17292
17293 },
17294
17295 distanceSq: function () {
17296
17297 return this.start.distanceToSquared( this.end );
17298
17299 },
17300
17301 distance: function () {
17302
17303 return this.start.distanceTo( this.end );
17304
17305 },
17306
17307 at: function ( t, optionalTarget ) {
17308
17309 var result = optionalTarget || new Vector3();
17310
17311 return this.delta( result ).multiplyScalar( t ).add( this.start );
17312
17313 },
17314
17315 closestPointToPointParameter: function () {
17316
17317 var startP = new Vector3();
17318 var startEnd = new Vector3();
17319
17320 return function closestPointToPointParameter( point, clampToLine ) {
17321
17322 startP.subVectors( point, this.start );
17323 startEnd.subVectors( this.end, this.start );
17324
17325 var startEnd2 = startEnd.dot( startEnd );
17326 var startEnd_startP = startEnd.dot( startP );
17327
17328 var t = startEnd_startP / startEnd2;
17329
17330 if ( clampToLine ) {
17331
17332 t = _Math.clamp( t, 0, 1 );
17333
17334 }
17335
17336 return t;
17337
17338 };
17339
17340 }(),
17341
17342 closestPointToPoint: function ( point, clampToLine, optionalTarget ) {
17343
17344 var t = this.closestPointToPointParameter( point, clampToLine );
17345
17346 var result = optionalTarget || new Vector3();
17347
17348 return this.delta( result ).multiplyScalar( t ).add( this.start );
17349
17350 },
17351
17352 applyMatrix4: function ( matrix ) {
17353
17354 this.start.applyMatrix4( matrix );
17355 this.end.applyMatrix4( matrix );
17356
17357 return this;
17358
17359 },
17360
17361 equals: function ( line ) {
17362
17363 return line.start.equals( this.start ) && line.end.equals( this.end );
17364
17365 }
17366
17367} );
17368
17369/**
17370 * @author bhouston / http://clara.io
17371 * @author mrdoob / http://mrdoob.com/
17372 */
17373
17374function Triangle( a, b, c ) {
17375
17376 this.a = ( a !== undefined ) ? a : new Vector3();
17377 this.b = ( b !== undefined ) ? b : new Vector3();
17378 this.c = ( c !== undefined ) ? c : new Vector3();
17379
17380}
17381
17382Object.assign( Triangle, {
17383
17384 normal: function () {
17385
17386 var v0 = new Vector3();
17387
17388 return function normal( a, b, c, optionalTarget ) {
17389
17390 var result = optionalTarget || new Vector3();
17391
17392 result.subVectors( c, b );
17393 v0.subVectors( a, b );
17394 result.cross( v0 );
17395
17396 var resultLengthSq = result.lengthSq();
17397 if ( resultLengthSq > 0 ) {
17398
17399 return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) );
17400
17401 }
17402
17403 return result.set( 0, 0, 0 );
17404
17405 };
17406
17407 }(),
17408
17409 // static/instance method to calculate barycentric coordinates
17410 // based on: http://www.blackpawn.com/texts/pointinpoly/default.html
17411 barycoordFromPoint: function () {
17412
17413 var v0 = new Vector3();
17414 var v1 = new Vector3();
17415 var v2 = new Vector3();
17416
17417 return function barycoordFromPoint( point, a, b, c, optionalTarget ) {
17418
17419 v0.subVectors( c, a );
17420 v1.subVectors( b, a );
17421 v2.subVectors( point, a );
17422
17423 var dot00 = v0.dot( v0 );
17424 var dot01 = v0.dot( v1 );
17425 var dot02 = v0.dot( v2 );
17426 var dot11 = v1.dot( v1 );
17427 var dot12 = v1.dot( v2 );
17428
17429 var denom = ( dot00 * dot11 - dot01 * dot01 );
17430
17431 var result = optionalTarget || new Vector3();
17432
17433 // collinear or singular triangle
17434 if ( denom === 0 ) {
17435
17436 // arbitrary location outside of triangle?
17437 // not sure if this is the best idea, maybe should be returning undefined
17438 return result.set( - 2, - 1, - 1 );
17439
17440 }
17441
17442 var invDenom = 1 / denom;
17443 var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
17444 var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
17445
17446 // barycentric coordinates must always sum to 1
17447 return result.set( 1 - u - v, v, u );
17448
17449 };
17450
17451 }(),
17452
17453 containsPoint: function () {
17454
17455 var v1 = new Vector3();
17456
17457 return function containsPoint( point, a, b, c ) {
17458
17459 var result = Triangle.barycoordFromPoint( point, a, b, c, v1 );
17460
17461 return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 );
17462
17463 };
17464
17465 }()
17466
17467} );
17468
17469Object.assign( Triangle.prototype, {
17470
17471 set: function ( a, b, c ) {
17472
17473 this.a.copy( a );
17474 this.b.copy( b );
17475 this.c.copy( c );
17476
17477 return this;
17478
17479 },
17480
17481 setFromPointsAndIndices: function ( points, i0, i1, i2 ) {
17482
17483 this.a.copy( points[ i0 ] );
17484 this.b.copy( points[ i1 ] );
17485 this.c.copy( points[ i2 ] );
17486
17487 return this;
17488
17489 },
17490
17491 clone: function () {
17492
17493 return new this.constructor().copy( this );
17494
17495 },
17496
17497 copy: function ( triangle ) {
17498
17499 this.a.copy( triangle.a );
17500 this.b.copy( triangle.b );
17501 this.c.copy( triangle.c );
17502
17503 return this;
17504
17505 },
17506
17507 area: function () {
17508
17509 var v0 = new Vector3();
17510 var v1 = new Vector3();
17511
17512 return function area() {
17513
17514 v0.subVectors( this.c, this.b );
17515 v1.subVectors( this.a, this.b );
17516
17517 return v0.cross( v1 ).length() * 0.5;
17518
17519 };
17520
17521 }(),
17522
17523 midpoint: function ( optionalTarget ) {
17524
17525 var result = optionalTarget || new Vector3();
17526 return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
17527
17528 },
17529
17530 normal: function ( optionalTarget ) {
17531
17532 return Triangle.normal( this.a, this.b, this.c, optionalTarget );
17533
17534 },
17535
17536 plane: function ( optionalTarget ) {
17537
17538 var result = optionalTarget || new Plane();
17539
17540 return result.setFromCoplanarPoints( this.a, this.b, this.c );
17541
17542 },
17543
17544 barycoordFromPoint: function ( point, optionalTarget ) {
17545
17546 return Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget );
17547
17548 },
17549
17550 containsPoint: function ( point ) {
17551
17552 return Triangle.containsPoint( point, this.a, this.b, this.c );
17553
17554 },
17555
17556 closestPointToPoint: function () {
17557
17558 var plane = new Plane();
17559 var edgeList = [ new Line3(), new Line3(), new Line3() ];
17560 var projectedPoint = new Vector3();
17561 var closestPoint = new Vector3();
17562
17563 return function closestPointToPoint( point, optionalTarget ) {
17564
17565 var result = optionalTarget || new Vector3();
17566 var minDistance = Infinity;
17567
17568 // project the point onto the plane of the triangle
17569
17570 plane.setFromCoplanarPoints( this.a, this.b, this.c );
17571 plane.projectPoint( point, projectedPoint );
17572
17573 // check if the projection lies within the triangle
17574
17575 if ( this.containsPoint( projectedPoint ) === true ) {
17576
17577 // if so, this is the closest point
17578
17579 result.copy( projectedPoint );
17580
17581 } else {
17582
17583 // if not, the point falls outside the triangle. the result is the closest point to the triangle's edges or vertices
17584
17585 edgeList[ 0 ].set( this.a, this.b );
17586 edgeList[ 1 ].set( this.b, this.c );
17587 edgeList[ 2 ].set( this.c, this.a );
17588
17589 for ( var i = 0; i < edgeList.length; i ++ ) {
17590
17591 edgeList[ i ].closestPointToPoint( projectedPoint, true, closestPoint );
17592
17593 var distance = projectedPoint.distanceToSquared( closestPoint );
17594
17595 if ( distance < minDistance ) {
17596
17597 minDistance = distance;
17598
17599 result.copy( closestPoint );
17600
17601 }
17602
17603 }
17604
17605 }
17606
17607 return result;
17608
17609 };
17610
17611 }(),
17612
17613 equals: function ( triangle ) {
17614
17615 return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
17616
17617 }
17618
17619} );
17620
17621/**
17622 * @author mrdoob / http://mrdoob.com/
17623 * @author alteredq / http://alteredqualia.com/
17624 * @author mikael emtinger / http://gomo.se/
17625 * @author jonobr1 / http://jonobr1.com/
17626 */
17627
17628function Mesh( geometry, material ) {
17629
17630 Object3D.call( this );
17631
17632 this.type = 'Mesh';
17633
17634 this.geometry = geometry !== undefined ? geometry : new BufferGeometry();
17635 this.material = material !== undefined ? material : new MeshBasicMaterial( { color: Math.random() * 0xffffff } );
17636
17637 this.drawMode = TrianglesDrawMode;
17638
17639 this.updateMorphTargets();
17640
17641}
17642
17643Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), {
17644
17645 constructor: Mesh,
17646
17647 isMesh: true,
17648
17649 setDrawMode: function ( value ) {
17650
17651 this.drawMode = value;
17652
17653 },
17654
17655 copy: function ( source ) {
17656
17657 Object3D.prototype.copy.call( this, source );
17658
17659 this.drawMode = source.drawMode;
17660
17661 if ( source.morphTargetInfluences !== undefined ) {
17662
17663 this.morphTargetInfluences = source.morphTargetInfluences.slice();
17664
17665 }
17666
17667 if ( source.morphTargetDictionary !== undefined ) {
17668
17669 this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary );
17670
17671 }
17672
17673 return this;
17674
17675 },
17676
17677 updateMorphTargets: function () {
17678
17679 var geometry = this.geometry;
17680 var m, ml, name;
17681
17682 if ( geometry.isBufferGeometry ) {
17683
17684 var morphAttributes = geometry.morphAttributes;
17685 var keys = Object.keys( morphAttributes );
17686
17687 if ( keys.length > 0 ) {
17688
17689 var morphAttribute = morphAttributes[ keys[ 0 ] ];
17690
17691 if ( morphAttribute !== undefined ) {
17692
17693 this.morphTargetInfluences = [];
17694 this.morphTargetDictionary = {};
17695
17696 for ( m = 0, ml = morphAttribute.length; m < ml; m ++ ) {
17697
17698 name = morphAttribute[ m ].name || String( m );
17699
17700 this.morphTargetInfluences.push( 0 );
17701 this.morphTargetDictionary[ name ] = m;
17702
17703 }
17704
17705 }
17706
17707 }
17708
17709 } else {
17710
17711 var morphTargets = geometry.morphTargets;
17712
17713 if ( morphTargets !== undefined && morphTargets.length > 0 ) {
17714
17715 this.morphTargetInfluences = [];
17716 this.morphTargetDictionary = {};
17717
17718 for ( m = 0, ml = morphTargets.length; m < ml; m ++ ) {
17719
17720 name = morphTargets[ m ].name || String( m );
17721
17722 this.morphTargetInfluences.push( 0 );
17723 this.morphTargetDictionary[ name ] = m;
17724
17725 }
17726
17727 }
17728
17729 }
17730
17731 },
17732
17733 raycast: ( function () {
17734
17735 var inverseMatrix = new Matrix4();
17736 var ray = new Ray();
17737 var sphere = new Sphere();
17738
17739 var vA = new Vector3();
17740 var vB = new Vector3();
17741 var vC = new Vector3();
17742
17743 var tempA = new Vector3();
17744 var tempB = new Vector3();
17745 var tempC = new Vector3();
17746
17747 var uvA = new Vector2();
17748 var uvB = new Vector2();
17749 var uvC = new Vector2();
17750
17751 var barycoord = new Vector3();
17752
17753 var intersectionPoint = new Vector3();
17754 var intersectionPointWorld = new Vector3();
17755
17756 function uvIntersection( point, p1, p2, p3, uv1, uv2, uv3 ) {
17757
17758 Triangle.barycoordFromPoint( point, p1, p2, p3, barycoord );
17759
17760 uv1.multiplyScalar( barycoord.x );
17761 uv2.multiplyScalar( barycoord.y );
17762 uv3.multiplyScalar( barycoord.z );
17763
17764 uv1.add( uv2 ).add( uv3 );
17765
17766 return uv1.clone();
17767
17768 }
17769
17770 function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) {
17771
17772 var intersect;
17773
17774 if ( material.side === BackSide ) {
17775
17776 intersect = ray.intersectTriangle( pC, pB, pA, true, point );
17777
17778 } else {
17779
17780 intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point );
17781
17782 }
17783
17784 if ( intersect === null ) return null;
17785
17786 intersectionPointWorld.copy( point );
17787 intersectionPointWorld.applyMatrix4( object.matrixWorld );
17788
17789 var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld );
17790
17791 if ( distance < raycaster.near || distance > raycaster.far ) return null;
17792
17793 return {
17794 distance: distance,
17795 point: intersectionPointWorld.clone(),
17796 object: object
17797 };
17798
17799 }
17800
17801 function checkBufferGeometryIntersection( object, raycaster, ray, position, uv, a, b, c ) {
17802
17803 vA.fromBufferAttribute( position, a );
17804 vB.fromBufferAttribute( position, b );
17805 vC.fromBufferAttribute( position, c );
17806
17807 var intersection = checkIntersection( object, object.material, raycaster, ray, vA, vB, vC, intersectionPoint );
17808
17809 if ( intersection ) {
17810
17811 if ( uv ) {
17812
17813 uvA.fromBufferAttribute( uv, a );
17814 uvB.fromBufferAttribute( uv, b );
17815 uvC.fromBufferAttribute( uv, c );
17816
17817 intersection.uv = uvIntersection( intersectionPoint, vA, vB, vC, uvA, uvB, uvC );
17818
17819 }
17820
17821 intersection.face = new Face3( a, b, c, Triangle.normal( vA, vB, vC ) );
17822 intersection.faceIndex = a;
17823
17824 }
17825
17826 return intersection;
17827
17828 }
17829
17830 return function raycast( raycaster, intersects ) {
17831
17832 var geometry = this.geometry;
17833 var material = this.material;
17834 var matrixWorld = this.matrixWorld;
17835
17836 if ( material === undefined ) return;
17837
17838 // Checking boundingSphere distance to ray
17839
17840 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
17841
17842 sphere.copy( geometry.boundingSphere );
17843 sphere.applyMatrix4( matrixWorld );
17844
17845 if ( raycaster.ray.intersectsSphere( sphere ) === false ) return;
17846
17847 //
17848
17849 inverseMatrix.getInverse( matrixWorld );
17850 ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
17851
17852 // Check boundingBox before continuing
17853
17854 if ( geometry.boundingBox !== null ) {
17855
17856 if ( ray.intersectsBox( geometry.boundingBox ) === false ) return;
17857
17858 }
17859
17860 var intersection;
17861
17862 if ( geometry.isBufferGeometry ) {
17863
17864 var a, b, c;
17865 var index = geometry.index;
17866 var position = geometry.attributes.position;
17867 var uv = geometry.attributes.uv;
17868 var i, l;
17869
17870 if ( index !== null ) {
17871
17872 // indexed buffer geometry
17873
17874 for ( i = 0, l = index.count; i < l; i += 3 ) {
17875
17876 a = index.getX( i );
17877 b = index.getX( i + 1 );
17878 c = index.getX( i + 2 );
17879
17880 intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );
17881
17882 if ( intersection ) {
17883
17884 intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indices buffer semantics
17885 intersects.push( intersection );
17886
17887 }
17888
17889 }
17890
17891 } else if ( position !== undefined ) {
17892
17893 // non-indexed buffer geometry
17894
17895 for ( i = 0, l = position.count; i < l; i += 3 ) {
17896
17897 a = i;
17898 b = i + 1;
17899 c = i + 2;
17900
17901 intersection = checkBufferGeometryIntersection( this, raycaster, ray, position, uv, a, b, c );
17902
17903 if ( intersection ) {
17904
17905 intersection.index = a; // triangle number in positions buffer semantics
17906 intersects.push( intersection );
17907
17908 }
17909
17910 }
17911
17912 }
17913
17914 } else if ( geometry.isGeometry ) {
17915
17916 var fvA, fvB, fvC;
17917 var isMultiMaterial = Array.isArray( material );
17918
17919 var vertices = geometry.vertices;
17920 var faces = geometry.faces;
17921 var uvs;
17922
17923 var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
17924 if ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs;
17925
17926 for ( var f = 0, fl = faces.length; f < fl; f ++ ) {
17927
17928 var face = faces[ f ];
17929 var faceMaterial = isMultiMaterial ? material[ face.materialIndex ] : material;
17930
17931 if ( faceMaterial === undefined ) continue;
17932
17933 fvA = vertices[ face.a ];
17934 fvB = vertices[ face.b ];
17935 fvC = vertices[ face.c ];
17936
17937 if ( faceMaterial.morphTargets === true ) {
17938
17939 var morphTargets = geometry.morphTargets;
17940 var morphInfluences = this.morphTargetInfluences;
17941
17942 vA.set( 0, 0, 0 );
17943 vB.set( 0, 0, 0 );
17944 vC.set( 0, 0, 0 );
17945
17946 for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
17947
17948 var influence = morphInfluences[ t ];
17949
17950 if ( influence === 0 ) continue;
17951
17952 var targets = morphTargets[ t ].vertices;
17953
17954 vA.addScaledVector( tempA.subVectors( targets[ face.a ], fvA ), influence );
17955 vB.addScaledVector( tempB.subVectors( targets[ face.b ], fvB ), influence );
17956 vC.addScaledVector( tempC.subVectors( targets[ face.c ], fvC ), influence );
17957
17958 }
17959
17960 vA.add( fvA );
17961 vB.add( fvB );
17962 vC.add( fvC );
17963
17964 fvA = vA;
17965 fvB = vB;
17966 fvC = vC;
17967
17968 }
17969
17970 intersection = checkIntersection( this, faceMaterial, raycaster, ray, fvA, fvB, fvC, intersectionPoint );
17971
17972 if ( intersection ) {
17973
17974 if ( uvs && uvs[ f ] ) {
17975
17976 var uvs_f = uvs[ f ];
17977 uvA.copy( uvs_f[ 0 ] );
17978 uvB.copy( uvs_f[ 1 ] );
17979 uvC.copy( uvs_f[ 2 ] );
17980
17981 intersection.uv = uvIntersection( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC );
17982
17983 }
17984
17985 intersection.face = face;
17986 intersection.faceIndex = f;
17987 intersects.push( intersection );
17988
17989 }
17990
17991 }
17992
17993 }
17994
17995 };
17996
17997 }() ),
17998
17999 clone: function () {
18000
18001 return new this.constructor( this.geometry, this.material ).copy( this );
18002
18003 }
18004
18005} );
18006
18007/**
18008 * @author mrdoob / http://mrdoob.com/
18009 */
18010
18011function WebGLBackground( renderer, state, geometries, premultipliedAlpha ) {
18012
18013 var clearColor = new Color( 0x000000 );
18014 var clearAlpha = 0;
18015
18016 var planeCamera, planeMesh;
18017 var boxMesh;
18018
18019 function render( renderList, scene, camera, forceClear ) {
18020
18021 var background = scene.background;
18022
18023 if ( background === null ) {
18024
18025 setClear( clearColor, clearAlpha );
18026
18027 } else if ( background && background.isColor ) {
18028
18029 setClear( background, 1 );
18030 forceClear = true;
18031
18032 }
18033
18034 if ( renderer.autoClear || forceClear ) {
18035
18036 renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
18037
18038 }
18039
18040 if ( background && background.isCubeTexture ) {
18041
18042 if ( boxMesh === undefined ) {
18043
18044 boxMesh = new Mesh(
18045 new BoxBufferGeometry( 1, 1, 1 ),
18046 new ShaderMaterial( {
18047 uniforms: ShaderLib.cube.uniforms,
18048 vertexShader: ShaderLib.cube.vertexShader,
18049 fragmentShader: ShaderLib.cube.fragmentShader,
18050 side: BackSide,
18051 depthTest: true,
18052 depthWrite: false,
18053 fog: false
18054 } )
18055 );
18056
18057 boxMesh.geometry.removeAttribute( 'normal' );
18058 boxMesh.geometry.removeAttribute( 'uv' );
18059
18060 boxMesh.onBeforeRender = function ( renderer, scene, camera ) {
18061
18062 this.matrixWorld.copyPosition( camera.matrixWorld );
18063
18064 };
18065
18066 geometries.update( boxMesh.geometry );
18067
18068 }
18069
18070 boxMesh.material.uniforms.tCube.value = background;
18071
18072 renderList.push( boxMesh, boxMesh.geometry, boxMesh.material, 0, null );
18073
18074 } else if ( background && background.isTexture ) {
18075
18076 if ( planeCamera === undefined ) {
18077
18078 planeCamera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
18079
18080 planeMesh = new Mesh(
18081 new PlaneBufferGeometry( 2, 2 ),
18082 new MeshBasicMaterial( { depthTest: false, depthWrite: false, fog: false } )
18083 );
18084
18085 geometries.update( planeMesh.geometry );
18086
18087 }
18088
18089 planeMesh.material.map = background;
18090
18091 // TODO Push this to renderList
18092
18093 renderer.renderBufferDirect( planeCamera, null, planeMesh.geometry, planeMesh.material, planeMesh, null );
18094
18095 }
18096
18097 }
18098
18099 function setClear( color, alpha ) {
18100
18101 state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha );
18102
18103 }
18104
18105 return {
18106
18107 getClearColor: function () {
18108
18109 return clearColor;
18110
18111 },
18112 setClearColor: function ( color, alpha ) {
18113
18114 clearColor.set( color );
18115 clearAlpha = alpha !== undefined ? alpha : 1;
18116 setClear( clearColor, clearAlpha );
18117
18118 },
18119 getClearAlpha: function () {
18120
18121 return clearAlpha;
18122
18123 },
18124 setClearAlpha: function ( alpha ) {
18125
18126 clearAlpha = alpha;
18127 setClear( clearColor, clearAlpha );
18128
18129 },
18130 render: render
18131
18132 };
18133
18134}
18135
18136/**
18137 * @author mrdoob / http://mrdoob.com/
18138 */
18139
18140function painterSortStable( a, b ) {
18141
18142 if ( a.renderOrder !== b.renderOrder ) {
18143
18144 return a.renderOrder - b.renderOrder;
18145
18146 } else if ( a.program && b.program && a.program !== b.program ) {
18147
18148 return a.program.id - b.program.id;
18149
18150 } else if ( a.material.id !== b.material.id ) {
18151
18152 return a.material.id - b.material.id;
18153
18154 } else if ( a.z !== b.z ) {
18155
18156 return a.z - b.z;
18157
18158 } else {
18159
18160 return a.id - b.id;
18161
18162 }
18163
18164}
18165
18166function reversePainterSortStable( a, b ) {
18167
18168 if ( a.renderOrder !== b.renderOrder ) {
18169
18170 return a.renderOrder - b.renderOrder;
18171
18172 } if ( a.z !== b.z ) {
18173
18174 return b.z - a.z;
18175
18176 } else {
18177
18178 return a.id - b.id;
18179
18180 }
18181
18182}
18183
18184function WebGLRenderList() {
18185
18186 var renderItems = [];
18187 var renderItemsIndex = 0;
18188
18189 var opaque = [];
18190 var transparent = [];
18191
18192 function init() {
18193
18194 renderItemsIndex = 0;
18195
18196 opaque.length = 0;
18197 transparent.length = 0;
18198
18199 }
18200
18201 function push( object, geometry, material, z, group ) {
18202
18203 var renderItem = renderItems[ renderItemsIndex ];
18204
18205 if ( renderItem === undefined ) {
18206
18207 renderItem = {
18208 id: object.id,
18209 object: object,
18210 geometry: geometry,
18211 material: material,
18212 program: material.program,
18213 renderOrder: object.renderOrder,
18214 z: z,
18215 group: group
18216 };
18217
18218 renderItems[ renderItemsIndex ] = renderItem;
18219
18220 } else {
18221
18222 renderItem.id = object.id;
18223 renderItem.object = object;
18224 renderItem.geometry = geometry;
18225 renderItem.material = material;
18226 renderItem.program = material.program;
18227 renderItem.renderOrder = object.renderOrder;
18228 renderItem.z = z;
18229 renderItem.group = group;
18230
18231 }
18232
18233 ( material.transparent === true ? transparent : opaque ).push( renderItem );
18234
18235 renderItemsIndex ++;
18236
18237 }
18238
18239 function sort() {
18240
18241 if ( opaque.length > 1 ) opaque.sort( painterSortStable );
18242 if ( transparent.length > 1 ) transparent.sort( reversePainterSortStable );
18243
18244 }
18245
18246 return {
18247 opaque: opaque,
18248 transparent: transparent,
18249
18250 init: init,
18251 push: push,
18252
18253 sort: sort
18254 };
18255
18256}
18257
18258function WebGLRenderLists() {
18259
18260 var lists = {};
18261
18262 function get( scene, camera ) {
18263
18264 var hash = scene.id + ',' + camera.id;
18265 var list = lists[ hash ];
18266
18267 if ( list === undefined ) {
18268
18269 // console.log( 'THREE.WebGLRenderLists:', hash );
18270
18271 list = new WebGLRenderList();
18272 lists[ hash ] = list;
18273
18274 }
18275
18276 return list;
18277
18278 }
18279
18280 function dispose() {
18281
18282 lists = {};
18283
18284 }
18285
18286 return {
18287 get: get,
18288 dispose: dispose
18289 };
18290
18291}
18292
18293/**
18294 * @author mrdoob / http://mrdoob.com/
18295 */
18296
18297function absNumericalSort( a, b ) {
18298
18299 return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] );
18300
18301}
18302
18303function WebGLMorphtargets( gl ) {
18304
18305 var influencesList = {};
18306 var morphInfluences = new Float32Array( 8 );
18307
18308 function update( object, geometry, material, program ) {
18309
18310 var objectInfluences = object.morphTargetInfluences;
18311
18312 var length = objectInfluences.length;
18313
18314 var influences = influencesList[ geometry.id ];
18315
18316 if ( influences === undefined ) {
18317
18318 // initialise list
18319
18320 influences = [];
18321
18322 for ( var i = 0; i < length; i ++ ) {
18323
18324 influences[ i ] = [ i, 0 ];
18325
18326 }
18327
18328 influencesList[ geometry.id ] = influences;
18329
18330 }
18331
18332 var morphTargets = material.morphTargets && geometry.morphAttributes.position;
18333 var morphNormals = material.morphNormals && geometry.morphAttributes.normal;
18334
18335 // Remove current morphAttributes
18336
18337 for ( var i = 0; i < length; i ++ ) {
18338
18339 var influence = influences[ i ];
18340
18341 if ( influence[ 1 ] !== 0 ) {
18342
18343 if ( morphTargets ) geometry.removeAttribute( 'morphTarget' + i );
18344 if ( morphNormals ) geometry.removeAttribute( 'morphNormal' + i );
18345
18346 }
18347
18348 }
18349
18350 // Collect influences
18351
18352 for ( var i = 0; i < length; i ++ ) {
18353
18354 var influence = influences[ i ];
18355
18356 influence[ 0 ] = i;
18357 influence[ 1 ] = objectInfluences[ i ];
18358
18359 }
18360
18361 influences.sort( absNumericalSort );
18362
18363 // Add morphAttributes
18364
18365 for ( var i = 0; i < 8; i ++ ) {
18366
18367 var influence = influences[ i ];
18368
18369 if ( influence ) {
18370
18371 var index = influence[ 0 ];
18372 var value = influence[ 1 ];
18373
18374 if ( value ) {
18375
18376 if ( morphTargets ) geometry.addAttribute( 'morphTarget' + i, morphTargets[ index ] );
18377 if ( morphNormals ) geometry.addAttribute( 'morphNormal' + i, morphNormals[ index ] );
18378
18379 morphInfluences[ i ] = value;
18380 continue;
18381
18382 }
18383
18384 }
18385
18386 morphInfluences[ i ] = 0;
18387
18388 }
18389
18390 program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences );
18391
18392 }
18393
18394 return {
18395
18396 update: update
18397
18398 };
18399
18400}
18401
18402/**
18403 * @author mrdoob / http://mrdoob.com/
18404 */
18405
18406function WebGLIndexedBufferRenderer( gl, extensions, infoRender ) {
18407
18408 var mode;
18409
18410 function setMode( value ) {
18411
18412 mode = value;
18413
18414 }
18415
18416 var type, bytesPerElement;
18417
18418 function setIndex( value ) {
18419
18420 type = value.type;
18421 bytesPerElement = value.bytesPerElement;
18422
18423 }
18424
18425 function render( start, count ) {
18426
18427 gl.drawElements( mode, count, type, start * bytesPerElement );
18428
18429 infoRender.calls ++;
18430 infoRender.vertices += count;
18431
18432 if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3;
18433 else if ( mode === gl.POINTS ) infoRender.points += count;
18434
18435 }
18436
18437 function renderInstances( geometry, start, count ) {
18438
18439 var extension = extensions.get( 'ANGLE_instanced_arrays' );
18440
18441 if ( extension === null ) {
18442
18443 console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
18444 return;
18445
18446 }
18447
18448 extension.drawElementsInstancedANGLE( mode, count, type, start * bytesPerElement, geometry.maxInstancedCount );
18449
18450 infoRender.calls ++;
18451 infoRender.vertices += count * geometry.maxInstancedCount;
18452
18453 if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3;
18454 else if ( mode === gl.POINTS ) infoRender.points += geometry.maxInstancedCount * count;
18455
18456 }
18457
18458 //
18459
18460 this.setMode = setMode;
18461 this.setIndex = setIndex;
18462 this.render = render;
18463 this.renderInstances = renderInstances;
18464
18465}
18466
18467/**
18468 * @author mrdoob / http://mrdoob.com/
18469 */
18470
18471function WebGLBufferRenderer( gl, extensions, infoRender ) {
18472
18473 var mode;
18474
18475 function setMode( value ) {
18476
18477 mode = value;
18478
18479 }
18480
18481 function render( start, count ) {
18482
18483 gl.drawArrays( mode, start, count );
18484
18485 infoRender.calls ++;
18486 infoRender.vertices += count;
18487
18488 if ( mode === gl.TRIANGLES ) infoRender.faces += count / 3;
18489 else if ( mode === gl.POINTS ) infoRender.points += count;
18490
18491 }
18492
18493 function renderInstances( geometry, start, count ) {
18494
18495 var extension = extensions.get( 'ANGLE_instanced_arrays' );
18496
18497 if ( extension === null ) {
18498
18499 console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
18500 return;
18501
18502 }
18503
18504 var position = geometry.attributes.position;
18505
18506 if ( position.isInterleavedBufferAttribute ) {
18507
18508 count = position.data.count;
18509
18510 extension.drawArraysInstancedANGLE( mode, 0, count, geometry.maxInstancedCount );
18511
18512 } else {
18513
18514 extension.drawArraysInstancedANGLE( mode, start, count, geometry.maxInstancedCount );
18515
18516 }
18517
18518 infoRender.calls ++;
18519 infoRender.vertices += count * geometry.maxInstancedCount;
18520
18521 if ( mode === gl.TRIANGLES ) infoRender.faces += geometry.maxInstancedCount * count / 3;
18522 else if ( mode === gl.POINTS ) infoRender.points += geometry.maxInstancedCount * count;
18523
18524 }
18525
18526 //
18527
18528 this.setMode = setMode;
18529 this.render = render;
18530 this.renderInstances = renderInstances;
18531
18532}
18533
18534/**
18535 * @author mrdoob / http://mrdoob.com/
18536 */
18537
18538function WebGLGeometries( gl, attributes, infoMemory ) {
18539
18540 var geometries = {};
18541 var wireframeAttributes = {};
18542
18543 function onGeometryDispose( event ) {
18544
18545 var geometry = event.target;
18546 var buffergeometry = geometries[ geometry.id ];
18547
18548 if ( buffergeometry.index !== null ) {
18549
18550 attributes.remove( buffergeometry.index );
18551
18552 }
18553
18554 for ( var name in buffergeometry.attributes ) {
18555
18556 attributes.remove( buffergeometry.attributes[ name ] );
18557
18558 }
18559
18560 geometry.removeEventListener( 'dispose', onGeometryDispose );
18561
18562 delete geometries[ geometry.id ];
18563
18564 // TODO Remove duplicate code
18565
18566 var attribute = wireframeAttributes[ geometry.id ];
18567
18568 if ( attribute ) {
18569
18570 attributes.remove( attribute );
18571 delete wireframeAttributes[ geometry.id ];
18572
18573 }
18574
18575 attribute = wireframeAttributes[ buffergeometry.id ];
18576
18577 if ( attribute ) {
18578
18579 attributes.remove( attribute );
18580 delete wireframeAttributes[ buffergeometry.id ];
18581
18582 }
18583
18584 //
18585
18586 infoMemory.geometries --;
18587
18588 }
18589
18590 function get( object, geometry ) {
18591
18592 var buffergeometry = geometries[ geometry.id ];
18593
18594 if ( buffergeometry ) return buffergeometry;
18595
18596 geometry.addEventListener( 'dispose', onGeometryDispose );
18597
18598 if ( geometry.isBufferGeometry ) {
18599
18600 buffergeometry = geometry;
18601
18602 } else if ( geometry.isGeometry ) {
18603
18604 if ( geometry._bufferGeometry === undefined ) {
18605
18606 geometry._bufferGeometry = new BufferGeometry().setFromObject( object );
18607
18608 }
18609
18610 buffergeometry = geometry._bufferGeometry;
18611
18612 }
18613
18614 geometries[ geometry.id ] = buffergeometry;
18615
18616 infoMemory.geometries ++;
18617
18618 return buffergeometry;
18619
18620 }
18621
18622 function update( geometry ) {
18623
18624 var index = geometry.index;
18625 var geometryAttributes = geometry.attributes;
18626
18627 if ( index !== null ) {
18628
18629 attributes.update( index, gl.ELEMENT_ARRAY_BUFFER );
18630
18631 }
18632
18633 for ( var name in geometryAttributes ) {
18634
18635 attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );
18636
18637 }
18638
18639 // morph targets
18640
18641 var morphAttributes = geometry.morphAttributes;
18642
18643 for ( var name in morphAttributes ) {
18644
18645 var array = morphAttributes[ name ];
18646
18647 for ( var i = 0, l = array.length; i < l; i ++ ) {
18648
18649 attributes.update( array[ i ], gl.ARRAY_BUFFER );
18650
18651 }
18652
18653 }
18654
18655 }
18656
18657 function getWireframeAttribute( geometry ) {
18658
18659 var attribute = wireframeAttributes[ geometry.id ];
18660
18661 if ( attribute ) return attribute;
18662
18663 var indices = [];
18664
18665 var geometryIndex = geometry.index;
18666 var geometryAttributes = geometry.attributes;
18667
18668 // console.time( 'wireframe' );
18669
18670 if ( geometryIndex !== null ) {
18671
18672 var array = geometryIndex.array;
18673
18674 for ( var i = 0, l = array.length; i < l; i += 3 ) {
18675
18676 var a = array[ i + 0 ];
18677 var b = array[ i + 1 ];
18678 var c = array[ i + 2 ];
18679
18680 indices.push( a, b, b, c, c, a );
18681
18682 }
18683
18684 } else {
18685
18686 var array = geometryAttributes.position.array;
18687
18688 for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
18689
18690 var a = i + 0;
18691 var b = i + 1;
18692 var c = i + 2;
18693
18694 indices.push( a, b, b, c, c, a );
18695
18696 }
18697
18698 }
18699
18700 // console.timeEnd( 'wireframe' );
18701
18702 attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
18703
18704 attributes.update( attribute, gl.ELEMENT_ARRAY_BUFFER );
18705
18706 wireframeAttributes[ geometry.id ] = attribute;
18707
18708 return attribute;
18709
18710 }
18711
18712 return {
18713
18714 get: get,
18715 update: update,
18716
18717 getWireframeAttribute: getWireframeAttribute
18718
18719 };
18720
18721}
18722
18723/**
18724 * @author mrdoob / http://mrdoob.com/
18725 */
18726
18727function UniformsCache() {
18728
18729 var lights = {};
18730
18731 return {
18732
18733 get: function ( light ) {
18734
18735 if ( lights[ light.id ] !== undefined ) {
18736
18737 return lights[ light.id ];
18738
18739 }
18740
18741 var uniforms;
18742
18743 switch ( light.type ) {
18744
18745 case 'DirectionalLight':
18746 uniforms = {
18747 direction: new Vector3(),
18748 color: new Color(),
18749
18750 shadow: false,
18751 shadowBias: 0,
18752 shadowRadius: 1,
18753 shadowMapSize: new Vector2()
18754 };
18755 break;
18756
18757 case 'SpotLight':
18758 uniforms = {
18759 position: new Vector3(),
18760 direction: new Vector3(),
18761 color: new Color(),
18762 distance: 0,
18763 coneCos: 0,
18764 penumbraCos: 0,
18765 decay: 0,
18766
18767 shadow: false,
18768 shadowBias: 0,
18769 shadowRadius: 1,
18770 shadowMapSize: new Vector2()
18771 };
18772 break;
18773
18774 case 'PointLight':
18775 uniforms = {
18776 position: new Vector3(),
18777 color: new Color(),
18778 distance: 0,
18779 decay: 0,
18780
18781 shadow: false,
18782 shadowBias: 0,
18783 shadowRadius: 1,
18784 shadowMapSize: new Vector2(),
18785 shadowCameraNear: 1,
18786 shadowCameraFar: 1000
18787 };
18788 break;
18789
18790 case 'HemisphereLight':
18791 uniforms = {
18792 direction: new Vector3(),
18793 skyColor: new Color(),
18794 groundColor: new Color()
18795 };
18796 break;
18797
18798 case 'RectAreaLight':
18799 uniforms = {
18800 color: new Color(),
18801 position: new Vector3(),
18802 halfWidth: new Vector3(),
18803 halfHeight: new Vector3()
18804 // TODO (abelnation): set RectAreaLight shadow uniforms
18805 };
18806 break;
18807
18808 }
18809
18810 lights[ light.id ] = uniforms;
18811
18812 return uniforms;
18813
18814 }
18815
18816 };
18817
18818}
18819
18820function WebGLLights() {
18821
18822 var cache = new UniformsCache();
18823
18824 var state = {
18825
18826 hash: '',
18827
18828 ambient: [ 0, 0, 0 ],
18829 directional: [],
18830 directionalShadowMap: [],
18831 directionalShadowMatrix: [],
18832 spot: [],
18833 spotShadowMap: [],
18834 spotShadowMatrix: [],
18835 rectArea: [],
18836 point: [],
18837 pointShadowMap: [],
18838 pointShadowMatrix: [],
18839 hemi: []
18840
18841 };
18842
18843 var vector3 = new Vector3();
18844 var matrix4 = new Matrix4();
18845 var matrix42 = new Matrix4();
18846
18847 function setup( lights, shadows, camera ) {
18848
18849 var r = 0, g = 0, b = 0;
18850
18851 var directionalLength = 0;
18852 var pointLength = 0;
18853 var spotLength = 0;
18854 var rectAreaLength = 0;
18855 var hemiLength = 0;
18856
18857 var viewMatrix = camera.matrixWorldInverse;
18858
18859 for ( var i = 0, l = lights.length; i < l; i ++ ) {
18860
18861 var light = lights[ i ];
18862
18863 var color = light.color;
18864 var intensity = light.intensity;
18865 var distance = light.distance;
18866
18867 var shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;
18868
18869 if ( light.isAmbientLight ) {
18870
18871 r += color.r * intensity;
18872 g += color.g * intensity;
18873 b += color.b * intensity;
18874
18875 } else if ( light.isDirectionalLight ) {
18876
18877 var uniforms = cache.get( light );
18878
18879 uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
18880 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
18881 vector3.setFromMatrixPosition( light.target.matrixWorld );
18882 uniforms.direction.sub( vector3 );
18883 uniforms.direction.transformDirection( viewMatrix );
18884
18885 uniforms.shadow = light.castShadow;
18886
18887 if ( light.castShadow ) {
18888
18889 var shadow = light.shadow;
18890
18891 uniforms.shadowBias = shadow.bias;
18892 uniforms.shadowRadius = shadow.radius;
18893 uniforms.shadowMapSize = shadow.mapSize;
18894
18895 }
18896
18897 state.directionalShadowMap[ directionalLength ] = shadowMap;
18898 state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
18899 state.directional[ directionalLength ] = uniforms;
18900
18901 directionalLength ++;
18902
18903 } else if ( light.isSpotLight ) {
18904
18905 var uniforms = cache.get( light );
18906
18907 uniforms.position.setFromMatrixPosition( light.matrixWorld );
18908 uniforms.position.applyMatrix4( viewMatrix );
18909
18910 uniforms.color.copy( color ).multiplyScalar( intensity );
18911 uniforms.distance = distance;
18912
18913 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
18914 vector3.setFromMatrixPosition( light.target.matrixWorld );
18915 uniforms.direction.sub( vector3 );
18916 uniforms.direction.transformDirection( viewMatrix );
18917
18918 uniforms.coneCos = Math.cos( light.angle );
18919 uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
18920 uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;
18921
18922 uniforms.shadow = light.castShadow;
18923
18924 if ( light.castShadow ) {
18925
18926 var shadow = light.shadow;
18927
18928 uniforms.shadowBias = shadow.bias;
18929 uniforms.shadowRadius = shadow.radius;
18930 uniforms.shadowMapSize = shadow.mapSize;
18931
18932 }
18933
18934 state.spotShadowMap[ spotLength ] = shadowMap;
18935 state.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
18936 state.spot[ spotLength ] = uniforms;
18937
18938 spotLength ++;
18939
18940 } else if ( light.isRectAreaLight ) {
18941
18942 var uniforms = cache.get( light );
18943
18944 // (a) intensity controls irradiance of entire light
18945 uniforms.color
18946 .copy( color )
18947 .multiplyScalar( intensity / ( light.width * light.height ) );
18948
18949 // (b) intensity controls the radiance per light area
18950 // uniforms.color.copy( color ).multiplyScalar( intensity );
18951
18952 uniforms.position.setFromMatrixPosition( light.matrixWorld );
18953 uniforms.position.applyMatrix4( viewMatrix );
18954
18955 // extract local rotation of light to derive width/height half vectors
18956 matrix42.identity();
18957 matrix4.copy( light.matrixWorld );
18958 matrix4.premultiply( viewMatrix );
18959 matrix42.extractRotation( matrix4 );
18960
18961 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
18962 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );
18963
18964 uniforms.halfWidth.applyMatrix4( matrix42 );
18965 uniforms.halfHeight.applyMatrix4( matrix42 );
18966
18967 // TODO (abelnation): RectAreaLight distance?
18968 // uniforms.distance = distance;
18969
18970 state.rectArea[ rectAreaLength ] = uniforms;
18971
18972 rectAreaLength ++;
18973
18974 } else if ( light.isPointLight ) {
18975
18976 var uniforms = cache.get( light );
18977
18978 uniforms.position.setFromMatrixPosition( light.matrixWorld );
18979 uniforms.position.applyMatrix4( viewMatrix );
18980
18981 uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
18982 uniforms.distance = light.distance;
18983 uniforms.decay = ( light.distance === 0 ) ? 0.0 : light.decay;
18984
18985 uniforms.shadow = light.castShadow;
18986
18987 if ( light.castShadow ) {
18988
18989 var shadow = light.shadow;
18990
18991 uniforms.shadowBias = shadow.bias;
18992 uniforms.shadowRadius = shadow.radius;
18993 uniforms.shadowMapSize = shadow.mapSize;
18994 uniforms.shadowCameraNear = shadow.camera.near;
18995 uniforms.shadowCameraFar = shadow.camera.far;
18996
18997 }
18998
18999 state.pointShadowMap[ pointLength ] = shadowMap;
19000 state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
19001 state.point[ pointLength ] = uniforms;
19002
19003 pointLength ++;
19004
19005 } else if ( light.isHemisphereLight ) {
19006
19007 var uniforms = cache.get( light );
19008
19009 uniforms.direction.setFromMatrixPosition( light.matrixWorld );
19010 uniforms.direction.transformDirection( viewMatrix );
19011 uniforms.direction.normalize();
19012
19013 uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
19014 uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );
19015
19016 state.hemi[ hemiLength ] = uniforms;
19017
19018 hemiLength ++;
19019
19020 }
19021
19022 }
19023
19024 state.ambient[ 0 ] = r;
19025 state.ambient[ 1 ] = g;
19026 state.ambient[ 2 ] = b;
19027
19028 state.directional.length = directionalLength;
19029 state.spot.length = spotLength;
19030 state.rectArea.length = rectAreaLength;
19031 state.point.length = pointLength;
19032 state.hemi.length = hemiLength;
19033
19034 // TODO (sam-g-steel) why aren't we using join
19035 state.hash = directionalLength + ',' + pointLength + ',' + spotLength + ',' + rectAreaLength + ',' + hemiLength + ',' + shadows.length;
19036
19037 }
19038
19039 return {
19040 setup: setup,
19041 state: state
19042 };
19043
19044}
19045
19046/**
19047 * @author mrdoob / http://mrdoob.com/
19048 */
19049
19050function WebGLObjects( geometries, infoRender ) {
19051
19052 var updateList = {};
19053
19054 function update( object ) {
19055
19056 var frame = infoRender.frame;
19057
19058 var geometry = object.geometry;
19059 var buffergeometry = geometries.get( object, geometry );
19060
19061 // Update once per frame
19062
19063 if ( updateList[ buffergeometry.id ] !== frame ) {
19064
19065 if ( geometry.isGeometry ) {
19066
19067 buffergeometry.updateFromObject( object );
19068
19069 }
19070
19071 geometries.update( buffergeometry );
19072
19073 updateList[ buffergeometry.id ] = frame;
19074
19075 }
19076
19077 return buffergeometry;
19078
19079 }
19080
19081 function clear() {
19082
19083 updateList = {};
19084
19085 }
19086
19087 return {
19088
19089 update: update,
19090 clear: clear
19091
19092 };
19093
19094}
19095
19096/**
19097 * @author mrdoob / http://mrdoob.com/
19098 */
19099
19100function addLineNumbers( string ) {
19101
19102 var lines = string.split( '\n' );
19103
19104 for ( var i = 0; i < lines.length; i ++ ) {
19105
19106 lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];
19107
19108 }
19109
19110 return lines.join( '\n' );
19111
19112}
19113
19114function WebGLShader( gl, type, string ) {
19115
19116 var shader = gl.createShader( type );
19117
19118 gl.shaderSource( shader, string );
19119 gl.compileShader( shader );
19120
19121 if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) {
19122
19123 console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' );
19124
19125 }
19126
19127 if ( gl.getShaderInfoLog( shader ) !== '' ) {
19128
19129 console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === gl.VERTEX_SHADER ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) );
19130
19131 }
19132
19133 // --enable-privileged-webgl-extension
19134 // console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
19135
19136 return shader;
19137
19138}
19139
19140/**
19141 * @author mrdoob / http://mrdoob.com/
19142 */
19143
19144var programIdCount = 0;
19145
19146function getEncodingComponents( encoding ) {
19147
19148 switch ( encoding ) {
19149
19150 case LinearEncoding:
19151 return [ 'Linear', '( value )' ];
19152 case sRGBEncoding:
19153 return [ 'sRGB', '( value )' ];
19154 case RGBEEncoding:
19155 return [ 'RGBE', '( value )' ];
19156 case RGBM7Encoding:
19157 return [ 'RGBM', '( value, 7.0 )' ];
19158 case RGBM16Encoding:
19159 return [ 'RGBM', '( value, 16.0 )' ];
19160 case RGBDEncoding:
19161 return [ 'RGBD', '( value, 256.0 )' ];
19162 case GammaEncoding:
19163 return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ];
19164 default:
19165 throw new Error( 'unsupported encoding: ' + encoding );
19166
19167 }
19168
19169}
19170
19171function getTexelDecodingFunction( functionName, encoding ) {
19172
19173 var components = getEncodingComponents( encoding );
19174 return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }';
19175
19176}
19177
19178function getTexelEncodingFunction( functionName, encoding ) {
19179
19180 var components = getEncodingComponents( encoding );
19181 return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }';
19182
19183}
19184
19185function getToneMappingFunction( functionName, toneMapping ) {
19186
19187 var toneMappingName;
19188
19189 switch ( toneMapping ) {
19190
19191 case LinearToneMapping:
19192 toneMappingName = 'Linear';
19193 break;
19194
19195 case ReinhardToneMapping:
19196 toneMappingName = 'Reinhard';
19197 break;
19198
19199 case Uncharted2ToneMapping:
19200 toneMappingName = 'Uncharted2';
19201 break;
19202
19203 case CineonToneMapping:
19204 toneMappingName = 'OptimizedCineon';
19205 break;
19206
19207 default:
19208 throw new Error( 'unsupported toneMapping: ' + toneMapping );
19209
19210 }
19211
19212 return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';
19213
19214}
19215
19216function generateExtensions( extensions, parameters, rendererExtensions ) {
19217
19218 extensions = extensions || {};
19219
19220 var chunks = [
19221 ( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '',
19222 ( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '',
19223 ( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '',
19224 ( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : ''
19225 ];
19226
19227 return chunks.filter( filterEmptyLine ).join( '\n' );
19228
19229}
19230
19231function generateDefines( defines ) {
19232
19233 var chunks = [];
19234
19235 for ( var name in defines ) {
19236
19237 var value = defines[ name ];
19238
19239 if ( value === false ) continue;
19240
19241 chunks.push( '#define ' + name + ' ' + value );
19242
19243 }
19244
19245 return chunks.join( '\n' );
19246
19247}
19248
19249function fetchAttributeLocations( gl, program ) {
19250
19251 var attributes = {};
19252
19253 var n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );
19254
19255 for ( var i = 0; i < n; i ++ ) {
19256
19257 var info = gl.getActiveAttrib( program, i );
19258 var name = info.name;
19259
19260 // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );
19261
19262 attributes[ name ] = gl.getAttribLocation( program, name );
19263
19264 }
19265
19266 return attributes;
19267
19268}
19269
19270function filterEmptyLine( string ) {
19271
19272 return string !== '';
19273
19274}
19275
19276function replaceLightNums( string, parameters ) {
19277
19278 return string
19279 .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
19280 .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
19281 .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
19282 .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
19283 .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights );
19284
19285}
19286
19287function parseIncludes( string ) {
19288
19289 var pattern = /^[ \t]*#include +<([\w\d.]+)>/gm;
19290
19291 function replace( match, include ) {
19292
19293 var replace = ShaderChunk[ include ];
19294
19295 if ( replace === undefined ) {
19296
19297 throw new Error( 'Can not resolve #include <' + include + '>' );
19298
19299 }
19300
19301 return parseIncludes( replace );
19302
19303 }
19304
19305 return string.replace( pattern, replace );
19306
19307}
19308
19309function unrollLoops( string ) {
19310
19311 var pattern = /for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g;
19312
19313 function replace( match, start, end, snippet ) {
19314
19315 var unroll = '';
19316
19317 for ( var i = parseInt( start ); i < parseInt( end ); i ++ ) {
19318
19319 unroll += snippet.replace( /\[ i \]/g, '[ ' + i + ' ]' );
19320
19321 }
19322
19323 return unroll;
19324
19325 }
19326
19327 return string.replace( pattern, replace );
19328
19329}
19330
19331function WebGLProgram( renderer, extensions, code, material, shader, parameters ) {
19332
19333 var gl = renderer.context;
19334
19335 var defines = material.defines;
19336
19337 var vertexShader = shader.vertexShader;
19338 var fragmentShader = shader.fragmentShader;
19339
19340 var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
19341
19342 if ( parameters.shadowMapType === PCFShadowMap ) {
19343
19344 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
19345
19346 } else if ( parameters.shadowMapType === PCFSoftShadowMap ) {
19347
19348 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
19349
19350 }
19351
19352 var envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
19353 var envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
19354 var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
19355
19356 if ( parameters.envMap ) {
19357
19358 switch ( material.envMap.mapping ) {
19359
19360 case CubeReflectionMapping:
19361 case CubeRefractionMapping:
19362 envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
19363 break;
19364
19365 case CubeUVReflectionMapping:
19366 case CubeUVRefractionMapping:
19367 envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
19368 break;
19369
19370 case EquirectangularReflectionMapping:
19371 case EquirectangularRefractionMapping:
19372 envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC';
19373 break;
19374
19375 case SphericalReflectionMapping:
19376 envMapTypeDefine = 'ENVMAP_TYPE_SPHERE';
19377 break;
19378
19379 }
19380
19381 switch ( material.envMap.mapping ) {
19382
19383 case CubeRefractionMapping:
19384 case EquirectangularRefractionMapping:
19385 envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
19386 break;
19387
19388 }
19389
19390 switch ( material.combine ) {
19391
19392 case MultiplyOperation:
19393 envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
19394 break;
19395
19396 case MixOperation:
19397 envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
19398 break;
19399
19400 case AddOperation:
19401 envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
19402 break;
19403
19404 }
19405
19406 }
19407
19408 var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0;
19409
19410 // console.log( 'building new program ' );
19411
19412 //
19413
19414 var customExtensions = generateExtensions( material.extensions, parameters, extensions );
19415
19416 var customDefines = generateDefines( defines );
19417
19418 //
19419
19420 var program = gl.createProgram();
19421
19422 var prefixVertex, prefixFragment;
19423
19424 if ( material.isRawShaderMaterial ) {
19425
19426 prefixVertex = [
19427
19428 customDefines
19429
19430 ].filter( filterEmptyLine ).join( '\n' );
19431
19432 if ( prefixVertex.length > 0 ) {
19433
19434 prefixVertex += '\n';
19435
19436 }
19437
19438 prefixFragment = [
19439
19440 customExtensions,
19441 customDefines
19442
19443 ].filter( filterEmptyLine ).join( '\n' );
19444
19445 if ( prefixFragment.length > 0 ) {
19446
19447 prefixFragment += '\n';
19448
19449 }
19450
19451 } else {
19452
19453 prefixVertex = [
19454
19455 'precision ' + parameters.precision + ' float;',
19456 'precision ' + parameters.precision + ' int;',
19457
19458 '#define SHADER_NAME ' + shader.name,
19459
19460 customDefines,
19461
19462 parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',
19463
19464 '#define GAMMA_FACTOR ' + gammaFactorDefine,
19465
19466 '#define MAX_BONES ' + parameters.maxBones,
19467 ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
19468 ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',
19469
19470 parameters.map ? '#define USE_MAP' : '',
19471 parameters.envMap ? '#define USE_ENVMAP' : '',
19472 parameters.envMap ? '#define ' + envMapModeDefine : '',
19473 parameters.lightMap ? '#define USE_LIGHTMAP' : '',
19474 parameters.aoMap ? '#define USE_AOMAP' : '',
19475 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
19476 parameters.bumpMap ? '#define USE_BUMPMAP' : '',
19477 parameters.normalMap ? '#define USE_NORMALMAP' : '',
19478 parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
19479 parameters.specularMap ? '#define USE_SPECULARMAP' : '',
19480 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
19481 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
19482 parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
19483 parameters.vertexColors ? '#define USE_COLOR' : '',
19484
19485 parameters.flatShading ? '#define FLAT_SHADED' : '',
19486
19487 parameters.skinning ? '#define USE_SKINNING' : '',
19488 parameters.useVertexTexture ? '#define BONE_TEXTURE' : '',
19489
19490 parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
19491 parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
19492 parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
19493 parameters.flipSided ? '#define FLIP_SIDED' : '',
19494
19495 '#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes,
19496
19497 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
19498 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
19499
19500 parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',
19501
19502 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
19503 parameters.logarithmicDepthBuffer && extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
19504
19505 'uniform mat4 modelMatrix;',
19506 'uniform mat4 modelViewMatrix;',
19507 'uniform mat4 projectionMatrix;',
19508 'uniform mat4 viewMatrix;',
19509 'uniform mat3 normalMatrix;',
19510 'uniform vec3 cameraPosition;',
19511
19512 'attribute vec3 position;',
19513 'attribute vec3 normal;',
19514 'attribute vec2 uv;',
19515
19516 '#ifdef USE_COLOR',
19517
19518 ' attribute vec3 color;',
19519
19520 '#endif',
19521
19522 '#ifdef USE_MORPHTARGETS',
19523
19524 ' attribute vec3 morphTarget0;',
19525 ' attribute vec3 morphTarget1;',
19526 ' attribute vec3 morphTarget2;',
19527 ' attribute vec3 morphTarget3;',
19528
19529 ' #ifdef USE_MORPHNORMALS',
19530
19531 ' attribute vec3 morphNormal0;',
19532 ' attribute vec3 morphNormal1;',
19533 ' attribute vec3 morphNormal2;',
19534 ' attribute vec3 morphNormal3;',
19535
19536 ' #else',
19537
19538 ' attribute vec3 morphTarget4;',
19539 ' attribute vec3 morphTarget5;',
19540 ' attribute vec3 morphTarget6;',
19541 ' attribute vec3 morphTarget7;',
19542
19543 ' #endif',
19544
19545 '#endif',
19546
19547 '#ifdef USE_SKINNING',
19548
19549 ' attribute vec4 skinIndex;',
19550 ' attribute vec4 skinWeight;',
19551
19552 '#endif',
19553
19554 '\n'
19555
19556 ].filter( filterEmptyLine ).join( '\n' );
19557
19558 prefixFragment = [
19559
19560 customExtensions,
19561
19562 'precision ' + parameters.precision + ' float;',
19563 'precision ' + parameters.precision + ' int;',
19564
19565 '#define SHADER_NAME ' + shader.name,
19566
19567 customDefines,
19568
19569 parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '',
19570
19571 '#define GAMMA_FACTOR ' + gammaFactorDefine,
19572
19573 ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
19574 ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '',
19575
19576 parameters.map ? '#define USE_MAP' : '',
19577 parameters.envMap ? '#define USE_ENVMAP' : '',
19578 parameters.envMap ? '#define ' + envMapTypeDefine : '',
19579 parameters.envMap ? '#define ' + envMapModeDefine : '',
19580 parameters.envMap ? '#define ' + envMapBlendingDefine : '',
19581 parameters.lightMap ? '#define USE_LIGHTMAP' : '',
19582 parameters.aoMap ? '#define USE_AOMAP' : '',
19583 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
19584 parameters.bumpMap ? '#define USE_BUMPMAP' : '',
19585 parameters.normalMap ? '#define USE_NORMALMAP' : '',
19586 parameters.specularMap ? '#define USE_SPECULARMAP' : '',
19587 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
19588 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
19589 parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
19590 parameters.vertexColors ? '#define USE_COLOR' : '',
19591
19592 parameters.gradientMap ? '#define USE_GRADIENTMAP' : '',
19593
19594 parameters.flatShading ? '#define FLAT_SHADED' : '',
19595
19596 parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
19597 parameters.flipSided ? '#define FLIP_SIDED' : '',
19598
19599 '#define NUM_CLIPPING_PLANES ' + parameters.numClippingPlanes,
19600 '#define UNION_CLIPPING_PLANES ' + ( parameters.numClippingPlanes - parameters.numClipIntersection ),
19601
19602 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
19603 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
19604
19605 parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',
19606
19607 parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '',
19608
19609 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
19610 parameters.logarithmicDepthBuffer && extensions.get( 'EXT_frag_depth' ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
19611
19612 parameters.envMap && extensions.get( 'EXT_shader_texture_lod' ) ? '#define TEXTURE_LOD_EXT' : '',
19613
19614 'uniform mat4 viewMatrix;',
19615 'uniform vec3 cameraPosition;',
19616
19617 ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',
19618 ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below
19619 ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '',
19620
19621 parameters.dithering ? '#define DITHERING' : '',
19622
19623 ( parameters.outputEncoding || parameters.mapEncoding || parameters.envMapEncoding || parameters.emissiveMapEncoding ) ? ShaderChunk[ 'encodings_pars_fragment' ] : '', // this code is required here because it is used by the various encoding/decoding function defined below
19624 parameters.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '',
19625 parameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '',
19626 parameters.emissiveMapEncoding ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '',
19627 parameters.outputEncoding ? getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ) : '',
19628
19629 parameters.depthPacking ? '#define DEPTH_PACKING ' + material.depthPacking : '',
19630
19631 '\n'
19632
19633 ].filter( filterEmptyLine ).join( '\n' );
19634
19635 }
19636
19637 vertexShader = parseIncludes( vertexShader );
19638 vertexShader = replaceLightNums( vertexShader, parameters );
19639
19640 fragmentShader = parseIncludes( fragmentShader );
19641 fragmentShader = replaceLightNums( fragmentShader, parameters );
19642
19643 if ( ! material.isShaderMaterial ) {
19644
19645 vertexShader = unrollLoops( vertexShader );
19646 fragmentShader = unrollLoops( fragmentShader );
19647
19648 }
19649
19650 var vertexGlsl = prefixVertex + vertexShader;
19651 var fragmentGlsl = prefixFragment + fragmentShader;
19652
19653 // console.log( '*VERTEX*', vertexGlsl );
19654 // console.log( '*FRAGMENT*', fragmentGlsl );
19655
19656 var glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
19657 var glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );
19658
19659 gl.attachShader( program, glVertexShader );
19660 gl.attachShader( program, glFragmentShader );
19661
19662 // Force a particular attribute to index 0.
19663
19664 if ( material.index0AttributeName !== undefined ) {
19665
19666 gl.bindAttribLocation( program, 0, material.index0AttributeName );
19667
19668 } else if ( parameters.morphTargets === true ) {
19669
19670 // programs with morphTargets displace position out of attribute 0
19671 gl.bindAttribLocation( program, 0, 'position' );
19672
19673 }
19674
19675 gl.linkProgram( program );
19676
19677 var programLog = gl.getProgramInfoLog( program );
19678 var vertexLog = gl.getShaderInfoLog( glVertexShader );
19679 var fragmentLog = gl.getShaderInfoLog( glFragmentShader );
19680
19681 var runnable = true;
19682 var haveDiagnostics = true;
19683
19684 // console.log( '**VERTEX**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) );
19685 // console.log( '**FRAGMENT**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) );
19686
19687 if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {
19688
19689 runnable = false;
19690
19691 console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), 'gl.VALIDATE_STATUS', gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog );
19692
19693 } else if ( programLog !== '' ) {
19694
19695 console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog );
19696
19697 } else if ( vertexLog === '' || fragmentLog === '' ) {
19698
19699 haveDiagnostics = false;
19700
19701 }
19702
19703 if ( haveDiagnostics ) {
19704
19705 this.diagnostics = {
19706
19707 runnable: runnable,
19708 material: material,
19709
19710 programLog: programLog,
19711
19712 vertexShader: {
19713
19714 log: vertexLog,
19715 prefix: prefixVertex
19716
19717 },
19718
19719 fragmentShader: {
19720
19721 log: fragmentLog,
19722 prefix: prefixFragment
19723
19724 }
19725
19726 };
19727
19728 }
19729
19730 // clean up
19731
19732 gl.deleteShader( glVertexShader );
19733 gl.deleteShader( glFragmentShader );
19734
19735 // set up caching for uniform locations
19736
19737 var cachedUniforms;
19738
19739 this.getUniforms = function () {
19740
19741 if ( cachedUniforms === undefined ) {
19742
19743 cachedUniforms = new WebGLUniforms( gl, program, renderer );
19744
19745 }
19746
19747 return cachedUniforms;
19748
19749 };
19750
19751 // set up caching for attribute locations
19752
19753 var cachedAttributes;
19754
19755 this.getAttributes = function () {
19756
19757 if ( cachedAttributes === undefined ) {
19758
19759 cachedAttributes = fetchAttributeLocations( gl, program );
19760
19761 }
19762
19763 return cachedAttributes;
19764
19765 };
19766
19767 // free resource
19768
19769 this.destroy = function () {
19770
19771 gl.deleteProgram( program );
19772 this.program = undefined;
19773
19774 };
19775
19776 // DEPRECATED
19777
19778 Object.defineProperties( this, {
19779
19780 uniforms: {
19781 get: function () {
19782
19783 console.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' );
19784 return this.getUniforms();
19785
19786 }
19787 },
19788
19789 attributes: {
19790 get: function () {
19791
19792 console.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' );
19793 return this.getAttributes();
19794
19795 }
19796 }
19797
19798 } );
19799
19800
19801 //
19802
19803 this.id = programIdCount ++;
19804 this.code = code;
19805 this.usedTimes = 1;
19806 this.program = program;
19807 this.vertexShader = glVertexShader;
19808 this.fragmentShader = glFragmentShader;
19809
19810 return this;
19811
19812}
19813
19814/**
19815 * @author mrdoob / http://mrdoob.com/
19816 */
19817
19818function WebGLPrograms( renderer, extensions, capabilities ) {
19819
19820 var programs = [];
19821
19822 var shaderIDs = {
19823 MeshDepthMaterial: 'depth',
19824 MeshDistanceMaterial: 'distanceRGBA',
19825 MeshNormalMaterial: 'normal',
19826 MeshBasicMaterial: 'basic',
19827 MeshLambertMaterial: 'lambert',
19828 MeshPhongMaterial: 'phong',
19829 MeshToonMaterial: 'phong',
19830 MeshStandardMaterial: 'physical',
19831 MeshPhysicalMaterial: 'physical',
19832 LineBasicMaterial: 'basic',
19833 LineDashedMaterial: 'dashed',
19834 PointsMaterial: 'points',
19835 ShadowMaterial: 'shadow'
19836 };
19837
19838 var parameterNames = [
19839 "precision", "supportsVertexTextures", "map", "mapEncoding", "envMap", "envMapMode", "envMapEncoding",
19840 "lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "displacementMap", "specularMap",
19841 "roughnessMap", "metalnessMap", "gradientMap",
19842 "alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp",
19843 "flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning",
19844 "maxBones", "useVertexTexture", "morphTargets", "morphNormals",
19845 "maxMorphTargets", "maxMorphNormals", "premultipliedAlpha",
19846 "numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights",
19847 "shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights',
19848 "alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering"
19849 ];
19850
19851
19852 function allocateBones( object ) {
19853
19854 var skeleton = object.skeleton;
19855 var bones = skeleton.bones;
19856
19857 if ( capabilities.floatVertexTextures ) {
19858
19859 return 1024;
19860
19861 } else {
19862
19863 // default for when object is not specified
19864 // ( for example when prebuilding shader to be used with multiple objects )
19865 //
19866 // - leave some extra space for other uniforms
19867 // - limit here is ANGLE's 254 max uniform vectors
19868 // (up to 54 should be safe)
19869
19870 var nVertexUniforms = capabilities.maxVertexUniforms;
19871 var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 );
19872
19873 var maxBones = Math.min( nVertexMatrices, bones.length );
19874
19875 if ( maxBones < bones.length ) {
19876
19877 console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' );
19878 return 0;
19879
19880 }
19881
19882 return maxBones;
19883
19884 }
19885
19886 }
19887
19888 function getTextureEncodingFromMap( map, gammaOverrideLinear ) {
19889
19890 var encoding;
19891
19892 if ( ! map ) {
19893
19894 encoding = LinearEncoding;
19895
19896 } else if ( map.isTexture ) {
19897
19898 encoding = map.encoding;
19899
19900 } else if ( map.isWebGLRenderTarget ) {
19901
19902 console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." );
19903 encoding = map.texture.encoding;
19904
19905 }
19906
19907 // add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point.
19908 if ( encoding === LinearEncoding && gammaOverrideLinear ) {
19909
19910 encoding = GammaEncoding;
19911
19912 }
19913
19914 return encoding;
19915
19916 }
19917
19918 this.getParameters = function ( material, lights, shadows, fog, nClipPlanes, nClipIntersection, object ) {
19919
19920 var shaderID = shaderIDs[ material.type ];
19921
19922 // heuristics to create shader parameters according to lights in the scene
19923 // (not to blow over maxLights budget)
19924
19925 var maxBones = object.isSkinnedMesh ? allocateBones( object ) : 0;
19926 var precision = capabilities.precision;
19927
19928 if ( material.precision !== null ) {
19929
19930 precision = capabilities.getMaxPrecision( material.precision );
19931
19932 if ( precision !== material.precision ) {
19933
19934 console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );
19935
19936 }
19937
19938 }
19939
19940 var currentRenderTarget = renderer.getRenderTarget();
19941
19942 var parameters = {
19943
19944 shaderID: shaderID,
19945
19946 precision: precision,
19947 supportsVertexTextures: capabilities.vertexTextures,
19948 outputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ),
19949 map: !! material.map,
19950 mapEncoding: getTextureEncodingFromMap( material.map, renderer.gammaInput ),
19951 envMap: !! material.envMap,
19952 envMapMode: material.envMap && material.envMap.mapping,
19953 envMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ),
19954 envMapCubeUV: ( !! material.envMap ) && ( ( material.envMap.mapping === CubeUVReflectionMapping ) || ( material.envMap.mapping === CubeUVRefractionMapping ) ),
19955 lightMap: !! material.lightMap,
19956 aoMap: !! material.aoMap,
19957 emissiveMap: !! material.emissiveMap,
19958 emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ),
19959 bumpMap: !! material.bumpMap,
19960 normalMap: !! material.normalMap,
19961 displacementMap: !! material.displacementMap,
19962 roughnessMap: !! material.roughnessMap,
19963 metalnessMap: !! material.metalnessMap,
19964 specularMap: !! material.specularMap,
19965 alphaMap: !! material.alphaMap,
19966
19967 gradientMap: !! material.gradientMap,
19968
19969 combine: material.combine,
19970
19971 vertexColors: material.vertexColors,
19972
19973 fog: !! fog,
19974 useFog: material.fog,
19975 fogExp: ( fog && fog.isFogExp2 ),
19976
19977 flatShading: material.flatShading,
19978
19979 sizeAttenuation: material.sizeAttenuation,
19980 logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer,
19981
19982 skinning: material.skinning && maxBones > 0,
19983 maxBones: maxBones,
19984 useVertexTexture: capabilities.floatVertexTextures,
19985
19986 morphTargets: material.morphTargets,
19987 morphNormals: material.morphNormals,
19988 maxMorphTargets: renderer.maxMorphTargets,
19989 maxMorphNormals: renderer.maxMorphNormals,
19990
19991 numDirLights: lights.directional.length,
19992 numPointLights: lights.point.length,
19993 numSpotLights: lights.spot.length,
19994 numRectAreaLights: lights.rectArea.length,
19995 numHemiLights: lights.hemi.length,
19996
19997 numClippingPlanes: nClipPlanes,
19998 numClipIntersection: nClipIntersection,
19999
20000 dithering: material.dithering,
20001
20002 shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && shadows.length > 0,
20003 shadowMapType: renderer.shadowMap.type,
20004
20005 toneMapping: renderer.toneMapping,
20006 physicallyCorrectLights: renderer.physicallyCorrectLights,
20007
20008 premultipliedAlpha: material.premultipliedAlpha,
20009
20010 alphaTest: material.alphaTest,
20011 doubleSided: material.side === DoubleSide,
20012 flipSided: material.side === BackSide,
20013
20014 depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false
20015
20016 };
20017
20018 return parameters;
20019
20020 };
20021
20022 this.getProgramCode = function ( material, parameters ) {
20023
20024 var array = [];
20025
20026 if ( parameters.shaderID ) {
20027
20028 array.push( parameters.shaderID );
20029
20030 } else {
20031
20032 array.push( material.fragmentShader );
20033 array.push( material.vertexShader );
20034
20035 }
20036
20037 if ( material.defines !== undefined ) {
20038
20039 for ( var name in material.defines ) {
20040
20041 array.push( name );
20042 array.push( material.defines[ name ] );
20043
20044 }
20045
20046 }
20047
20048 for ( var i = 0; i < parameterNames.length; i ++ ) {
20049
20050 array.push( parameters[ parameterNames[ i ] ] );
20051
20052 }
20053
20054 array.push( material.onBeforeCompile.toString() );
20055
20056 array.push( renderer.gammaOutput );
20057
20058 return array.join();
20059
20060 };
20061
20062 this.acquireProgram = function ( material, shader, parameters, code ) {
20063
20064 var program;
20065
20066 // Check if code has been already compiled
20067 for ( var p = 0, pl = programs.length; p < pl; p ++ ) {
20068
20069 var programInfo = programs[ p ];
20070
20071 if ( programInfo.code === code ) {
20072
20073 program = programInfo;
20074 ++ program.usedTimes;
20075
20076 break;
20077
20078 }
20079
20080 }
20081
20082 if ( program === undefined ) {
20083
20084 program = new WebGLProgram( renderer, extensions, code, material, shader, parameters );
20085 programs.push( program );
20086
20087 }
20088
20089 return program;
20090
20091 };
20092
20093 this.releaseProgram = function ( program ) {
20094
20095 if ( -- program.usedTimes === 0 ) {
20096
20097 // Remove from unordered set
20098 var i = programs.indexOf( program );
20099 programs[ i ] = programs[ programs.length - 1 ];
20100 programs.pop();
20101
20102 // Free WebGL resources
20103 program.destroy();
20104
20105 }
20106
20107 };
20108
20109 // Exposed for resource monitoring & error feedback via renderer.info:
20110 this.programs = programs;
20111
20112}
20113
20114/**
20115 * @author mrdoob / http://mrdoob.com/
20116 */
20117
20118function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, infoMemory ) {
20119
20120 var _isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && _gl instanceof window.WebGL2RenderingContext );
20121 var _videoTextures = {};
20122
20123 //
20124
20125 function clampToMaxSize( image, maxSize ) {
20126
20127 if ( image.width > maxSize || image.height > maxSize ) {
20128
20129 // Warning: Scaling through the canvas will only work with images that use
20130 // premultiplied alpha.
20131
20132 var scale = maxSize / Math.max( image.width, image.height );
20133
20134 var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
20135 canvas.width = Math.floor( image.width * scale );
20136 canvas.height = Math.floor( image.height * scale );
20137
20138 var context = canvas.getContext( '2d' );
20139 context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height );
20140
20141 console.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image );
20142
20143 return canvas;
20144
20145 }
20146
20147 return image;
20148
20149 }
20150
20151 function isPowerOfTwo( image ) {
20152
20153 return _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height );
20154
20155 }
20156
20157 function makePowerOfTwo( image ) {
20158
20159 if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof ImageBitmap ) {
20160
20161 var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
20162 canvas.width = _Math.floorPowerOfTwo( image.width );
20163 canvas.height = _Math.floorPowerOfTwo( image.height );
20164
20165 var context = canvas.getContext( '2d' );
20166 context.drawImage( image, 0, 0, canvas.width, canvas.height );
20167
20168 console.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image );
20169
20170 return canvas;
20171
20172 }
20173
20174 return image;
20175
20176 }
20177
20178 function textureNeedsPowerOfTwo( texture ) {
20179
20180 return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
20181 ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );
20182
20183 }
20184
20185 function textureNeedsGenerateMipmaps( texture, isPowerOfTwo ) {
20186
20187 return texture.generateMipmaps && isPowerOfTwo &&
20188 texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
20189
20190 }
20191
20192 // Fallback filters for non-power-of-2 textures
20193
20194 function filterFallback( f ) {
20195
20196 if ( f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter ) {
20197
20198 return _gl.NEAREST;
20199
20200 }
20201
20202 return _gl.LINEAR;
20203
20204 }
20205
20206 //
20207
20208 function onTextureDispose( event ) {
20209
20210 var texture = event.target;
20211
20212 texture.removeEventListener( 'dispose', onTextureDispose );
20213
20214 deallocateTexture( texture );
20215
20216 if ( texture.isVideoTexture ) {
20217
20218 delete _videoTextures[ texture.id ];
20219
20220 }
20221
20222 infoMemory.textures --;
20223
20224 }
20225
20226 function onRenderTargetDispose( event ) {
20227
20228 var renderTarget = event.target;
20229
20230 renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
20231
20232 deallocateRenderTarget( renderTarget );
20233
20234 infoMemory.textures --;
20235
20236 }
20237
20238 //
20239
20240 function deallocateTexture( texture ) {
20241
20242 var textureProperties = properties.get( texture );
20243
20244 if ( texture.image && textureProperties.__image__webglTextureCube ) {
20245
20246 // cube texture
20247
20248 _gl.deleteTexture( textureProperties.__image__webglTextureCube );
20249
20250 } else {
20251
20252 // 2D texture
20253
20254 if ( textureProperties.__webglInit === undefined ) return;
20255
20256 _gl.deleteTexture( textureProperties.__webglTexture );
20257
20258 }
20259
20260 // remove all webgl properties
20261 properties.remove( texture );
20262
20263 }
20264
20265 function deallocateRenderTarget( renderTarget ) {
20266
20267 var renderTargetProperties = properties.get( renderTarget );
20268 var textureProperties = properties.get( renderTarget.texture );
20269
20270 if ( ! renderTarget ) return;
20271
20272 if ( textureProperties.__webglTexture !== undefined ) {
20273
20274 _gl.deleteTexture( textureProperties.__webglTexture );
20275
20276 }
20277
20278 if ( renderTarget.depthTexture ) {
20279
20280 renderTarget.depthTexture.dispose();
20281
20282 }
20283
20284 if ( renderTarget.isWebGLRenderTargetCube ) {
20285
20286 for ( var i = 0; i < 6; i ++ ) {
20287
20288 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
20289 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );
20290
20291 }
20292
20293 } else {
20294
20295 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
20296 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );
20297
20298 }
20299
20300 properties.remove( renderTarget.texture );
20301 properties.remove( renderTarget );
20302
20303 }
20304
20305 //
20306
20307
20308
20309 function setTexture2D( texture, slot ) {
20310
20311 var textureProperties = properties.get( texture );
20312
20313 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
20314
20315 var image = texture.image;
20316
20317 if ( image === undefined ) {
20318
20319 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined', texture );
20320
20321 } else if ( image.complete === false ) {
20322
20323 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete', texture );
20324
20325 } else {
20326
20327 uploadTexture( textureProperties, texture, slot );
20328 return;
20329
20330 }
20331
20332 }
20333
20334 state.activeTexture( _gl.TEXTURE0 + slot );
20335 state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
20336
20337 }
20338
20339 function setTextureCube( texture, slot ) {
20340
20341 var textureProperties = properties.get( texture );
20342
20343 if ( texture.image.length === 6 ) {
20344
20345 if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
20346
20347 if ( ! textureProperties.__image__webglTextureCube ) {
20348
20349 texture.addEventListener( 'dispose', onTextureDispose );
20350
20351 textureProperties.__image__webglTextureCube = _gl.createTexture();
20352
20353 infoMemory.textures ++;
20354
20355 }
20356
20357 state.activeTexture( _gl.TEXTURE0 + slot );
20358 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );
20359
20360 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
20361
20362 var isCompressed = ( texture && texture.isCompressedTexture );
20363 var isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
20364
20365 var cubeImage = [];
20366
20367 for ( var i = 0; i < 6; i ++ ) {
20368
20369 if ( ! isCompressed && ! isDataTexture ) {
20370
20371 cubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize );
20372
20373 } else {
20374
20375 cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
20376
20377 }
20378
20379 }
20380
20381 var image = cubeImage[ 0 ],
20382 isPowerOfTwoImage = isPowerOfTwo( image ),
20383 glFormat = utils.convert( texture.format ),
20384 glType = utils.convert( texture.type );
20385
20386 setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isPowerOfTwoImage );
20387
20388 for ( var i = 0; i < 6; i ++ ) {
20389
20390 if ( ! isCompressed ) {
20391
20392 if ( isDataTexture ) {
20393
20394 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
20395
20396 } else {
20397
20398 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );
20399
20400 }
20401
20402 } else {
20403
20404 var mipmap, mipmaps = cubeImage[ i ].mipmaps;
20405
20406 for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {
20407
20408 mipmap = mipmaps[ j ];
20409
20410 if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
20411
20412 if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {
20413
20414 state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
20415
20416 } else {
20417
20418 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );
20419
20420 }
20421
20422 } else {
20423
20424 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
20425
20426 }
20427
20428 }
20429
20430 }
20431
20432 }
20433
20434 if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) {
20435
20436 _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
20437
20438 }
20439
20440 textureProperties.__version = texture.version;
20441
20442 if ( texture.onUpdate ) texture.onUpdate( texture );
20443
20444 } else {
20445
20446 state.activeTexture( _gl.TEXTURE0 + slot );
20447 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__image__webglTextureCube );
20448
20449 }
20450
20451 }
20452
20453 }
20454
20455 function setTextureCubeDynamic( texture, slot ) {
20456
20457 state.activeTexture( _gl.TEXTURE0 + slot );
20458 state.bindTexture( _gl.TEXTURE_CUBE_MAP, properties.get( texture ).__webglTexture );
20459
20460 }
20461
20462 function setTextureParameters( textureType, texture, isPowerOfTwoImage ) {
20463
20464 var extension;
20465
20466 if ( isPowerOfTwoImage ) {
20467
20468 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, utils.convert( texture.wrapS ) );
20469 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, utils.convert( texture.wrapT ) );
20470
20471 _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, utils.convert( texture.magFilter ) );
20472 _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, utils.convert( texture.minFilter ) );
20473
20474 } else {
20475
20476 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
20477 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
20478
20479 if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {
20480
20481 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.', texture );
20482
20483 }
20484
20485 _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
20486 _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
20487
20488 if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {
20489
20490 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.', texture );
20491
20492 }
20493
20494 }
20495
20496 extension = extensions.get( 'EXT_texture_filter_anisotropic' );
20497
20498 if ( extension ) {
20499
20500 if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return;
20501 if ( texture.type === HalfFloatType && extensions.get( 'OES_texture_half_float_linear' ) === null ) return;
20502
20503 if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {
20504
20505 _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
20506 properties.get( texture ).__currentAnisotropy = texture.anisotropy;
20507
20508 }
20509
20510 }
20511
20512 }
20513
20514 function uploadTexture( textureProperties, texture, slot ) {
20515
20516 if ( textureProperties.__webglInit === undefined ) {
20517
20518 textureProperties.__webglInit = true;
20519
20520 texture.addEventListener( 'dispose', onTextureDispose );
20521
20522 textureProperties.__webglTexture = _gl.createTexture();
20523
20524 if ( texture.isVideoTexture ) {
20525
20526 _videoTextures[ texture.id ] = texture;
20527
20528 }
20529
20530 infoMemory.textures ++;
20531
20532 }
20533
20534 state.activeTexture( _gl.TEXTURE0 + slot );
20535 state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
20536
20537 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
20538 _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
20539 _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
20540
20541 var image = clampToMaxSize( texture.image, capabilities.maxTextureSize );
20542
20543 if ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( image ) === false ) {
20544
20545 image = makePowerOfTwo( image );
20546
20547 }
20548
20549 var isPowerOfTwoImage = isPowerOfTwo( image ),
20550 glFormat = utils.convert( texture.format ),
20551 glType = utils.convert( texture.type );
20552
20553 setTextureParameters( _gl.TEXTURE_2D, texture, isPowerOfTwoImage );
20554
20555 var mipmap, mipmaps = texture.mipmaps;
20556
20557 if ( texture.isDepthTexture ) {
20558
20559 // populate depth texture with dummy data
20560
20561 var internalFormat = _gl.DEPTH_COMPONENT;
20562
20563 if ( texture.type === FloatType ) {
20564
20565 if ( ! _isWebGL2 ) throw new Error( 'Float Depth Texture only supported in WebGL2.0' );
20566 internalFormat = _gl.DEPTH_COMPONENT32F;
20567
20568 } else if ( _isWebGL2 ) {
20569
20570 // WebGL 2.0 requires signed internalformat for glTexImage2D
20571 internalFormat = _gl.DEPTH_COMPONENT16;
20572
20573 }
20574
20575 if ( texture.format === DepthFormat && internalFormat === _gl.DEPTH_COMPONENT ) {
20576
20577 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
20578 // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
20579 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
20580 if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {
20581
20582 console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );
20583
20584 texture.type = UnsignedShortType;
20585 glType = utils.convert( texture.type );
20586
20587 }
20588
20589 }
20590
20591 // Depth stencil textures need the DEPTH_STENCIL internal format
20592 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
20593 if ( texture.format === DepthStencilFormat ) {
20594
20595 internalFormat = _gl.DEPTH_STENCIL;
20596
20597 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
20598 // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
20599 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
20600 if ( texture.type !== UnsignedInt248Type ) {
20601
20602 console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );
20603
20604 texture.type = UnsignedInt248Type;
20605 glType = utils.convert( texture.type );
20606
20607 }
20608
20609 }
20610
20611 state.texImage2D( _gl.TEXTURE_2D, 0, internalFormat, image.width, image.height, 0, glFormat, glType, null );
20612
20613 } else if ( texture.isDataTexture ) {
20614
20615 // use manually created mipmaps if available
20616 // if there are no manual mipmaps
20617 // set 0 level mipmap and then use GL to generate other mipmap levels
20618
20619 if ( mipmaps.length > 0 && isPowerOfTwoImage ) {
20620
20621 for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
20622
20623 mipmap = mipmaps[ i ];
20624 state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
20625
20626 }
20627
20628 texture.generateMipmaps = false;
20629
20630 } else {
20631
20632 state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );
20633
20634 }
20635
20636 } else if ( texture.isCompressedTexture ) {
20637
20638 for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
20639
20640 mipmap = mipmaps[ i ];
20641
20642 if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) {
20643
20644 if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) {
20645
20646 state.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
20647
20648 } else {
20649
20650 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
20651
20652 }
20653
20654 } else {
20655
20656 state.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
20657
20658 }
20659
20660 }
20661
20662 } else {
20663
20664 // regular Texture (image, video, canvas)
20665
20666 // use manually created mipmaps if available
20667 // if there are no manual mipmaps
20668 // set 0 level mipmap and then use GL to generate other mipmap levels
20669
20670 if ( mipmaps.length > 0 && isPowerOfTwoImage ) {
20671
20672 for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
20673
20674 mipmap = mipmaps[ i ];
20675 state.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );
20676
20677 }
20678
20679 texture.generateMipmaps = false;
20680
20681 } else {
20682
20683 state.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, image );
20684
20685 }
20686
20687 }
20688
20689 if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) _gl.generateMipmap( _gl.TEXTURE_2D );
20690
20691 textureProperties.__version = texture.version;
20692
20693 if ( texture.onUpdate ) texture.onUpdate( texture );
20694
20695 }
20696
20697 // Render targets
20698
20699 // Setup storage for target texture and bind it to correct framebuffer
20700 function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) {
20701
20702 var glFormat = utils.convert( renderTarget.texture.format );
20703 var glType = utils.convert( renderTarget.texture.type );
20704 state.texImage2D( textureTarget, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
20705 _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
20706 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 );
20707 _gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
20708
20709 }
20710
20711 // Setup storage for internal depth/stencil buffers and bind to correct framebuffer
20712 function setupRenderBufferStorage( renderbuffer, renderTarget ) {
20713
20714 _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
20715
20716 if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
20717
20718 _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );
20719 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
20720
20721 } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
20722
20723 _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
20724 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
20725
20726 } else {
20727
20728 // FIXME: We don't support !depth !stencil
20729 _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );
20730
20731 }
20732
20733 _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
20734
20735 }
20736
20737 // Setup resources for a Depth Texture for a FBO (needs an extension)
20738 function setupDepthTexture( framebuffer, renderTarget ) {
20739
20740 var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube );
20741 if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );
20742
20743 _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
20744
20745 if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {
20746
20747 throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );
20748
20749 }
20750
20751 // upload an empty depth texture with framebuffer size
20752 if ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||
20753 renderTarget.depthTexture.image.width !== renderTarget.width ||
20754 renderTarget.depthTexture.image.height !== renderTarget.height ) {
20755
20756 renderTarget.depthTexture.image.width = renderTarget.width;
20757 renderTarget.depthTexture.image.height = renderTarget.height;
20758 renderTarget.depthTexture.needsUpdate = true;
20759
20760 }
20761
20762 setTexture2D( renderTarget.depthTexture, 0 );
20763
20764 var webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
20765
20766 if ( renderTarget.depthTexture.format === DepthFormat ) {
20767
20768 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
20769
20770 } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
20771
20772 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
20773
20774 } else {
20775
20776 throw new Error( 'Unknown depthTexture format' );
20777
20778 }
20779
20780 }
20781
20782 // Setup GL resources for a non-texture depth buffer
20783 function setupDepthRenderbuffer( renderTarget ) {
20784
20785 var renderTargetProperties = properties.get( renderTarget );
20786
20787 var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
20788
20789 if ( renderTarget.depthTexture ) {
20790
20791 if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
20792
20793 setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );
20794
20795 } else {
20796
20797 if ( isCube ) {
20798
20799 renderTargetProperties.__webglDepthbuffer = [];
20800
20801 for ( var i = 0; i < 6; i ++ ) {
20802
20803 _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );
20804 renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
20805 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget );
20806
20807 }
20808
20809 } else {
20810
20811 _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
20812 renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
20813 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget );
20814
20815 }
20816
20817 }
20818
20819 _gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
20820
20821 }
20822
20823 // Set up GL resources for the render target
20824 function setupRenderTarget( renderTarget ) {
20825
20826 var renderTargetProperties = properties.get( renderTarget );
20827 var textureProperties = properties.get( renderTarget.texture );
20828
20829 renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
20830
20831 textureProperties.__webglTexture = _gl.createTexture();
20832
20833 infoMemory.textures ++;
20834
20835 var isCube = ( renderTarget.isWebGLRenderTargetCube === true );
20836 var isTargetPowerOfTwo = isPowerOfTwo( renderTarget );
20837
20838 // Setup framebuffer
20839
20840 if ( isCube ) {
20841
20842 renderTargetProperties.__webglFramebuffer = [];
20843
20844 for ( var i = 0; i < 6; i ++ ) {
20845
20846 renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();
20847
20848 }
20849
20850 } else {
20851
20852 renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
20853
20854 }
20855
20856 // Setup color buffer
20857
20858 if ( isCube ) {
20859
20860 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
20861 setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.texture, isTargetPowerOfTwo );
20862
20863 for ( var i = 0; i < 6; i ++ ) {
20864
20865 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
20866
20867 }
20868
20869 if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
20870 state.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
20871
20872 } else {
20873
20874 state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
20875 setTextureParameters( _gl.TEXTURE_2D, renderTarget.texture, isTargetPowerOfTwo );
20876 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D );
20877
20878 if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) _gl.generateMipmap( _gl.TEXTURE_2D );
20879 state.bindTexture( _gl.TEXTURE_2D, null );
20880
20881 }
20882
20883 // Setup depth and stencil buffers
20884
20885 if ( renderTarget.depthBuffer ) {
20886
20887 setupDepthRenderbuffer( renderTarget );
20888
20889 }
20890
20891 }
20892
20893 function updateRenderTargetMipmap( renderTarget ) {
20894
20895 var texture = renderTarget.texture;
20896 var isTargetPowerOfTwo = isPowerOfTwo( renderTarget );
20897
20898 if ( textureNeedsGenerateMipmaps( texture, isTargetPowerOfTwo ) ) {
20899
20900 var target = renderTarget.isWebGLRenderTargetCube ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;
20901 var webglTexture = properties.get( texture ).__webglTexture;
20902
20903 state.bindTexture( target, webglTexture );
20904 _gl.generateMipmap( target );
20905 state.bindTexture( target, null );
20906
20907 }
20908
20909 }
20910
20911 function updateVideoTextures() {
20912
20913 for ( var id in _videoTextures ) {
20914
20915 _videoTextures[ id ].update();
20916
20917 }
20918
20919 }
20920
20921 this.setTexture2D = setTexture2D;
20922 this.setTextureCube = setTextureCube;
20923 this.setTextureCubeDynamic = setTextureCubeDynamic;
20924 this.setupRenderTarget = setupRenderTarget;
20925 this.updateRenderTargetMipmap = updateRenderTargetMipmap;
20926 this.updateVideoTextures = updateVideoTextures;
20927
20928}
20929
20930/**
20931 * @author fordacious / fordacious.github.io
20932 */
20933
20934function WebGLProperties() {
20935
20936 var properties = {};
20937
20938 function get( object ) {
20939
20940 var uuid = object.uuid;
20941 var map = properties[ uuid ];
20942
20943 if ( map === undefined ) {
20944
20945 map = {};
20946 properties[ uuid ] = map;
20947
20948 }
20949
20950 return map;
20951
20952 }
20953
20954 function remove( object ) {
20955
20956 delete properties[ object.uuid ];
20957
20958 }
20959
20960 function clear() {
20961
20962 properties = {};
20963
20964 }
20965
20966 return {
20967 get: get,
20968 remove: remove,
20969 clear: clear
20970 };
20971
20972}
20973
20974/**
20975 * @author mrdoob / http://mrdoob.com/
20976 */
20977
20978function WebGLState( gl, extensions, utils ) {
20979
20980 function ColorBuffer() {
20981
20982 var locked = false;
20983
20984 var color = new Vector4();
20985 var currentColorMask = null;
20986 var currentColorClear = new Vector4( 0, 0, 0, 0 );
20987
20988 return {
20989
20990 setMask: function ( colorMask ) {
20991
20992 if ( currentColorMask !== colorMask && ! locked ) {
20993
20994 gl.colorMask( colorMask, colorMask, colorMask, colorMask );
20995 currentColorMask = colorMask;
20996
20997 }
20998
20999 },
21000
21001 setLocked: function ( lock ) {
21002
21003 locked = lock;
21004
21005 },
21006
21007 setClear: function ( r, g, b, a, premultipliedAlpha ) {
21008
21009 if ( premultipliedAlpha === true ) {
21010
21011 r *= a; g *= a; b *= a;
21012
21013 }
21014
21015 color.set( r, g, b, a );
21016
21017 if ( currentColorClear.equals( color ) === false ) {
21018
21019 gl.clearColor( r, g, b, a );
21020 currentColorClear.copy( color );
21021
21022 }
21023
21024 },
21025
21026 reset: function () {
21027
21028 locked = false;
21029
21030 currentColorMask = null;
21031 currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state
21032
21033 }
21034
21035 };
21036
21037 }
21038
21039 function DepthBuffer() {
21040
21041 var locked = false;
21042
21043 var currentDepthMask = null;
21044 var currentDepthFunc = null;
21045 var currentDepthClear = null;
21046
21047 return {
21048
21049 setTest: function ( depthTest ) {
21050
21051 if ( depthTest ) {
21052
21053 enable( gl.DEPTH_TEST );
21054
21055 } else {
21056
21057 disable( gl.DEPTH_TEST );
21058
21059 }
21060
21061 },
21062
21063 setMask: function ( depthMask ) {
21064
21065 if ( currentDepthMask !== depthMask && ! locked ) {
21066
21067 gl.depthMask( depthMask );
21068 currentDepthMask = depthMask;
21069
21070 }
21071
21072 },
21073
21074 setFunc: function ( depthFunc ) {
21075
21076 if ( currentDepthFunc !== depthFunc ) {
21077
21078 if ( depthFunc ) {
21079
21080 switch ( depthFunc ) {
21081
21082 case NeverDepth:
21083
21084 gl.depthFunc( gl.NEVER );
21085 break;
21086
21087 case AlwaysDepth:
21088
21089 gl.depthFunc( gl.ALWAYS );
21090 break;
21091
21092 case LessDepth:
21093
21094 gl.depthFunc( gl.LESS );
21095 break;
21096
21097 case LessEqualDepth:
21098
21099 gl.depthFunc( gl.LEQUAL );
21100 break;
21101
21102 case EqualDepth:
21103
21104 gl.depthFunc( gl.EQUAL );
21105 break;
21106
21107 case GreaterEqualDepth:
21108
21109 gl.depthFunc( gl.GEQUAL );
21110 break;
21111
21112 case GreaterDepth:
21113
21114 gl.depthFunc( gl.GREATER );
21115 break;
21116
21117 case NotEqualDepth:
21118
21119 gl.depthFunc( gl.NOTEQUAL );
21120 break;
21121
21122 default:
21123
21124 gl.depthFunc( gl.LEQUAL );
21125
21126 }
21127
21128 } else {
21129
21130 gl.depthFunc( gl.LEQUAL );
21131
21132 }
21133
21134 currentDepthFunc = depthFunc;
21135
21136 }
21137
21138 },
21139
21140 setLocked: function ( lock ) {
21141
21142 locked = lock;
21143
21144 },
21145
21146 setClear: function ( depth ) {
21147
21148 if ( currentDepthClear !== depth ) {
21149
21150 gl.clearDepth( depth );
21151 currentDepthClear = depth;
21152
21153 }
21154
21155 },
21156
21157 reset: function () {
21158
21159 locked = false;
21160
21161 currentDepthMask = null;
21162 currentDepthFunc = null;
21163 currentDepthClear = null;
21164
21165 }
21166
21167 };
21168
21169 }
21170
21171 function StencilBuffer() {
21172
21173 var locked = false;
21174
21175 var currentStencilMask = null;
21176 var currentStencilFunc = null;
21177 var currentStencilRef = null;
21178 var currentStencilFuncMask = null;
21179 var currentStencilFail = null;
21180 var currentStencilZFail = null;
21181 var currentStencilZPass = null;
21182 var currentStencilClear = null;
21183
21184 return {
21185
21186 setTest: function ( stencilTest ) {
21187
21188 if ( stencilTest ) {
21189
21190 enable( gl.STENCIL_TEST );
21191
21192 } else {
21193
21194 disable( gl.STENCIL_TEST );
21195
21196 }
21197
21198 },
21199
21200 setMask: function ( stencilMask ) {
21201
21202 if ( currentStencilMask !== stencilMask && ! locked ) {
21203
21204 gl.stencilMask( stencilMask );
21205 currentStencilMask = stencilMask;
21206
21207 }
21208
21209 },
21210
21211 setFunc: function ( stencilFunc, stencilRef, stencilMask ) {
21212
21213 if ( currentStencilFunc !== stencilFunc ||
21214 currentStencilRef !== stencilRef ||
21215 currentStencilFuncMask !== stencilMask ) {
21216
21217 gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
21218
21219 currentStencilFunc = stencilFunc;
21220 currentStencilRef = stencilRef;
21221 currentStencilFuncMask = stencilMask;
21222
21223 }
21224
21225 },
21226
21227 setOp: function ( stencilFail, stencilZFail, stencilZPass ) {
21228
21229 if ( currentStencilFail !== stencilFail ||
21230 currentStencilZFail !== stencilZFail ||
21231 currentStencilZPass !== stencilZPass ) {
21232
21233 gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
21234
21235 currentStencilFail = stencilFail;
21236 currentStencilZFail = stencilZFail;
21237 currentStencilZPass = stencilZPass;
21238
21239 }
21240
21241 },
21242
21243 setLocked: function ( lock ) {
21244
21245 locked = lock;
21246
21247 },
21248
21249 setClear: function ( stencil ) {
21250
21251 if ( currentStencilClear !== stencil ) {
21252
21253 gl.clearStencil( stencil );
21254 currentStencilClear = stencil;
21255
21256 }
21257
21258 },
21259
21260 reset: function () {
21261
21262 locked = false;
21263
21264 currentStencilMask = null;
21265 currentStencilFunc = null;
21266 currentStencilRef = null;
21267 currentStencilFuncMask = null;
21268 currentStencilFail = null;
21269 currentStencilZFail = null;
21270 currentStencilZPass = null;
21271 currentStencilClear = null;
21272
21273 }
21274
21275 };
21276
21277 }
21278
21279 //
21280
21281 var colorBuffer = new ColorBuffer();
21282 var depthBuffer = new DepthBuffer();
21283 var stencilBuffer = new StencilBuffer();
21284
21285 var maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
21286 var newAttributes = new Uint8Array( maxVertexAttributes );
21287 var enabledAttributes = new Uint8Array( maxVertexAttributes );
21288 var attributeDivisors = new Uint8Array( maxVertexAttributes );
21289
21290 var capabilities = {};
21291
21292 var compressedTextureFormats = null;
21293
21294 var currentProgram = null;
21295
21296 var currentBlending = null;
21297 var currentBlendEquation = null;
21298 var currentBlendSrc = null;
21299 var currentBlendDst = null;
21300 var currentBlendEquationAlpha = null;
21301 var currentBlendSrcAlpha = null;
21302 var currentBlendDstAlpha = null;
21303 var currentPremultipledAlpha = false;
21304
21305 var currentFlipSided = null;
21306 var currentCullFace = null;
21307
21308 var currentLineWidth = null;
21309
21310 var currentPolygonOffsetFactor = null;
21311 var currentPolygonOffsetUnits = null;
21312
21313 var maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS );
21314
21315 var version = parseFloat( /^WebGL\ ([0-9])/.exec( gl.getParameter( gl.VERSION ) )[ 1 ] );
21316 var lineWidthAvailable = parseFloat( version ) >= 1.0;
21317
21318 var currentTextureSlot = null;
21319 var currentBoundTextures = {};
21320
21321 var currentScissor = new Vector4();
21322 var currentViewport = new Vector4();
21323
21324 function createTexture( type, target, count ) {
21325
21326 var data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.
21327 var texture = gl.createTexture();
21328
21329 gl.bindTexture( type, texture );
21330 gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
21331 gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
21332
21333 for ( var i = 0; i < count; i ++ ) {
21334
21335 gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );
21336
21337 }
21338
21339 return texture;
21340
21341 }
21342
21343 var emptyTextures = {};
21344 emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 );
21345 emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 );
21346
21347 // init
21348
21349 colorBuffer.setClear( 0, 0, 0, 1 );
21350 depthBuffer.setClear( 1 );
21351 stencilBuffer.setClear( 0 );
21352
21353 enable( gl.DEPTH_TEST );
21354 depthBuffer.setFunc( LessEqualDepth );
21355
21356 setFlipSided( false );
21357 setCullFace( CullFaceBack );
21358 enable( gl.CULL_FACE );
21359
21360 enable( gl.BLEND );
21361 setBlending( NormalBlending );
21362
21363 //
21364
21365 function initAttributes() {
21366
21367 for ( var i = 0, l = newAttributes.length; i < l; i ++ ) {
21368
21369 newAttributes[ i ] = 0;
21370
21371 }
21372
21373 }
21374
21375 function enableAttribute( attribute ) {
21376
21377 newAttributes[ attribute ] = 1;
21378
21379 if ( enabledAttributes[ attribute ] === 0 ) {
21380
21381 gl.enableVertexAttribArray( attribute );
21382 enabledAttributes[ attribute ] = 1;
21383
21384 }
21385
21386 if ( attributeDivisors[ attribute ] !== 0 ) {
21387
21388 var extension = extensions.get( 'ANGLE_instanced_arrays' );
21389
21390 extension.vertexAttribDivisorANGLE( attribute, 0 );
21391 attributeDivisors[ attribute ] = 0;
21392
21393 }
21394
21395 }
21396
21397 function enableAttributeAndDivisor( attribute, meshPerAttribute ) {
21398
21399 newAttributes[ attribute ] = 1;
21400
21401 if ( enabledAttributes[ attribute ] === 0 ) {
21402
21403 gl.enableVertexAttribArray( attribute );
21404 enabledAttributes[ attribute ] = 1;
21405
21406 }
21407
21408 if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {
21409
21410 var extension = extensions.get( 'ANGLE_instanced_arrays' );
21411
21412 extension.vertexAttribDivisorANGLE( attribute, meshPerAttribute );
21413 attributeDivisors[ attribute ] = meshPerAttribute;
21414
21415 }
21416
21417 }
21418
21419 function disableUnusedAttributes() {
21420
21421 for ( var i = 0, l = enabledAttributes.length; i !== l; ++ i ) {
21422
21423 if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {
21424
21425 gl.disableVertexAttribArray( i );
21426 enabledAttributes[ i ] = 0;
21427
21428 }
21429
21430 }
21431
21432 }
21433
21434 function enable( id ) {
21435
21436 if ( capabilities[ id ] !== true ) {
21437
21438 gl.enable( id );
21439 capabilities[ id ] = true;
21440
21441 }
21442
21443 }
21444
21445 function disable( id ) {
21446
21447 if ( capabilities[ id ] !== false ) {
21448
21449 gl.disable( id );
21450 capabilities[ id ] = false;
21451
21452 }
21453
21454 }
21455
21456 function getCompressedTextureFormats() {
21457
21458 if ( compressedTextureFormats === null ) {
21459
21460 compressedTextureFormats = [];
21461
21462 if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) ||
21463 extensions.get( 'WEBGL_compressed_texture_s3tc' ) ||
21464 extensions.get( 'WEBGL_compressed_texture_etc1' ) ) {
21465
21466 var formats = gl.getParameter( gl.COMPRESSED_TEXTURE_FORMATS );
21467
21468 for ( var i = 0; i < formats.length; i ++ ) {
21469
21470 compressedTextureFormats.push( formats[ i ] );
21471
21472 }
21473
21474 }
21475
21476 }
21477
21478 return compressedTextureFormats;
21479
21480 }
21481
21482 function useProgram( program ) {
21483
21484 if ( currentProgram !== program ) {
21485
21486 gl.useProgram( program );
21487
21488 currentProgram = program;
21489
21490 return true;
21491
21492 }
21493
21494 return false;
21495
21496 }
21497
21498 function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) {
21499
21500 if ( blending !== NoBlending ) {
21501
21502 enable( gl.BLEND );
21503
21504 } else {
21505
21506 disable( gl.BLEND );
21507
21508 }
21509
21510 if ( blending !== CustomBlending ) {
21511
21512 if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {
21513
21514 switch ( blending ) {
21515
21516 case AdditiveBlending:
21517
21518 if ( premultipliedAlpha ) {
21519
21520 gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
21521 gl.blendFuncSeparate( gl.ONE, gl.ONE, gl.ONE, gl.ONE );
21522
21523 } else {
21524
21525 gl.blendEquation( gl.FUNC_ADD );
21526 gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
21527
21528 }
21529 break;
21530
21531 case SubtractiveBlending:
21532
21533 if ( premultipliedAlpha ) {
21534
21535 gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
21536 gl.blendFuncSeparate( gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA );
21537
21538 } else {
21539
21540 gl.blendEquation( gl.FUNC_ADD );
21541 gl.blendFunc( gl.ZERO, gl.ONE_MINUS_SRC_COLOR );
21542
21543 }
21544 break;
21545
21546 case MultiplyBlending:
21547
21548 if ( premultipliedAlpha ) {
21549
21550 gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
21551 gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );
21552
21553 } else {
21554
21555 gl.blendEquation( gl.FUNC_ADD );
21556 gl.blendFunc( gl.ZERO, gl.SRC_COLOR );
21557
21558 }
21559 break;
21560
21561 default:
21562
21563 if ( premultipliedAlpha ) {
21564
21565 gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
21566 gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
21567
21568 } else {
21569
21570 gl.blendEquationSeparate( gl.FUNC_ADD, gl.FUNC_ADD );
21571 gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
21572
21573 }
21574
21575 }
21576
21577 }
21578
21579 currentBlendEquation = null;
21580 currentBlendSrc = null;
21581 currentBlendDst = null;
21582 currentBlendEquationAlpha = null;
21583 currentBlendSrcAlpha = null;
21584 currentBlendDstAlpha = null;
21585
21586 } else {
21587
21588 blendEquationAlpha = blendEquationAlpha || blendEquation;
21589 blendSrcAlpha = blendSrcAlpha || blendSrc;
21590 blendDstAlpha = blendDstAlpha || blendDst;
21591
21592 if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {
21593
21594 gl.blendEquationSeparate( utils.convert( blendEquation ), utils.convert( blendEquationAlpha ) );
21595
21596 currentBlendEquation = blendEquation;
21597 currentBlendEquationAlpha = blendEquationAlpha;
21598
21599 }
21600
21601 if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {
21602
21603 gl.blendFuncSeparate( utils.convert( blendSrc ), utils.convert( blendDst ), utils.convert( blendSrcAlpha ), utils.convert( blendDstAlpha ) );
21604
21605 currentBlendSrc = blendSrc;
21606 currentBlendDst = blendDst;
21607 currentBlendSrcAlpha = blendSrcAlpha;
21608 currentBlendDstAlpha = blendDstAlpha;
21609
21610 }
21611
21612 }
21613
21614 currentBlending = blending;
21615 currentPremultipledAlpha = premultipliedAlpha;
21616
21617 }
21618
21619 function setMaterial( material, frontFaceCW ) {
21620
21621 material.side === DoubleSide
21622 ? disable( gl.CULL_FACE )
21623 : enable( gl.CULL_FACE );
21624
21625 var flipSided = ( material.side === BackSide );
21626 if ( frontFaceCW ) flipSided = ! flipSided;
21627
21628 setFlipSided( flipSided );
21629
21630 material.transparent === true
21631 ? setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha )
21632 : setBlending( NoBlending );
21633
21634 depthBuffer.setFunc( material.depthFunc );
21635 depthBuffer.setTest( material.depthTest );
21636 depthBuffer.setMask( material.depthWrite );
21637 colorBuffer.setMask( material.colorWrite );
21638
21639 setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );
21640
21641 }
21642
21643 //
21644
21645 function setFlipSided( flipSided ) {
21646
21647 if ( currentFlipSided !== flipSided ) {
21648
21649 if ( flipSided ) {
21650
21651 gl.frontFace( gl.CW );
21652
21653 } else {
21654
21655 gl.frontFace( gl.CCW );
21656
21657 }
21658
21659 currentFlipSided = flipSided;
21660
21661 }
21662
21663 }
21664
21665 function setCullFace( cullFace ) {
21666
21667 if ( cullFace !== CullFaceNone ) {
21668
21669 enable( gl.CULL_FACE );
21670
21671 if ( cullFace !== currentCullFace ) {
21672
21673 if ( cullFace === CullFaceBack ) {
21674
21675 gl.cullFace( gl.BACK );
21676
21677 } else if ( cullFace === CullFaceFront ) {
21678
21679 gl.cullFace( gl.FRONT );
21680
21681 } else {
21682
21683 gl.cullFace( gl.FRONT_AND_BACK );
21684
21685 }
21686
21687 }
21688
21689 } else {
21690
21691 disable( gl.CULL_FACE );
21692
21693 }
21694
21695 currentCullFace = cullFace;
21696
21697 }
21698
21699 function setLineWidth( width ) {
21700
21701 if ( width !== currentLineWidth ) {
21702
21703 if ( lineWidthAvailable ) gl.lineWidth( width );
21704
21705 currentLineWidth = width;
21706
21707 }
21708
21709 }
21710
21711 function setPolygonOffset( polygonOffset, factor, units ) {
21712
21713 if ( polygonOffset ) {
21714
21715 enable( gl.POLYGON_OFFSET_FILL );
21716
21717 if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {
21718
21719 gl.polygonOffset( factor, units );
21720
21721 currentPolygonOffsetFactor = factor;
21722 currentPolygonOffsetUnits = units;
21723
21724 }
21725
21726 } else {
21727
21728 disable( gl.POLYGON_OFFSET_FILL );
21729
21730 }
21731
21732 }
21733
21734 function setScissorTest( scissorTest ) {
21735
21736 if ( scissorTest ) {
21737
21738 enable( gl.SCISSOR_TEST );
21739
21740 } else {
21741
21742 disable( gl.SCISSOR_TEST );
21743
21744 }
21745
21746 }
21747
21748 // texture
21749
21750 function activeTexture( webglSlot ) {
21751
21752 if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;
21753
21754 if ( currentTextureSlot !== webglSlot ) {
21755
21756 gl.activeTexture( webglSlot );
21757 currentTextureSlot = webglSlot;
21758
21759 }
21760
21761 }
21762
21763 function bindTexture( webglType, webglTexture ) {
21764
21765 if ( currentTextureSlot === null ) {
21766
21767 activeTexture();
21768
21769 }
21770
21771 var boundTexture = currentBoundTextures[ currentTextureSlot ];
21772
21773 if ( boundTexture === undefined ) {
21774
21775 boundTexture = { type: undefined, texture: undefined };
21776 currentBoundTextures[ currentTextureSlot ] = boundTexture;
21777
21778 }
21779
21780 if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {
21781
21782 gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );
21783
21784 boundTexture.type = webglType;
21785 boundTexture.texture = webglTexture;
21786
21787 }
21788
21789 }
21790
21791 function compressedTexImage2D() {
21792
21793 try {
21794
21795 gl.compressedTexImage2D.apply( gl, arguments );
21796
21797 } catch ( error ) {
21798
21799 console.error( 'THREE.WebGLState:', error );
21800
21801 }
21802
21803 }
21804
21805 function texImage2D() {
21806
21807 try {
21808
21809 gl.texImage2D.apply( gl, arguments );
21810
21811 } catch ( error ) {
21812
21813 console.error( 'THREE.WebGLState:', error );
21814
21815 }
21816
21817 }
21818
21819 //
21820
21821 function scissor( scissor ) {
21822
21823 if ( currentScissor.equals( scissor ) === false ) {
21824
21825 gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
21826 currentScissor.copy( scissor );
21827
21828 }
21829
21830 }
21831
21832 function viewport( viewport ) {
21833
21834 if ( currentViewport.equals( viewport ) === false ) {
21835
21836 gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
21837 currentViewport.copy( viewport );
21838
21839 }
21840
21841 }
21842
21843 //
21844
21845 function reset() {
21846
21847 for ( var i = 0; i < enabledAttributes.length; i ++ ) {
21848
21849 if ( enabledAttributes[ i ] === 1 ) {
21850
21851 gl.disableVertexAttribArray( i );
21852 enabledAttributes[ i ] = 0;
21853
21854 }
21855
21856 }
21857
21858 capabilities = {};
21859
21860 compressedTextureFormats = null;
21861
21862 currentTextureSlot = null;
21863 currentBoundTextures = {};
21864
21865 currentProgram = null;
21866
21867 currentBlending = null;
21868
21869 currentFlipSided = null;
21870 currentCullFace = null;
21871
21872 colorBuffer.reset();
21873 depthBuffer.reset();
21874 stencilBuffer.reset();
21875
21876 }
21877
21878 return {
21879
21880 buffers: {
21881 color: colorBuffer,
21882 depth: depthBuffer,
21883 stencil: stencilBuffer
21884 },
21885
21886 initAttributes: initAttributes,
21887 enableAttribute: enableAttribute,
21888 enableAttributeAndDivisor: enableAttributeAndDivisor,
21889 disableUnusedAttributes: disableUnusedAttributes,
21890 enable: enable,
21891 disable: disable,
21892 getCompressedTextureFormats: getCompressedTextureFormats,
21893
21894 useProgram: useProgram,
21895
21896 setBlending: setBlending,
21897 setMaterial: setMaterial,
21898
21899 setFlipSided: setFlipSided,
21900 setCullFace: setCullFace,
21901
21902 setLineWidth: setLineWidth,
21903 setPolygonOffset: setPolygonOffset,
21904
21905 setScissorTest: setScissorTest,
21906
21907 activeTexture: activeTexture,
21908 bindTexture: bindTexture,
21909 compressedTexImage2D: compressedTexImage2D,
21910 texImage2D: texImage2D,
21911
21912 scissor: scissor,
21913 viewport: viewport,
21914
21915 reset: reset
21916
21917 };
21918
21919}
21920
21921/**
21922 * @author mrdoob / http://mrdoob.com/
21923 */
21924
21925function WebGLCapabilities( gl, extensions, parameters ) {
21926
21927 var maxAnisotropy;
21928
21929 function getMaxAnisotropy() {
21930
21931 if ( maxAnisotropy !== undefined ) return maxAnisotropy;
21932
21933 var extension = extensions.get( 'EXT_texture_filter_anisotropic' );
21934
21935 if ( extension !== null ) {
21936
21937 maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
21938
21939 } else {
21940
21941 maxAnisotropy = 0;
21942
21943 }
21944
21945 return maxAnisotropy;
21946
21947 }
21948
21949 function getMaxPrecision( precision ) {
21950
21951 if ( precision === 'highp' ) {
21952
21953 if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&
21954 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) {
21955
21956 return 'highp';
21957
21958 }
21959
21960 precision = 'mediump';
21961
21962 }
21963
21964 if ( precision === 'mediump' ) {
21965
21966 if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&
21967 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) {
21968
21969 return 'mediump';
21970
21971 }
21972
21973 }
21974
21975 return 'lowp';
21976
21977 }
21978
21979 var precision = parameters.precision !== undefined ? parameters.precision : 'highp';
21980 var maxPrecision = getMaxPrecision( precision );
21981
21982 if ( maxPrecision !== precision ) {
21983
21984 console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );
21985 precision = maxPrecision;
21986
21987 }
21988
21989 var logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
21990
21991 var maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );
21992 var maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
21993 var maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE );
21994 var maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE );
21995
21996 var maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );
21997 var maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS );
21998 var maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS );
21999 var maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS );
22000
22001 var vertexTextures = maxVertexTextures > 0;
22002 var floatFragmentTextures = !! extensions.get( 'OES_texture_float' );
22003 var floatVertexTextures = vertexTextures && floatFragmentTextures;
22004
22005 return {
22006
22007 getMaxAnisotropy: getMaxAnisotropy,
22008 getMaxPrecision: getMaxPrecision,
22009
22010 precision: precision,
22011 logarithmicDepthBuffer: logarithmicDepthBuffer,
22012
22013 maxTextures: maxTextures,
22014 maxVertexTextures: maxVertexTextures,
22015 maxTextureSize: maxTextureSize,
22016 maxCubemapSize: maxCubemapSize,
22017
22018 maxAttributes: maxAttributes,
22019 maxVertexUniforms: maxVertexUniforms,
22020 maxVaryings: maxVaryings,
22021 maxFragmentUniforms: maxFragmentUniforms,
22022
22023 vertexTextures: vertexTextures,
22024 floatFragmentTextures: floatFragmentTextures,
22025 floatVertexTextures: floatVertexTextures
22026
22027 };
22028
22029}
22030
22031/**
22032 * @author mrdoob / http://mrdoob.com/
22033 * @author greggman / http://games.greggman.com/
22034 * @author zz85 / http://www.lab4games.net/zz85/blog
22035 * @author tschw
22036 */
22037
22038function PerspectiveCamera( fov, aspect, near, far ) {
22039
22040 Camera.call( this );
22041
22042 this.type = 'PerspectiveCamera';
22043
22044 this.fov = fov !== undefined ? fov : 50;
22045 this.zoom = 1;
22046
22047 this.near = near !== undefined ? near : 0.1;
22048 this.far = far !== undefined ? far : 2000;
22049 this.focus = 10;
22050
22051 this.aspect = aspect !== undefined ? aspect : 1;
22052 this.view = null;
22053
22054 this.filmGauge = 35; // width of the film (default in millimeters)
22055 this.filmOffset = 0; // horizontal film offset (same unit as gauge)
22056
22057 this.updateProjectionMatrix();
22058
22059}
22060
22061PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), {
22062
22063 constructor: PerspectiveCamera,
22064
22065 isPerspectiveCamera: true,
22066
22067 copy: function ( source, recursive ) {
22068
22069 Camera.prototype.copy.call( this, source, recursive );
22070
22071 this.fov = source.fov;
22072 this.zoom = source.zoom;
22073
22074 this.near = source.near;
22075 this.far = source.far;
22076 this.focus = source.focus;
22077
22078 this.aspect = source.aspect;
22079 this.view = source.view === null ? null : Object.assign( {}, source.view );
22080
22081 this.filmGauge = source.filmGauge;
22082 this.filmOffset = source.filmOffset;
22083
22084 return this;
22085
22086 },
22087
22088 /**
22089 * Sets the FOV by focal length in respect to the current .filmGauge.
22090 *
22091 * The default film gauge is 35, so that the focal length can be specified for
22092 * a 35mm (full frame) camera.
22093 *
22094 * Values for focal length and film gauge must have the same unit.
22095 */
22096 setFocalLength: function ( focalLength ) {
22097
22098 // see http://www.bobatkins.com/photography/technical/field_of_view.html
22099 var vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
22100
22101 this.fov = _Math.RAD2DEG * 2 * Math.atan( vExtentSlope );
22102 this.updateProjectionMatrix();
22103
22104 },
22105
22106 /**
22107 * Calculates the focal length from the current .fov and .filmGauge.
22108 */
22109 getFocalLength: function () {
22110
22111 var vExtentSlope = Math.tan( _Math.DEG2RAD * 0.5 * this.fov );
22112
22113 return 0.5 * this.getFilmHeight() / vExtentSlope;
22114
22115 },
22116
22117 getEffectiveFOV: function () {
22118
22119 return _Math.RAD2DEG * 2 * Math.atan(
22120 Math.tan( _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom );
22121
22122 },
22123
22124 getFilmWidth: function () {
22125
22126 // film not completely covered in portrait format (aspect < 1)
22127 return this.filmGauge * Math.min( this.aspect, 1 );
22128
22129 },
22130
22131 getFilmHeight: function () {
22132
22133 // film not completely covered in landscape format (aspect > 1)
22134 return this.filmGauge / Math.max( this.aspect, 1 );
22135
22136 },
22137
22138 /**
22139 * Sets an offset in a larger frustum. This is useful for multi-window or
22140 * multi-monitor/multi-machine setups.
22141 *
22142 * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
22143 * the monitors are in grid like this
22144 *
22145 * +---+---+---+
22146 * | A | B | C |
22147 * +---+---+---+
22148 * | D | E | F |
22149 * +---+---+---+
22150 *
22151 * then for each monitor you would call it like this
22152 *
22153 * var w = 1920;
22154 * var h = 1080;
22155 * var fullWidth = w * 3;
22156 * var fullHeight = h * 2;
22157 *
22158 * --A--
22159 * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
22160 * --B--
22161 * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
22162 * --C--
22163 * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
22164 * --D--
22165 * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
22166 * --E--
22167 * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
22168 * --F--
22169 * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
22170 *
22171 * Note there is no reason monitors have to be the same size or in a grid.
22172 */
22173 setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) {
22174
22175 this.aspect = fullWidth / fullHeight;
22176
22177 if ( this.view === null ) {
22178
22179 this.view = {
22180 enabled: true,
22181 fullWidth: 1,
22182 fullHeight: 1,
22183 offsetX: 0,
22184 offsetY: 0,
22185 width: 1,
22186 height: 1
22187 };
22188
22189 }
22190
22191 this.view.enabled = true;
22192 this.view.fullWidth = fullWidth;
22193 this.view.fullHeight = fullHeight;
22194 this.view.offsetX = x;
22195 this.view.offsetY = y;
22196 this.view.width = width;
22197 this.view.height = height;
22198
22199 this.updateProjectionMatrix();
22200
22201 },
22202
22203 clearViewOffset: function () {
22204
22205 if ( this.view !== null ) {
22206
22207 this.view.enabled = false;
22208
22209 }
22210
22211 this.updateProjectionMatrix();
22212
22213 },
22214
22215 updateProjectionMatrix: function () {
22216
22217 var near = this.near,
22218 top = near * Math.tan(
22219 _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom,
22220 height = 2 * top,
22221 width = this.aspect * height,
22222 left = - 0.5 * width,
22223 view = this.view;
22224
22225 if ( this.view !== null && this.view.enabled ) {
22226
22227 var fullWidth = view.fullWidth,
22228 fullHeight = view.fullHeight;
22229
22230 left += view.offsetX * width / fullWidth;
22231 top -= view.offsetY * height / fullHeight;
22232 width *= view.width / fullWidth;
22233 height *= view.height / fullHeight;
22234
22235 }
22236
22237 var skew = this.filmOffset;
22238 if ( skew !== 0 ) left += near * skew / this.getFilmWidth();
22239
22240 this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far );
22241
22242 },
22243
22244 toJSON: function ( meta ) {
22245
22246 var data = Object3D.prototype.toJSON.call( this, meta );
22247
22248 data.object.fov = this.fov;
22249 data.object.zoom = this.zoom;
22250
22251 data.object.near = this.near;
22252 data.object.far = this.far;
22253 data.object.focus = this.focus;
22254
22255 data.object.aspect = this.aspect;
22256
22257 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view );
22258
22259 data.object.filmGauge = this.filmGauge;
22260 data.object.filmOffset = this.filmOffset;
22261
22262 return data;
22263
22264 }
22265
22266} );
22267
22268/**
22269 * @author mrdoob / http://mrdoob.com/
22270 */
22271
22272function ArrayCamera( array ) {
22273
22274 PerspectiveCamera.call( this );
22275
22276 this.cameras = array || [];
22277
22278}
22279
22280ArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototype ), {
22281
22282 constructor: ArrayCamera,
22283
22284 isArrayCamera: true
22285
22286} );
22287
22288/**
22289 * @author mrdoob / http://mrdoob.com/
22290 */
22291
22292function WebVRManager( renderer ) {
22293
22294 var scope = this;
22295
22296 var device = null;
22297 var frameData = null;
22298
22299 var poseTarget = null;
22300
22301 if ( typeof window !== 'undefined' && 'VRFrameData' in window ) {
22302
22303 frameData = new window.VRFrameData();
22304
22305 }
22306
22307 var matrixWorldInverse = new Matrix4();
22308
22309 var cameraL = new PerspectiveCamera();
22310 cameraL.bounds = new Vector4( 0.0, 0.0, 0.5, 1.0 );
22311 cameraL.layers.enable( 1 );
22312
22313 var cameraR = new PerspectiveCamera();
22314 cameraR.bounds = new Vector4( 0.5, 0.0, 0.5, 1.0 );
22315 cameraR.layers.enable( 2 );
22316
22317 var cameraVR = new ArrayCamera( [ cameraL, cameraR ] );
22318 cameraVR.layers.enable( 1 );
22319 cameraVR.layers.enable( 2 );
22320
22321 //
22322
22323 var currentSize, currentPixelRatio;
22324
22325 function onVRDisplayPresentChange() {
22326
22327 if ( device !== null && device.isPresenting ) {
22328
22329 var eyeParameters = device.getEyeParameters( 'left' );
22330 var renderWidth = eyeParameters.renderWidth;
22331 var renderHeight = eyeParameters.renderHeight;
22332
22333 currentPixelRatio = renderer.getPixelRatio();
22334 currentSize = renderer.getSize();
22335
22336 renderer.setDrawingBufferSize( renderWidth * 2, renderHeight, 1 );
22337
22338 } else if ( scope.enabled ) {
22339
22340 renderer.setDrawingBufferSize( currentSize.width, currentSize.height, currentPixelRatio );
22341
22342 }
22343
22344 }
22345
22346 if ( typeof window !== 'undefined' ) {
22347
22348 window.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false );
22349
22350 }
22351
22352 //
22353
22354 this.enabled = false;
22355
22356 this.getDevice = function () {
22357
22358 return device;
22359
22360 };
22361
22362 this.setDevice = function ( value ) {
22363
22364 if ( value !== undefined ) device = value;
22365
22366 };
22367
22368 this.setPoseTarget = function ( object ) {
22369
22370 if ( object !== undefined ) poseTarget = object;
22371
22372 };
22373
22374 this.getCamera = function ( camera ) {
22375
22376 if ( device === null ) return camera;
22377
22378 device.depthNear = camera.near;
22379 device.depthFar = camera.far;
22380
22381 device.getFrameData( frameData );
22382
22383 //
22384
22385 var pose = frameData.pose;
22386 var poseObject = poseTarget !== null ? poseTarget : camera;
22387
22388 if ( pose.position !== null ) {
22389
22390 poseObject.position.fromArray( pose.position );
22391
22392 } else {
22393
22394 poseObject.position.set( 0, 0, 0 );
22395
22396 }
22397
22398 if ( pose.orientation !== null ) {
22399
22400 poseObject.quaternion.fromArray( pose.orientation );
22401
22402 }
22403
22404 poseObject.updateMatrixWorld();
22405
22406 if ( device.isPresenting === false ) return camera;
22407
22408 //
22409
22410 cameraL.near = camera.near;
22411 cameraR.near = camera.near;
22412
22413 cameraL.far = camera.far;
22414 cameraR.far = camera.far;
22415
22416 cameraVR.matrixWorld.copy( camera.matrixWorld );
22417 cameraVR.matrixWorldInverse.copy( camera.matrixWorldInverse );
22418
22419 cameraL.matrixWorldInverse.fromArray( frameData.leftViewMatrix );
22420 cameraR.matrixWorldInverse.fromArray( frameData.rightViewMatrix );
22421
22422 var parent = poseObject.parent;
22423
22424 if ( parent !== null ) {
22425
22426 matrixWorldInverse.getInverse( parent.matrixWorld );
22427
22428 cameraL.matrixWorldInverse.multiply( matrixWorldInverse );
22429 cameraR.matrixWorldInverse.multiply( matrixWorldInverse );
22430
22431 }
22432
22433 // envMap and Mirror needs camera.matrixWorld
22434
22435 cameraL.matrixWorld.getInverse( cameraL.matrixWorldInverse );
22436 cameraR.matrixWorld.getInverse( cameraR.matrixWorldInverse );
22437
22438 cameraL.projectionMatrix.fromArray( frameData.leftProjectionMatrix );
22439 cameraR.projectionMatrix.fromArray( frameData.rightProjectionMatrix );
22440
22441 // HACK @mrdoob
22442 // https://github.com/w3c/webvr/issues/203
22443
22444 cameraVR.projectionMatrix.copy( cameraL.projectionMatrix );
22445
22446 //
22447
22448 var layers = device.getLayers();
22449
22450 if ( layers.length ) {
22451
22452 var layer = layers[ 0 ];
22453
22454 if ( layer.leftBounds !== null && layer.leftBounds.length === 4 ) {
22455
22456 cameraL.bounds.fromArray( layer.leftBounds );
22457
22458 }
22459
22460 if ( layer.rightBounds !== null && layer.rightBounds.length === 4 ) {
22461
22462 cameraR.bounds.fromArray( layer.rightBounds );
22463
22464 }
22465
22466 }
22467
22468 return cameraVR;
22469
22470 };
22471
22472 this.submitFrame = function () {
22473
22474 if ( device && device.isPresenting ) device.submitFrame();
22475
22476 };
22477
22478 this.dispose = function () {
22479
22480 if ( typeof window !== 'undefined' ) {
22481
22482 window.removeEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange );
22483
22484 }
22485
22486 };
22487
22488}
22489
22490/**
22491 * @author mrdoob / http://mrdoob.com/
22492 */
22493
22494function WebGLExtensions( gl ) {
22495
22496 var extensions = {};
22497
22498 return {
22499
22500 get: function ( name ) {
22501
22502 if ( extensions[ name ] !== undefined ) {
22503
22504 return extensions[ name ];
22505
22506 }
22507
22508 var extension;
22509
22510 switch ( name ) {
22511
22512 case 'WEBGL_depth_texture':
22513 extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
22514 break;
22515
22516 case 'EXT_texture_filter_anisotropic':
22517 extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
22518 break;
22519
22520 case 'WEBGL_compressed_texture_s3tc':
22521 extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
22522 break;
22523
22524 case 'WEBGL_compressed_texture_pvrtc':
22525 extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
22526 break;
22527
22528 case 'WEBGL_compressed_texture_etc1':
22529 extension = gl.getExtension( 'WEBGL_compressed_texture_etc1' );
22530 break;
22531
22532 default:
22533 extension = gl.getExtension( name );
22534
22535 }
22536
22537 if ( extension === null ) {
22538
22539 console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );
22540
22541 }
22542
22543 extensions[ name ] = extension;
22544
22545 return extension;
22546
22547 }
22548
22549 };
22550
22551}
22552
22553/**
22554 * @author tschw
22555 */
22556
22557function WebGLClipping() {
22558
22559 var scope = this,
22560
22561 globalState = null,
22562 numGlobalPlanes = 0,
22563 localClippingEnabled = false,
22564 renderingShadows = false,
22565
22566 plane = new Plane(),
22567 viewNormalMatrix = new Matrix3(),
22568
22569 uniform = { value: null, needsUpdate: false };
22570
22571 this.uniform = uniform;
22572 this.numPlanes = 0;
22573 this.numIntersection = 0;
22574
22575 this.init = function ( planes, enableLocalClipping, camera ) {
22576
22577 var enabled =
22578 planes.length !== 0 ||
22579 enableLocalClipping ||
22580 // enable state of previous frame - the clipping code has to
22581 // run another frame in order to reset the state:
22582 numGlobalPlanes !== 0 ||
22583 localClippingEnabled;
22584
22585 localClippingEnabled = enableLocalClipping;
22586
22587 globalState = projectPlanes( planes, camera, 0 );
22588 numGlobalPlanes = planes.length;
22589
22590 return enabled;
22591
22592 };
22593
22594 this.beginShadows = function () {
22595
22596 renderingShadows = true;
22597 projectPlanes( null );
22598
22599 };
22600
22601 this.endShadows = function () {
22602
22603 renderingShadows = false;
22604 resetGlobalState();
22605
22606 };
22607
22608 this.setState = function ( planes, clipIntersection, clipShadows, camera, cache, fromCache ) {
22609
22610 if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) {
22611
22612 // there's no local clipping
22613
22614 if ( renderingShadows ) {
22615
22616 // there's no global clipping
22617
22618 projectPlanes( null );
22619
22620 } else {
22621
22622 resetGlobalState();
22623
22624 }
22625
22626 } else {
22627
22628 var nGlobal = renderingShadows ? 0 : numGlobalPlanes,
22629 lGlobal = nGlobal * 4,
22630
22631 dstArray = cache.clippingState || null;
22632
22633 uniform.value = dstArray; // ensure unique state
22634
22635 dstArray = projectPlanes( planes, camera, lGlobal, fromCache );
22636
22637 for ( var i = 0; i !== lGlobal; ++ i ) {
22638
22639 dstArray[ i ] = globalState[ i ];
22640
22641 }
22642
22643 cache.clippingState = dstArray;
22644 this.numIntersection = clipIntersection ? this.numPlanes : 0;
22645 this.numPlanes += nGlobal;
22646
22647 }
22648
22649
22650 };
22651
22652 function resetGlobalState() {
22653
22654 if ( uniform.value !== globalState ) {
22655
22656 uniform.value = globalState;
22657 uniform.needsUpdate = numGlobalPlanes > 0;
22658
22659 }
22660
22661 scope.numPlanes = numGlobalPlanes;
22662 scope.numIntersection = 0;
22663
22664 }
22665
22666 function projectPlanes( planes, camera, dstOffset, skipTransform ) {
22667
22668 var nPlanes = planes !== null ? planes.length : 0,
22669 dstArray = null;
22670
22671 if ( nPlanes !== 0 ) {
22672
22673 dstArray = uniform.value;
22674
22675 if ( skipTransform !== true || dstArray === null ) {
22676
22677 var flatSize = dstOffset + nPlanes * 4,
22678 viewMatrix = camera.matrixWorldInverse;
22679
22680 viewNormalMatrix.getNormalMatrix( viewMatrix );
22681
22682 if ( dstArray === null || dstArray.length < flatSize ) {
22683
22684 dstArray = new Float32Array( flatSize );
22685
22686 }
22687
22688 for ( var i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {
22689
22690 plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );
22691
22692 plane.normal.toArray( dstArray, i4 );
22693 dstArray[ i4 + 3 ] = plane.constant;
22694
22695 }
22696
22697 }
22698
22699 uniform.value = dstArray;
22700 uniform.needsUpdate = true;
22701
22702 }
22703
22704 scope.numPlanes = nPlanes;
22705
22706 return dstArray;
22707
22708 }
22709
22710}
22711
22712/**
22713 * @author thespite / http://www.twitter.com/thespite
22714 */
22715
22716function WebGLUtils( gl, extensions ) {
22717
22718 function convert( p ) {
22719
22720 var extension;
22721
22722 if ( p === RepeatWrapping ) return gl.REPEAT;
22723 if ( p === ClampToEdgeWrapping ) return gl.CLAMP_TO_EDGE;
22724 if ( p === MirroredRepeatWrapping ) return gl.MIRRORED_REPEAT;
22725
22726 if ( p === NearestFilter ) return gl.NEAREST;
22727 if ( p === NearestMipMapNearestFilter ) return gl.NEAREST_MIPMAP_NEAREST;
22728 if ( p === NearestMipMapLinearFilter ) return gl.NEAREST_MIPMAP_LINEAR;
22729
22730 if ( p === LinearFilter ) return gl.LINEAR;
22731 if ( p === LinearMipMapNearestFilter ) return gl.LINEAR_MIPMAP_NEAREST;
22732 if ( p === LinearMipMapLinearFilter ) return gl.LINEAR_MIPMAP_LINEAR;
22733
22734 if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE;
22735 if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4;
22736 if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1;
22737 if ( p === UnsignedShort565Type ) return gl.UNSIGNED_SHORT_5_6_5;
22738
22739 if ( p === ByteType ) return gl.BYTE;
22740 if ( p === ShortType ) return gl.SHORT;
22741 if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT;
22742 if ( p === IntType ) return gl.INT;
22743 if ( p === UnsignedIntType ) return gl.UNSIGNED_INT;
22744 if ( p === FloatType ) return gl.FLOAT;
22745
22746 if ( p === HalfFloatType ) {
22747
22748 extension = extensions.get( 'OES_texture_half_float' );
22749
22750 if ( extension !== null ) return extension.HALF_FLOAT_OES;
22751
22752 }
22753
22754 if ( p === AlphaFormat ) return gl.ALPHA;
22755 if ( p === RGBFormat ) return gl.RGB;
22756 if ( p === RGBAFormat ) return gl.RGBA;
22757 if ( p === LuminanceFormat ) return gl.LUMINANCE;
22758 if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA;
22759 if ( p === DepthFormat ) return gl.DEPTH_COMPONENT;
22760 if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL;
22761
22762 if ( p === AddEquation ) return gl.FUNC_ADD;
22763 if ( p === SubtractEquation ) return gl.FUNC_SUBTRACT;
22764 if ( p === ReverseSubtractEquation ) return gl.FUNC_REVERSE_SUBTRACT;
22765
22766 if ( p === ZeroFactor ) return gl.ZERO;
22767 if ( p === OneFactor ) return gl.ONE;
22768 if ( p === SrcColorFactor ) return gl.SRC_COLOR;
22769 if ( p === OneMinusSrcColorFactor ) return gl.ONE_MINUS_SRC_COLOR;
22770 if ( p === SrcAlphaFactor ) return gl.SRC_ALPHA;
22771 if ( p === OneMinusSrcAlphaFactor ) return gl.ONE_MINUS_SRC_ALPHA;
22772 if ( p === DstAlphaFactor ) return gl.DST_ALPHA;
22773 if ( p === OneMinusDstAlphaFactor ) return gl.ONE_MINUS_DST_ALPHA;
22774
22775 if ( p === DstColorFactor ) return gl.DST_COLOR;
22776 if ( p === OneMinusDstColorFactor ) return gl.ONE_MINUS_DST_COLOR;
22777 if ( p === SrcAlphaSaturateFactor ) return gl.SRC_ALPHA_SATURATE;
22778
22779 if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format ||
22780 p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {
22781
22782 extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
22783
22784 if ( extension !== null ) {
22785
22786 if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
22787 if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
22788 if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
22789 if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
22790
22791 }
22792
22793 }
22794
22795 if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format ||
22796 p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {
22797
22798 extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
22799
22800 if ( extension !== null ) {
22801
22802 if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
22803 if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
22804 if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
22805 if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
22806
22807 }
22808
22809 }
22810
22811 if ( p === RGB_ETC1_Format ) {
22812
22813 extension = extensions.get( 'WEBGL_compressed_texture_etc1' );
22814
22815 if ( extension !== null ) return extension.COMPRESSED_RGB_ETC1_WEBGL;
22816
22817 }
22818
22819 if ( p === MinEquation || p === MaxEquation ) {
22820
22821 extension = extensions.get( 'EXT_blend_minmax' );
22822
22823 if ( extension !== null ) {
22824
22825 if ( p === MinEquation ) return extension.MIN_EXT;
22826 if ( p === MaxEquation ) return extension.MAX_EXT;
22827
22828 }
22829
22830 }
22831
22832 if ( p === UnsignedInt248Type ) {
22833
22834 extension = extensions.get( 'WEBGL_depth_texture' );
22835
22836 if ( extension !== null ) return extension.UNSIGNED_INT_24_8_WEBGL;
22837
22838 }
22839
22840 return 0;
22841
22842 }
22843
22844 return { convert: convert };
22845
22846}
22847
22848/**
22849 * @author supereggbert / http://www.paulbrunt.co.uk/
22850 * @author mrdoob / http://mrdoob.com/
22851 * @author alteredq / http://alteredqualia.com/
22852 * @author szimek / https://github.com/szimek/
22853 * @author tschw
22854 */
22855
22856function WebGLRenderer( parameters ) {
22857
22858 console.log( 'THREE.WebGLRenderer', REVISION );
22859
22860 parameters = parameters || {};
22861
22862 var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ),
22863 _context = parameters.context !== undefined ? parameters.context : null,
22864
22865 _alpha = parameters.alpha !== undefined ? parameters.alpha : false,
22866 _depth = parameters.depth !== undefined ? parameters.depth : true,
22867 _stencil = parameters.stencil !== undefined ? parameters.stencil : true,
22868 _antialias = parameters.antialias !== undefined ? parameters.antialias : false,
22869 _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
22870 _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
22871 _powerPreference = parameters.powerPreference !== undefined ? parameters.powerPreference : 'default';
22872
22873 var lightsArray = [];
22874 var shadowsArray = [];
22875
22876 var currentRenderList = null;
22877
22878 var spritesArray = [];
22879 var flaresArray = [];
22880
22881 // public properties
22882
22883 this.domElement = _canvas;
22884 this.context = null;
22885
22886 // clearing
22887
22888 this.autoClear = true;
22889 this.autoClearColor = true;
22890 this.autoClearDepth = true;
22891 this.autoClearStencil = true;
22892
22893 // scene graph
22894
22895 this.sortObjects = true;
22896
22897 // user-defined clipping
22898
22899 this.clippingPlanes = [];
22900 this.localClippingEnabled = false;
22901
22902 // physically based shading
22903
22904 this.gammaFactor = 2.0; // for backwards compatibility
22905 this.gammaInput = false;
22906 this.gammaOutput = false;
22907
22908 // physical lights
22909
22910 this.physicallyCorrectLights = false;
22911
22912 // tone mapping
22913
22914 this.toneMapping = LinearToneMapping;
22915 this.toneMappingExposure = 1.0;
22916 this.toneMappingWhitePoint = 1.0;
22917
22918 // morphs
22919
22920 this.maxMorphTargets = 8;
22921 this.maxMorphNormals = 4;
22922
22923 // internal properties
22924
22925 var _this = this,
22926
22927 _isContextLost = false,
22928
22929 // internal state cache
22930
22931 _currentRenderTarget = null,
22932 _currentFramebuffer = null,
22933 _currentMaterialId = - 1,
22934 _currentGeometryProgram = '',
22935
22936 _currentCamera = null,
22937 _currentArrayCamera = null,
22938
22939 _currentViewport = new Vector4(),
22940 _currentScissor = new Vector4(),
22941 _currentScissorTest = null,
22942
22943 //
22944
22945 _usedTextureUnits = 0,
22946
22947 //
22948
22949 _width = _canvas.width,
22950 _height = _canvas.height,
22951
22952 _pixelRatio = 1,
22953
22954 _viewport = new Vector4( 0, 0, _width, _height ),
22955 _scissor = new Vector4( 0, 0, _width, _height ),
22956 _scissorTest = false,
22957
22958 // frustum
22959
22960 _frustum = new Frustum(),
22961
22962 // clipping
22963
22964 _clipping = new WebGLClipping(),
22965 _clippingEnabled = false,
22966 _localClippingEnabled = false,
22967
22968 // camera matrices cache
22969
22970 _projScreenMatrix = new Matrix4(),
22971
22972 _vector3 = new Vector3(),
22973
22974 // info
22975
22976 _infoMemory = {
22977 geometries: 0,
22978 textures: 0
22979 },
22980
22981 _infoRender = {
22982
22983 frame: 0,
22984 calls: 0,
22985 vertices: 0,
22986 faces: 0,
22987 points: 0
22988
22989 };
22990
22991 this.info = {
22992
22993 render: _infoRender,
22994 memory: _infoMemory,
22995 programs: null
22996
22997 };
22998
22999 function getTargetPixelRatio() {
23000
23001 return _currentRenderTarget === null ? _pixelRatio : 1;
23002
23003 }
23004
23005 // initialize
23006
23007 var _gl;
23008
23009 try {
23010
23011 var contextAttributes = {
23012 alpha: _alpha,
23013 depth: _depth,
23014 stencil: _stencil,
23015 antialias: _antialias,
23016 premultipliedAlpha: _premultipliedAlpha,
23017 preserveDrawingBuffer: _preserveDrawingBuffer,
23018 powerPreference: _powerPreference
23019 };
23020
23021 // event listeners must be registered before WebGL context is created, see #12753
23022
23023 _canvas.addEventListener( 'webglcontextlost', onContextLost, false );
23024 _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false );
23025
23026 _gl = _context || _canvas.getContext( 'webgl', contextAttributes ) || _canvas.getContext( 'experimental-webgl', contextAttributes );
23027
23028 if ( _gl === null ) {
23029
23030 if ( _canvas.getContext( 'webgl' ) !== null ) {
23031
23032 throw new Error( 'Error creating WebGL context with your selected attributes.' );
23033
23034 } else {
23035
23036 throw new Error( 'Error creating WebGL context.' );
23037
23038 }
23039
23040 }
23041
23042 // Some experimental-webgl implementations do not have getShaderPrecisionFormat
23043
23044 if ( _gl.getShaderPrecisionFormat === undefined ) {
23045
23046 _gl.getShaderPrecisionFormat = function () {
23047
23048 return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };
23049
23050 };
23051
23052 }
23053
23054 } catch ( error ) {
23055
23056 console.error( 'THREE.WebGLRenderer: ' + error.message );
23057
23058 }
23059
23060 var extensions, capabilities, state;
23061 var properties, textures, attributes, geometries, objects, lights;
23062 var programCache, renderLists;
23063
23064 var background, morphtargets, bufferRenderer, indexedBufferRenderer;
23065 var flareRenderer, spriteRenderer;
23066
23067 var utils;
23068
23069 function initGLContext() {
23070
23071 extensions = new WebGLExtensions( _gl );
23072 extensions.get( 'WEBGL_depth_texture' );
23073 extensions.get( 'OES_texture_float' );
23074 extensions.get( 'OES_texture_float_linear' );
23075 extensions.get( 'OES_texture_half_float' );
23076 extensions.get( 'OES_texture_half_float_linear' );
23077 extensions.get( 'OES_standard_derivatives' );
23078 extensions.get( 'OES_element_index_uint' );
23079 extensions.get( 'ANGLE_instanced_arrays' );
23080
23081 utils = new WebGLUtils( _gl, extensions );
23082
23083 capabilities = new WebGLCapabilities( _gl, extensions, parameters );
23084
23085 state = new WebGLState( _gl, extensions, utils );
23086 state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );
23087 state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );
23088
23089 properties = new WebGLProperties();
23090 textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, _infoMemory );
23091 attributes = new WebGLAttributes( _gl );
23092 geometries = new WebGLGeometries( _gl, attributes, _infoMemory );
23093 objects = new WebGLObjects( geometries, _infoRender );
23094 morphtargets = new WebGLMorphtargets( _gl );
23095 programCache = new WebGLPrograms( _this, extensions, capabilities );
23096 lights = new WebGLLights();
23097 renderLists = new WebGLRenderLists();
23098
23099 background = new WebGLBackground( _this, state, geometries, _premultipliedAlpha );
23100
23101 bufferRenderer = new WebGLBufferRenderer( _gl, extensions, _infoRender );
23102 indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, _infoRender );
23103
23104 flareRenderer = new WebGLFlareRenderer( _this, _gl, state, textures, capabilities );
23105 spriteRenderer = new WebGLSpriteRenderer( _this, _gl, state, textures, capabilities );
23106
23107 _this.info.programs = programCache.programs;
23108
23109 _this.context = _gl;
23110 _this.capabilities = capabilities;
23111 _this.extensions = extensions;
23112 _this.properties = properties;
23113 _this.renderLists = renderLists;
23114 _this.state = state;
23115
23116 }
23117
23118 initGLContext();
23119
23120 // vr
23121
23122 var vr = new WebVRManager( _this );
23123
23124 this.vr = vr;
23125
23126 // shadow map
23127
23128 var shadowMap = new WebGLShadowMap( _this, objects, capabilities.maxTextureSize );
23129
23130 this.shadowMap = shadowMap;
23131
23132 // API
23133
23134 this.getContext = function () {
23135
23136 return _gl;
23137
23138 };
23139
23140 this.getContextAttributes = function () {
23141
23142 return _gl.getContextAttributes();
23143
23144 };
23145
23146 this.forceContextLoss = function () {
23147
23148 var extension = extensions.get( 'WEBGL_lose_context' );
23149 if ( extension ) extension.loseContext();
23150
23151 };
23152
23153 this.forceContextRestore = function () {
23154
23155 var extension = extensions.get( 'WEBGL_lose_context' );
23156 if ( extension ) extension.restoreContext();
23157
23158 };
23159
23160 this.getPixelRatio = function () {
23161
23162 return _pixelRatio;
23163
23164 };
23165
23166 this.setPixelRatio = function ( value ) {
23167
23168 if ( value === undefined ) return;
23169
23170 _pixelRatio = value;
23171
23172 this.setSize( _width, _height, false );
23173
23174 };
23175
23176 this.getSize = function () {
23177
23178 return {
23179 width: _width,
23180 height: _height
23181 };
23182
23183 };
23184
23185 this.setSize = function ( width, height, updateStyle ) {
23186
23187 var device = vr.getDevice();
23188
23189 if ( device && device.isPresenting ) {
23190
23191 console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
23192 return;
23193
23194 }
23195
23196 _width = width;
23197 _height = height;
23198
23199 _canvas.width = width * _pixelRatio;
23200 _canvas.height = height * _pixelRatio;
23201
23202 if ( updateStyle !== false ) {
23203
23204 _canvas.style.width = width + 'px';
23205 _canvas.style.height = height + 'px';
23206
23207 }
23208
23209 this.setViewport( 0, 0, width, height );
23210
23211 };
23212
23213 this.getDrawingBufferSize = function () {
23214
23215 return {
23216 width: _width * _pixelRatio,
23217 height: _height * _pixelRatio
23218 };
23219
23220 };
23221
23222 this.setDrawingBufferSize = function ( width, height, pixelRatio ) {
23223
23224 _width = width;
23225 _height = height;
23226
23227 _pixelRatio = pixelRatio;
23228
23229 _canvas.width = width * pixelRatio;
23230 _canvas.height = height * pixelRatio;
23231
23232 this.setViewport( 0, 0, width, height );
23233
23234 };
23235
23236 this.setViewport = function ( x, y, width, height ) {
23237
23238 _viewport.set( x, _height - y - height, width, height );
23239 state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) );
23240
23241 };
23242
23243 this.setScissor = function ( x, y, width, height ) {
23244
23245 _scissor.set( x, _height - y - height, width, height );
23246 state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) );
23247
23248 };
23249
23250 this.setScissorTest = function ( boolean ) {
23251
23252 state.setScissorTest( _scissorTest = boolean );
23253
23254 };
23255
23256 // Clearing
23257
23258 this.getClearColor = function () {
23259
23260 return background.getClearColor();
23261
23262 };
23263
23264 this.setClearColor = function () {
23265
23266 background.setClearColor.apply( background, arguments );
23267
23268 };
23269
23270 this.getClearAlpha = function () {
23271
23272 return background.getClearAlpha();
23273
23274 };
23275
23276 this.setClearAlpha = function () {
23277
23278 background.setClearAlpha.apply( background, arguments );
23279
23280 };
23281
23282 this.clear = function ( color, depth, stencil ) {
23283
23284 var bits = 0;
23285
23286 if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;
23287 if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;
23288 if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;
23289
23290 _gl.clear( bits );
23291
23292 };
23293
23294 this.clearColor = function () {
23295
23296 this.clear( true, false, false );
23297
23298 };
23299
23300 this.clearDepth = function () {
23301
23302 this.clear( false, true, false );
23303
23304 };
23305
23306 this.clearStencil = function () {
23307
23308 this.clear( false, false, true );
23309
23310 };
23311
23312 this.clearTarget = function ( renderTarget, color, depth, stencil ) {
23313
23314 this.setRenderTarget( renderTarget );
23315 this.clear( color, depth, stencil );
23316
23317 };
23318
23319 //
23320
23321 this.dispose = function () {
23322
23323 _canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
23324 _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );
23325
23326 renderLists.dispose();
23327
23328 vr.dispose();
23329
23330 };
23331
23332 // Events
23333
23334 function onContextLost( event ) {
23335
23336 event.preventDefault();
23337
23338 console.log( 'THREE.WebGLRenderer: Context Lost.' );
23339
23340 _isContextLost = true;
23341
23342 }
23343
23344 function onContextRestore( /* event */ ) {
23345
23346 console.log( 'THREE.WebGLRenderer: Context Restored.' );
23347
23348 _isContextLost = false;
23349
23350 initGLContext();
23351
23352 }
23353
23354 function onMaterialDispose( event ) {
23355
23356 var material = event.target;
23357
23358 material.removeEventListener( 'dispose', onMaterialDispose );
23359
23360 deallocateMaterial( material );
23361
23362 }
23363
23364 // Buffer deallocation
23365
23366 function deallocateMaterial( material ) {
23367
23368 releaseMaterialProgramReference( material );
23369
23370 properties.remove( material );
23371
23372 }
23373
23374
23375 function releaseMaterialProgramReference( material ) {
23376
23377 var programInfo = properties.get( material ).program;
23378
23379 material.program = undefined;
23380
23381 if ( programInfo !== undefined ) {
23382
23383 programCache.releaseProgram( programInfo );
23384
23385 }
23386
23387 }
23388
23389 // Buffer rendering
23390
23391 function renderObjectImmediate( object, program, material ) {
23392
23393 object.render( function ( object ) {
23394
23395 _this.renderBufferImmediate( object, program, material );
23396
23397 } );
23398
23399 }
23400
23401 this.renderBufferImmediate = function ( object, program, material ) {
23402
23403 state.initAttributes();
23404
23405 var buffers = properties.get( object );
23406
23407 if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer();
23408 if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer();
23409 if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer();
23410 if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer();
23411
23412 var programAttributes = program.getAttributes();
23413
23414 if ( object.hasPositions ) {
23415
23416 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.position );
23417 _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
23418
23419 state.enableAttribute( programAttributes.position );
23420 _gl.vertexAttribPointer( programAttributes.position, 3, _gl.FLOAT, false, 0, 0 );
23421
23422 }
23423
23424 if ( object.hasNormals ) {
23425
23426 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.normal );
23427
23428 if ( ! material.isMeshPhongMaterial &&
23429 ! material.isMeshStandardMaterial &&
23430 ! material.isMeshNormalMaterial &&
23431 material.flatShading === true ) {
23432
23433 for ( var i = 0, l = object.count * 3; i < l; i += 9 ) {
23434
23435 var array = object.normalArray;
23436
23437 var nx = ( array[ i + 0 ] + array[ i + 3 ] + array[ i + 6 ] ) / 3;
23438 var ny = ( array[ i + 1 ] + array[ i + 4 ] + array[ i + 7 ] ) / 3;
23439 var nz = ( array[ i + 2 ] + array[ i + 5 ] + array[ i + 8 ] ) / 3;
23440
23441 array[ i + 0 ] = nx;
23442 array[ i + 1 ] = ny;
23443 array[ i + 2 ] = nz;
23444
23445 array[ i + 3 ] = nx;
23446 array[ i + 4 ] = ny;
23447 array[ i + 5 ] = nz;
23448
23449 array[ i + 6 ] = nx;
23450 array[ i + 7 ] = ny;
23451 array[ i + 8 ] = nz;
23452
23453 }
23454
23455 }
23456
23457 _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW );
23458
23459 state.enableAttribute( programAttributes.normal );
23460
23461 _gl.vertexAttribPointer( programAttributes.normal, 3, _gl.FLOAT, false, 0, 0 );
23462
23463 }
23464
23465 if ( object.hasUvs && material.map ) {
23466
23467 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.uv );
23468 _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
23469
23470 state.enableAttribute( programAttributes.uv );
23471
23472 _gl.vertexAttribPointer( programAttributes.uv, 2, _gl.FLOAT, false, 0, 0 );
23473
23474 }
23475
23476 if ( object.hasColors && material.vertexColors !== NoColors ) {
23477
23478 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffers.color );
23479 _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW );
23480
23481 state.enableAttribute( programAttributes.color );
23482
23483 _gl.vertexAttribPointer( programAttributes.color, 3, _gl.FLOAT, false, 0, 0 );
23484
23485 }
23486
23487 state.disableUnusedAttributes();
23488
23489 _gl.drawArrays( _gl.TRIANGLES, 0, object.count );
23490
23491 object.count = 0;
23492
23493 };
23494
23495 this.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) {
23496
23497 var frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );
23498
23499 state.setMaterial( material, frontFaceCW );
23500
23501 var program = setProgram( camera, fog, material, object );
23502 var geometryProgram = geometry.id + '_' + program.id + '_' + ( material.wireframe === true );
23503
23504 var updateBuffers = false;
23505
23506 if ( geometryProgram !== _currentGeometryProgram ) {
23507
23508 _currentGeometryProgram = geometryProgram;
23509 updateBuffers = true;
23510
23511 }
23512
23513 if ( object.morphTargetInfluences ) {
23514
23515 morphtargets.update( object, geometry, material, program );
23516
23517 updateBuffers = true;
23518
23519 }
23520
23521 //
23522
23523 var index = geometry.index;
23524 var position = geometry.attributes.position;
23525 var rangeFactor = 1;
23526
23527 if ( material.wireframe === true ) {
23528
23529 index = geometries.getWireframeAttribute( geometry );
23530 rangeFactor = 2;
23531
23532 }
23533
23534 var attribute;
23535 var renderer = bufferRenderer;
23536
23537 if ( index !== null ) {
23538
23539 attribute = attributes.get( index );
23540
23541 renderer = indexedBufferRenderer;
23542 renderer.setIndex( attribute );
23543
23544 }
23545
23546 if ( updateBuffers ) {
23547
23548 setupVertexAttributes( material, program, geometry );
23549
23550 if ( index !== null ) {
23551
23552 _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attribute.buffer );
23553
23554 }
23555
23556 }
23557
23558 //
23559
23560 var dataCount = 0;
23561
23562 if ( index !== null ) {
23563
23564 dataCount = index.count;
23565
23566 } else if ( position !== undefined ) {
23567
23568 dataCount = position.count;
23569
23570 }
23571
23572 var rangeStart = geometry.drawRange.start * rangeFactor;
23573 var rangeCount = geometry.drawRange.count * rangeFactor;
23574
23575 var groupStart = group !== null ? group.start * rangeFactor : 0;
23576 var groupCount = group !== null ? group.count * rangeFactor : Infinity;
23577
23578 var drawStart = Math.max( rangeStart, groupStart );
23579 var drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1;
23580
23581 var drawCount = Math.max( 0, drawEnd - drawStart + 1 );
23582
23583 if ( drawCount === 0 ) return;
23584
23585 //
23586
23587 if ( object.isMesh ) {
23588
23589 if ( material.wireframe === true ) {
23590
23591 state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );
23592 renderer.setMode( _gl.LINES );
23593
23594 } else {
23595
23596 switch ( object.drawMode ) {
23597
23598 case TrianglesDrawMode:
23599 renderer.setMode( _gl.TRIANGLES );
23600 break;
23601
23602 case TriangleStripDrawMode:
23603 renderer.setMode( _gl.TRIANGLE_STRIP );
23604 break;
23605
23606 case TriangleFanDrawMode:
23607 renderer.setMode( _gl.TRIANGLE_FAN );
23608 break;
23609
23610 }
23611
23612 }
23613
23614
23615 } else if ( object.isLine ) {
23616
23617 var lineWidth = material.linewidth;
23618
23619 if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material
23620
23621 state.setLineWidth( lineWidth * getTargetPixelRatio() );
23622
23623 if ( object.isLineSegments ) {
23624
23625 renderer.setMode( _gl.LINES );
23626
23627 } else if ( object.isLineLoop ) {
23628
23629 renderer.setMode( _gl.LINE_LOOP );
23630
23631 } else {
23632
23633 renderer.setMode( _gl.LINE_STRIP );
23634
23635 }
23636
23637 } else if ( object.isPoints ) {
23638
23639 renderer.setMode( _gl.POINTS );
23640
23641 }
23642
23643 if ( geometry && geometry.isInstancedBufferGeometry ) {
23644
23645 if ( geometry.maxInstancedCount > 0 ) {
23646
23647 renderer.renderInstances( geometry, drawStart, drawCount );
23648
23649 }
23650
23651 } else {
23652
23653 renderer.render( drawStart, drawCount );
23654
23655 }
23656
23657 };
23658
23659 function setupVertexAttributes( material, program, geometry, startIndex ) {
23660
23661 if ( geometry && geometry.isInstancedBufferGeometry ) {
23662
23663 if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) {
23664
23665 console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' );
23666 return;
23667
23668 }
23669
23670 }
23671
23672 if ( startIndex === undefined ) startIndex = 0;
23673
23674 state.initAttributes();
23675
23676 var geometryAttributes = geometry.attributes;
23677
23678 var programAttributes = program.getAttributes();
23679
23680 var materialDefaultAttributeValues = material.defaultAttributeValues;
23681
23682 for ( var name in programAttributes ) {
23683
23684 var programAttribute = programAttributes[ name ];
23685
23686 if ( programAttribute >= 0 ) {
23687
23688 var geometryAttribute = geometryAttributes[ name ];
23689
23690 if ( geometryAttribute !== undefined ) {
23691
23692 var normalized = geometryAttribute.normalized;
23693 var size = geometryAttribute.itemSize;
23694
23695 var attribute = attributes.get( geometryAttribute );
23696
23697 // TODO Attribute may not be available on context restore
23698
23699 if ( attribute === undefined ) continue;
23700
23701 var buffer = attribute.buffer;
23702 var type = attribute.type;
23703 var bytesPerElement = attribute.bytesPerElement;
23704
23705 if ( geometryAttribute.isInterleavedBufferAttribute ) {
23706
23707 var data = geometryAttribute.data;
23708 var stride = data.stride;
23709 var offset = geometryAttribute.offset;
23710
23711 if ( data && data.isInstancedInterleavedBuffer ) {
23712
23713 state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute );
23714
23715 if ( geometry.maxInstancedCount === undefined ) {
23716
23717 geometry.maxInstancedCount = data.meshPerAttribute * data.count;
23718
23719 }
23720
23721 } else {
23722
23723 state.enableAttribute( programAttribute );
23724
23725 }
23726
23727 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
23728 _gl.vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, ( startIndex * stride + offset ) * bytesPerElement );
23729
23730 } else {
23731
23732 if ( geometryAttribute.isInstancedBufferAttribute ) {
23733
23734 state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute );
23735
23736 if ( geometry.maxInstancedCount === undefined ) {
23737
23738 geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;
23739
23740 }
23741
23742 } else {
23743
23744 state.enableAttribute( programAttribute );
23745
23746 }
23747
23748 _gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
23749 _gl.vertexAttribPointer( programAttribute, size, type, normalized, 0, startIndex * size * bytesPerElement );
23750
23751 }
23752
23753 } else if ( materialDefaultAttributeValues !== undefined ) {
23754
23755 var value = materialDefaultAttributeValues[ name ];
23756
23757 if ( value !== undefined ) {
23758
23759 switch ( value.length ) {
23760
23761 case 2:
23762 _gl.vertexAttrib2fv( programAttribute, value );
23763 break;
23764
23765 case 3:
23766 _gl.vertexAttrib3fv( programAttribute, value );
23767 break;
23768
23769 case 4:
23770 _gl.vertexAttrib4fv( programAttribute, value );
23771 break;
23772
23773 default:
23774 _gl.vertexAttrib1fv( programAttribute, value );
23775
23776 }
23777
23778 }
23779
23780 }
23781
23782 }
23783
23784 }
23785
23786 state.disableUnusedAttributes();
23787
23788 }
23789
23790 // Compile
23791
23792 this.compile = function ( scene, camera ) {
23793
23794 lightsArray.length = 0;
23795 shadowsArray.length = 0;
23796
23797 scene.traverse( function ( object ) {
23798
23799 if ( object.isLight ) {
23800
23801 lightsArray.push( object );
23802
23803 if ( object.castShadow ) {
23804
23805 shadowsArray.push( object );
23806
23807 }
23808
23809 }
23810
23811 } );
23812
23813 lights.setup( lightsArray, shadowsArray, camera );
23814
23815 scene.traverse( function ( object ) {
23816
23817 if ( object.material ) {
23818
23819 if ( Array.isArray( object.material ) ) {
23820
23821 for ( var i = 0; i < object.material.length; i ++ ) {
23822
23823 initMaterial( object.material[ i ], scene.fog, object );
23824
23825 }
23826
23827 } else {
23828
23829 initMaterial( object.material, scene.fog, object );
23830
23831 }
23832
23833 }
23834
23835 } );
23836
23837 };
23838
23839 // Animation Loop
23840
23841 var isAnimating = false;
23842 var onAnimationFrame = null;
23843
23844 function start() {
23845
23846 if ( isAnimating ) return;
23847
23848 var device = vr.getDevice();
23849
23850 if ( device && device.isPresenting ) {
23851
23852 device.requestAnimationFrame( loop );
23853
23854 } else {
23855
23856 window.requestAnimationFrame( loop );
23857
23858 }
23859
23860 isAnimating = true;
23861
23862 }
23863
23864 function loop( time ) {
23865
23866 if ( onAnimationFrame !== null ) onAnimationFrame( time );
23867
23868 var device = vr.getDevice();
23869
23870 if ( device && device.isPresenting ) {
23871
23872 device.requestAnimationFrame( loop );
23873
23874 } else {
23875
23876 window.requestAnimationFrame( loop );
23877
23878 }
23879
23880 }
23881
23882 this.animate = function ( callback ) {
23883
23884 onAnimationFrame = callback;
23885 start();
23886
23887 };
23888
23889 // Rendering
23890
23891 this.render = function ( scene, camera, renderTarget, forceClear ) {
23892
23893 if ( ! ( camera && camera.isCamera ) ) {
23894
23895 console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
23896 return;
23897
23898 }
23899
23900 if ( _isContextLost ) return;
23901
23902 // reset caching for this frame
23903
23904 _currentGeometryProgram = '';
23905 _currentMaterialId = - 1;
23906 _currentCamera = null;
23907
23908 // update scene graph
23909
23910 if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
23911
23912 // update camera matrices and frustum
23913
23914 if ( camera.parent === null ) camera.updateMatrixWorld();
23915
23916 if ( vr.enabled ) {
23917
23918 camera = vr.getCamera( camera );
23919
23920 }
23921
23922 _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
23923 _frustum.setFromMatrix( _projScreenMatrix );
23924
23925 lightsArray.length = 0;
23926 shadowsArray.length = 0;
23927
23928 spritesArray.length = 0;
23929 flaresArray.length = 0;
23930
23931 _localClippingEnabled = this.localClippingEnabled;
23932 _clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera );
23933
23934 currentRenderList = renderLists.get( scene, camera );
23935 currentRenderList.init();
23936
23937 projectObject( scene, camera, _this.sortObjects );
23938
23939 if ( _this.sortObjects === true ) {
23940
23941 currentRenderList.sort();
23942
23943 }
23944
23945 //
23946
23947 textures.updateVideoTextures();
23948
23949 //
23950
23951 if ( _clippingEnabled ) _clipping.beginShadows();
23952
23953 shadowMap.render( shadowsArray, scene, camera );
23954
23955 lights.setup( lightsArray, shadowsArray, camera );
23956
23957 if ( _clippingEnabled ) _clipping.endShadows();
23958
23959 //
23960
23961 _infoRender.frame ++;
23962 _infoRender.calls = 0;
23963 _infoRender.vertices = 0;
23964 _infoRender.faces = 0;
23965 _infoRender.points = 0;
23966
23967 if ( renderTarget === undefined ) {
23968
23969 renderTarget = null;
23970
23971 }
23972
23973 this.setRenderTarget( renderTarget );
23974
23975 //
23976
23977 background.render( currentRenderList, scene, camera, forceClear );
23978
23979 // render scene
23980
23981 var opaqueObjects = currentRenderList.opaque;
23982 var transparentObjects = currentRenderList.transparent;
23983
23984 if ( scene.overrideMaterial ) {
23985
23986 var overrideMaterial = scene.overrideMaterial;
23987
23988 if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera, overrideMaterial );
23989 if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera, overrideMaterial );
23990
23991 } else {
23992
23993 // opaque pass (front-to-back order)
23994
23995 if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera );
23996
23997 // transparent pass (back-to-front order)
23998
23999 if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera );
24000
24001 }
24002
24003 // custom renderers
24004
24005 spriteRenderer.render( spritesArray, scene, camera );
24006 flareRenderer.render( flaresArray, scene, camera, _currentViewport );
24007
24008 // Generate mipmap if we're using any kind of mipmap filtering
24009
24010 if ( renderTarget ) {
24011
24012 textures.updateRenderTargetMipmap( renderTarget );
24013
24014 }
24015
24016 // Ensure depth buffer writing is enabled so it can be cleared on next render
24017
24018 state.buffers.depth.setTest( true );
24019 state.buffers.depth.setMask( true );
24020 state.buffers.color.setMask( true );
24021
24022 state.setPolygonOffset( false );
24023
24024 if ( vr.enabled ) {
24025
24026 vr.submitFrame();
24027
24028 }
24029
24030 // _gl.finish();
24031
24032 };
24033
24034 /*
24035 // TODO Duplicated code (Frustum)
24036
24037 var _sphere = new Sphere();
24038
24039 function isObjectViewable( object ) {
24040
24041 var geometry = object.geometry;
24042
24043 if ( geometry.boundingSphere === null )
24044 geometry.computeBoundingSphere();
24045
24046 _sphere.copy( geometry.boundingSphere ).
24047 applyMatrix4( object.matrixWorld );
24048
24049 return isSphereViewable( _sphere );
24050
24051 }
24052
24053 function isSpriteViewable( sprite ) {
24054
24055 _sphere.center.set( 0, 0, 0 );
24056 _sphere.radius = 0.7071067811865476;
24057 _sphere.applyMatrix4( sprite.matrixWorld );
24058
24059 return isSphereViewable( _sphere );
24060
24061 }
24062
24063 function isSphereViewable( sphere ) {
24064
24065 if ( ! _frustum.intersectsSphere( sphere ) ) return false;
24066
24067 var numPlanes = _clipping.numPlanes;
24068
24069 if ( numPlanes === 0 ) return true;
24070
24071 var planes = _this.clippingPlanes,
24072
24073 center = sphere.center,
24074 negRad = - sphere.radius,
24075 i = 0;
24076
24077 do {
24078
24079 // out when deeper than radius in the negative halfspace
24080 if ( planes[ i ].distanceToPoint( center ) < negRad ) return false;
24081
24082 } while ( ++ i !== numPlanes );
24083
24084 return true;
24085
24086 }
24087 */
24088
24089 function projectObject( object, camera, sortObjects ) {
24090
24091 if ( object.visible === false ) return;
24092
24093 var visible = object.layers.test( camera.layers );
24094
24095 if ( visible ) {
24096
24097 if ( object.isLight ) {
24098
24099 lightsArray.push( object );
24100
24101 if ( object.castShadow ) {
24102
24103 shadowsArray.push( object );
24104
24105 }
24106
24107 } else if ( object.isSprite ) {
24108
24109 if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
24110
24111 spritesArray.push( object );
24112
24113 }
24114
24115 } else if ( object.isLensFlare ) {
24116
24117 flaresArray.push( object );
24118
24119 } else if ( object.isImmediateRenderObject ) {
24120
24121 if ( sortObjects ) {
24122
24123 _vector3.setFromMatrixPosition( object.matrixWorld )
24124 .applyMatrix4( _projScreenMatrix );
24125
24126 }
24127
24128 currentRenderList.push( object, null, object.material, _vector3.z, null );
24129
24130 } else if ( object.isMesh || object.isLine || object.isPoints ) {
24131
24132 if ( object.isSkinnedMesh ) {
24133
24134 object.skeleton.update();
24135
24136 }
24137
24138 if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
24139
24140 if ( sortObjects ) {
24141
24142 _vector3.setFromMatrixPosition( object.matrixWorld )
24143 .applyMatrix4( _projScreenMatrix );
24144
24145 }
24146
24147 var geometry = objects.update( object );
24148 var material = object.material;
24149
24150 if ( Array.isArray( material ) ) {
24151
24152 var groups = geometry.groups;
24153
24154 for ( var i = 0, l = groups.length; i < l; i ++ ) {
24155
24156 var group = groups[ i ];
24157 var groupMaterial = material[ group.materialIndex ];
24158
24159 if ( groupMaterial && groupMaterial.visible ) {
24160
24161 currentRenderList.push( object, geometry, groupMaterial, _vector3.z, group );
24162
24163 }
24164
24165 }
24166
24167 } else if ( material.visible ) {
24168
24169 currentRenderList.push( object, geometry, material, _vector3.z, null );
24170
24171 }
24172
24173 }
24174
24175 }
24176
24177 }
24178
24179 var children = object.children;
24180
24181 for ( var i = 0, l = children.length; i < l; i ++ ) {
24182
24183 projectObject( children[ i ], camera, sortObjects );
24184
24185 }
24186
24187 }
24188
24189 function renderObjects( renderList, scene, camera, overrideMaterial ) {
24190
24191 for ( var i = 0, l = renderList.length; i < l; i ++ ) {
24192
24193 var renderItem = renderList[ i ];
24194
24195 var object = renderItem.object;
24196 var geometry = renderItem.geometry;
24197 var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial;
24198 var group = renderItem.group;
24199
24200 if ( camera.isArrayCamera ) {
24201
24202 _currentArrayCamera = camera;
24203
24204 var cameras = camera.cameras;
24205
24206 for ( var j = 0, jl = cameras.length; j < jl; j ++ ) {
24207
24208 var camera2 = cameras[ j ];
24209
24210 if ( object.layers.test( camera2.layers ) ) {
24211
24212 var bounds = camera2.bounds;
24213
24214 var x = bounds.x * _width;
24215 var y = bounds.y * _height;
24216 var width = bounds.z * _width;
24217 var height = bounds.w * _height;
24218
24219 state.viewport( _currentViewport.set( x, y, width, height ).multiplyScalar( _pixelRatio ) );
24220
24221 renderObject( object, scene, camera2, geometry, material, group );
24222
24223 }
24224
24225 }
24226
24227 } else {
24228
24229 _currentArrayCamera = null;
24230
24231 renderObject( object, scene, camera, geometry, material, group );
24232
24233 }
24234
24235 }
24236
24237 }
24238
24239 function renderObject( object, scene, camera, geometry, material, group ) {
24240
24241 object.onBeforeRender( _this, scene, camera, geometry, material, group );
24242
24243 object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
24244 object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
24245
24246 if ( object.isImmediateRenderObject ) {
24247
24248 var frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );
24249
24250 state.setMaterial( material, frontFaceCW );
24251
24252 var program = setProgram( camera, scene.fog, material, object );
24253
24254 _currentGeometryProgram = '';
24255
24256 renderObjectImmediate( object, program, material );
24257
24258 } else {
24259
24260 _this.renderBufferDirect( camera, scene.fog, geometry, material, object, group );
24261
24262 }
24263
24264 object.onAfterRender( _this, scene, camera, geometry, material, group );
24265
24266 }
24267
24268 function initMaterial( material, fog, object ) {
24269
24270 var materialProperties = properties.get( material );
24271
24272 var parameters = programCache.getParameters(
24273 material, lights.state, shadowsArray, fog, _clipping.numPlanes, _clipping.numIntersection, object );
24274
24275 var code = programCache.getProgramCode( material, parameters );
24276
24277 var program = materialProperties.program;
24278 var programChange = true;
24279
24280 if ( program === undefined ) {
24281
24282 // new material
24283 material.addEventListener( 'dispose', onMaterialDispose );
24284
24285 } else if ( program.code !== code ) {
24286
24287 // changed glsl or parameters
24288 releaseMaterialProgramReference( material );
24289
24290 } else if ( parameters.shaderID !== undefined ) {
24291
24292 // same glsl and uniform list
24293 return;
24294
24295 } else {
24296
24297 // only rebuild uniform list
24298 programChange = false;
24299
24300 }
24301
24302 if ( programChange ) {
24303
24304 if ( parameters.shaderID ) {
24305
24306 var shader = ShaderLib[ parameters.shaderID ];
24307
24308 materialProperties.shader = {
24309 name: material.type,
24310 uniforms: UniformsUtils.clone( shader.uniforms ),
24311 vertexShader: shader.vertexShader,
24312 fragmentShader: shader.fragmentShader
24313 };
24314
24315 } else {
24316
24317 materialProperties.shader = {
24318 name: material.type,
24319 uniforms: material.uniforms,
24320 vertexShader: material.vertexShader,
24321 fragmentShader: material.fragmentShader
24322 };
24323
24324 }
24325
24326 material.onBeforeCompile( materialProperties.shader );
24327
24328 program = programCache.acquireProgram( material, materialProperties.shader, parameters, code );
24329
24330 materialProperties.program = program;
24331 material.program = program;
24332
24333 }
24334
24335 var programAttributes = program.getAttributes();
24336
24337 if ( material.morphTargets ) {
24338
24339 material.numSupportedMorphTargets = 0;
24340
24341 for ( var i = 0; i < _this.maxMorphTargets; i ++ ) {
24342
24343 if ( programAttributes[ 'morphTarget' + i ] >= 0 ) {
24344
24345 material.numSupportedMorphTargets ++;
24346
24347 }
24348
24349 }
24350
24351 }
24352
24353 if ( material.morphNormals ) {
24354
24355 material.numSupportedMorphNormals = 0;
24356
24357 for ( var i = 0; i < _this.maxMorphNormals; i ++ ) {
24358
24359 if ( programAttributes[ 'morphNormal' + i ] >= 0 ) {
24360
24361 material.numSupportedMorphNormals ++;
24362
24363 }
24364
24365 }
24366
24367 }
24368
24369 var uniforms = materialProperties.shader.uniforms;
24370
24371 if ( ! material.isShaderMaterial &&
24372 ! material.isRawShaderMaterial ||
24373 material.clipping === true ) {
24374
24375 materialProperties.numClippingPlanes = _clipping.numPlanes;
24376 materialProperties.numIntersection = _clipping.numIntersection;
24377 uniforms.clippingPlanes = _clipping.uniform;
24378
24379 }
24380
24381 materialProperties.fog = fog;
24382
24383 // store the light setup it was created for
24384
24385 materialProperties.lightsHash = lights.state.hash;
24386
24387 if ( material.lights ) {
24388
24389 // wire up the material to this renderer's lighting state
24390
24391 uniforms.ambientLightColor.value = lights.state.ambient;
24392 uniforms.directionalLights.value = lights.state.directional;
24393 uniforms.spotLights.value = lights.state.spot;
24394 uniforms.rectAreaLights.value = lights.state.rectArea;
24395 uniforms.pointLights.value = lights.state.point;
24396 uniforms.hemisphereLights.value = lights.state.hemi;
24397
24398 uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
24399 uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
24400 uniforms.spotShadowMap.value = lights.state.spotShadowMap;
24401 uniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix;
24402 uniforms.pointShadowMap.value = lights.state.pointShadowMap;
24403 uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
24404 // TODO (abelnation): add area lights shadow info to uniforms
24405
24406 }
24407
24408 var progUniforms = materialProperties.program.getUniforms(),
24409 uniformsList =
24410 WebGLUniforms.seqWithValue( progUniforms.seq, uniforms );
24411
24412 materialProperties.uniformsList = uniformsList;
24413
24414 }
24415
24416 function setProgram( camera, fog, material, object ) {
24417
24418 _usedTextureUnits = 0;
24419
24420 var materialProperties = properties.get( material );
24421
24422 if ( _clippingEnabled ) {
24423
24424 if ( _localClippingEnabled || camera !== _currentCamera ) {
24425
24426 var useCache =
24427 camera === _currentCamera &&
24428 material.id === _currentMaterialId;
24429
24430 // we might want to call this function with some ClippingGroup
24431 // object instead of the material, once it becomes feasible
24432 // (#8465, #8379)
24433 _clipping.setState(
24434 material.clippingPlanes, material.clipIntersection, material.clipShadows,
24435 camera, materialProperties, useCache );
24436
24437 }
24438
24439 }
24440
24441 if ( material.needsUpdate === false ) {
24442
24443 if ( materialProperties.program === undefined ) {
24444
24445 material.needsUpdate = true;
24446
24447 } else if ( material.fog && materialProperties.fog !== fog ) {
24448
24449 material.needsUpdate = true;
24450
24451 } else if ( material.lights && materialProperties.lightsHash !== lights.state.hash ) {
24452
24453 material.needsUpdate = true;
24454
24455 } else if ( materialProperties.numClippingPlanes !== undefined &&
24456 ( materialProperties.numClippingPlanes !== _clipping.numPlanes ||
24457 materialProperties.numIntersection !== _clipping.numIntersection ) ) {
24458
24459 material.needsUpdate = true;
24460
24461 }
24462
24463 }
24464
24465 if ( material.needsUpdate ) {
24466
24467 initMaterial( material, fog, object );
24468 material.needsUpdate = false;
24469
24470 }
24471
24472 var refreshProgram = false;
24473 var refreshMaterial = false;
24474 var refreshLights = false;
24475
24476 var program = materialProperties.program,
24477 p_uniforms = program.getUniforms(),
24478 m_uniforms = materialProperties.shader.uniforms;
24479
24480 if ( state.useProgram( program.program ) ) {
24481
24482 refreshProgram = true;
24483 refreshMaterial = true;
24484 refreshLights = true;
24485
24486 }
24487
24488 if ( material.id !== _currentMaterialId ) {
24489
24490 _currentMaterialId = material.id;
24491
24492 refreshMaterial = true;
24493
24494 }
24495
24496 if ( refreshProgram || camera !== _currentCamera ) {
24497
24498 p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
24499
24500 if ( capabilities.logarithmicDepthBuffer ) {
24501
24502 p_uniforms.setValue( _gl, 'logDepthBufFC',
24503 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
24504
24505 }
24506
24507 // Avoid unneeded uniform updates per ArrayCamera's sub-camera
24508
24509 if ( _currentCamera !== ( _currentArrayCamera || camera ) ) {
24510
24511 _currentCamera = ( _currentArrayCamera || camera );
24512
24513 // lighting uniforms depend on the camera so enforce an update
24514 // now, in case this material supports lights - or later, when
24515 // the next material that does gets activated:
24516
24517 refreshMaterial = true; // set to true on material change
24518 refreshLights = true; // remains set until update done
24519
24520 }
24521
24522 // load material specific uniforms
24523 // (shader material also gets them for the sake of genericity)
24524
24525 if ( material.isShaderMaterial ||
24526 material.isMeshPhongMaterial ||
24527 material.isMeshStandardMaterial ||
24528 material.envMap ) {
24529
24530 var uCamPos = p_uniforms.map.cameraPosition;
24531
24532 if ( uCamPos !== undefined ) {
24533
24534 uCamPos.setValue( _gl,
24535 _vector3.setFromMatrixPosition( camera.matrixWorld ) );
24536
24537 }
24538
24539 }
24540
24541 if ( material.isMeshPhongMaterial ||
24542 material.isMeshLambertMaterial ||
24543 material.isMeshBasicMaterial ||
24544 material.isMeshStandardMaterial ||
24545 material.isShaderMaterial ||
24546 material.skinning ) {
24547
24548 p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
24549
24550 }
24551
24552 }
24553
24554 // skinning uniforms must be set even if material didn't change
24555 // auto-setting of texture unit for bone texture must go before other textures
24556 // not sure why, but otherwise weird things happen
24557
24558 if ( material.skinning ) {
24559
24560 p_uniforms.setOptional( _gl, object, 'bindMatrix' );
24561 p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );
24562
24563 var skeleton = object.skeleton;
24564
24565 if ( skeleton ) {
24566
24567 var bones = skeleton.bones;
24568
24569 if ( capabilities.floatVertexTextures ) {
24570
24571 if ( skeleton.boneTexture === undefined ) {
24572
24573 // layout (1 matrix = 4 pixels)
24574 // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
24575 // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8)
24576 // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16)
24577 // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32)
24578 // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)
24579
24580
24581 var size = Math.sqrt( bones.length * 4 ); // 4 pixels needed for 1 matrix
24582 size = _Math.ceilPowerOfTwo( size );
24583 size = Math.max( size, 4 );
24584
24585 var boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel
24586 boneMatrices.set( skeleton.boneMatrices ); // copy current values
24587
24588 var boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType );
24589
24590 skeleton.boneMatrices = boneMatrices;
24591 skeleton.boneTexture = boneTexture;
24592 skeleton.boneTextureSize = size;
24593
24594 }
24595
24596 p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture );
24597 p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize );
24598
24599 } else {
24600
24601 p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' );
24602
24603 }
24604
24605 }
24606
24607 }
24608
24609 if ( refreshMaterial ) {
24610
24611 p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );
24612 p_uniforms.setValue( _gl, 'toneMappingWhitePoint', _this.toneMappingWhitePoint );
24613
24614 if ( material.lights ) {
24615
24616 // the current material requires lighting info
24617
24618 // note: all lighting uniforms are always set correctly
24619 // they simply reference the renderer's state for their
24620 // values
24621 //
24622 // use the current material's .needsUpdate flags to set
24623 // the GL state when required
24624
24625 markUniformsLightsNeedsUpdate( m_uniforms, refreshLights );
24626
24627 }
24628
24629 // refresh uniforms common to several materials
24630
24631 if ( fog && material.fog ) {
24632
24633 refreshUniformsFog( m_uniforms, fog );
24634
24635 }
24636
24637 if ( material.isMeshBasicMaterial ) {
24638
24639 refreshUniformsCommon( m_uniforms, material );
24640
24641 } else if ( material.isMeshLambertMaterial ) {
24642
24643 refreshUniformsCommon( m_uniforms, material );
24644 refreshUniformsLambert( m_uniforms, material );
24645
24646 } else if ( material.isMeshPhongMaterial ) {
24647
24648 refreshUniformsCommon( m_uniforms, material );
24649
24650 if ( material.isMeshToonMaterial ) {
24651
24652 refreshUniformsToon( m_uniforms, material );
24653
24654 } else {
24655
24656 refreshUniformsPhong( m_uniforms, material );
24657
24658 }
24659
24660 } else if ( material.isMeshStandardMaterial ) {
24661
24662 refreshUniformsCommon( m_uniforms, material );
24663
24664 if ( material.isMeshPhysicalMaterial ) {
24665
24666 refreshUniformsPhysical( m_uniforms, material );
24667
24668 } else {
24669
24670 refreshUniformsStandard( m_uniforms, material );
24671
24672 }
24673
24674 } else if ( material.isMeshDepthMaterial ) {
24675
24676 refreshUniformsCommon( m_uniforms, material );
24677 refreshUniformsDepth( m_uniforms, material );
24678
24679 } else if ( material.isMeshDistanceMaterial ) {
24680
24681 refreshUniformsCommon( m_uniforms, material );
24682 refreshUniformsDistance( m_uniforms, material );
24683
24684 } else if ( material.isMeshNormalMaterial ) {
24685
24686 refreshUniformsCommon( m_uniforms, material );
24687 refreshUniformsNormal( m_uniforms, material );
24688
24689 } else if ( material.isLineBasicMaterial ) {
24690
24691 refreshUniformsLine( m_uniforms, material );
24692
24693 if ( material.isLineDashedMaterial ) {
24694
24695 refreshUniformsDash( m_uniforms, material );
24696
24697 }
24698
24699 } else if ( material.isPointsMaterial ) {
24700
24701 refreshUniformsPoints( m_uniforms, material );
24702
24703 } else if ( material.isShadowMaterial ) {
24704
24705 m_uniforms.color.value = material.color;
24706 m_uniforms.opacity.value = material.opacity;
24707
24708 }
24709
24710 // RectAreaLight Texture
24711 // TODO (mrdoob): Find a nicer implementation
24712
24713 if ( m_uniforms.ltcMat !== undefined ) m_uniforms.ltcMat.value = UniformsLib.LTC_MAT_TEXTURE;
24714 if ( m_uniforms.ltcMag !== undefined ) m_uniforms.ltcMag.value = UniformsLib.LTC_MAG_TEXTURE;
24715
24716 WebGLUniforms.upload(
24717 _gl, materialProperties.uniformsList, m_uniforms, _this );
24718
24719 }
24720
24721
24722 // common matrices
24723
24724 p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
24725 p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
24726 p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
24727
24728 return program;
24729
24730 }
24731
24732 // Uniforms (refresh uniforms objects)
24733
24734 function refreshUniformsCommon( uniforms, material ) {
24735
24736 uniforms.opacity.value = material.opacity;
24737
24738 if ( material.color ) {
24739
24740 uniforms.diffuse.value = material.color;
24741
24742 }
24743
24744 if ( material.emissive ) {
24745
24746 uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );
24747
24748 }
24749
24750 if ( material.map ) {
24751
24752 uniforms.map.value = material.map;
24753
24754 }
24755
24756 if ( material.alphaMap ) {
24757
24758 uniforms.alphaMap.value = material.alphaMap;
24759
24760 }
24761
24762 if ( material.specularMap ) {
24763
24764 uniforms.specularMap.value = material.specularMap;
24765
24766 }
24767
24768 if ( material.envMap ) {
24769
24770 uniforms.envMap.value = material.envMap;
24771
24772 // don't flip CubeTexture envMaps, flip everything else:
24773 // WebGLRenderTargetCube will be flipped for backwards compatibility
24774 // WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture
24775 // this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future
24776 uniforms.flipEnvMap.value = ( ! ( material.envMap && material.envMap.isCubeTexture ) ) ? 1 : - 1;
24777
24778 uniforms.reflectivity.value = material.reflectivity;
24779 uniforms.refractionRatio.value = material.refractionRatio;
24780
24781 }
24782
24783 if ( material.lightMap ) {
24784
24785 uniforms.lightMap.value = material.lightMap;
24786 uniforms.lightMapIntensity.value = material.lightMapIntensity;
24787
24788 }
24789
24790 if ( material.aoMap ) {
24791
24792 uniforms.aoMap.value = material.aoMap;
24793 uniforms.aoMapIntensity.value = material.aoMapIntensity;
24794
24795 }
24796
24797 // uv repeat and offset setting priorities
24798 // 1. color map
24799 // 2. specular map
24800 // 3. normal map
24801 // 4. bump map
24802 // 5. alpha map
24803 // 6. emissive map
24804
24805 var uvScaleMap;
24806
24807 if ( material.map ) {
24808
24809 uvScaleMap = material.map;
24810
24811 } else if ( material.specularMap ) {
24812
24813 uvScaleMap = material.specularMap;
24814
24815 } else if ( material.displacementMap ) {
24816
24817 uvScaleMap = material.displacementMap;
24818
24819 } else if ( material.normalMap ) {
24820
24821 uvScaleMap = material.normalMap;
24822
24823 } else if ( material.bumpMap ) {
24824
24825 uvScaleMap = material.bumpMap;
24826
24827 } else if ( material.roughnessMap ) {
24828
24829 uvScaleMap = material.roughnessMap;
24830
24831 } else if ( material.metalnessMap ) {
24832
24833 uvScaleMap = material.metalnessMap;
24834
24835 } else if ( material.alphaMap ) {
24836
24837 uvScaleMap = material.alphaMap;
24838
24839 } else if ( material.emissiveMap ) {
24840
24841 uvScaleMap = material.emissiveMap;
24842
24843 }
24844
24845 if ( uvScaleMap !== undefined ) {
24846
24847 // backwards compatibility
24848 if ( uvScaleMap.isWebGLRenderTarget ) {
24849
24850 uvScaleMap = uvScaleMap.texture;
24851
24852 }
24853
24854 if ( uvScaleMap.matrixAutoUpdate === true ) {
24855
24856 var offset = uvScaleMap.offset;
24857 var repeat = uvScaleMap.repeat;
24858 var rotation = uvScaleMap.rotation;
24859 var center = uvScaleMap.center;
24860
24861 uvScaleMap.matrix.setUvTransform( offset.x, offset.y, repeat.x, repeat.y, rotation, center.x, center.y );
24862
24863 }
24864
24865 uniforms.uvTransform.value.copy( uvScaleMap.matrix );
24866
24867 }
24868
24869 }
24870
24871 function refreshUniformsLine( uniforms, material ) {
24872
24873 uniforms.diffuse.value = material.color;
24874 uniforms.opacity.value = material.opacity;
24875
24876 }
24877
24878 function refreshUniformsDash( uniforms, material ) {
24879
24880 uniforms.dashSize.value = material.dashSize;
24881 uniforms.totalSize.value = material.dashSize + material.gapSize;
24882 uniforms.scale.value = material.scale;
24883
24884 }
24885
24886 function refreshUniformsPoints( uniforms, material ) {
24887
24888 uniforms.diffuse.value = material.color;
24889 uniforms.opacity.value = material.opacity;
24890 uniforms.size.value = material.size * _pixelRatio;
24891 uniforms.scale.value = _height * 0.5;
24892
24893 uniforms.map.value = material.map;
24894
24895 if ( material.map !== null ) {
24896
24897 if ( material.map.matrixAutoUpdate === true ) {
24898
24899 var offset = material.map.offset;
24900 var repeat = material.map.repeat;
24901 var rotation = material.map.rotation;
24902 var center = material.map.center;
24903
24904 material.map.matrix.setUvTransform( offset.x, offset.y, repeat.x, repeat.y, rotation, center.x, center.y );
24905
24906 }
24907
24908 uniforms.uvTransform.value.copy( material.map.matrix );
24909
24910 }
24911
24912 }
24913
24914 function refreshUniformsFog( uniforms, fog ) {
24915
24916 uniforms.fogColor.value = fog.color;
24917
24918 if ( fog.isFog ) {
24919
24920 uniforms.fogNear.value = fog.near;
24921 uniforms.fogFar.value = fog.far;
24922
24923 } else if ( fog.isFogExp2 ) {
24924
24925 uniforms.fogDensity.value = fog.density;
24926
24927 }
24928
24929 }
24930
24931 function refreshUniformsLambert( uniforms, material ) {
24932
24933 if ( material.emissiveMap ) {
24934
24935 uniforms.emissiveMap.value = material.emissiveMap;
24936
24937 }
24938
24939 }
24940
24941 function refreshUniformsPhong( uniforms, material ) {
24942
24943 uniforms.specular.value = material.specular;
24944 uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
24945
24946 if ( material.emissiveMap ) {
24947
24948 uniforms.emissiveMap.value = material.emissiveMap;
24949
24950 }
24951
24952 if ( material.bumpMap ) {
24953
24954 uniforms.bumpMap.value = material.bumpMap;
24955 uniforms.bumpScale.value = material.bumpScale;
24956
24957 }
24958
24959 if ( material.normalMap ) {
24960
24961 uniforms.normalMap.value = material.normalMap;
24962 uniforms.normalScale.value.copy( material.normalScale );
24963
24964 }
24965
24966 if ( material.displacementMap ) {
24967
24968 uniforms.displacementMap.value = material.displacementMap;
24969 uniforms.displacementScale.value = material.displacementScale;
24970 uniforms.displacementBias.value = material.displacementBias;
24971
24972 }
24973
24974 }
24975
24976 function refreshUniformsToon( uniforms, material ) {
24977
24978 refreshUniformsPhong( uniforms, material );
24979
24980 if ( material.gradientMap ) {
24981
24982 uniforms.gradientMap.value = material.gradientMap;
24983
24984 }
24985
24986 }
24987
24988 function refreshUniformsStandard( uniforms, material ) {
24989
24990 uniforms.roughness.value = material.roughness;
24991 uniforms.metalness.value = material.metalness;
24992
24993 if ( material.roughnessMap ) {
24994
24995 uniforms.roughnessMap.value = material.roughnessMap;
24996
24997 }
24998
24999 if ( material.metalnessMap ) {
25000
25001 uniforms.metalnessMap.value = material.metalnessMap;
25002
25003 }
25004
25005 if ( material.emissiveMap ) {
25006
25007 uniforms.emissiveMap.value = material.emissiveMap;
25008
25009 }
25010
25011 if ( material.bumpMap ) {
25012
25013 uniforms.bumpMap.value = material.bumpMap;
25014 uniforms.bumpScale.value = material.bumpScale;
25015
25016 }
25017
25018 if ( material.normalMap ) {
25019
25020 uniforms.normalMap.value = material.normalMap;
25021 uniforms.normalScale.value.copy( material.normalScale );
25022
25023 }
25024
25025 if ( material.displacementMap ) {
25026
25027 uniforms.displacementMap.value = material.displacementMap;
25028 uniforms.displacementScale.value = material.displacementScale;
25029 uniforms.displacementBias.value = material.displacementBias;
25030
25031 }
25032
25033 if ( material.envMap ) {
25034
25035 //uniforms.envMap.value = material.envMap; // part of uniforms common
25036 uniforms.envMapIntensity.value = material.envMapIntensity;
25037
25038 }
25039
25040 }
25041
25042 function refreshUniformsPhysical( uniforms, material ) {
25043
25044 uniforms.clearCoat.value = material.clearCoat;
25045 uniforms.clearCoatRoughness.value = material.clearCoatRoughness;
25046
25047 refreshUniformsStandard( uniforms, material );
25048
25049 }
25050
25051 function refreshUniformsDepth( uniforms, material ) {
25052
25053 if ( material.displacementMap ) {
25054
25055 uniforms.displacementMap.value = material.displacementMap;
25056 uniforms.displacementScale.value = material.displacementScale;
25057 uniforms.displacementBias.value = material.displacementBias;
25058
25059 }
25060
25061 }
25062
25063 function refreshUniformsDistance( uniforms, material ) {
25064
25065 if ( material.displacementMap ) {
25066
25067 uniforms.displacementMap.value = material.displacementMap;
25068 uniforms.displacementScale.value = material.displacementScale;
25069 uniforms.displacementBias.value = material.displacementBias;
25070
25071 }
25072
25073 uniforms.referencePosition.value.copy( material.referencePosition );
25074 uniforms.nearDistance.value = material.nearDistance;
25075 uniforms.farDistance.value = material.farDistance;
25076
25077 }
25078
25079 function refreshUniformsNormal( uniforms, material ) {
25080
25081 if ( material.bumpMap ) {
25082
25083 uniforms.bumpMap.value = material.bumpMap;
25084 uniforms.bumpScale.value = material.bumpScale;
25085
25086 }
25087
25088 if ( material.normalMap ) {
25089
25090 uniforms.normalMap.value = material.normalMap;
25091 uniforms.normalScale.value.copy( material.normalScale );
25092
25093 }
25094
25095 if ( material.displacementMap ) {
25096
25097 uniforms.displacementMap.value = material.displacementMap;
25098 uniforms.displacementScale.value = material.displacementScale;
25099 uniforms.displacementBias.value = material.displacementBias;
25100
25101 }
25102
25103 }
25104
25105 // If uniforms are marked as clean, they don't need to be loaded to the GPU.
25106
25107 function markUniformsLightsNeedsUpdate( uniforms, value ) {
25108
25109 uniforms.ambientLightColor.needsUpdate = value;
25110
25111 uniforms.directionalLights.needsUpdate = value;
25112 uniforms.pointLights.needsUpdate = value;
25113 uniforms.spotLights.needsUpdate = value;
25114 uniforms.rectAreaLights.needsUpdate = value;
25115 uniforms.hemisphereLights.needsUpdate = value;
25116
25117 }
25118
25119 // GL state setting
25120
25121 this.setFaceCulling = function ( cullFace, frontFaceDirection ) {
25122
25123 state.setCullFace( cullFace );
25124 state.setFlipSided( frontFaceDirection === FrontFaceDirectionCW );
25125
25126 };
25127
25128 // Textures
25129
25130 function allocTextureUnit() {
25131
25132 var textureUnit = _usedTextureUnits;
25133
25134 if ( textureUnit >= capabilities.maxTextures ) {
25135
25136 console.warn( 'THREE.WebGLRenderer: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures );
25137
25138 }
25139
25140 _usedTextureUnits += 1;
25141
25142 return textureUnit;
25143
25144 }
25145
25146 this.allocTextureUnit = allocTextureUnit;
25147
25148 // this.setTexture2D = setTexture2D;
25149 this.setTexture2D = ( function () {
25150
25151 var warned = false;
25152
25153 // backwards compatibility: peel texture.texture
25154 return function setTexture2D( texture, slot ) {
25155
25156 if ( texture && texture.isWebGLRenderTarget ) {
25157
25158 if ( ! warned ) {
25159
25160 console.warn( "THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead." );
25161 warned = true;
25162
25163 }
25164
25165 texture = texture.texture;
25166
25167 }
25168
25169 textures.setTexture2D( texture, slot );
25170
25171 };
25172
25173 }() );
25174
25175 this.setTexture = ( function () {
25176
25177 var warned = false;
25178
25179 return function setTexture( texture, slot ) {
25180
25181 if ( ! warned ) {
25182
25183 console.warn( "THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead." );
25184 warned = true;
25185
25186 }
25187
25188 textures.setTexture2D( texture, slot );
25189
25190 };
25191
25192 }() );
25193
25194 this.setTextureCube = ( function () {
25195
25196 var warned = false;
25197
25198 return function setTextureCube( texture, slot ) {
25199
25200 // backwards compatibility: peel texture.texture
25201 if ( texture && texture.isWebGLRenderTargetCube ) {
25202
25203 if ( ! warned ) {
25204
25205 console.warn( "THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead." );
25206 warned = true;
25207
25208 }
25209
25210 texture = texture.texture;
25211
25212 }
25213
25214 // currently relying on the fact that WebGLRenderTargetCube.texture is a Texture and NOT a CubeTexture
25215 // TODO: unify these code paths
25216 if ( ( texture && texture.isCubeTexture ) ||
25217 ( Array.isArray( texture.image ) && texture.image.length === 6 ) ) {
25218
25219 // CompressedTexture can have Array in image :/
25220
25221 // this function alone should take care of cube textures
25222 textures.setTextureCube( texture, slot );
25223
25224 } else {
25225
25226 // assumed: texture property of THREE.WebGLRenderTargetCube
25227
25228 textures.setTextureCubeDynamic( texture, slot );
25229
25230 }
25231
25232 };
25233
25234 }() );
25235
25236 this.getRenderTarget = function () {
25237
25238 return _currentRenderTarget;
25239
25240 };
25241
25242 this.setRenderTarget = function ( renderTarget ) {
25243
25244 _currentRenderTarget = renderTarget;
25245
25246 if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) {
25247
25248 textures.setupRenderTarget( renderTarget );
25249
25250 }
25251
25252 var framebuffer = null;
25253 var isCube = false;
25254
25255 if ( renderTarget ) {
25256
25257 var __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;
25258
25259 if ( renderTarget.isWebGLRenderTargetCube ) {
25260
25261 framebuffer = __webglFramebuffer[ renderTarget.activeCubeFace ];
25262 isCube = true;
25263
25264 } else {
25265
25266 framebuffer = __webglFramebuffer;
25267
25268 }
25269
25270 _currentViewport.copy( renderTarget.viewport );
25271 _currentScissor.copy( renderTarget.scissor );
25272 _currentScissorTest = renderTarget.scissorTest;
25273
25274 } else {
25275
25276 _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio );
25277 _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio );
25278 _currentScissorTest = _scissorTest;
25279
25280 }
25281
25282 if ( _currentFramebuffer !== framebuffer ) {
25283
25284 _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
25285 _currentFramebuffer = framebuffer;
25286
25287 }
25288
25289 state.viewport( _currentViewport );
25290 state.scissor( _currentScissor );
25291 state.setScissorTest( _currentScissorTest );
25292
25293 if ( isCube ) {
25294
25295 var textureProperties = properties.get( renderTarget.texture );
25296 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + renderTarget.activeCubeFace, textureProperties.__webglTexture, renderTarget.activeMipMapLevel );
25297
25298 }
25299
25300 };
25301
25302 this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) {
25303
25304 if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
25305
25306 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
25307 return;
25308
25309 }
25310
25311 var framebuffer = properties.get( renderTarget ).__webglFramebuffer;
25312
25313 if ( framebuffer ) {
25314
25315 var restore = false;
25316
25317 if ( framebuffer !== _currentFramebuffer ) {
25318
25319 _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
25320
25321 restore = true;
25322
25323 }
25324
25325 try {
25326
25327 var texture = renderTarget.texture;
25328 var textureFormat = texture.format;
25329 var textureType = texture.type;
25330
25331 if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {
25332
25333 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
25334 return;
25335
25336 }
25337
25338 if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // IE11, Edge and Chrome Mac < 52 (#9513)
25339 ! ( textureType === FloatType && ( extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
25340 ! ( textureType === HalfFloatType && extensions.get( 'EXT_color_buffer_half_float' ) ) ) {
25341
25342 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
25343 return;
25344
25345 }
25346
25347 if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) {
25348
25349 // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
25350
25351 if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
25352
25353 _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );
25354
25355 }
25356
25357 } else {
25358
25359 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' );
25360
25361 }
25362
25363 } finally {
25364
25365 if ( restore ) {
25366
25367 _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer );
25368
25369 }
25370
25371 }
25372
25373 }
25374
25375 };
25376
25377}
25378
25379/**
25380 * @author mrdoob / http://mrdoob.com/
25381 */
25382
25383function Scene() {
25384
25385 Object3D.call( this );
25386
25387 this.type = 'Scene';
25388
25389 this.background = null;
25390 this.fog = null;
25391 this.overrideMaterial = null;
25392
25393 this.autoUpdate = true; // checked by the renderer
25394
25395}
25396
25397Scene.prototype = Object.assign( Object.create( Object3D.prototype ), {
25398
25399 constructor: Scene,
25400
25401 copy: function ( source, recursive ) {
25402
25403 Object3D.prototype.copy.call( this, source, recursive );
25404
25405 if ( source.background !== null ) this.background = source.background.clone();
25406 if ( source.fog !== null ) this.fog = source.fog.clone();
25407 if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();
25408
25409 this.autoUpdate = source.autoUpdate;
25410 this.matrixAutoUpdate = source.matrixAutoUpdate;
25411
25412 return this;
25413
25414 },
25415
25416 toJSON: function ( meta ) {
25417
25418 var data = Object3D.prototype.toJSON.call( this, meta );
25419
25420 if ( this.background !== null ) data.object.background = this.background.toJSON( meta );
25421 if ( this.fog !== null ) data.object.fog = this.fog.toJSON();
25422
25423 return data;
25424
25425 }
25426
25427} );
25428
25429/**
25430 * @author mrdoob / http://mrdoob.com/
25431 */
25432
25433var Cache = {
25434
25435 enabled: false,
25436
25437 files: {},
25438
25439 add: function ( key, file ) {
25440
25441 if ( this.enabled === false ) return;
25442
25443 // console.log( 'THREE.Cache', 'Adding key:', key );
25444
25445 this.files[ key ] = file;
25446
25447 },
25448
25449 get: function ( key ) {
25450
25451 if ( this.enabled === false ) return;
25452
25453 // console.log( 'THREE.Cache', 'Checking key:', key );
25454
25455 return this.files[ key ];
25456
25457 },
25458
25459 remove: function ( key ) {
25460
25461 delete this.files[ key ];
25462
25463 },
25464
25465 clear: function () {
25466
25467 this.files = {};
25468
25469 }
25470
25471};
25472
25473/**
25474 * @author mrdoob / http://mrdoob.com/
25475 */
25476
25477function LoadingManager( onLoad, onProgress, onError ) {
25478
25479 var scope = this;
25480
25481 var isLoading = false;
25482 var itemsLoaded = 0;
25483 var itemsTotal = 0;
25484 var urlModifier = undefined;
25485
25486 this.onStart = undefined;
25487 this.onLoad = onLoad;
25488 this.onProgress = onProgress;
25489 this.onError = onError;
25490
25491 this.itemStart = function ( url ) {
25492
25493 itemsTotal ++;
25494
25495 if ( isLoading === false ) {
25496
25497 if ( scope.onStart !== undefined ) {
25498
25499 scope.onStart( url, itemsLoaded, itemsTotal );
25500
25501 }
25502
25503 }
25504
25505 isLoading = true;
25506
25507 };
25508
25509 this.itemEnd = function ( url ) {
25510
25511 itemsLoaded ++;
25512
25513 if ( scope.onProgress !== undefined ) {
25514
25515 scope.onProgress( url, itemsLoaded, itemsTotal );
25516
25517 }
25518
25519 if ( itemsLoaded === itemsTotal ) {
25520
25521 isLoading = false;
25522
25523 if ( scope.onLoad !== undefined ) {
25524
25525 scope.onLoad();
25526
25527 }
25528
25529 }
25530
25531 };
25532
25533 this.itemError = function ( url ) {
25534
25535 if ( scope.onError !== undefined ) {
25536
25537 scope.onError( url );
25538
25539 }
25540
25541 };
25542
25543 this.resolveURL = function ( url ) {
25544
25545 if ( urlModifier ) {
25546
25547 return urlModifier( url );
25548
25549 }
25550
25551 return url;
25552
25553 };
25554
25555 this.setURLModifier = function ( transform ) {
25556
25557 urlModifier = transform;
25558 return this;
25559
25560 };
25561
25562}
25563
25564var DefaultLoadingManager = new LoadingManager();
25565
25566/**
25567 * @author mrdoob / http://mrdoob.com/
25568 */
25569
25570function ImageLoader( manager ) {
25571
25572 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
25573
25574}
25575
25576Object.assign( ImageLoader.prototype, {
25577
25578 crossOrigin: 'Anonymous',
25579
25580 load: function ( url, onLoad, onProgress, onError ) {
25581
25582 if ( url === undefined ) url = '';
25583
25584 if ( this.path !== undefined ) url = this.path + url;
25585
25586 url = this.manager.resolveURL( url );
25587
25588 var scope = this;
25589
25590 var cached = Cache.get( url );
25591
25592 if ( cached !== undefined ) {
25593
25594 scope.manager.itemStart( url );
25595
25596 setTimeout( function () {
25597
25598 if ( onLoad ) onLoad( cached );
25599
25600 scope.manager.itemEnd( url );
25601
25602 }, 0 );
25603
25604 return cached;
25605
25606 }
25607
25608 var image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' );
25609
25610 image.addEventListener( 'load', function () {
25611
25612 Cache.add( url, this );
25613
25614 if ( onLoad ) onLoad( this );
25615
25616 scope.manager.itemEnd( url );
25617
25618 }, false );
25619
25620 /*
25621 image.addEventListener( 'progress', function ( event ) {
25622
25623 if ( onProgress ) onProgress( event );
25624
25625 }, false );
25626 */
25627
25628 image.addEventListener( 'error', function ( event ) {
25629
25630 if ( onError ) onError( event );
25631
25632 scope.manager.itemEnd( url );
25633 scope.manager.itemError( url );
25634
25635 }, false );
25636
25637 if ( url.substr( 0, 5 ) !== 'data:' ) {
25638
25639 if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;
25640
25641 }
25642
25643 scope.manager.itemStart( url );
25644
25645 image.src = url;
25646
25647 return image;
25648
25649 },
25650
25651 setCrossOrigin: function ( value ) {
25652
25653 this.crossOrigin = value;
25654 return this;
25655
25656 },
25657
25658 setPath: function ( value ) {
25659
25660 this.path = value;
25661 return this;
25662
25663 }
25664
25665} );
25666
25667/**
25668 * @author mrdoob / http://mrdoob.com/
25669 */
25670
25671function TextureLoader( manager ) {
25672
25673 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
25674
25675}
25676
25677Object.assign( TextureLoader.prototype, {
25678
25679 crossOrigin: 'Anonymous',
25680
25681 load: function ( url, onLoad, onProgress, onError ) {
25682
25683 var texture = new Texture();
25684
25685 var loader = new ImageLoader( this.manager );
25686 loader.setCrossOrigin( this.crossOrigin );
25687 loader.setPath( this.path );
25688
25689 loader.load( url, function ( image ) {
25690
25691 texture.image = image;
25692
25693 // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB.
25694 var isJPEG = url.search( /\.(jpg|jpeg)$/ ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0;
25695
25696 texture.format = isJPEG ? RGBFormat : RGBAFormat;
25697 texture.needsUpdate = true;
25698
25699 if ( onLoad !== undefined ) {
25700
25701 onLoad( texture );
25702
25703 }
25704
25705 }, onProgress, onError );
25706
25707 return texture;
25708
25709 },
25710
25711 setCrossOrigin: function ( value ) {
25712
25713 this.crossOrigin = value;
25714 return this;
25715
25716 },
25717
25718 setPath: function ( value ) {
25719
25720 this.path = value;
25721 return this;
25722
25723 }
25724
25725} );
25726
25727exports.WebGLRenderTarget = WebGLRenderTarget;
25728exports.WebGLRenderer = WebGLRenderer;
25729exports.Scene = Scene;
25730exports.Mesh = Mesh;
25731exports.DataTexture = DataTexture;
25732exports.PlaneGeometry = PlaneGeometry;
25733exports.ShaderMaterial = ShaderMaterial;
25734exports.MeshBasicMaterial = MeshBasicMaterial;
25735exports.Material = Material;
25736exports.TextureLoader = TextureLoader;
25737exports.OrthographicCamera = OrthographicCamera;
25738exports.ClampToEdgeWrapping = ClampToEdgeWrapping;
25739exports.FloatType = FloatType;
25740exports.LinearFilter = LinearFilter;
25741exports.NearestFilter = NearestFilter;
25742exports.NearestMipMapNearestFilter = NearestMipMapNearestFilter;
25743exports.RepeatWrapping = RepeatWrapping;
25744exports.RGBAFormat = RGBAFormat;
25745exports.UnsignedByteType = UnsignedByteType;
25746
25747Object.defineProperty(exports, '__esModule', { value: true });
25748
25749})));
25750require=(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}return e})()({1:[function(require,module,exports){
25751(function (global){
25752global.THREE = require('three');
25753
25754THREE = {
25755 ClampToEdgeWrapping: THREE.ClampToEdgeWrapping,
25756 DataTexture: THREE.DataTexture,
25757 FloatType: THREE.FloatType,
25758 LinearFilter: THREE.LinearFilter,
25759 Material: THREE.Material,
25760 Mesh: THREE.Mesh,
25761 MeshBasicMaterial: THREE.MeshBasicMaterial,
25762 NearestFilter: THREE.NearestFilter,
25763 NearestMipMapNearestFilter: THREE.NearestMipMapNearestFilter,
25764 OrthographicCamera: THREE.OrthographicCamera,
25765 PlaneGeometry: THREE.PlaneGeometry,
25766 RepeatWrapping: THREE.RepeatWrapping,
25767 RGBAFormat: THREE.RGBAFormat,
25768 Scene: THREE.Scene,
25769 ShaderMaterial: THREE.ShaderMaterial,
25770 TextureLoader: THREE.TextureLoader,
25771 UnsignedByteType: THREE.UnsignedByteType,
25772 WebGLRenderer: THREE.WebGLRenderer,
25773 WebGLRenderTarget: THREE.WebGLRenderTarget
25774};
25775
25776}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
25777},{"three":"three"}],"three":[function(require,module,exports){
25778module.exports = window.THREE;
25779},{}]},{},[1]);
25780
25781/**
25782 * @author alteredq / http://alteredqualia.com/
25783 * @author mr.doob / http://mrdoob.com/
25784 */
25785
25786var Detector = {
25787
25788 canvas: !! window.CanvasRenderingContext2D,
25789 webgl: ( function () {
25790
25791 try {
25792
25793 var canvas = document.createElement( 'canvas' ); return !! ( window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) ) );
25794
25795 } catch ( e ) {
25796
25797 return false;
25798
25799 }
25800
25801 } )(),
25802 workers: !! window.Worker,
25803 fileapi: window.File && window.FileReader && window.FileList && window.Blob,
25804
25805 getWebGLErrorMessage: function () {
25806
25807 var element = document.createElement( 'div' );
25808 element.id = 'webgl-error-message';
25809 element.style.fontFamily = 'monospace';
25810 element.style.fontSize = '13px';
25811 element.style.fontWeight = 'normal';
25812 element.style.textAlign = 'center';
25813 element.style.background = '#fff';
25814 element.style.color = '#000';
25815 element.style.padding = '1.5em';
25816 element.style.width = '400px';
25817 element.style.margin = '5em auto 0';
25818
25819 if ( ! this.webgl ) {
25820
25821 element.innerHTML = window.WebGLRenderingContext ? [
25822 'Your graphics card does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000">WebGL</a>.<br />',
25823 'Find out how to get it <a href="http://get.webgl.org/" style="color:#000">here</a>.'
25824 ].join( '\n' ) : [
25825 'Your browser does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000">WebGL</a>.<br/>',
25826 'Find out how to get it <a href="http://get.webgl.org/" style="color:#000">here</a>.'
25827 ].join( '\n' );
25828
25829 }
25830
25831 return element;
25832
25833 },
25834
25835 addGetWebGLMessage: function ( parameters ) {
25836
25837 var parent, id, element;
25838
25839 parameters = parameters || {};
25840
25841 parent = parameters.parent !== undefined ? parameters.parent : document.body;
25842 id = parameters.id !== undefined ? parameters.id : 'oldie';
25843
25844 element = Detector.getWebGLErrorMessage();
25845 element.id = id;
25846
25847 parent.appendChild( element );
25848
25849 }
25850
25851};
25852
25853// browserify support
25854if ( typeof module === 'object' ) {
25855
25856 module.exports = Detector;
25857
25858}
25859/* jshint -W067 */
25860/* jshint unused: false */
25861(function(global, undefined) {
25862 'use strict';
25863
25864 if (!notUseNative() && (global.msSetImmediate || global.setImmediate)) {
25865 if (!global.setImmediate) {
25866 global.setImmediate = global.msSetImmediate;
25867 global.clearImmediate = global.msClearImmediate;
25868 }
25869
25870 return;
25871 }
25872
25873 var doc = global.document;
25874 var slice = Array.prototype.slice;
25875 var toString = Object.prototype.toString;
25876 var Timer = {};
25877
25878 Timer.polifill = {};
25879 Timer.nextId = 1;
25880 Timer.tasks = {};
25881 Timer.lock = false;
25882
25883 Timer.run = function(handleId) {
25884 if (Timer.lock) {
25885 global.setTimeout( Timer.wrap( Timer.run, handleId ), 0 );
25886
25887 } else {
25888 var task = Timer.tasks[ handleId ];
25889
25890 if (task) {
25891 Timer.lock = true;
25892
25893 try {
25894 task();
25895
25896 } finally {
25897 Timer.clear( handleId );
25898 Timer.lock = false;
25899 }
25900 }
25901 }
25902 };
25903
25904 Timer.wrap = function(handler) {
25905 var args = slice.call(arguments, 1);
25906
25907 return function() {
25908 handler.apply(undefined, args);
25909 };
25910 };
25911
25912 Timer.create = function(args) {
25913 Timer.tasks[ Timer.nextId ] = Timer.wrap.apply(undefined, args);
25914 return Timer.nextId++;
25915 };
25916
25917 Timer.clear = function(handleId) {
25918 delete Timer.tasks[ handleId ];
25919 };
25920
25921 /* polifill/messageChannel.js begin */
25922/* global global, Timer */
25923
25924Timer.polifill.messageChannel = function() {
25925 var channel = new global.MessageChannel();
25926
25927 channel.port1.onmessage = function(event) {
25928 Timer.run(Number(event.data));
25929 };
25930
25931 return function() {
25932 var handleId = Timer.create(arguments);
25933 channel.port2.postMessage(handleId);
25934 return handleId;
25935 };
25936};
25937
25938/* polifill/messageChannel.js end */
25939
25940 /* polifill/nextTick.js begin */
25941/* global global, Timer */
25942
25943Timer.polifill.nextTick = function() {
25944 return function() {
25945 var handleId = Timer.create(arguments);
25946 global.process.nextTick( Timer.wrap( Timer.run, handleId ) );
25947 return handleId;
25948 };
25949};
25950
25951/* polifill/nextTick.js end */
25952
25953 /* polifill/postMessage.js begin */
25954/* global global, Timer */
25955
25956Timer.polifill.postMessage = function() {
25957 var messagePrefix = 'setImmediate$' + Math.random() + '$';
25958
25959 var onGlobalMessage = function(event) {
25960 if (event.source === global &&
25961 typeof(event.data) === 'string' &&
25962 event.data.indexOf(messagePrefix) === 0) {
25963
25964 Timer.run(Number(event.data.slice(messagePrefix.length)));
25965 }
25966 };
25967
25968 if (global.addEventListener) {
25969 global.addEventListener('message', onGlobalMessage, false);
25970
25971 } else {
25972 global.attachEvent('onmessage', onGlobalMessage);
25973 }
25974
25975 return function() {
25976 var handleId = Timer.create(arguments);
25977 global.postMessage(messagePrefix + handleId, '*');
25978 return handleId;
25979 };
25980};
25981
25982/* polifill/postMessage.js end */
25983
25984 /* polifill/readyStateChange.js begin */
25985/* global Timer, doc */
25986
25987Timer.polifill.readyStateChange = function() {
25988 var html = doc.documentElement;
25989
25990 return function() {
25991 var handleId = Timer.create(arguments);
25992 var script = doc.createElement('script');
25993
25994 script.onreadystatechange = function() {
25995 Timer.run(handleId);
25996 script.onreadystatechange = null;
25997 html.removeChild(script);
25998 script = null;
25999 };
26000
26001 html.appendChild(script);
26002
26003 return handleId;
26004 };
26005};
26006
26007/* polifill/readyStateChange.js end */
26008
26009 /* polifill/setTimeout.js begin */
26010/* global global, Timer */
26011
26012Timer.polifill.setTimeout = function() {
26013 return function() {
26014 var handleId = Timer.create(arguments);
26015 global.setTimeout( Timer.wrap( Timer.run, handleId ), 0 );
26016 return handleId;
26017 };
26018};
26019
26020/* polifill/setTimeout.js end */
26021
26022
26023
26024
26025 function canUsePostMessage() {
26026 if (global.postMessage && !global.importScripts) {
26027 var asynch = true;
26028 var oldOnMessage = global.onmessage;
26029 global.onmessage = function() {
26030 asynch = false;
26031 };
26032 global.postMessage('', '*');
26033 global.onmessage = oldOnMessage;
26034 return asynch;
26035 }
26036 }
26037
26038 function notUseNative() {
26039 // @see http://codeforhire.com/2013/09/21/setimmediate-and-messagechannel-broken-on-internet-explorer-10/
26040 return (global.navigator && /Trident/.test(global.navigator.userAgent));
26041 }
26042
26043
26044 var polifill;
26045
26046 if (notUseNative()) {
26047 polifill = 'setTimeout';
26048
26049 // Don't get fooled by e.g. browserify environments.
26050 // For Node.js before 0.9
26051 } else if (toString.call(global.process) === '[object process]') {
26052 polifill = 'nextTick';
26053
26054 // For non-IE10 modern browsers
26055 } else if (canUsePostMessage()) {
26056 polifill = 'postMessage';
26057
26058 // For web workers, where supported
26059 } else if (global.MessageChannel) {
26060 polifill = 'messageChannel';
26061
26062 // For IE 6?8
26063 } else if (doc && ('onreadystatechange' in doc.createElement('script'))) {
26064 polifill = 'readyStateChange';
26065
26066 // For older browsers
26067 } else {
26068 polifill = 'setTimeout';
26069 }
26070
26071 // If supported, we should attach to the prototype of global, since that is where setTimeout et al. live.
26072 var attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global);
26073 attachTo = (attachTo && attachTo.setTimeout ? attachTo : global);
26074
26075 attachTo.setImmediate = Timer.polifill[ polifill ]();
26076 attachTo.setImmediate.usePolifill = polifill;
26077 attachTo.msSetImmediate = attachTo.setImmediate;
26078
26079 attachTo.clearImmediate = Timer.clear;
26080 attachTo.msClearImmediate = Timer.clear;
26081
26082}(function() {
26083 return this || (1, eval)('this');
26084}()));
26085/*!
26086 * EventEmitter v4.2.11 - git.io/ee
26087 * Unlicense - http://unlicense.org/
26088 * Oliver Caldwell - http://oli.me.uk/
26089 * @preserve
26090 */
26091
26092;(function () {
26093 'use strict';
26094
26095 /**
26096 * Class for managing events.
26097 * Can be extended to provide event functionality in other classes.
26098 *
26099 * @class EventEmitter Manages event registering and emitting.
26100 */
26101 function EventEmitter() {}
26102
26103 // Shortcuts to improve speed and size
26104 var proto = EventEmitter.prototype;
26105 var exports = this;
26106 var originalGlobalValue = exports.EventEmitter;
26107
26108 /**
26109 * Finds the index of the listener for the event in its storage array.
26110 *
26111 * @param {Function[]} listeners Array of listeners to search through.
26112 * @param {Function} listener Method to look for.
26113 * @return {Number} Index of the specified listener, -1 if not found
26114 * @api private
26115 */
26116 function indexOfListener(listeners, listener) {
26117 var i = listeners.length;
26118 while (i--) {
26119 if (listeners[i].listener === listener) {
26120 return i;
26121 }
26122 }
26123
26124 return -1;
26125 }
26126
26127 /**
26128 * Alias a method while keeping the context correct, to allow for overwriting of target method.
26129 *
26130 * @param {String} name The name of the target method.
26131 * @return {Function} The aliased method
26132 * @api private
26133 */
26134 function alias(name) {
26135 return function aliasClosure() {
26136 return this[name].apply(this, arguments);
26137 };
26138 }
26139
26140 /**
26141 * Returns the listener array for the specified event.
26142 * Will initialise the event object and listener arrays if required.
26143 * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.
26144 * Each property in the object response is an array of listener functions.
26145 *
26146 * @param {String|RegExp} evt Name of the event to return the listeners from.
26147 * @return {Function[]|Object} All listener functions for the event.
26148 */
26149 proto.getListeners = function getListeners(evt) {
26150 var events = this._getEvents();
26151 var response;
26152 var key;
26153
26154 // Return a concatenated array of all matching events if
26155 // the selector is a regular expression.
26156 if (evt instanceof RegExp) {
26157 response = {};
26158 for (key in events) {
26159 if (events.hasOwnProperty(key) && evt.test(key)) {
26160 response[key] = events[key];
26161 }
26162 }
26163 }
26164 else {
26165 response = events[evt] || (events[evt] = []);
26166 }
26167
26168 return response;
26169 };
26170
26171 /**
26172 * Takes a list of listener objects and flattens it into a list of listener functions.
26173 *
26174 * @param {Object[]} listeners Raw listener objects.
26175 * @return {Function[]} Just the listener functions.
26176 */
26177 proto.flattenListeners = function flattenListeners(listeners) {
26178 var flatListeners = [];
26179 var i;
26180
26181 for (i = 0; i < listeners.length; i += 1) {
26182 flatListeners.push(listeners[i].listener);
26183 }
26184
26185 return flatListeners;
26186 };
26187
26188 /**
26189 * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.
26190 *
26191 * @param {String|RegExp} evt Name of the event to return the listeners from.
26192 * @return {Object} All listener functions for an event in an object.
26193 */
26194 proto.getListenersAsObject = function getListenersAsObject(evt) {
26195 var listeners = this.getListeners(evt);
26196 var response;
26197
26198 if (listeners instanceof Array) {
26199 response = {};
26200 response[evt] = listeners;
26201 }
26202
26203 return response || listeners;
26204 };
26205
26206 /**
26207 * Adds a listener function to the specified event.
26208 * The listener will not be added if it is a duplicate.
26209 * If the listener returns true then it will be removed after it is called.
26210 * If you pass a regular expression as the event name then the listener will be added to all events that match it.
26211 *
26212 * @param {String|RegExp} evt Name of the event to attach the listener to.
26213 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
26214 * @return {Object} Current instance of EventEmitter for chaining.
26215 */
26216 proto.addListener = function addListener(evt, listener) {
26217 var listeners = this.getListenersAsObject(evt);
26218 var listenerIsWrapped = typeof listener === 'object';
26219 var key;
26220
26221 for (key in listeners) {
26222 if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
26223 listeners[key].push(listenerIsWrapped ? listener : {
26224 listener: listener,
26225 once: false
26226 });
26227 }
26228 }
26229
26230 return this;
26231 };
26232
26233 /**
26234 * Alias of addListener
26235 */
26236 proto.on = alias('addListener');
26237
26238 /**
26239 * Semi-alias of addListener. It will add a listener that will be
26240 * automatically removed after its first execution.
26241 *
26242 * @param {String|RegExp} evt Name of the event to attach the listener to.
26243 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
26244 * @return {Object} Current instance of EventEmitter for chaining.
26245 */
26246 proto.addOnceListener = function addOnceListener(evt, listener) {
26247 return this.addListener(evt, {
26248 listener: listener,
26249 once: true
26250 });
26251 };
26252
26253 /**
26254 * Alias of addOnceListener.
26255 */
26256 proto.once = alias('addOnceListener');
26257
26258 /**
26259 * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.
26260 * You need to tell it what event names should be matched by a regex.
26261 *
26262 * @param {String} evt Name of the event to create.
26263 * @return {Object} Current instance of EventEmitter for chaining.
26264 */
26265 proto.defineEvent = function defineEvent(evt) {
26266 this.getListeners(evt);
26267 return this;
26268 };
26269
26270 /**
26271 * Uses defineEvent to define multiple events.
26272 *
26273 * @param {String[]} evts An array of event names to define.
26274 * @return {Object} Current instance of EventEmitter for chaining.
26275 */
26276 proto.defineEvents = function defineEvents(evts) {
26277 for (var i = 0; i < evts.length; i += 1) {
26278 this.defineEvent(evts[i]);
26279 }
26280 return this;
26281 };
26282
26283 /**
26284 * Removes a listener function from the specified event.
26285 * When passed a regular expression as the event name, it will remove the listener from all events that match it.
26286 *
26287 * @param {String|RegExp} evt Name of the event to remove the listener from.
26288 * @param {Function} listener Method to remove from the event.
26289 * @return {Object} Current instance of EventEmitter for chaining.
26290 */
26291 proto.removeListener = function removeListener(evt, listener) {
26292 var listeners = this.getListenersAsObject(evt);
26293 var index;
26294 var key;
26295
26296 for (key in listeners) {
26297 if (listeners.hasOwnProperty(key)) {
26298 index = indexOfListener(listeners[key], listener);
26299
26300 if (index !== -1) {
26301 listeners[key].splice(index, 1);
26302 }
26303 }
26304 }
26305
26306 return this;
26307 };
26308
26309 /**
26310 * Alias of removeListener
26311 */
26312 proto.off = alias('removeListener');
26313
26314 /**
26315 * Adds listeners in bulk using the manipulateListeners method.
26316 * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.
26317 * You can also pass it a regular expression to add the array of listeners to all events that match it.
26318 * Yeah, this function does quite a bit. That's probably a bad thing.
26319 *
26320 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.
26321 * @param {Function[]} [listeners] An optional array of listener functions to add.
26322 * @return {Object} Current instance of EventEmitter for chaining.
26323 */
26324 proto.addListeners = function addListeners(evt, listeners) {
26325 // Pass through to manipulateListeners
26326 return this.manipulateListeners(false, evt, listeners);
26327 };
26328
26329 /**
26330 * Removes listeners in bulk using the manipulateListeners method.
26331 * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
26332 * You can also pass it an event name and an array of listeners to be removed.
26333 * You can also pass it a regular expression to remove the listeners from all events that match it.
26334 *
26335 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.
26336 * @param {Function[]} [listeners] An optional array of listener functions to remove.
26337 * @return {Object} Current instance of EventEmitter for chaining.
26338 */
26339 proto.removeListeners = function removeListeners(evt, listeners) {
26340 // Pass through to manipulateListeners
26341 return this.manipulateListeners(true, evt, listeners);
26342 };
26343
26344 /**
26345 * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.
26346 * The first argument will determine if the listeners are removed (true) or added (false).
26347 * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
26348 * You can also pass it an event name and an array of listeners to be added/removed.
26349 * You can also pass it a regular expression to manipulate the listeners of all events that match it.
26350 *
26351 * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
26352 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.
26353 * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
26354 * @return {Object} Current instance of EventEmitter for chaining.
26355 */
26356 proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
26357 var i;
26358 var value;
26359 var single = remove ? this.removeListener : this.addListener;
26360 var multiple = remove ? this.removeListeners : this.addListeners;
26361
26362 // If evt is an object then pass each of its properties to this method
26363 if (typeof evt === 'object' && !(evt instanceof RegExp)) {
26364 for (i in evt) {
26365 if (evt.hasOwnProperty(i) && (value = evt[i])) {
26366 // Pass the single listener straight through to the singular method
26367 if (typeof value === 'function') {
26368 single.call(this, i, value);
26369 }
26370 else {
26371 // Otherwise pass back to the multiple function
26372 multiple.call(this, i, value);
26373 }
26374 }
26375 }
26376 }
26377 else {
26378 // So evt must be a string
26379 // And listeners must be an array of listeners
26380 // Loop over it and pass each one to the multiple method
26381 i = listeners.length;
26382 while (i--) {
26383 single.call(this, evt, listeners[i]);
26384 }
26385 }
26386
26387 return this;
26388 };
26389
26390 /**
26391 * Removes all listeners from a specified event.
26392 * If you do not specify an event then all listeners will be removed.
26393 * That means every event will be emptied.
26394 * You can also pass a regex to remove all events that match it.
26395 *
26396 * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
26397 * @return {Object} Current instance of EventEmitter for chaining.
26398 */
26399 proto.removeEvent = function removeEvent(evt) {
26400 var type = typeof evt;
26401 var events = this._getEvents();
26402 var key;
26403
26404 // Remove different things depending on the state of evt
26405 if (type === 'string') {
26406 // Remove all listeners for the specified event
26407 delete events[evt];
26408 }
26409 else if (evt instanceof RegExp) {
26410 // Remove all events matching the regex.
26411 for (key in events) {
26412 if (events.hasOwnProperty(key) && evt.test(key)) {
26413 delete events[key];
26414 }
26415 }
26416 }
26417 else {
26418 // Remove all listeners in all events
26419 delete this._events;
26420 }
26421
26422 return this;
26423 };
26424
26425 /**
26426 * Alias of removeEvent.
26427 *
26428 * Added to mirror the node API.
26429 */
26430 proto.removeAllListeners = alias('removeEvent');
26431
26432 /**
26433 * Emits an event of your choice.
26434 * When emitted, every listener attached to that event will be executed.
26435 * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
26436 * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
26437 * So they will not arrive within the array on the other side, they will be separate.
26438 * You can also pass a regular expression to emit to all events that match it.
26439 *
26440 * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
26441 * @param {Array} [args] Optional array of arguments to be passed to each listener.
26442 * @return {Object} Current instance of EventEmitter for chaining.
26443 */
26444 proto.emitEvent = function emitEvent(evt, args) {
26445 var listenersMap = this.getListenersAsObject(evt);
26446 var listeners;
26447 var listener;
26448 var i;
26449 var key;
26450 var response;
26451
26452 for (key in listenersMap) {
26453 if (listenersMap.hasOwnProperty(key)) {
26454 listeners = listenersMap[key].slice(0);
26455 i = listeners.length;
26456
26457 while (i--) {
26458 // If the listener returns true then it shall be removed from the event
26459 // The function is executed either with a basic call or an apply if there is an args array
26460 listener = listeners[i];
26461
26462 if (listener.once === true) {
26463 this.removeListener(evt, listener.listener);
26464 }
26465
26466 response = listener.listener.apply(this, args || []);
26467
26468 if (response === this._getOnceReturnValue()) {
26469 this.removeListener(evt, listener.listener);
26470 }
26471 }
26472 }
26473 }
26474
26475 return this;
26476 };
26477
26478 /**
26479 * Alias of emitEvent
26480 */
26481 proto.trigger = alias('emitEvent');
26482
26483 /**
26484 * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.
26485 * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
26486 *
26487 * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
26488 * @param {...*} Optional additional arguments to be passed to each listener.
26489 * @return {Object} Current instance of EventEmitter for chaining.
26490 */
26491 proto.emit = function emit(evt) {
26492 var args = Array.prototype.slice.call(arguments, 1);
26493 return this.emitEvent(evt, args);
26494 };
26495
26496 /**
26497 * Sets the current value to check against when executing listeners. If a
26498 * listeners return value matches the one set here then it will be removed
26499 * after execution. This value defaults to true.
26500 *
26501 * @param {*} value The new value to check for when executing listeners.
26502 * @return {Object} Current instance of EventEmitter for chaining.
26503 */
26504 proto.setOnceReturnValue = function setOnceReturnValue(value) {
26505 this._onceReturnValue = value;
26506 return this;
26507 };
26508
26509 /**
26510 * Fetches the current value to check against when executing listeners. If
26511 * the listeners return value matches this one then it should be removed
26512 * automatically. It will return true by default.
26513 *
26514 * @return {*|Boolean} The current value to check for or the default, true.
26515 * @api private
26516 */
26517 proto._getOnceReturnValue = function _getOnceReturnValue() {
26518 if (this.hasOwnProperty('_onceReturnValue')) {
26519 return this._onceReturnValue;
26520 }
26521 else {
26522 return true;
26523 }
26524 };
26525
26526 /**
26527 * Fetches the events object and creates one if required.
26528 *
26529 * @return {Object} The events storage object.
26530 * @api private
26531 */
26532 proto._getEvents = function _getEvents() {
26533 return this._events || (this._events = {});
26534 };
26535
26536 /**
26537 * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
26538 *
26539 * @return {Function} Non conflicting EventEmitter class.
26540 */
26541 EventEmitter.noConflict = function noConflict() {
26542 exports.EventEmitter = originalGlobalValue;
26543 return EventEmitter;
26544 };
26545
26546 // Expose the class either via AMD, CommonJS or the global object
26547 if (typeof define === 'function' && define.amd) {
26548 define(function () {
26549 return EventEmitter;
26550 });
26551 }
26552 else if (typeof module === 'object' && module.exports){
26553 module.exports = EventEmitter;
26554 }
26555 else {
26556 exports.EventEmitter = EventEmitter;
26557 }
26558}.call(this));
26559/******************************************************************************
26560
26561This is a binary tree based bin packing algorithm that is more complex than
26562the simple Packer (packer.js). Instead of starting off with a fixed width and
26563height, it starts with the width and height of the first block passed and then
26564grows as necessary to accomodate each subsequent block. As it grows it attempts
26565to maintain a roughly square ratio by making 'smart' choices about whether to
26566grow right or down.
26567
26568When growing, the algorithm can only grow to the right OR down. Therefore, if
26569the new block is BOTH wider and taller than the current target then it will be
26570rejected. This makes it very important to initialize with a sensible starting
26571width and height. If you are providing sorted input (largest first) then this
26572will not be an issue.
26573
26574A potential way to solve this limitation would be to allow growth in BOTH
26575directions at once, but this requires maintaining a more complex tree
26576with 3 children (down, right and center) and that complexity can be avoided
26577by simply chosing a sensible starting block.
26578
26579Best results occur when the input blocks are sorted by height, or even better
26580when sorted by max(width,height).
26581
26582Inputs:
26583------
26584
26585 blocks: array of any objects that have .w and .h attributes
26586
26587Outputs:
26588-------
26589
26590 marks each block that fits with a .fit attribute pointing to a
26591 node with .x and .y coordinates
26592
26593Example:
26594-------
26595
26596 var blocks = [
26597 { w: 100, h: 100 },
26598 { w: 100, h: 100 },
26599 { w: 80, h: 80 },
26600 { w: 80, h: 80 },
26601 etc
26602 etc
26603 ];
26604
26605 var packer = new GrowingPacker();
26606 packer.fit(blocks);
26607
26608 for(var n = 0 ; n < blocks.length ; n++) {
26609 var block = blocks[n];
26610 if (block.fit) {
26611 Draw(block.fit.x, block.fit.y, block.w, block.h);
26612 }
26613 }
26614
26615
26616******************************************************************************/
26617
26618GrowingPacker = function() { };
26619
26620GrowingPacker.prototype = {
26621
26622 fit: function(blocks) {
26623 var n, node, block, len = blocks.length;
26624 var w = len > 0 ? blocks[0].w : 0;
26625 var h = len > 0 ? blocks[0].h : 0;
26626 this.root = { x: 0, y: 0, w: w, h: h };
26627 for (n = 0; n < len ; n++) {
26628 block = blocks[n];
26629 if (node = this.findNode(this.root, block.w, block.h))
26630 block.fit = this.splitNode(node, block.w, block.h);
26631 else
26632 block.fit = this.growNode(block.w, block.h);
26633 }
26634 },
26635
26636 findNode: function(root, w, h) {
26637 if (root.used)
26638 return this.findNode(root.right, w, h) || this.findNode(root.down, w, h);
26639 else if ((w <= root.w) && (h <= root.h))
26640 return root;
26641 else
26642 return null;
26643 },
26644
26645 splitNode: function(node, w, h) {
26646 node.used = true;
26647 node.down = { x: node.x, y: node.y + h, w: node.w, h: node.h - h };
26648 node.right = { x: node.x + w, y: node.y, w: node.w - w, h: h };
26649 return node;
26650 },
26651
26652 growNode: function(w, h) {
26653 var canGrowDown = (w <= this.root.w);
26654 var canGrowRight = (h <= this.root.h);
26655
26656 var shouldGrowRight = canGrowRight && (this.root.h >= (this.root.w + w)); // attempt to keep square-ish by growing right when height is much greater than width
26657 var shouldGrowDown = canGrowDown && (this.root.w >= (this.root.h + h)); // attempt to keep square-ish by growing down when width is much greater than height
26658
26659 if (shouldGrowRight)
26660 return this.growRight(w, h);
26661 else if (shouldGrowDown)
26662 return this.growDown(w, h);
26663 else if (canGrowRight)
26664 return this.growRight(w, h);
26665 else if (canGrowDown)
26666 return this.growDown(w, h);
26667 else
26668 return null; // need to ensure sensible root starting size to avoid this happening
26669 },
26670
26671 growRight: function(w, h) {
26672 this.root = {
26673 used: true,
26674 x: 0,
26675 y: 0,
26676 w: this.root.w + w,
26677 h: this.root.h,
26678 down: this.root,
26679 right: { x: this.root.w, y: 0, w: w, h: this.root.h }
26680 };
26681 var node = this.findNode(this.root, w, h);
26682 if (node)
26683 return this.splitNode(node, w, h);
26684 else
26685 return null;
26686 },
26687
26688 growDown: function(w, h) {
26689 this.root = {
26690 used: true,
26691 x: 0,
26692 y: 0,
26693 w: this.root.w,
26694 h: this.root.h + h,
26695 down: { x: 0, y: this.root.h, w: this.root.w, h: h },
26696 right: this.root
26697 };
26698 var node = this.findNode(this.root, w, h);
26699 if (node)
26700 return this.splitNode(node, w, h);
26701 else
26702 return null;
26703 }
26704
26705};
26706
26707/**
26708 * http://paulirish.com/2011/requestanimationframe-for-smart-animating/
26709 * And modified to work with node.js
26710 */
26711
26712(function() {
26713
26714 var root = this;
26715 var lastTime = 0;
26716 var vendors = ['ms', 'moz', 'webkit', 'o'];
26717
26718 for (var x = 0; x < vendors.length && !root.requestAnimationFrame; ++x) {
26719 root.requestAnimationFrame = root[vendors[x]+'RequestAnimationFrame'];
26720 root.cancelAnimationFrame =
26721 root[vendors[x]+'CancelAnimationFrame'] || root[vendors[x]+'CancelRequestAnimationFrame'];
26722 }
26723
26724 if (!root.requestAnimationFrame)
26725 root.requestAnimationFrame = raf;
26726
26727 if (!root.cancelAnimationFrame)
26728 root.cancelAnimationFrame = function(id) {
26729 clearTimeout(id);
26730 };
26731
26732 if (typeof exports !== 'undefined') {
26733 if (typeof module !== 'undefined' && module.exports) {
26734 exports = module.exports = root.requestAnimationFrame;
26735 }
26736 exports.requestAnimationFrame = root.requestAnimationFrame;
26737 } else {
26738 root.requestAnimationFrame = root.requestAnimationFrame;
26739 }
26740
26741 if (typeof define === 'function' && define.amd) {
26742 define('requestAnimationFrame', [], function() {
26743 return root.requestAnimationFrame;
26744 });
26745 }
26746
26747 function raf(callback, element) {
26748 var currTime = new Date().getTime();
26749 var timeToCall = Math.max(0, 16 - (currTime - lastTime));
26750 var id = root.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
26751 lastTime = currTime + timeToCall;
26752 return id;
26753 }
26754
26755})();
26756(function(previousBlotter, _, THREE, Detector, EventEmitter) {
26757
26758 var root = this;
26759
26760 var Blotter = root.Blotter = previousBlotter = function (material, options) {
26761 if (!Detector.webgl) {
26762 Blotter.Messaging.throwError("Blotter", false, "device does not support webgl");
26763 }
26764
26765 this._texts = [];
26766 this._textEventBindings = {};
26767
26768 this._scopes = {};
26769 this._scopeEventBindings = {};
26770
26771 this._renderer = new Blotter.Renderer();
26772
26773 this._startTime = 0;
26774 this._lastDrawTime = 0;
26775
26776 this.init.apply(this, arguments);
26777 };
26778
26779 Blotter.prototype = (function () {
26780
26781 function _updateMaterialUniforms () {
26782 var now = Date.now();
26783
26784 this._material.uniforms.uTimeDelta.value = (now - (this._lastDrawTime || now)) / 1000;
26785 this._material.uniforms.uGlobalTime.value = (now - this._startTime) / 1000;
26786
26787 this._lastDrawTime = now;
26788 }
26789
26790 function _rendererRendered () {
26791 _updateMaterialUniforms.call(this);
26792
26793 _.each(this._scopes, _.bind(function (scope) {
26794 if (scope.playing) {
26795 scope.render();
26796 }
26797 this.trigger("render");
26798 }, this));
26799 }
26800
26801 function _updateUniformValue (uniformName) {
26802 if (this.mappingMaterial) {
26803 var value = this._material.uniforms[uniformName].value;
26804
26805 this.mappingMaterial.uniformInterface[uniformName].value = value;
26806 }
26807 }
26808
26809 function _updateTextUniformValue (textId, uniformName) {
26810 if (this.mappingMaterial) {
26811 var scope = this._scopes[textId],
26812 value = scope.material.uniforms[uniformName].value;
26813
26814 this.mappingMaterial.textUniformInterface[textId][uniformName].value = value;
26815 }
26816 }
26817
26818 function _update () {
26819 var buildMapping,
26820 buildMappingMaterial,
26821 mappingMaterial,
26822 buildStages;
26823
26824 buildMapping = _.bind(function () {
26825 return _.bind(function (next) {
26826 Blotter.MappingBuilder.build(this._texts, _.bind(function (newMapping) {
26827 this._mapping = newMapping;
26828 this._mapping.ratio = this.ratio;
26829
26830 next();
26831 }, this));
26832 }, this);
26833 }, this);
26834
26835 buildMappingMaterial = _.bind(function () {
26836 return _.bind(function (next) {
26837 Blotter.MappingMaterialBuilder.build(this._mapping, this._material, _.bind(function (newMappingMaterial) {
26838 this.mappingMaterial = newMappingMaterial;
26839
26840 next();
26841 }, this));
26842 }, this);
26843 }, this);
26844
26845 buildStages = [
26846 buildMapping(),
26847 buildMappingMaterial()
26848 ];
26849
26850 _(buildStages).reduceRight(_.wrap, _.bind(function () {
26851 this._renderer.stop();
26852
26853 _.each(this._scopes, _.bind(function (scope, textId) {
26854 scope.mappingMaterial = this.mappingMaterial;
26855 scope.needsUpdate = true;
26856 }, this));
26857
26858 this._renderer.material = this.mappingMaterial.shaderMaterial;
26859 this._renderer.width = this._mapping.width;
26860 this._renderer.height = this._mapping.height;
26861
26862 if (this.autostart) {
26863 this.start();
26864 }
26865
26866 this.trigger(this.lastUpdated ? "update" : "ready");
26867 this.lastUpdated = Date.now();
26868 }, this))();
26869 }
26870
26871 return {
26872
26873 constructor : Blotter,
26874
26875 get needsUpdate () { }, // jshint
26876
26877 set needsUpdate (value) {
26878 if (value === true) {
26879 _update.call(this);
26880 }
26881 },
26882
26883 get material () {
26884 return this._material;
26885 },
26886
26887 set material (material) {
26888 this.setMaterial(material);
26889 },
26890
26891 get texts () {
26892 return this._texts;
26893 },
26894
26895 set texts (texts) {
26896 this.removeTexts(this._texts);
26897 this.addTexts(texts);
26898 },
26899
26900 get imageData () {
26901 return this._renderer.imageData;
26902 },
26903
26904 init : function (material, options) {
26905 options = options || {};
26906 _.defaults(this, options, {
26907 ratio : Blotter.CanvasUtils.pixelRatio,
26908 autobuild : true,
26909 autostart : true,
26910 autoplay : true
26911 });
26912
26913 this.setMaterial(material);
26914 this.addTexts(options.texts);
26915
26916 this._renderer.on("render", _.bind(_rendererRendered, this));
26917
26918 if (this.autobuild) {
26919 this.needsUpdate = true;
26920 }
26921
26922 if (this.autostart) {
26923 this.start();
26924 }
26925 },
26926
26927 start : function () {
26928 this.autostart = true;
26929 this._startTime = Date.now();
26930 this._renderer.start();
26931 },
26932
26933 stop : function () {
26934 this.autostart = false;
26935 this._renderer.stop();
26936 },
26937
26938 teardown : function () {
26939 this._renderer.teardown();
26940 },
26941
26942 setMaterial : function (material) {
26943 Blotter.Messaging.ensureInstanceOf(material, Blotter.Material, "Blotter.Material", "Blotter", "setMaterial");
26944
26945 this._material = material;
26946
26947 if (this._materialEventBinding) {
26948 this._materialEventBinding.unsetEventCallbacks();
26949 }
26950
26951 this._materialEventBinding = new Blotter.ModelEventBinding(material, {
26952 update : _.bind(function () {
26953 _update.call(this);
26954 }, this),
26955
26956 updateUniform : _.bind(function (uniformName) {
26957 _updateUniformValue.call(this, uniformName);
26958 }, this),
26959 });
26960 material.on("update", this._materialEventBinding.eventCallbacks.update);
26961 material.on("update:uniform", this._materialEventBinding.eventCallbacks.updateUniform);
26962 },
26963
26964 addText : function (text) {
26965 this.addTexts(text);
26966 },
26967
26968 addTexts : function (texts) {
26969 var filteredTexts = Blotter.TextUtils.filterTexts(texts),
26970 newTexts = _.difference(filteredTexts, this._texts);
26971
26972 _.each(newTexts, _.bind(function (text) {
26973 this._texts.push(text);
26974
26975 this._textEventBindings[text.id] = new Blotter.ModelEventBinding(text, {
26976 update : _.bind(function () {
26977 _update.call(this);
26978 }, this)
26979 });
26980 text.on("update", this._textEventBindings[text.id].eventCallbacks.update);
26981
26982 this._scopes[text.id] = new Blotter.RenderScope(text, this);
26983
26984 this._scopeEventBindings[text.id] = new Blotter.ModelEventBinding(this._scopes[text.id], {
26985 updateUniform : _.bind(function (uniformName) {
26986 _updateTextUniformValue.call(this, text.id, uniformName);
26987 }, this),
26988 });
26989 this._scopes[text.id].on("update:uniform", this._scopeEventBindings[text.id].eventCallbacks.updateUniform);
26990 }, this));
26991 },
26992
26993 removeText : function (text) {
26994 this.removeTexts(text);
26995 },
26996
26997 removeTexts : function (texts) {
26998 var filteredTexts = Blotter.TextUtils.filterTexts(texts),
26999 removedTexts = _.intersection(this._texts, filteredTexts);
27000
27001 _.each(removedTexts, _.bind(function (text) {
27002 this._texts = _.without(this._texts, text);
27003
27004 this._textEventBindings[text.id].unsetEventCallbacks();
27005 this._scopeEventBindings[text.id].unsetEventCallbacks();
27006
27007 delete this._textEventBindings[text.id];
27008 delete this._scopeEventBindings[text.id];
27009 delete this._scopes[text.id];
27010 }, this));
27011 },
27012
27013 forText : function (text) {
27014 Blotter.Messaging.ensureInstanceOf(text, Blotter.Text, "Blotter.Text", "Blotter", "forText");
27015
27016 if (!(this._scopes[text.id])) {
27017 Blotter.Messaging.logError("Blotter", "forText", "Blotter.Text object not found in blotter");
27018 return;
27019 }
27020
27021 return this._scopes[text.id];
27022 },
27023
27024 boundsForText : function (text) {
27025 Blotter.Messaging.ensureInstanceOf(text, Blotter.Text, "Blotter.Text", "Blotter", "boundsForText");
27026
27027 if (!(this._scopes[text.id])) {
27028 Blotter.Messaging.logError("Blotter", "boundsForText", "Blotter.Text object not found in blotter");
27029 return;
27030 }
27031
27032 if (this._mapping) {
27033 return this.mappingMaterial.boundsForText(text);
27034 }
27035 }
27036 };
27037 })();
27038
27039 _.extend(Blotter.prototype, EventEmitter.prototype);
27040
27041 Blotter.Version = "v0.1.0";
27042
27043 // Use a single webgl context regardless of number of blotter instances.
27044 Blotter.webglRenderer = Blotter.webglRenderer || new THREE.WebGLRenderer({ antialias: true, alpha: true, premultipliedAlpha : false });
27045
27046 Blotter.Assets = Blotter.Assets || {};
27047 Blotter.Assets.Shaders = Blotter.Assets.Shaders || {};
27048
27049})(
27050 this.Blotter, this._, this.THREE, this.Detector, this.EventEmitter
27051);
27052
27053(function(Blotter) {
27054
27055 Blotter.Math = {
27056 generateUUID : (function () {
27057 // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
27058 var lut = [];
27059
27060 for ( var i = 0; i < 256; i ++ ) {
27061 lut[i] = ( i < 16 ? '0' : '' ) + (i).toString(16).toUpperCase();
27062 }
27063
27064 return function generateUUID() {
27065 var d0 = Math.random() * 0xffffffff | 0;
27066 var d1 = Math.random() * 0xffffffff | 0;
27067 var d2 = Math.random() * 0xffffffff | 0;
27068 var d3 = Math.random() * 0xffffffff | 0;
27069 return lut[d0 & 0xff] + lut[d0 >> 8 & 0xff] + lut[d0 >> 16 & 0xff] + lut[d0 >> 24 & 0xff] + '-' +
27070 lut[d1 & 0xff] + lut[d1 >> 8 & 0xff] + '-' + lut[d1 >> 16 & 0x0f | 0x40] + lut[d1 >> 24 & 0xff] + '-' +
27071 lut[d2 & 0x3f | 0x80] + lut[d2 >> 8 & 0xff] + '-' + lut[d2 >> 16 & 0xff] + lut[d2 >> 24 & 0xff] +
27072 lut[d3 & 0xff] + lut[d3 >> 8 & 0xff] + lut[d3 >> 16 & 0xff] + lut[d3 >> 24 & 0xff];
27073 };
27074 })()
27075 };
27076
27077})(
27078 this.Blotter
27079);
27080
27081(function(Blotter) {
27082
27083 Blotter.Messaging = (function () {
27084
27085 function _formattedMessage (domain, method, message) {
27086 return domain + (method ? ("#" + method) : "") + ": " + message;
27087 }
27088
27089 return {
27090
27091 ensureInstanceOf : function (object, constructor, constructorStr, domain, method) {
27092 if (!(object instanceof constructor)) {
27093 this.logError(domain, method, "argument must be instanceof " + constructorStr);
27094 return;
27095 }
27096 },
27097
27098 logError : function (domain, method, message) {
27099 var formatted = _formattedMessage(domain, method, message);
27100
27101 console.error(formatted);
27102 },
27103
27104 logWarning : function (domain, method, message) {
27105 var formatted = _formattedMessage(domain, method, message);
27106
27107 console.warn(formatted);
27108 },
27109
27110 throwError : function (domain, method, message) {
27111 var formatted = _formattedMessage(domain, method, message);
27112
27113 throw formatted;
27114 }
27115 };
27116 })();
27117
27118})(
27119 this.Blotter
27120);
27121
27122(function(Blotter, _) {
27123
27124 Blotter._extendWithGettersSetters = function (obj) {
27125 _.each(Array.prototype.slice.call(arguments, 1), function (source) {
27126 if (source) {
27127 for (var prop in source) {
27128 if (obj[prop] && Object.getOwnPropertyDescriptor(obj, prop) && Object.getOwnPropertyDescriptor(obj, prop).set) {
27129 Object.getOwnPropertyDescriptor(obj, prop).set(source[prop]);
27130 } else {
27131 obj[prop] = source[prop];
27132 }
27133 }
27134 }
27135 });
27136 return obj;
27137 };
27138
27139})(
27140 this.Blotter, this._
27141);
27142
27143(function(Blotter) {
27144
27145 Blotter.VendorPrefixes = ["ms", "moz", "webkit", "o"];
27146
27147})(
27148 this.Blotter
27149);
27150
27151 (function(Blotter, _) {
27152
27153 Blotter.ModelEventBinding = function (model, eventCallbacks) {
27154 this.model = model;
27155 this.eventCallbacks = eventCallbacks || {};
27156 };
27157
27158 Blotter.ModelEventBinding.prototype = {
27159
27160 constructor : Blotter.ModelEventBinding,
27161
27162 unsetEventCallbacks : function () {
27163 _.each(this.eventCallbacks, _.bind(function (callback, eventKey) {
27164 this.model.off(eventKey, callback);
27165 }, this));
27166 }
27167 };
27168
27169})(
27170 this.Blotter, this._
27171);
27172
27173(function(Blotter) {
27174
27175 Blotter.CanvasUtils = {
27176
27177 // Creates and returns a high a canvas
27178
27179 canvas : function (w, h, options) {
27180 options = options || {};
27181 var canvas = document.createElement("canvas");
27182
27183 canvas.className = options.class;
27184 canvas.innerHTML = options.html;
27185
27186 canvas.width = w;
27187 canvas.height = h;
27188
27189 return canvas;
27190 },
27191
27192 // Creates and returns a high DPI canvas based on a device specific pixel ratio
27193
27194 hiDpiCanvas : function (w, h, ratio, options) {
27195 ratio = ratio || this.pixelRatio;
27196 options = options || {};
27197 var canvas = document.createElement("canvas");
27198
27199 canvas.className = options.class;
27200 canvas.innerHTML = options.html;
27201
27202 this.updateCanvasSize(canvas, w, h, ratio);
27203
27204 return canvas;
27205 },
27206
27207 updateCanvasSize : function (canvas, w, h, ratio) {
27208 ratio = ratio || 1;
27209
27210 canvas.width = w * ratio;
27211 canvas.height = h * ratio;
27212 canvas.style.width = w + "px";
27213 canvas.style.height = h + "px";
27214 canvas.getContext("2d").setTransform(ratio, 0, 0, ratio, 0, 0);
27215 },
27216
27217 // Returns the device's pixel ratio
27218
27219 pixelRatio : (function () {
27220 var ctx = document.createElement("canvas").getContext("2d"),
27221 dpr = window.devicePixelRatio || 1,
27222 bsr = ctx.backingStorePixelRatio;
27223
27224 for(var x = 0; x < Blotter.VendorPrefixes.length && !bsr; ++x) {
27225 bsr = ctx[Blotter.VendorPrefixes[x]+"BackingStorePixelRatio"];
27226 }
27227
27228 bsr = bsr || 1;
27229
27230 return (dpr / bsr);
27231 })(),
27232
27233 // Returns the mouse position within a canvas
27234
27235 mousePosition : function (canvas, event) {
27236 var rect = canvas.getBoundingClientRect();
27237 return {
27238 x: event.clientX - rect.left,
27239 y: event.clientY - rect.top
27240 };
27241 },
27242
27243 // Returns the mouse position within a canvas, normalized to a value between 0 and 1
27244
27245 normalizedMousePosition : function (canvas, event) {
27246 var rect = canvas.getBoundingClientRect(),
27247 position = this.mousePosition(canvas, event);
27248
27249 return {
27250 x: position.x / rect.width,
27251 y: position.y / rect.height
27252 };
27253 }
27254 };
27255
27256})(
27257 this.Blotter
27258);
27259
27260(function(Blotter, _) {
27261
27262 Blotter.PropertyDefaults = {
27263 family : 'sans-serif',
27264 size : 12,
27265 leading : 1.5,
27266 fill : '#000',
27267 style : 'normal',
27268 weight : 400,
27269 padding : 0,
27270 paddingTop : 0,
27271 paddingRight : 0,
27272 paddingBottom: 0,
27273 paddingLeft : 0
27274 };
27275
27276 Blotter.TextUtils = {
27277
27278 Properties : _.keys(Blotter.PropertyDefaults),
27279
27280 // Recieves property values (optional) and fills in any missing values with default values
27281
27282 ensurePropertyValues : function(properties) {
27283 properties = _.defaults(properties || {}, Blotter.PropertyDefaults);
27284 return properties;
27285 },
27286
27287 filterTexts : function(texts) {
27288 if (texts instanceof Blotter.Text) {
27289 texts = [texts];
27290 } else {
27291 texts = _.toArray(texts);
27292 }
27293
27294 return _.filter(texts, _.bind(function (text) {
27295 var isText = text instanceof Blotter.Text;
27296
27297 if (!isText) {
27298 Blotter.Messaging.logWarning("Blotter.TextUtils", "filterTexts", "object must be instance of Blotter.Text");
27299 }
27300
27301 return isText;
27302 }, this));
27303 },
27304
27305 // Format padding values from style properties for passing to document
27306
27307 stringifiedPadding : function(properties) {
27308 var _properties = properties || this.ensurePropertyValues(),
27309 pTop = properties.paddingTop || _properties.padding,
27310 pRight = _properties.paddingRight || _properties.padding,
27311 pBottom = _properties.paddingBottom || _properties.padding,
27312 pLeft = _properties.paddingLeft || _properties.padding;
27313
27314 return pTop + "px " + pRight + "px " + pBottom + "px " + pLeft + "px";
27315 },
27316
27317 // Determines size of text within the document given certain style properties
27318
27319 sizeForText : function(textValue, properties) {
27320 // Using a <span> here may not be the best approach. In theory a user's stylesheet
27321 // could override the necessary styling for determining sizes below. With growing
27322 // support for custom tags in html, we may consider using them if this raises problems.
27323 var el = document.createElement("span"),
27324 size;
27325
27326 properties = this.ensurePropertyValues(properties);
27327
27328 el.innerHTML = textValue;
27329 el.style.display = "inline-block";
27330 el.style.fontFamily = properties.family;
27331 el.style.fontSize = properties.size + "px";
27332 el.style.fontWeight = properties.weight;
27333 el.style.fontStyle = properties.style;
27334 el.style.lineHeight = properties.leading;
27335 el.style.maxWidth = "none";
27336 el.style.padding = this.stringifiedPadding(properties);
27337 el.style.position = "absolute";
27338 el.style.width = "auto";
27339 el.style.visibility = "hidden";
27340
27341
27342 document.body.appendChild(el);
27343
27344 size = {
27345 w: el.offsetWidth,
27346 h: el.offsetHeight
27347 };
27348
27349 document.body.removeChild(el);
27350
27351 return size;
27352 }
27353 };
27354
27355})(
27356 this.Blotter, this._
27357);
27358
27359(function(Blotter, _) {
27360
27361 Blotter.UniformUtils = {
27362
27363 // Uniform type values we accept for public uniforms
27364
27365 UniformTypes : ["1f", "2f", "3f", "4f"],
27366
27367 // Default uniforms (required) provided to all materials
27368
27369 defaultUniforms : {
27370 uResolution : { type : "2f", value : [0.0, 0.0] }, // Resolution of individual text areas within mapping texture
27371 uGlobalTime : { type : "1f", value : 0.0 }, // The global time in seconds
27372 uTimeDelta : { type : "1f", value : 0.0 }, // The render time in seconds
27373 uBlendColor : { type : "4f", value : [1.0, 1.0, 1.0, 1.0] },
27374 uPixelRatio : { type : "1f", value : Blotter.CanvasUtils.pixelRatio } // The pixel ratio of the user's device
27375 },
27376
27377 // Determine if value is valid for public uniform type
27378
27379 validValueForUniformType : function (type, value) {
27380 var valid = false,
27381 isValid = function (element) {
27382 return !isNaN(element);
27383 };
27384
27385 switch (type) {
27386 case "1f":
27387 valid = !isNaN(value) && [value].every(isValid);
27388 break;
27389
27390 case "2f":
27391 valid = _.isArray(value) && value.length == 2 && value.every(isValid);
27392 break;
27393
27394 case "3f":
27395 valid = _.isArray(value) && value.length == 3 && value.every(isValid);
27396 break;
27397
27398 case "4f":
27399 valid = _.isArray(value) && value.length == 4 && value.every(isValid);
27400 break;
27401
27402 default:
27403 break;
27404 }
27405
27406 return valid;
27407 },
27408
27409 glslDataTypeForUniformType : function (type) {
27410 var dataType;
27411 switch (type) {
27412 case "1f":
27413 dataType = "float";
27414 break;
27415
27416 case "2f":
27417 dataType = "vec2";
27418 break;
27419
27420 case "3f":
27421 dataType = "vec3";
27422 break;
27423
27424 case "4f":
27425 dataType = "vec4";
27426 break;
27427
27428 default:
27429 break;
27430 }
27431
27432 return dataType;
27433 },
27434
27435 fullSwizzleStringForUniformType : function (type) {
27436 var swizzleString;
27437
27438 switch (type) {
27439 case "1f":
27440 swizzleString = "x";
27441 break;
27442
27443 case "2f":
27444 swizzleString = "xy";
27445 break;
27446
27447 case "3f":
27448 swizzleString = "xyz";
27449 break;
27450
27451 case "4f":
27452 swizzleString = "xyzw";
27453 break;
27454
27455 default:
27456 break;
27457 }
27458
27459 return swizzleString;
27460 },
27461
27462 // Given an object containing uniform descriptions, return an object containing only valid uniforms based on the uniform's type and value
27463
27464 extractValidUniforms : function (uniforms) {
27465 uniforms = uniforms || {};
27466 return _.reduce(uniforms, function (memo, uniformDescription, uniformName) {
27467 if (Blotter.UniformUtils.UniformTypes.indexOf(uniformDescription.type) == -1) {
27468 Blotter.Messaging.logError("Blotter.UniformUtils", "extractValidUniforms", "uniforms must be one of type: " +
27469 Blotter.UniformUtils.UniformTypes.join(", "));
27470 return memo;
27471 }
27472
27473 if (!Blotter.UniformUtils.validValueForUniformType(uniformDescription.type, uniformDescription.value)) {
27474 Blotter.Messaging.logError("Blotter.UniformUtils", "extractValidUniforms", "uniform value for " + uniformName + " is incorrect for type: " + uniformDescription.type);
27475 return memo;
27476 }
27477
27478 memo[uniformName] = _.pick(uniformDescription, "type", "value");
27479 return memo;
27480 }, {});
27481 },
27482
27483 ensureHasRequiredDefaultUniforms : function (uniforms, domain, method) {
27484 if (!(Blotter.UniformUtils.hasRequiredDefaultUniforms(uniforms))) {
27485 this.logError(domain, method, "uniforms object is missing required default uniforms defined in Blotter.UniformUtils.defaultUniforms");
27486 return;
27487 }
27488 },
27489
27490 hasRequiredDefaultUniforms : function (uniforms) {
27491 var missingKeys = _.difference(_.allKeys(Blotter.UniformUtils.defaultUniforms), _.allKeys(uniforms));
27492
27493 return !!!missingKeys.length;
27494 }
27495
27496 };
27497
27498})(
27499 this.Blotter, this._
27500);
27501
27502(function(Blotter, _, THREE, EventEmitter) {
27503
27504 Blotter.Text = function (value, properties) {
27505 this.id = Blotter.Math.generateUUID();
27506 this.value = value;
27507 this.properties = properties;
27508 };
27509
27510 Blotter.Text.prototype = {
27511 constructor : Blotter.Text,
27512
27513 get needsUpdate () { }, // jshint
27514
27515 set needsUpdate (value) {
27516 if (value === true) {
27517 this.trigger("update");
27518 }
27519 },
27520
27521 get properties () {
27522 return this._properties;
27523 },
27524
27525 set properties (properties) {
27526 this._properties = Blotter.TextUtils.ensurePropertyValues(properties);
27527 }
27528 };
27529
27530 Blotter._extendWithGettersSetters(Blotter.Text.prototype, EventEmitter.prototype);
27531
27532})(
27533 this.Blotter, this._, this.THREE, this.EventEmitter
27534);
27535
27536(function(Blotter, _) {
27537
27538 Blotter.Assets.Shaders.Blending = [
27539 "//",
27540 "// Author : Bradley Griffith",
27541 "// License : Distributed under the MIT License.",
27542 "//",
27543 "",
27544 "// Returns the resulting blend color by blending a top color over a base color",
27545 "highp vec4 normalBlend(highp vec4 topColor, highp vec4 baseColor) {",
27546 " highp vec4 blend = vec4(0.0);",
27547
27548 " // HACK",
27549 " // Cant divide by 0 (see the 'else' alpha) and after a lot of attempts",
27550 " // this simply seems like the only solution Im going to be able to come up with to get alpha back.",
27551 " if (baseColor.a == 1.0) {",
27552 " baseColor.a = 0.9999999;",
27553 " };",
27554
27555 " if (topColor.a >= 1.0) {",
27556 " blend.a = topColor.a;",
27557 " blend.r = topColor.r;",
27558 " blend.g = topColor.g;",
27559 " blend.b = topColor.b;",
27560 " } else if (topColor.a == 0.0) {",
27561 " blend.a = baseColor.a;",
27562 " blend.r = baseColor.r;",
27563 " blend.g = baseColor.g;",
27564 " blend.b = baseColor.b;",
27565 " } else {",
27566 " blend.a = 1.0 - (1.0 - topColor.a) * (1.0 - baseColor.a); // alpha",
27567 " blend.r = (topColor.r * topColor.a / blend.a) + (baseColor.r * baseColor.a * (1.0 - topColor.a) / blend.a);",
27568 " blend.g = (topColor.g * topColor.a / blend.a) + (baseColor.g * baseColor.a * (1.0 - topColor.a) / blend.a);",
27569 " blend.b = (topColor.b * topColor.a / blend.a) + (baseColor.b * baseColor.a * (1.0 - topColor.a) / blend.a);",
27570 " }",
27571
27572 " return blend;",
27573 "}",
27574
27575 "// Returns a vec4 representing the original top color that would have been needed to blend",
27576 "// against a passed in base color in order to result in the passed in blend color.",
27577 "highp vec4 normalUnblend(highp vec4 blendColor, highp vec4 baseColor) {",
27578 " highp vec4 unblend = vec4(0.0);",
27579
27580 " // HACKY",
27581 " // Cant divide by 0 (see alpha) and after a lot of attempts",
27582 " // this simply seems like the only solution Im going to be able to come up with to get alpha back.",
27583 " if (baseColor.a == 1.0) {",
27584 " baseColor.a = 0.9999999;",
27585 " }",
27586
27587 " unblend.a = 1.0 - ((1.0 - blendColor.a) / (1.0 - baseColor.a));",
27588 " // Round to two decimal places",
27589 " unblend.a = (sign(100.0 * unblend.a) * floor(abs(100.0 * unblend.a) + 0.5)) / 100.0;",
27590
27591 " if (unblend.a >= 1.0) {",
27592 " unblend.r = blendColor.r;",
27593 " unblend.g = blendColor.g;",
27594 " unblend.b = blendColor.b;",
27595 " } else if (unblend.a == 0.0) {",
27596 " unblend.r = baseColor.r;",
27597 " unblend.g = baseColor.g;",
27598 " unblend.b = baseColor.b;",
27599 " } else {",
27600 " unblend.r = (blendColor.r - (baseColor.r * baseColor.a * (1.0 - unblend.a) / blendColor.a)) / (unblend.a / blendColor.a);",
27601 " unblend.g = (blendColor.g - (baseColor.g * baseColor.a * (1.0 - unblend.a) / blendColor.a)) / (unblend.a / blendColor.a);",
27602 " unblend.b = (blendColor.b - (baseColor.b * baseColor.a * (1.0 - unblend.a) / blendColor.a)) / (unblend.a / blendColor.a);",
27603 " }",
27604
27605 " return unblend;",
27606 "}",
27607 ].join("\n");
27608
27609})(
27610 this.Blotter, this._
27611);
27612
27613(function(Blotter, _) {
27614
27615 Blotter.Assets.Shaders.Inf = [
27616 "//",
27617 "// Author : Bradley Griffith",
27618 "// License : Distributed under the MIT License.",
27619 "//",
27620 "bool isinf(float val) {",
27621 " return (val != 0.0 && val * 2.0 == val) ? true : false;",
27622 "}",
27623 ].join("\n");
27624
27625})(
27626 this.Blotter, this._
27627);
27628
27629(function(Blotter, _) {
27630
27631 Blotter.Assets.Shaders.LineMath = [
27632 Blotter.Assets.Shaders.Inf,
27633 "",
27634 "//",
27635 "// Author : Bradley Griffith",
27636 "// License : Distributed under the MIT License.",
27637 "//",
27638 "",
27639 "// Returns the slope of a line given the degrees of the angle on which that line is rotated;",
27640 "float slopeForDegrees(float deg) {",
27641 " // Ensure degrees stay withing 0.0 - 360.0",
27642 " deg = mod(deg, 360.0);",
27643
27644 " float radians = deg * (PI / 180.0);",
27645
27646 " return tan(radians);",
27647 "}",
27648
27649 "// Given x, a slope, and another point, find y for x.",
27650 "float yForXOnSlope(float x, float slope, vec2 p2) {",
27651 " return -1.0 * ((slope * (p2.x - x)) - p2.y);",
27652 "}",
27653
27654 "// Given y, a slope, and another point, find x for y.",
27655 "float xForYOnSlope(float y, float slope, vec2 p2) {",
27656 " return ((y - p2.y) + (slope * p2.x)) / slope;",
27657 "}",
27658
27659 "// Returns slope adjusted for screen ratio.",
27660 "float normalizedSlope(float slope, vec2 resolution) {",
27661 " vec2 p = vec2(1.0) / resolution;",
27662 " return ((slope * 100.0) / p.x) / (100.0 / p.x);",
27663 "}",
27664
27665 "// Returns offsets (+/-) for any coordinate at distance given slope.",
27666 "// Note: This function does not normalize distance.",
27667 "// Note: This function does not adjust slope for screen ratio.",
27668 "vec2 offsetsForCoordAtDistanceOnSlope(float d, float slope) {",
27669 " return vec2(",
27670 " (d * cos(atan(slope))),",
27671 " (d * sin(atan(slope)))",
27672 " );",
27673 "}",
27674 "// Returns a boolean designating whether or not an infinite line intersects with an infinite line, and sets an `out` variable for the intersection point if it is found.",
27675 "// Note: This function does not adjust slope for screen ratio.",
27676 "bool lineLineIntersection (out vec2 intersect, in vec2 p1, in float m1, in vec2 p2, in float m2) {",
27677 " // See: http://gamedev.stackexchange.com/questions/44720/line-intersection-from-parametric-equation",
27678 " // http://stackoverflow.com/questions/41687083/formula-to-determine-if-an-infinite-line-and-a-line-segment-intersect/41687904#41687904",
27679
27680 " bool isIntersecting = false;",
27681
27682 " float dx = 1.0;",
27683 " float dy = m1;",
27684
27685 " float dxx = 1.0;",
27686 " float dyy = m2;",
27687
27688 " float denominator = ((dxx * dy) - (dyy * dx));",
27689 " if (denominator == 0.0) {",
27690 " // Lines are parallel",
27691 " return isIntersecting;",
27692 " }",
27693
27694 " if (isinf(dy)) {",
27695 " float y = yForXOnSlope(p1.x, m2, p2);",
27696 " isIntersecting = true;",
27697 " intersect = vec2(p1.x, y);",
27698 " return isIntersecting;",
27699 " }",
27700
27701 " if (isinf(dyy)) {",
27702 " float y = yForXOnSlope(p2.x, m1, p1);",
27703 " isIntersecting = true;",
27704 " intersect = vec2(p2.x, y);",
27705 " return isIntersecting;",
27706 " }",
27707
27708 " float u = ((dx * (p2.y - p1.y)) + (dy * (p1.x - p2.x))) / denominator;",
27709
27710 " isIntersecting = true;",
27711 " intersect = p2 + (u * vec2(dxx, dyy));",
27712
27713 " return isIntersecting;",
27714 "}",
27715
27716 "// Returns a boolean designating whether or not an infinite line intersects with a line segment, and sets an `out` variable for the intersection point if it is found.",
27717 "// Note: This function does not adjust slope for screen ratio.",
27718 "bool lineLineSegmentIntersection (out vec2 intersect, in vec2 point, in float m, in vec2 pA, in vec2 pB) {",
27719 " // See: http://gamedev.stackexchange.com/questions/44720/line-intersection-from-parametric-equation",
27720 " // http://stackoverflow.com/questions/41687083/formula-to-determine-if-an-infinite-line-and-a-line-segment-intersect/41687904#41687904",
27721
27722 " bool isIntersecting = false;",
27723
27724 " float dx = 1.0;",
27725 " float dy = m;",
27726
27727 " float dxx = pB.x - pA.x;",
27728 " float dyy = pB.y - pA.y;",
27729
27730 " float denominator = ((dxx * dy) - (dyy * dx));",
27731 " if (denominator == 0.0 || (isinf(dyy / dxx) && isinf(dy))) {",
27732 " // Lines are parallel",
27733 " return isIntersecting;",
27734 " }",
27735
27736 " if (isinf(dy)) {",
27737 " float m2 = dyy / dxx;",
27738 " float y = yForXOnSlope(point.x, m2, pB);",
27739 " isIntersecting = true;",
27740 " intersect = vec2(point.x, y);",
27741 " return isIntersecting;",
27742 " }",
27743
27744 " float u = ((dx * (pA.y - point.y)) + (dy * (point.x - pA.x))) / denominator;",
27745
27746 " if (u >= 0.0 && u <= 1.0) {",
27747 " // Intersection occured on line segment",
27748 " isIntersecting = true;",
27749 " intersect = pA + (u * vec2(dxx, dyy));",
27750 " }",
27751
27752 " return isIntersecting;",
27753 "}",
27754 "// Dev Note: Terrible code. Needs refactor. Just trying to find ",
27755 "// which two edges of the rect the intersections occur at.",
27756 "void intersectsOnRectForLine(out vec2 iA, out vec2 iB, in vec2 rMinXY, in vec2 rMaxXY, in vec2 point, in float slope) {",
27757 " bool firstIntersectFound = false;",
27758
27759 " vec2 intersectLeft = vec2(0.0);",
27760 " vec2 intersectTop = vec2(0.0);",
27761 " vec2 intersectRight = vec2(0.0);",
27762 " vec2 intersectBottom = vec2(0.0);",
27763
27764 " bool intersectsLeft = lineLineSegmentIntersection(intersectLeft, point, slope, rMinXY, vec2(rMinXY.x, rMaxXY.y));",
27765 " bool intersectsTop = lineLineSegmentIntersection(intersectTop, point, slope, vec2(rMinXY.x, rMaxXY.y), rMaxXY);",
27766 " bool intersectsRight = lineLineSegmentIntersection(intersectRight, point, slope, rMaxXY, vec2(rMaxXY.x, rMinXY.y));",
27767 " bool intersectsBottom = lineLineSegmentIntersection(intersectBottom, point, slope, rMinXY, vec2(rMaxXY.x, rMinXY.y));",
27768
27769
27770 " if (intersectsLeft) {",
27771 " if (firstIntersectFound) {",
27772 " iB = intersectLeft;",
27773 " }",
27774 " else {",
27775 " iA = intersectLeft;",
27776 " firstIntersectFound = true;",
27777 " }",
27778 " }",
27779
27780 " if (intersectsTop) {",
27781 " if (firstIntersectFound) {",
27782 " iB = intersectTop;",
27783 " }",
27784 " else {",
27785 " iA = intersectTop;",
27786 " firstIntersectFound = true;",
27787 " }",
27788 " }",
27789
27790 " if (intersectsRight) {",
27791 " if (firstIntersectFound) {",
27792 " iB = intersectRight;",
27793 " }",
27794 " else {",
27795 " iA = intersectRight;",
27796 " firstIntersectFound = true;",
27797 " }",
27798 " }",
27799
27800 " if (intersectsBottom) {",
27801 " if (firstIntersectFound) {",
27802 " iB = intersectBottom;",
27803 " }",
27804 " else {",
27805 " iA = intersectBottom;",
27806 " }",
27807 " }",
27808 "}"
27809
27810 ].join("\n");
27811
27812})(
27813 this.Blotter, this._
27814);
27815
27816// See License comments in shader string
27817
27818(function(Blotter, _) {
27819
27820 Blotter.Assets.Shaders.BlinnPhongSpecular = [
27821 "//",
27822 "// Author : Reza Ali",
27823 "// License : Distributed under the MIT License.",
27824 "//",
27825 "",
27826 "float blinnPhongSpecular( vec3 lightDirection, vec3 viewDirection, vec3 surfaceNormal, float shininess ) {",
27827 "",
27828 " //Calculate Blinn-Phong power",
27829 " vec3 H = normalize(viewDirection + lightDirection);",
27830 " return pow(max(0.0, dot(surfaceNormal, H)), shininess);",
27831 "}"
27832 ].join("\n");
27833
27834})(
27835 this.Blotter, this._
27836);
27837
27838// See License comments in shader string
27839
27840(function(Blotter, _) {
27841
27842 Blotter.Assets.Shaders.Easing = [
27843 "//",
27844 "// Author : Reza Ali",
27845 "// License : Distributed under the MIT License.",
27846 "//",
27847 "",
27848 "float linear( float t, float b, float c, float d )",
27849 "{",
27850 " return t * ( c / d ) + b;",
27851 "}",
27852 "",
27853 "float linear( float t )",
27854 "{",
27855 " return t;",
27856 "}",
27857 "",
27858 "float inQuad( float t, float b, float c, float d )",
27859 "{",
27860 " return c * ( t /= d ) * t + b;",
27861 "}",
27862 "",
27863 "float inQuad( float t )",
27864 "{",
27865 " return t * t;",
27866 "}",
27867 "",
27868 "float outQuad( float t, float b, float c, float d )",
27869 "{",
27870 " return -c * ( t /= d ) * ( t - 2.0 ) + b;",
27871 "}",
27872 "",
27873 "float outQuad( float t )",
27874 "{",
27875 " return - ( t -= 1.0 ) * t + 1.0;",
27876 "}",
27877 "",
27878 "float inOutQuad( float t, float b, float c, float d )",
27879 "{",
27880 " if( ( t /= d / 2.0 ) < 1.0 ) {",
27881 " return c / 2.0 * t * t + b;",
27882 " }",
27883 " return - c / 2.0 * ( ( --t ) * ( t - 2.0 ) - 1.0 ) + b;",
27884 "}",
27885 "",
27886 "float inOutQuad( float t )",
27887 "{",
27888 " if( ( t /= 0.5 ) < 1.0 ) return 0.5 * t * t;",
27889 " return -0.5 * ( ( --t ) * ( t-2 ) - 1 );",
27890 "}",
27891 "",
27892 "float inCubic( float t, float b, float c, float d )",
27893 "{",
27894 " return c * ( t /= d ) * t * t + b;",
27895 "}",
27896 "",
27897 "float inCubic( float t )",
27898 "{",
27899 " return t * t * t;",
27900 "}",
27901 "",
27902 "float outCubic( float t, float b, float c, float d )",
27903 "{",
27904 " return c * ( ( t = t/d - 1.0 ) * t * t + 1.0 ) + b;",
27905 "}",
27906 "",
27907 "float outCubic( float t )",
27908 "{",
27909 " return ( ( --t ) * t * t + 1.0 );",
27910 "}",
27911 "",
27912 "float inOutCubic( float t, float b, float c, float d )",
27913 "{",
27914 " if( ( t /= d / 2.0 ) < 1.0 ) return c / 2.0 * t * t * t + b;",
27915 " return c / 2.0 * ( ( t -= 2.0 ) * t * t + 2.0 ) + b;",
27916 "}",
27917 "",
27918 "float inOutCubic( float t )",
27919 "{",
27920 " if( ( t /= 0.5 ) < 1.0 ) return 0.5 * t * t * t;",
27921 " return 0.5 * ( ( t -= 2.0 ) * t * t + 2.0 );",
27922 "}",
27923 "",
27924 "float inQuart( float t, float b, float c, float d )",
27925 "{",
27926 " return c * ( t /= d ) * t * t * t + b;",
27927 "}",
27928 "",
27929 "float inQuart( float t )",
27930 "{",
27931 " return t * t * t * t;",
27932 "}",
27933 "",
27934 "float outQuart( float t, float b, float c, float d )",
27935 "{",
27936 " return -c * ( ( t = t/d - 1.0 ) * t * t * t - 1.0 ) + b;",
27937 "}",
27938 "",
27939 "float outQuart( float t )",
27940 "{",
27941 " return - ( ( --t ) * t * t * t - 1.0 );",
27942 "}",
27943 "",
27944 "float inOutQuart( float t, float b, float c, float d )",
27945 "{",
27946 " if ( ( t /= d / 2.0 ) < 1.0 ) return c / 2.0 * t * t * t * t + b;",
27947 " return -c / 2.0 * ( ( t -= 2.0 ) * t * t * t - 2.0 ) + b;",
27948 "}",
27949 "",
27950 "float inOutQuart( float t )",
27951 "{",
27952 " if ( (t /= 0.5 ) < 1.0 ) return 0.5 * t * t * t * t;",
27953 " return -0.5 * ( ( t -= 2.0 ) * t * t * t - 2.0 );",
27954 "}",
27955 "",
27956 "float inQuint( float t, float b, float c, float d )",
27957 "{",
27958 " return c * ( t /= d ) * t * t * t * t + b;",
27959 "}",
27960 "",
27961 "float inQuint( float t )",
27962 "{",
27963 " return t * t * t * t * t;",
27964 "}",
27965 "",
27966 "float outQuint( float t, float b, float c, float d )",
27967 "{",
27968 " return c * ( ( t = t/d - 1.0) * t * t * t * t + 1.0 ) + b;",
27969 "}",
27970 "",
27971 "float outQuint( float t )",
27972 "{",
27973 " return ( ( --t ) * t * t * t * t + 1.0 );",
27974 "}",
27975 "",
27976 "float inOutQuint( float t, float b, float c, float d )",
27977 "{",
27978 " if( ( t /= d /2.0 ) < 1.0 ) return c / 2.0 * t * t * t * t * t + b;",
27979 " return c / 2.0 * ( ( t -= 2.0 ) * t * t * t * t + 2.0) + b;",
27980 "}",
27981 "",
27982 "float inOutQuint( float t )",
27983 "{",
27984 " if ( ( t /= 0.5 ) < 1.0 ) return 0.5 * t * t * t * t * t;",
27985 " return 0.5 * ( ( t -= 2 ) * t * t * t * t + 2.0 );",
27986 "}",
27987 "",
27988 "float inSine( float t, float b, float c, float d )",
27989 "{",
27990 " return -c * cos( t / d * ( 1.5707963268 ) ) + c + b;",
27991 "}",
27992 "",
27993 "float inSine( float t )",
27994 "{",
27995 " return -1.0 * cos( t * ( 1.5707963268 ) ) + 1.0;",
27996 "}",
27997 "",
27998 "float outSine( float t, float b, float c, float d )",
27999 "{",
28000 " return c * sin( t / d * ( 1.5707963268 ) ) + b;",
28001 "}",
28002 "",
28003 "float outSine( float t )",
28004 "{",
28005 " return sin( t * ( 1.5707963268 ) );",
28006 "}",
28007 "",
28008 "float inOutSine( float t, float b, float c, float d )",
28009 "{",
28010 " return - c / 2.0 * ( cos( 3.1415926536 * t / d ) - 1.0 ) + b;",
28011 "}",
28012 "",
28013 "float inOutSine( float t )",
28014 "{",
28015 " return -0.5 * ( cos( 3.1415926536 * t ) - 1.0 );",
28016 "}",
28017 "",
28018 "float inExpo( float t, float b, float c, float d )",
28019 "{",
28020 " return ( t == 0.0 ) ? b : c * pow( 2.0, 10.0 * ( t / d - 1.0 ) ) + b;",
28021 "}",
28022 "",
28023 "float inExpo( float t )",
28024 "{",
28025 " return ( t == 0 ) ? 0.0 : pow( 2.0, 10.0 * ( t - 1.0 ) );",
28026 "}",
28027 "",
28028 "float outExpo( float t, float b, float c, float d )",
28029 "{",
28030 " return ( t == d ) ? b + c : c * ( - pow( 2.0, -10.0 * t / d ) + 1.0 ) + b;",
28031 "}",
28032 "",
28033 "float outExpo( float t )",
28034 "{",
28035 " return ( t == 1.0 ) ? 1.0 : ( - pow( 2.0, -10.0 * t ) + 1.0 );",
28036 "}",
28037 "",
28038 "float inOutExpo( float t, float b, float c, float d )",
28039 "{",
28040 " if( t == 0 ) return b;",
28041 " if( t == d ) return b + c;",
28042 " if(( t /= d / 2.0 ) < 1.0 ) return c / 2.0 * pow( 2.0, 10.0 * ( t - 1.0 ) ) + b;",
28043 " return c / 2.0 * ( - pow( 2.0, -10.0 * --t ) + 2.0 ) + b;",
28044 "}",
28045 "",
28046 "float inOutExpo( float t )",
28047 "{",
28048 " if( t == 0.0 ) return 0.0;",
28049 " if( t == 1.0 ) return 1.0;",
28050 " if( ( t /= 0.5 ) < 1.0 ) return 0.5 * pow( 2.0, 10.0 * ( t - 1.0 ) );",
28051 " return 0.5 * ( - pow( 2.0, -10.0 * --t ) + 2.0 );",
28052 "}",
28053 "",
28054 "float inCirc( float t, float b, float c, float d )",
28055 "{",
28056 " return -c * ( sqrt( 1.0 - (t/=d)*t) - 1) + b;",
28057 "}",
28058 "",
28059 "float inCirc( float t )",
28060 "{",
28061 " return - ( sqrt( 1.0 - t*t) - 1);",
28062 "}",
28063 "",
28064 "float outCirc( float t, float b, float c, float d )",
28065 "{",
28066 " return c * sqrt( 1.0 - (t=t/d-1)*t) + b;",
28067 "}",
28068 "",
28069 "float outCirc( float t )",
28070 "{",
28071 " return sqrt( 1.0 - (--t)*t);",
28072 "}",
28073 "",
28074 "float inOutCirc( float t, float b, float c, float d )",
28075 "{",
28076 " if ( ( t /= d / 2.0 ) < 1 ) return - c / 2.0 * ( sqrt( 1.0 - t * t ) - 1.0 ) + b;",
28077 " return c / 2.0 * ( sqrt( 1.0 - ( t -= 2.0 ) * t ) + 1.0 ) + b;",
28078 "}",
28079 "",
28080 "float inOutCirc( float t )",
28081 "{",
28082 " if( ( t /= 0.5 ) < 1.0 ) return -0.5 * ( sqrt( 1.0 - t * t ) - 1.0 );",
28083 " return 0.5 * ( sqrt( 1.0 - ( t -= 2.0 ) * t ) + 1.0 );",
28084 "}",
28085 "",
28086 "float inElastic( float t, float b, float c, float d )",
28087 "{",
28088 " float s = 1.70158; float p = 0.0; float a = c;",
28089 " if( t == 0 ) return b; if( ( t /= d ) == 1 ) return b + c;",
28090 " p = d * 0.3;",
28091 " if( a < abs( c ) ) { a = c; float s = p / 4.0; }",
28092 " else s = 0.1591549431 * p / ( 6.2831853072 ) * asin( c / a );",
28093 " return -( a * pow( 2.0, 10.0 * ( t -= 1.0 ) ) * sin( ( t * d - s ) * ( 6.2831853072 ) / p ) ) + b;",
28094 "}",
28095 "",
28096 "float inElastic( float t )",
28097 "{",
28098 " float s = 1.70158; float p = 0.0; float a = 1.0;",
28099 " if( t == 0.0 ) return 0.0;",
28100 " if( t == 1.0 ) return 1.0;",
28101 " p = 0.3;",
28102 " s = p / ( 6.2831853072 ) * asin( 1.0 / a );",
28103 " return -( a * pow( 2.0, 10.0 * ( t -= 1.0 ) ) * sin( ( t - s ) * ( 6.2831853072 ) / p ) );",
28104 "}",
28105 "",
28106 "float outElastic( float t, float b, float c, float d )",
28107 "{",
28108 " float s = 1.70158; float p = 0.0; float a = c;",
28109 " if( t == 0.0 ) return b;",
28110 " if( (t /= d ) == 1.0 ) return b + c;",
28111 " p = d * 0.3;",
28112 " if( a < abs( c ) ) { a = c; s = p / 4.0; }",
28113 " else { s = p / ( 6.2831853072 ) * asin( c / a ); }",
28114 " return a * pow( 2.0, -10.0 * t ) * sin( ( t * d - s ) * ( 6.2831853072 ) / p ) + c + b;",
28115 "}",
28116 "",
28117 "float outElastic( float t )",
28118 "{",
28119 " float s = 1.70158; float p = 0.0 ; float a = 1.0;",
28120 " if( t == 0.0 ) return 0.0; if( t == 1.0 ) return 1.0;",
28121 " p = 0.3;",
28122 " s = p / ( 6.2831853072 ) * asin( 1.0 / a );",
28123 " return a * pow( 2.0, -10.0 * t ) * sin( ( t - s ) * ( 6.2831853072 ) / p ) + 1.0;",
28124 "}",
28125 "",
28126 "float inOutElastic( float t, float b, float c, float d )",
28127 "{",
28128 " float s = 1.70158; float p = 0.0; float a = c;",
28129 " if( t == 0.0 ) return b;",
28130 " if( ( t /= d / 2.0 ) == 2.0 ) return b + c;",
28131 " p = d * ( 0.3 * 1.5 );",
28132 " if( a < abs( c ) ) { a = c; s = p / 4.0; }",
28133 " else { s = p / ( 6.2831853072 ) * asin( c / a ); }",
28134 " if( t < 1.0 ) return -0.5 * ( a * pow( 2.0, 10.0 * ( t -= 1.0 ) ) * sin( ( t * d - s ) * ( 6.2831853072 ) / p ) ) + b;",
28135 " return a * pow( 2.0, -10.0 * ( t -= 1.0 ) ) * sin( ( t * d - s ) * ( 6.2831853072 ) / p ) * 0.5 + c + b;",
28136 "}",
28137 "",
28138 "float inOutElastic( float t )",
28139 "{",
28140 " float s = 1.70158; float p = 0; float a = 1.0;",
28141 " if( t == 0 ) return 0.0;",
28142 " if( ( t /= 0.5 ) == 2.0 ) return 1.0;",
28143 " p = ( 0.3 * 1.5 );",
28144 " s = p / ( 6.2831853072 ) * asin( 1.0 / a );",
28145 " if( t < 1.0 ) return -0.5 * ( a * pow( 2.0, 10.0 * ( t -= 1.0 ) ) * sin( ( t - s ) * ( 6.2831853072 ) / p ) );",
28146 " return a * pow( 2.0, -10.0 * ( t -= 1.0 ) ) * sin( ( t - s ) * ( 6.2831853072 ) / p ) * 0.5 + 1.0;",
28147 "}",
28148 "",
28149 "float inBack( float t, float b, float c, float d )",
28150 "{",
28151 " float s = 1.70158;",
28152 " return c * ( t /= d ) * t * ( ( s + 1.0 ) * t - s ) + b;",
28153 "}",
28154 "",
28155 "float inBack( float t )",
28156 "{",
28157 " float s = 1.70158;",
28158 " return t * t * ( ( s + 1.0 ) * t - s);",
28159 "}",
28160 "",
28161 "float outBack( float t, float b, float c, float d )",
28162 "{",
28163 " float s = 1.70158;",
28164 " return c * ( ( t = t / d - 1.0 ) * t * ( ( s + 1.0 ) * t + s ) + 1.0 ) + b;",
28165 "}",
28166 "",
28167 "float outBack( float t )",
28168 "{",
28169 " float s = 1.70158;",
28170 " return ( ( --t ) * t * ( ( s + 1.0 ) * t + s ) + 1.0);",
28171 "}",
28172 "",
28173 "float inOutBack( float t, float b, float c, float d )",
28174 "{",
28175 " float s = 1.70158;",
28176 " if( ( t /= d / 2.0 ) < 1.0 ) return c / 2.0 * ( t * t * ( ( ( s *= 1.525 ) + 1.0 ) * t - s ) ) + b;",
28177 " return c / 2.0 * ( ( t -= 2.0 ) * t * ( ( ( s *= ( 1.525 ) ) + 1.0 ) * t + s ) + 2.0 ) + b;",
28178 "}",
28179 "",
28180 "float inOutBack( float t )",
28181 "{",
28182 " float s = 1.70158;",
28183 " if( ( t /= 0.5 ) < 1.0 ) return 0.5 * ( t * t * ( ( ( s *= 1.525 ) + 1.0 ) * t - s ) );",
28184 " return 0.5 * ( ( t -= 2 ) * t * ( ( ( s *= ( 1.525 ) ) + 1.0 ) * t + s ) + 2.0 );",
28185 "}",
28186 "",
28187 "float outBounce( float t, float b, float c, float d )",
28188 "{",
28189 " if( ( t /= d ) < ( 1.0 / 2.75 ) ) {",
28190 " return c * ( 7.5625 * t * t ) + b;",
28191 " } else if ( t < ( 2.0 / 2.75 ) ) {",
28192 " return c * ( 7.5625 * ( t -= ( 1.5 / 2.75 ) ) * t + 0.75 ) + b;",
28193 " } else if ( t < ( 2.5 / 2.75 ) ) {",
28194 " return c * ( 7.5625 * ( t -= ( 2.25 / 2.75 ) ) * t + 0.9375 ) + b;",
28195 " } else {",
28196 " return c * ( 7.5625 * ( t -= ( 2.625 / 2.75 ) ) * t + 0.984375 ) + b;",
28197 " }",
28198 "}",
28199 "",
28200 "float outBounce( float t )",
28201 "{",
28202 " if( t < ( 1.0 / 2.75 ) ) {",
28203 " return ( 7.5625 * t * t );",
28204 " } else if ( t < ( 2.0 / 2.75 ) ) {",
28205 " return ( 7.5625 * ( t-= ( 1.5 / 2.75 ) ) * t + .75 );",
28206 " } else if ( t < ( 2.5 / 2.75 ) ) {",
28207 " return ( 7.5625 * ( t -= ( 2.25 / 2.75 ) ) * t + 0.9375 );",
28208 " } else {",
28209 " return ( 7.5625 * ( t -= ( 2.625 / 2.75 ) ) * t + 0.984375 );",
28210 " }",
28211 "}",
28212 "",
28213 "float inBounce( float t, float b, float c, float d )",
28214 "{",
28215 " return c - outBounce( d - t, 0.0, c, d ) + b;",
28216 "}",
28217 "",
28218 "float inBounce( float t )",
28219 "{",
28220 " return 1.0 - outBounce( 1.0 - t);",
28221 "}",
28222 "",
28223 "float inOutBounce( float t, float b, float c, float d )",
28224 "{",
28225 " if ( t < d /2.0 ) return inBounce ( t * 2.0, 0.0, c, d ) * 0.5 + b;",
28226 " return outBounce ( t * 2.0 - d, 0, c, d ) * 0.5 + c * 0.5 + b;",
28227 "}",
28228 "",
28229 "float inOutBounce( float t )",
28230 "{",
28231 " if ( t < 0.5 ) return inBounce( t * 2.0 ) * 0.5;",
28232 " return outBounce( t * 2.0 - 1.0 ) * 0.5 + 0.5;",
28233 "}"
28234 ].join("\n");
28235
28236})(
28237 this.Blotter, this._
28238);
28239
28240// See License comments in shader string
28241
28242(function(Blotter, _) {
28243
28244 Blotter.Assets.Shaders.Gamma = [
28245 "//",
28246 "// Author : Reza Ali",
28247 "// License : Distributed under the MIT License.",
28248 "//",
28249 "",
28250 "const vec3 cGammaCorrection = vec3( 0.4545454545 );",
28251 "",
28252 "vec3 gamma( in vec3 color )",
28253 "{",
28254 " return pow( color, cGammaCorrection );",
28255 "}",
28256 "",
28257 "vec4 gamma( in vec4 color )",
28258 "{",
28259 " return vec4( gamma( color.rgb ), color.a );",
28260 "}"
28261 ].join("\n");
28262
28263})(
28264 this.Blotter, this._
28265);
28266
28267// See License comments in shader string
28268
28269(function(Blotter, _) {
28270
28271 Blotter.Assets.Shaders.Map = [
28272 "//",
28273 "// Author : Reza Ali",
28274 "// License : Distributed under the MIT License.",
28275 "//",
28276 "",
28277 "float map( float value, float inMin, float inMax, float outMin, float outMax )",
28278 "{",
28279 " return ( (value - inMin) / ( inMax - inMin ) * ( outMax - outMin ) ) + outMin;",
28280 "}"
28281 ].join("\n");
28282
28283})(
28284 this.Blotter, this._
28285);
28286
28287// See License comments in shader string
28288
28289(function(Blotter, _) {
28290
28291 Blotter.Assets.Shaders.Noise = [
28292 "//",
28293 "// Author : Patricio Gonzalez Vivo and Jen Lowe",
28294 "// License : Distributed under the MIT License.",
28295 "// Source : https://github.com/patriciogonzalezvivo/thebookofshaders",
28296 "//",
28297 "float random (in float _x) {",
28298 " return fract(sin(_x)*1e4);",
28299 "}",
28300 "",
28301 "float random (in vec2 co) {",
28302 " return fract(sin(dot(co.xy,vec2(12.9898,78.233)))*43758.5453);",
28303 "}",
28304 "",
28305 "float noise (in float _x) {",
28306 " float i = floor(_x);",
28307 " float f = fract(_x);",
28308 " float u = f * f * (3.0 - 2.0 * f);",
28309 " return mix(random(i), random(i + 1.0), u);",
28310 "}",
28311 "",
28312 "float noise (in vec2 _st) {",
28313 " vec2 i = floor(_st);",
28314 " vec2 f = fract(_st);",
28315 " // Four corners in 2D of a tile",
28316 " float a = random(i);",
28317 " float b = random(i + vec2(1.0, 0.0));",
28318 " float c = random(i + vec2(0.0, 1.0));",
28319 " float d = random(i + vec2(1.0, 1.0));",
28320 " vec2 u = f * f * (3.0 - 2.0 * f);",
28321 " return mix(a, b, u.x) + ",
28322 " (c - a)* u.y * (1.0 - u.x) + ",
28323 " (d - b) * u.x * u.y;",
28324 "}",
28325 ].join("\n");
28326
28327})(
28328 this.Blotter, this._
28329);
28330
28331// See License comments in shader string
28332
28333(function(Blotter, _) {
28334
28335 Blotter.Assets.Shaders.Noise2D = [
28336 "//",
28337 "// Description : Array and textureless GLSL 2D simplex noise function.",
28338 "// Author : Ian McEwan, Ashima Arts.",
28339 "// Maintainer : ijm",
28340 "// Lastmod : 20110822 (ijm)",
28341 "// License : Copyright (C) 2011 Ashima Arts. All rights reserved.",
28342 "// Distributed under the MIT License. See LICENSE file.",
28343 "// https://github.com/ashima/webgl-noise",
28344 "//",
28345 "",
28346 "vec2 n2mod289(vec2 x) {",
28347 " return x - floor(x * (1.0 / 289.0)) * 289.0;",
28348 "}",
28349 "",
28350 "vec3 n2mod289(vec3 x) {",
28351 " return x - floor(x * (1.0 / 289.0)) * 289.0;",
28352 "}",
28353 "",
28354 "vec4 n2mod289(vec4 x) {",
28355 " return x - floor(x * (1.0 / 289.0)) * 289.0;",
28356 "}",
28357 "",
28358 "vec3 permute(vec3 x) {",
28359 " return n2mod289(((x*34.0)+1.0)*x);",
28360 "}",
28361 "",
28362 "float snoise(vec2 v)",
28363 " {",
28364 " const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0",
28365 " 0.366025403784439, // 0.5*(sqrt(3.0)-1.0)",
28366 " -0.577350269189626, // -1.0 + 2.0 * C.x",
28367 " 0.024390243902439); // 1.0 / 41.0",
28368 "// First corner",
28369 " vec2 i = floor(v + dot(v, C.yy) );",
28370 " vec2 x0 = v - i + dot(i, C.xx);",
28371 "",
28372 "// Other corners",
28373 " vec2 i1;",
28374 " //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0",
28375 " //i1.y = 1.0 - i1.x;",
28376 " i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);",
28377 " // x0 = x0 - 0.0 + 0.0 * C.xx ;",
28378 " // x1 = x0 - i1 + 1.0 * C.xx ;",
28379 " // x2 = x0 - 1.0 + 2.0 * C.xx ;",
28380 " vec4 x12 = x0.xyxy + C.xxzz;",
28381 " x12.xy -= i1;",
28382 "",
28383 "// Permutations",
28384 " i = n2mod289(i); // Avoid truncation effects in permutation",
28385 " vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))",
28386 " + i.x + vec3(0.0, i1.x, 1.0 ));",
28387 "",
28388 " vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);",
28389 " m = m*m ;",
28390 " m = m*m ;",
28391 "",
28392 "// Gradients: 41 points uniformly over a line, mapped onto a diamond.",
28393 "// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)",
28394 "",
28395 " vec3 x = 2.0 * fract(p * C.www) - 1.0;",
28396 " vec3 h = abs(x) - 0.5;",
28397 " vec3 ox = floor(x + 0.5);",
28398 " vec3 a0 = x - ox;",
28399 "",
28400 "// Normalise gradients implicitly by scaling m",
28401 "// Approximation of: m *= inversesqrt( a0*a0 + h*h );",
28402 " m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );",
28403 "",
28404 "// Compute final noise value at P",
28405 " vec3 g;",
28406 " g.x = a0.x * x0.x + h.x * x0.y;",
28407 " g.yz = a0.yz * x12.xz + h.yz * x12.yw;",
28408 " return 130.0 * dot(m, g);",
28409 "}"
28410 ].join("\n");
28411
28412})(
28413 this.Blotter, this._
28414);
28415
28416// See License comments in shader string
28417
28418(function(Blotter, _) {
28419
28420 Blotter.Assets.Shaders.Noise3D = [
28421 "//",
28422 "// Description : Array and textureless GLSL 2D/3D/4D simplex",
28423 "// noise functions.",
28424 "// Author : Ian McEwan, Ashima Arts.",
28425 "// Maintainer : ijm",
28426 "// Lastmod : 20110822 (ijm)",
28427 "// License : Copyright (C) 2011 Ashima Arts. All rights reserved.",
28428 "// Distributed under the MIT License. See LICENSE file.",
28429 "// https://github.com/ashima/webgl-noise",
28430 "//",
28431 "",
28432 "vec2 n3mod289(vec2 x) {",
28433 " return x - floor(x * (1.0 / 289.0)) * 289.0;",
28434 "}",
28435 "",
28436 "vec3 n3mod289(vec3 x) {",
28437 " return x - floor(x * (1.0 / 289.0)) * 289.0;",
28438 "}",
28439 "",
28440 "vec4 n3mod289(vec4 x) {",
28441 " return x - floor(x * (1.0 / 289.0)) * 289.0;",
28442 "}",
28443 "",
28444 "vec4 permute(vec4 x) {",
28445 " return n3mod289(((x*34.0)+1.0)*x);",
28446 "}",
28447 "",
28448 "vec4 taylorInvSqrt(vec4 r)",
28449 "{",
28450 " return 1.79284291400159 - 0.85373472095314 * r;",
28451 "}",
28452 "",
28453 "float snoise(vec3 v)",
28454 " {",
28455 " const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;",
28456 " const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);",
28457 "",
28458 "// First corner",
28459 " vec3 i = floor(v + dot(v, C.yyy) );",
28460 " vec3 x0 = v - i + dot(i, C.xxx) ;",
28461 "",
28462 "// Other corners",
28463 " vec3 g = step(x0.yzx, x0.xyz);",
28464 " vec3 l = 1.0 - g;",
28465 " vec3 i1 = min( g.xyz, l.zxy );",
28466 " vec3 i2 = max( g.xyz, l.zxy );",
28467 "",
28468 " // x0 = x0 - 0.0 + 0.0 * C.xxx;",
28469 " // x1 = x0 - i1 + 1.0 * C.xxx;",
28470 " // x2 = x0 - i2 + 2.0 * C.xxx;",
28471 " // x3 = x0 - 1.0 + 3.0 * C.xxx;",
28472 " vec3 x1 = x0 - i1 + C.xxx;",
28473 " vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y",
28474 " vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y",
28475 "",
28476 "// Permutations",
28477 " i = n3mod289(i);",
28478 " vec4 p = permute( permute( permute(",
28479 " i.z + vec4(0.0, i1.z, i2.z, 1.0 ))",
28480 " + i.y + vec4(0.0, i1.y, i2.y, 1.0 ))",
28481 " + i.x + vec4(0.0, i1.x, i2.x, 1.0 ));",
28482 "",
28483 "// Gradients: 7x7 points over a square, mapped onto an octahedron.",
28484 "// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)",
28485 " float n_ = 0.142857142857; // 1.0/7.0",
28486 " vec3 ns = n_ * D.wyz - D.xzx;",
28487 "",
28488 " vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)",
28489 "",
28490 " vec4 x_ = floor(j * ns.z);",
28491 " vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)",
28492 "",
28493 " vec4 x = x_ *ns.x + ns.yyyy;",
28494 " vec4 y = y_ *ns.x + ns.yyyy;",
28495 " vec4 h = 1.0 - abs(x) - abs(y);",
28496 "",
28497 " vec4 b0 = vec4( x.xy, y.xy );",
28498 " vec4 b1 = vec4( x.zw, y.zw );",
28499 "",
28500 " //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;",
28501 " //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;",
28502 " vec4 s0 = floor(b0)*2.0 + 1.0;",
28503 " vec4 s1 = floor(b1)*2.0 + 1.0;",
28504 " vec4 sh = -step(h, vec4(0.0));",
28505 "",
28506 " vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;",
28507 " vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;",
28508 "",
28509 " vec3 p0 = vec3(a0.xy,h.x);",
28510 " vec3 p1 = vec3(a0.zw,h.y);",
28511 " vec3 p2 = vec3(a1.xy,h.z);",
28512 " vec3 p3 = vec3(a1.zw,h.w);",
28513 "",
28514 "//Normalise gradients",
28515 " vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));",
28516 " p0 *= norm.x;",
28517 " p1 *= norm.y;",
28518 " p2 *= norm.z;",
28519 " p3 *= norm.w;",
28520 "",
28521 "// Mix final noise value",
28522 " vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);",
28523 " m = m * m;",
28524 " return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),",
28525 " dot(p2,x2), dot(p3,x3) ) );",
28526 " }"
28527 ].join("\n");
28528
28529})(
28530 this.Blotter, this._
28531);
28532
28533// See License comments in shader string
28534
28535(function(Blotter, _) {
28536
28537 Blotter.Assets.Shaders.Noise4D = [
28538 "//",
28539 "// Description : Array and textureless GLSL 2D/3D/4D simplex",
28540 "// noise functions.",
28541 "// Author : Ian McEwan, Ashima Arts.",
28542 "// Maintainer : ijm",
28543 "// Lastmod : 20110822 (ijm)",
28544 "// License : Copyright (C) 2011 Ashima Arts. All rights reserved.",
28545 "// Distributed under the MIT License. See LICENSE file.",
28546 "// https://github.com/ashima/webgl-noise",
28547 "//",
28548 "",
28549 "vec4 mod289(vec4 x) {",
28550 " return x - floor(x * (1.0 / 289.0)) * 289.0; }",
28551 "",
28552 "float mod289(float x) {",
28553 " return x - floor(x * (1.0 / 289.0)) * 289.0; }",
28554 "",
28555 "vec4 permute(vec4 x) {",
28556 " return mod289(((x*34.0)+1.0)*x);",
28557 "}",
28558 "",
28559 "float permute(float x) {",
28560 " return mod289(((x*34.0)+1.0)*x);",
28561 "}",
28562 "",
28563 "vec4 taylorInvSqrt(vec4 r)",
28564 "{",
28565 " return 1.79284291400159 - 0.85373472095314 * r;",
28566 "}",
28567 "",
28568 "float taylorInvSqrt(float r)",
28569 "{",
28570 " return 1.79284291400159 - 0.85373472095314 * r;",
28571 "}",
28572 "",
28573 "vec4 grad4(float j, vec4 ip)",
28574 " {",
28575 " const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0);",
28576 " vec4 p,s;",
28577 "",
28578 " p.xyz = floor( fract (vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0;",
28579 " p.w = 1.5 - dot(abs(p.xyz), ones.xyz);",
28580 " s = vec4(lessThan(p, vec4(0.0)));",
28581 " p.xyz = p.xyz + (s.xyz*2.0 - 1.0) * s.www;",
28582 "",
28583 " return p;",
28584 " }",
28585 "",
28586 "// (sqrt(5) - 1)/4 = F4, used once below",
28587 "#define F4 0.309016994374947451",
28588 "",
28589 "float snoise(vec4 v)",
28590 " {",
28591 " const vec4 C = vec4( 0.138196601125011, // (5 - sqrt(5))/20 G4",
28592 " 0.276393202250021, // 2 * G4",
28593 " 0.414589803375032, // 3 * G4",
28594 " -0.447213595499958); // -1 + 4 * G4",
28595 "",
28596 "// First corner",
28597 " vec4 i = floor(v + dot(v, vec4(F4)) );",
28598 " vec4 x0 = v - i + dot(i, C.xxxx);",
28599 "",
28600 "// Other corners",
28601 "",
28602 "// Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI)",
28603 " vec4 i0;",
28604 " vec3 isX = step( x0.yzw, x0.xxx );",
28605 " vec3 isYZ = step( x0.zww, x0.yyz );",
28606 "// i0.x = dot( isX, vec3( 1.0 ) );",
28607 " i0.x = isX.x + isX.y + isX.z;",
28608 " i0.yzw = 1.0 - isX;",
28609 "// i0.y += dot( isYZ.xy, vec2( 1.0 ) );",
28610 " i0.y += isYZ.x + isYZ.y;",
28611 " i0.zw += 1.0 - isYZ.xy;",
28612 " i0.z += isYZ.z;",
28613 " i0.w += 1.0 - isYZ.z;",
28614 "",
28615 " // i0 now contains the unique values 0,1,2,3 in each channel",
28616 " vec4 i3 = clamp( i0, 0.0, 1.0 );",
28617 " vec4 i2 = clamp( i0-1.0, 0.0, 1.0 );",
28618 " vec4 i1 = clamp( i0-2.0, 0.0, 1.0 );",
28619 "",
28620 " // x0 = x0 - 0.0 + 0.0 * C.xxxx",
28621 " // x1 = x0 - i1 + 1.0 * C.xxxx",
28622 " // x2 = x0 - i2 + 2.0 * C.xxxx",
28623 " // x3 = x0 - i3 + 3.0 * C.xxxx",
28624 " // x4 = x0 - 1.0 + 4.0 * C.xxxx",
28625 " vec4 x1 = x0 - i1 + C.xxxx;",
28626 " vec4 x2 = x0 - i2 + C.yyyy;",
28627 " vec4 x3 = x0 - i3 + C.zzzz;",
28628 " vec4 x4 = x0 + C.wwww;",
28629 "",
28630 "// Permutations",
28631 " i = mod289(i);",
28632 " float j0 = permute( permute( permute( permute(i.w) + i.z) + i.y) + i.x);",
28633 " vec4 j1 = permute( permute( permute( permute (",
28634 " i.w + vec4(i1.w, i2.w, i3.w, 1.0 ))",
28635 " + i.z + vec4(i1.z, i2.z, i3.z, 1.0 ))",
28636 " + i.y + vec4(i1.y, i2.y, i3.y, 1.0 ))",
28637 " + i.x + vec4(i1.x, i2.x, i3.x, 1.0 ));",
28638 "",
28639 "// Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope",
28640 "// 7*7*6 = 294, which is close to the ring size 17*17 = 289.",
28641 " vec4 ip = vec4(1.0/294.0, 1.0/49.0, 1.0/7.0, 0.0) ;",
28642 "",
28643 " vec4 p0 = grad4(j0, ip);",
28644 " vec4 p1 = grad4(j1.x, ip);",
28645 " vec4 p2 = grad4(j1.y, ip);",
28646 " vec4 p3 = grad4(j1.z, ip);",
28647 " vec4 p4 = grad4(j1.w, ip);",
28648 "",
28649 "// Normalise gradients",
28650 " vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));",
28651 " p0 *= norm.x;",
28652 " p1 *= norm.y;",
28653 " p2 *= norm.z;",
28654 " p3 *= norm.w;",
28655 " p4 *= taylorInvSqrt(dot(p4,p4));",
28656 "",
28657 "// Mix contributions from the five corners",
28658 " vec3 m0 = max(0.6 - vec3(dot(x0,x0), dot(x1,x1), dot(x2,x2)), 0.0);",
28659 " vec2 m1 = max(0.6 - vec2(dot(x3,x3), dot(x4,x4) ), 0.0);",
28660 " m0 = m0 * m0;",
28661 " m1 = m1 * m1;",
28662 " return 49.0 * ( dot(m0*m0, vec3( dot( p0, x0 ), dot( p1, x1 ), dot( p2, x2 )))",
28663 " + dot(m1*m1, vec2( dot( p3, x3 ), dot( p4, x4 ) ) ) ) ;",
28664 "",
28665 " }"
28666 ].join("\n");
28667
28668})(
28669 this.Blotter, this._
28670);
28671
28672// See License comments in shader string
28673
28674(function(Blotter, _) {
28675
28676 Blotter.Assets.Shaders.PI = [
28677 "//",
28678 "// Author : Reza Ali",
28679 "// License : Distributed under the MIT License.",
28680 "//",
28681 "",
28682 "#define TWO_PI 6.2831853072",
28683 "#define PI 3.14159265359",
28684 "#define HALF_PI 1.57079632679"
28685 ].join("\n");
28686
28687})(
28688 this.Blotter, this._
28689);
28690
28691// See License comments in shader string
28692
28693(function(Blotter, _) {
28694
28695 Blotter.Assets.Shaders.Random = [
28696 "//",
28697 "// Author : Patricio Gonzalez Vivo and Jen Lowe",
28698 "// License : Distributed under the MIT License.",
28699 "// Source : https://github.com/patriciogonzalezvivo/thebookofshaders",
28700 "//",
28701 "",
28702 "float random (in float _x) {",
28703 " return fract(sin(_x)*1e4);",
28704 "}",
28705 "",
28706 "float random (in vec2 co) {",
28707 " return fract(sin(dot(co.xy,vec2(12.9898,78.233)))*43758.5453);",
28708 "}"
28709 ].join("\n");
28710
28711})(
28712 this.Blotter, this._
28713);
28714
28715(function(Blotter, _) {
28716
28717 Blotter.Mapping = function (texts, textBounds, width, height) {
28718 this.texts = texts;
28719
28720 this._textBounds = textBounds;
28721
28722 this._width = width;
28723 this._height = height;
28724
28725 this._ratio = 1;
28726 };
28727
28728 Blotter.Mapping.prototype = (function () {
28729
28730 function _getLineHeightPixels (size, lineHeight) {
28731 lineHeight = lineHeight || Blotter.TextUtils.ensurePropertyValues().leading;
28732 if (!isNaN(lineHeight)) {
28733 lineHeight = size * lineHeight;
28734 } else if (lineHeight.toString().indexOf("px") !== -1) {
28735 lineHeight = parseInt(lineHeight);
28736 } else if (lineHeight.toString().indexOf("%") !== -1) {
28737 lineHeight = (parseInt(lineHeight) / 100) * size;
28738 }
28739
28740 return lineHeight;
28741 }
28742
28743 return {
28744
28745 constructor : Blotter.Mapping,
28746
28747 get ratio () {
28748 return this._ratio;
28749 },
28750
28751 set ratio (ratio) {
28752 this._ratio = ratio || 1;
28753 },
28754
28755 get width () {
28756 return this._width * this._ratio;
28757 },
28758
28759 get height () {
28760 return this._height * this._ratio;
28761 },
28762
28763 boundsForText : function (text) {
28764 Blotter.Messaging.ensureInstanceOf(text, Blotter.Text, "Blotter.Text", "Blotter.Mapping", "boundsForText");
28765
28766 var bounds = this._textBounds[text.id];
28767
28768 if (bounds) {
28769 bounds = {
28770 w : bounds.w * this._ratio,
28771 h : bounds.h * this._ratio,
28772 x : bounds.x * this._ratio,
28773 y : bounds.y * this._ratio
28774 };
28775 }
28776
28777 return bounds;
28778 },
28779
28780 toCanvas : function (completion) {
28781 var canvas = Blotter.CanvasUtils.hiDpiCanvas(this._width, this._height, this._ratio),
28782 ctx = canvas.getContext("2d", { alpha: false }),
28783 img = new Image();
28784
28785 ctx.textBaseline = "middle";
28786
28787 for (var i = 0; i < this.texts.length; i++) {
28788 var text = this.texts[i],
28789 bounds = this._textBounds[text.id],
28790 halfLH = (_getLineHeightPixels.call(this, text.properties.size, text.properties.leading) / 2);
28791
28792 ctx.font = text.properties.style +
28793 " " + text.properties.weight +
28794 " " + text.properties.size + "px" +
28795 " " + text.properties.family;
28796
28797 ctx.save();
28798
28799 ctx.translate(
28800 bounds.x + text.properties.paddingLeft,
28801 (this._height - (bounds.y + bounds.h)) + text.properties.paddingTop
28802 );
28803 ctx.fillStyle = text.properties.fill;
28804 ctx.fillText(
28805 text.value,
28806 0,
28807 Math.round(halfLH)
28808 );
28809
28810 ctx.restore();
28811 }
28812
28813 img.onload = _.bind(function () {
28814 // Flip Y for WebGL
28815 ctx.save();
28816 ctx.scale(1, -1);
28817 ctx.clearRect(0, this._height * -1, this._width, this._height);
28818 ctx.drawImage(img, 0, this._height * -1, this._width, this._height);
28819 ctx.restore();
28820
28821 completion(canvas);
28822 }, this);
28823
28824 img.src = canvas.toDataURL("image/png");
28825 }
28826 };
28827 })();
28828
28829})(
28830 this.Blotter, this._
28831);
28832
28833(function(Blotter, _, EventEmitter) {
28834
28835 Blotter.MappingMaterial = function(mapping, material, shaderMaterial, userUniformDataTextureObjects) {
28836 this.mapping = mapping;
28837 this.material = material;
28838 this.shaderMaterial = shaderMaterial;
28839
28840 this._userUniformDataTextureObjects = userUniformDataTextureObjects;
28841
28842 this.init.apply(this, arguments);
28843 };
28844
28845 Blotter.MappingMaterial.prototype = (function() {
28846
28847 function _setValueAtIndexInDataTextureObject (value, i, data, userUniform) {
28848 var type = userUniform.type;
28849
28850 if (type == "1f") {
28851 data[4*i] = value; // x (r)
28852 data[4*i+1] = 0.0;
28853 data[4*i+2] = 0.0;
28854 data[4*i+3] = 0.0;
28855 } else if (type == "2f") {
28856 data[4*i] = value[0]; // x (r)
28857 data[4*i+1] = value[1]; // y (g)
28858 data[4*i+2] = 0.0;
28859 data[4*i+3] = 0.0;
28860 } else if (type == "3f") {
28861 data[4*i] = value[0]; // x (r)
28862 data[4*i+1] = value[1]; // y (g)
28863 data[4*i+2] = value[2]; // z (b)
28864 data[4*i+3] = 0.0;
28865 } else if (type == "4f") {
28866 data[4*i] = value[0]; // x (r)
28867 data[4*i+1] = value[1]; // y (g)
28868 data[4*i+2] = value[2]; // z (b)
28869 data[4*i+3] = value[3]; // w (a)
28870 } else {
28871 data[4*i] = 0.0;
28872 data[4*i+1] = 0.0;
28873 data[4*i+2] = 0.0;
28874 data[4*i+3] = 0.0;
28875 }
28876 }
28877
28878 function _getUniformInterfaceForDataTextureObject (dataTextureObject) {
28879 var interface = {
28880 _type : dataTextureObject.userUniform.type,
28881 _value : dataTextureObject.userUniform.value,
28882
28883 get value () {
28884 return this._value;
28885 },
28886
28887 set value (v) {
28888 if (!Blotter.UniformUtils.validValueForUniformType(this._type, v)) {
28889 Blotter.Messaging.logError("Blotter.MappingMaterial", false, "uniform value not valid for uniform type: " + this._type);
28890 return;
28891 }
28892 this._value = v;
28893
28894 this.trigger("update");
28895 }
28896 };
28897
28898 _.extend(interface, EventEmitter.prototype);
28899
28900 return interface;
28901 }
28902
28903 function _getTextUniformInterface (mapping, userUniformDataTextureObjects) {
28904 return _.reduce(mapping.texts, function (memo, text, textIndex) {
28905 memo[text.id] = _.reduce(userUniformDataTextureObjects.userUniforms, function (memo, dataTextureObject, uniformName) {
28906 var uniformIndex = dataTextureObject.position + textIndex;
28907
28908 memo[uniformName] = _getUniformInterfaceForDataTextureObject(dataTextureObject);
28909
28910 memo[uniformName].on("update", function () {
28911 _setValueAtIndexInDataTextureObject(
28912 memo[uniformName].value,
28913 uniformIndex,
28914 userUniformDataTextureObjects.data,
28915 dataTextureObject.userUniform
28916 );
28917
28918 userUniformDataTextureObjects.texture.needsUpdate = true;
28919 });
28920
28921 memo[uniformName].value = dataTextureObject.userUniform.value;
28922
28923 return memo;
28924 }, {});
28925
28926 return memo;
28927 }, {});
28928 }
28929
28930 function _getUniformInterface (mapping, userUniformDataTextureObjects, textUniformInterface) {
28931 return _.reduce(userUniformDataTextureObjects.userUniforms, function (memo, dataTextureObject, uniformName) {
28932 memo[uniformName] = _getUniformInterfaceForDataTextureObject(dataTextureObject);
28933
28934 memo[uniformName].on("update", function () {
28935 _.each(mapping.texts, function (text) {
28936 textUniformInterface[text.id][uniformName].value = memo[uniformName].value;
28937 });
28938
28939 userUniformDataTextureObjects.texture.needsUpdate = true;
28940 });
28941
28942 return memo;
28943 }, {});
28944 }
28945
28946 return {
28947
28948 constructor : Blotter.MappingMaterial,
28949
28950 get uniforms () {
28951 return this.material.uniforms;
28952 },
28953
28954 get mainImage () {
28955 return this.material.mainImage;
28956 },
28957
28958 get width () {
28959 return this.mapping.width;
28960 },
28961
28962 get height () {
28963 return this.mapping.height;
28964 },
28965
28966 get ratio () {
28967 return this.mapping.ratio;
28968 },
28969
28970 init : function (mapping, material, shaderMaterial, userUniformDataTextureObjects) {
28971 this.textUniformInterface = _getTextUniformInterface(this.mapping, this._userUniformDataTextureObjects);
28972 this.uniformInterface = _getUniformInterface(this.mapping, this._userUniformDataTextureObjects, this.textUniformInterface);
28973 },
28974
28975 boundsForText : function (text) {
28976 Blotter.Messaging.ensureInstanceOf(text, Blotter.Text, "Blotter.Text", "Blotter.MappingMaterial", "boundsForText");
28977 return this.mapping.boundsForText(text);
28978 }
28979 };
28980 })();
28981
28982})(
28983 this.Blotter, this._, this.EventEmitter
28984);
28985
28986(function(Blotter, _, EventEmitter) {
28987
28988 Blotter.Material = function () {
28989 this.init.apply(this, arguments);
28990 };
28991
28992 Blotter.Material.prototype = (function() {
28993
28994 function _defaultMainImageSrc () {
28995 var mainImage = [
28996
28997 "void mainImage( out vec4 mainImage, in vec2 fragCoord ) {",
28998
28999 "mainImage = textTexture(fragCoord / uResolution);",
29000
29001 "}"
29002
29003 ];
29004
29005 return mainImage.join("\n");
29006 }
29007
29008 function _getUniformInterfaceForUniformDescription (uniformDescription) {
29009 var interface = {
29010 _type : uniformDescription.type,
29011 _value : uniformDescription.value,
29012
29013 get type () {
29014 return this._type;
29015 },
29016
29017 set type (v) {
29018 this._type = v;
29019 },
29020
29021 get value () {
29022 return this._value;
29023 },
29024
29025 set value (v) {
29026 if (!Blotter.UniformUtils.validValueForUniformType(this._type, v)) {
29027 Blotter.Messaging.logError("Blotter.Material", false, "uniform value not valid for uniform type: " + this._type);
29028 return;
29029 }
29030 this._value = v;
29031
29032 this.trigger("update");
29033 }
29034 };
29035
29036 _.extend(interface, EventEmitter.prototype);
29037
29038 return interface;
29039 }
29040
29041 function _getUniformInterface (uniforms) {
29042 return _.reduce(uniforms, _.bind(function (memo, uniformDescription, uniformName) {
29043 memo[uniformName] = _getUniformInterfaceForUniformDescription(uniformDescription);
29044 memo[uniformName].on("update", _.bind(function () {
29045 this.trigger("update:uniform", [uniformName]);
29046 }, this));
29047
29048 return memo;
29049 }, this), {});
29050 }
29051
29052 return {
29053
29054 constructor : Blotter.Material,
29055
29056 get needsUpdate () { }, // jshint
29057
29058 set needsUpdate (value) {
29059 if (value === true) {
29060 this.trigger("update");
29061 }
29062 },
29063
29064 get mainImage () {
29065 return this._mainImage;
29066 },
29067
29068 set mainImage (mainImage) {
29069 this._mainImage = mainImage || _defaultMainImageSrc();
29070 },
29071
29072 get uniforms () {
29073 return this._uniforms;
29074 },
29075
29076 set uniforms (uniforms) {
29077 this._uniforms = _getUniformInterface.call(this, Blotter.UniformUtils.extractValidUniforms(
29078 _.extend(uniforms, Blotter.UniformUtils.defaultUniforms)
29079 ));
29080 },
29081
29082 init : function () {
29083 this.mainImage = _defaultMainImageSrc();
29084 this.uniforms = {};
29085 }
29086 };
29087 })();
29088
29089 Blotter._extendWithGettersSetters(Blotter.Material.prototype, EventEmitter.prototype);
29090
29091})(
29092 this.Blotter, this._, this.EventEmitter
29093);
29094
29095(function(Blotter, _) {
29096
29097 Blotter.ShaderMaterial = function(mainImage, options) {
29098 Blotter.Material.apply(this, arguments);
29099 };
29100
29101 Blotter.ShaderMaterial.prototype = Object.create(Blotter.Material.prototype);
29102
29103 Blotter._extendWithGettersSetters(Blotter.ShaderMaterial.prototype, (function () {
29104
29105 return {
29106
29107 constructor : Blotter.ShaderMaterial,
29108
29109 init : function (mainImage, options) {
29110 _.defaults(this, options);
29111
29112 this.mainImage = mainImage;
29113 }
29114 };
29115
29116 })());
29117
29118})(
29119 this.Blotter, this._
29120);
29121
29122(function(Blotter, _, EventEmitter) {
29123
29124 Blotter.RenderScope = function (text, blotter) {
29125 this.text = text;
29126 this.blotter = blotter;
29127
29128 this.material = {
29129 mainImage : this.blotter.material.mainImage
29130 };
29131
29132 this._mappingMaterial = blotter.mappingMaterial;
29133
29134 this.playing = this.blotter.autoplay;
29135 this.timeDelta = 0;
29136 this.lastDrawTime = false;
29137 this.frameCount = 0;
29138
29139 this.domElement = Blotter.CanvasUtils.hiDpiCanvas(0, 0, this.blotter.ratio, {
29140 class : "b-canvas",
29141 html : text.value
29142 });
29143
29144 this.context = this.domElement.getContext("2d");
29145 };
29146
29147 Blotter.RenderScope.prototype = (function () {
29148
29149 function _setMouseEventListeners () {
29150 var self = this,
29151 eventNames = ["mousedown", "mouseup", "mousemove", "mouseenter", "mouseleave"];
29152
29153 function setMouseListener (eventName) {
29154 self.domElement.addEventListener(eventName, function(e) {
29155 var position = Blotter.CanvasUtils.normalizedMousePosition(self.domElement, e);
29156
29157 self.emit(eventName, position);
29158 }, false);
29159 }
29160
29161 for (var i = 0; i < eventNames.length; i++) {
29162 var eventName = eventNames[i];
29163
29164 setMouseListener(eventName);
29165 }
29166 }
29167
29168 function _getBoundsForMappingMaterialAndText (mappingMaterial, text) {
29169 var bounds = mappingMaterial.boundsForText(text);
29170
29171 if (bounds) {
29172 return {
29173 w : bounds.w,
29174 h : bounds.h,
29175 x : -1 * Math.floor(bounds.x),
29176 y : -1 * Math.floor(mappingMaterial.height - (bounds.y + bounds.h))
29177 };
29178 }
29179 }
29180
29181 function _transferInferfaceValues (oldInterface, newInterface) {
29182 _.each(oldInterface, function(interfaceObject, uniformName) {
29183 var newInterfaceObject = newInterface[uniformName];
29184
29185 if (newInterfaceObject) {
29186 var typesMatch = newInterfaceObject.type == interfaceObject.type,
29187 valuesMatch = newInterfaceObject.value == interfaceObject.value;
29188
29189 if (typesMatch && !valuesMatch) {
29190 newInterfaceObject.value = interfaceObject.value;
29191 }
29192 }
29193 });
29194 }
29195
29196 function _getUniformInterfaceForUniformDescription (uniformDescription) {
29197 var interface = {
29198 _type : uniformDescription.type,
29199 _value : uniformDescription.value,
29200
29201 get type () {
29202 return this._type;
29203 },
29204
29205 set type (v) {
29206 Blotter.Messaging.logError("Blotter.RenderScope", false, "uniform types may not be updated through a text scope");
29207 },
29208
29209 get value () {
29210 return this._value;
29211 },
29212
29213 set value (v) {
29214 if (!Blotter.UniformUtils.validValueForUniformType(this._type, v)) {
29215 Blotter.Messaging.logError("Blotter.RenderScope", false, "uniform value not valid for uniform type: " + this._type);
29216 return;
29217 }
29218 this._value = v;
29219
29220 this.trigger("update");
29221 }
29222 };
29223
29224 _.extend(interface, EventEmitter.prototype);
29225
29226 return interface;
29227 }
29228
29229 function _getUniformInterfaceForMaterialUniforms (uniforms) {
29230 return _.reduce(uniforms, _.bind(function (memo, uniformDescription, uniformName) {
29231 memo[uniformName] = _getUniformInterfaceForUniformDescription(uniformDescription);
29232 memo[uniformName].on("update", _.bind(function () {
29233 this.trigger("update:uniform", [uniformName]);
29234 }, this));
29235
29236 return memo;
29237 }, this), {});
29238 }
29239
29240 function _update () {
29241 var mappingMaterial = this._mappingMaterial,
29242 bounds = mappingMaterial && _getBoundsForMappingMaterialAndText(mappingMaterial, this.text),
29243 previousUniforms = this.material.uniforms;
29244
29245 if (mappingMaterial && bounds) {
29246 Blotter.CanvasUtils.updateCanvasSize(
29247 this.domElement,
29248 bounds.w / this.blotter.ratio,
29249 bounds.h / this.blotter.ratio,
29250 this.blotter.ratio
29251 );
29252 this.domElement.innerHTML = this.text.value;
29253
29254 this.bounds = bounds;
29255
29256 this.material.uniforms = _getUniformInterfaceForMaterialUniforms.call(this, mappingMaterial.uniforms);
29257 this.material.mainImage = mappingMaterial.mainImage;
29258
29259 if (previousUniforms) {
29260 _transferInferfaceValues(previousUniforms, this.material.uniforms);
29261 }
29262
29263 this.trigger(this.lastUpdated ? "update" : "ready");
29264 this.lastUpdated = Date.now();
29265 }
29266 }
29267
29268 return {
29269
29270 constructor : Blotter.RenderScope,
29271
29272 get needsUpdate () { }, // jshint
29273
29274 set needsUpdate (value) {
29275 if (value === true) {
29276 _update.call(this);
29277 }
29278 },
29279
29280 get mappingMaterial () { },
29281
29282 set mappingMaterial (mappingMaterial) {
29283 this._mappingMaterial = mappingMaterial;
29284 },
29285
29286 play : function () {
29287 this.playing = true;
29288 },
29289
29290 pause : function () {
29291 this.playing = false;
29292 },
29293
29294 render : function () {
29295 if (this.bounds) {
29296 var now = Date.now();
29297
29298 this.frameCount += 1;
29299 this.timeDelta = (now - (this.lastDrawTime || now)) / 1000;
29300 this.lastDrawTime = now;
29301
29302 this.context.clearRect(0, 0, this.domElement.width, this.domElement.height);
29303
29304 this.context.putImageData(
29305 this.blotter.imageData,
29306 this.bounds.x,
29307 this.bounds.y
29308 );
29309
29310 this.trigger("render", [this.frameCount]);
29311 }
29312 },
29313
29314 appendTo : function (element) {
29315 if (typeof element.append === "function") {
29316 element.append(this.domElement);
29317 } else {
29318 element.appendChild(this.domElement);
29319 }
29320
29321 _setMouseEventListeners.call(this);
29322
29323 return this;
29324 }
29325 };
29326 })();
29327
29328 Blotter._extendWithGettersSetters(Blotter.RenderScope.prototype, EventEmitter.prototype);
29329
29330})(
29331 this.Blotter, this._, this.EventEmitter
29332);
29333
29334(function(Blotter, _, THREE, EventEmitter) {
29335
29336 var root = this;
29337
29338 Blotter.Renderer = function () {
29339 this._currentAnimationLoop = false;
29340
29341 this._scene = new THREE.Scene();
29342
29343 this._plane = new THREE.PlaneGeometry(1, 1);
29344
29345 this._material = new THREE.MeshBasicMaterial(); // Stub material.
29346
29347 this._mesh = new THREE.Mesh(this._plane, this._material);
29348 this._scene.add(this._mesh);
29349
29350 this._camera = new THREE.OrthographicCamera(0.5, 0.5, 0.5, 0.5, 0, 100);
29351
29352 this.init.apply(this, arguments);
29353 };
29354
29355 Blotter.Renderer.prototype = (function () {
29356
29357 function _getRenderTargetWithSize (width, height) {
29358 var renderTarget = new THREE.WebGLRenderTarget(width, height, {
29359 minFilter: THREE.LinearFilter,
29360 magFilter: THREE.LinearFilter,
29361 format: THREE.RGBAFormat,
29362 type: THREE.UnsignedByteType
29363 });
29364
29365 renderTarget.texture.generateMipmaps = false;
29366 renderTarget.width = width;
29367 renderTarget.height = height;
29368
29369 return renderTarget;
29370 }
29371
29372 function _loop () {
29373 Blotter.webglRenderer.render(this._scene, this._camera, this._renderTarget);
29374
29375 Blotter.webglRenderer.readRenderTargetPixels(
29376 this._renderTarget,
29377 0,
29378 0,
29379 this._renderTarget.width,
29380 this._renderTarget.height,
29381 this._imageDataArray
29382 );
29383
29384 this.trigger("render");
29385
29386 this._currentAnimationLoop = root.requestAnimationFrame(_.bind(_loop, this));
29387 }
29388
29389 return {
29390
29391 constructor : Blotter.Renderer,
29392
29393 get material () { }, // jshint
29394
29395 set material (material) {
29396 if (material instanceof THREE.Material) {
29397 this._material = material;
29398 this._mesh.material = material;
29399 }
29400 },
29401
29402 get width () {
29403 return this._width;
29404 },
29405
29406 set width (width) {
29407 this.setSize(width, this._height);
29408 },
29409
29410 get height () {
29411 return this._height;
29412 },
29413
29414 set height (height) {
29415 this.setSize(this._width, height);
29416 },
29417
29418 init : function () {
29419 this.setSize(1, 1);
29420 },
29421
29422 start : function () {
29423 if (!this._currentAnimationLoop) {
29424 _loop.call(this);
29425 }
29426 },
29427
29428 stop : function () {
29429 if (this._currentAnimationLoop) {
29430 root.cancelAnimationFrame(this._currentAnimationLoop);
29431 this._currentAnimationLoop = undefined;
29432 }
29433 },
29434
29435 setSize : function (width, height) {
29436 this._width = width || 1;
29437 this._height = height || 1;
29438
29439 this._mesh.scale.set(this._width, this._height, 1);
29440
29441 this._camera.left = this._width / - 2;
29442 this._camera.right = this._width / 2;
29443 this._camera.top = this._height / 2;
29444 this._camera.bottom = this._height / - 2;
29445 this._camera.updateProjectionMatrix();
29446
29447 this._renderTarget = _getRenderTargetWithSize(this._width, this._height);
29448
29449 this._viewBuffer = new ArrayBuffer(this._width * this._height * 4);
29450 this._imageDataArray = new Uint8Array(this._viewBuffer);
29451 this._clampedImageDataArray = new Uint8ClampedArray(this._viewBuffer);
29452
29453 this.imageData = new ImageData(this._clampedImageDataArray, this._width, this._height);
29454 },
29455
29456 teardown : function () {
29457 this.stop();
29458 }
29459 };
29460 })();
29461
29462 Blotter._extendWithGettersSetters(Blotter.Renderer.prototype, EventEmitter.prototype);
29463
29464})(
29465 this.Blotter, this._, this.THREE, this.EventEmitter
29466);
29467
29468(function(Blotter, _, THREE, setImmediate) {
29469
29470 // Create a Data Texture holding the boundaries (x/y offset and w/h) that should be available to any given texel for any given text.
29471
29472 Blotter.BoundsDataTextureBuilder = (function () {
29473
29474 function _boundsDataForMapping (mapping) {
29475 var texts = mapping.texts,
29476 data = new Float32Array(texts.length * 4);
29477
29478 for (var i = 0; i < texts.length; i++) {
29479 var text = texts[i],
29480 bounds = mapping.boundsForText(text);
29481
29482 data[4*i] = bounds.x; // x
29483 data[4*i+1] = mapping.height - (bounds.y + bounds.h); // y
29484 data[4*i+2] = bounds.w; // w
29485 data[4*i+3] = bounds.h; // h
29486 }
29487
29488 return data;
29489 }
29490
29491 return {
29492
29493 build : function (mapping, completion) {
29494 setImmediate(function() {
29495 var data = _boundsDataForMapping(mapping),
29496 texture = new THREE.DataTexture(data, mapping.texts.length, 1, THREE.RGBAFormat, THREE.FloatType);
29497
29498 texture.needsUpdate = true;
29499
29500 completion(texture);
29501 });
29502 }
29503 };
29504 })();
29505
29506})(
29507 this.Blotter, this._, this.THREE, this.setImmediate
29508);
29509
29510(function(Blotter, _, THREE, setImmediate) {
29511
29512 // Create a Data Texture the size of our text map wherein every texel holds the index of text whose boundaries contain the given texel's position.
29513
29514 Blotter.IndicesDataTextureBuilder = (function () {
29515
29516 function _indicesDataForMapping (mapping, width, height, sampleAccuracy) {
29517
29518 var ratio = mapping.ratio,
29519 points = new Float32Array((height * width) * 4),
29520 widthStepModifier = width % 1,
29521 indicesOffset = (1 / mapping.texts.length) / 2; // Values stored in this texture will be sampled from the 'middle' of their texel position.
29522
29523 for (var i = 1; i < points.length / 4; i++) {
29524
29525 var y = Math.ceil(i / (width - widthStepModifier)),
29526 x = i - ((width - widthStepModifier) * (y - 1)),
29527 refIndex = 0.0,
29528 bg = 0.0,
29529 a = 0.0;
29530
29531 for (var ki = 0; ki < mapping.texts.length; ki++) {
29532 var text = mapping.texts[ki],
29533 bounds = mapping.boundsForText(text),
29534 bW = (bounds.w / ratio) * sampleAccuracy,
29535 bH = (bounds.h / ratio) * sampleAccuracy,
29536 bX = (bounds.x / ratio) * sampleAccuracy,
29537 bY = (bounds.y / ratio) * sampleAccuracy;
29538
29539 // If x and y are within the fit bounds of the text space within our mapped texts texture.
29540 if (y >= bY &&
29541 y <= bY + bH &&
29542 x >= bX &&
29543 x <= bX + bW) {
29544 refIndex = (ki / mapping.texts.length) + indicesOffset;
29545 a = 1.0;
29546 break;
29547 }
29548 }
29549
29550 var index = i - 1;
29551
29552 points[4*index+0] = refIndex;
29553 points[4*index+1] = bg;
29554 points[4*index+2] = bg;
29555 points[4*index+3] = a;
29556 }
29557 return points;
29558 }
29559
29560 return {
29561
29562 build : function (mapping, completion) {
29563 // There is a negative coorelation between the sampleAccuracy value and
29564 // the speed at which texture generation happens.
29565 // However, the lower this value, the less sampleAccuracy you can expect
29566 // for indexing into uniforms for any given text.
29567 // Value must be between 0.0 and 1.0, and you are advised to keep it around 0.5.
29568 var sampleAccuracy = 0.5;
29569
29570 setImmediate(function() {
29571 var width = (mapping.width / mapping.ratio) * sampleAccuracy,
29572 height = (mapping.height / mapping.ratio) * sampleAccuracy,
29573 data = _indicesDataForMapping(mapping, width, height, sampleAccuracy),
29574 texture = new THREE.DataTexture(data, width, height, THREE.RGBAFormat, THREE.FloatType);
29575
29576 texture.flipY = true;
29577 texture.needsUpdate = true;
29578
29579 completion(texture);
29580 });
29581 }
29582 };
29583 })();
29584
29585})(
29586 this.Blotter, this._, this.THREE, this.setImmediate
29587);
29588
29589
29590(function(Blotter, _, THREE) {
29591
29592 Blotter.TextTextureBuilder = (function() {
29593
29594 return {
29595
29596 build : function (mapping, completion) {
29597 var loader = new THREE.TextureLoader(),
29598 url;
29599
29600 mapping.toCanvas(_.bind(function(canvas) {
29601 url = canvas.toDataURL();
29602
29603 loader.load(url, _.bind(function(texture) {
29604 texture.minFilter = THREE.LinearFilter;
29605 texture.magFilter = THREE.LinearFilter;
29606 texture.generateMipmaps = true;
29607 texture.needsUpdate = true;
29608
29609 completion(texture);
29610 }, this));
29611 }, this));
29612 }
29613 };
29614 })();
29615
29616})(
29617 this.Blotter, this._, this.THREE
29618);
29619
29620(function(Blotter, _, THREE, GrowingPacker, setImmediate) {
29621
29622 Blotter.MappingBuilder = (function () {
29623
29624 // Sort texts based on area of space required for any given text, descending
29625
29626 function _sortTexts (textA, textB) {
29627 var areaA = textA.w * textA.h,
29628 areaB = textB.w * textB.h;
29629
29630 return areaB - areaA;
29631 }
29632
29633 function _getTextSizes (texts) {
29634 return _.reduce(texts, function (textSizes, text) {
29635 var size = Blotter.TextUtils.sizeForText(text.value, text.properties);
29636 textSizes[text.id] = size;
29637 return textSizes;
29638 }, []);
29639 }
29640
29641 return {
29642
29643 build : function (texts, completion) {
29644 setImmediate(function() {
29645 var filteredTexts = Blotter.TextUtils.filterTexts(texts),
29646 textSizes = _getTextSizes(filteredTexts),
29647 packer = new GrowingPacker(),
29648 tempTextBounds = [],
29649 textBounds = {},
29650 mapping;
29651
29652 // Build array of objects holding a Text object's id, width, and height for sorting.
29653 for (var textId in textSizes) {
29654 if (textSizes.hasOwnProperty(textId)) {
29655 var tempSizesObject = textSizes[textId];
29656 tempSizesObject.referenceId = textId;
29657 tempTextBounds.push(tempSizesObject);
29658 }
29659 }
29660
29661 // Add fit object to all objects in tempTextBounds.
29662 packer.fit(tempTextBounds.sort(_sortTexts));
29663
29664 // Add fit objects back into this._textBounds for each Text id.
29665 for (var i = 0; i < tempTextBounds.length; i++) {
29666 var packedSizesObject = tempTextBounds[i];
29667 textBounds[packedSizesObject.referenceId] = {
29668 w : packedSizesObject.w,
29669 h : packedSizesObject.h,
29670 x : packedSizesObject.fit.x,
29671 y : packer.root.h - (packedSizesObject.fit.y + packedSizesObject.h)
29672 };
29673 }
29674
29675 completion(new Blotter.Mapping(filteredTexts, textBounds, packer.root.w, packer.root.h));
29676 });
29677 }
29678 };
29679 })();
29680
29681})(
29682 this.Blotter, this._, this.THREE, this.GrowingPacker, this.setImmediate
29683);
29684
29685(function(Blotter, _, THREE) {
29686
29687 Blotter.MappingMaterialBuilder = (function() {
29688
29689 function _vertexSrc () {
29690 var vertexSrc = [
29691
29692 "varying vec2 _vTexCoord;",
29693
29694 "void main() {",
29695
29696 " _vTexCoord = uv;",
29697 " gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
29698
29699 "}"
29700
29701 ];
29702
29703 return vertexSrc.join("\n");
29704 }
29705
29706 function _fragmentSrc (userUniformDataTextureObjects, textsLength, mainImageSrc) {
29707 var fragmentSrc,
29708 userUniforms = {
29709 // Strings of uniform declarations for each publicly facing version of each user defined and default uniform.
29710 publicUniformDeclarations : "",
29711 // Strings of uniform definitions for each publicly facing version of each user defined and default uniform.
29712 publicUniformDefinitions : ""
29713 },
29714 halfPixel = ((1 / userUniformDataTextureObjects.data.length) / 2).toFixed(20),
29715 userUniformsTextureWidth = (userUniformDataTextureObjects.texture.image.width).toFixed(1);
29716
29717 _.reduce(userUniformDataTextureObjects.userUniforms, function (userUniforms, uniformObject, uniformName) {
29718 var glslSwizzle = Blotter.UniformUtils.fullSwizzleStringForUniformType(uniformObject.userUniform.type),
29719 glslDataType = Blotter.UniformUtils.glslDataTypeForUniformType(uniformObject.userUniform.type);
29720
29721 // This is super convoluted. Sorry. All user uniforms are passed in a single texture, where for each uniform
29722 // there is a single rgba value per text. Within this texture data we need to be able to locate the position
29723 // of any given text's value for the given uniform. The maths here use the `textIndex` value, a value
29724 // sampled via the `indicesValueTexture`, to locate the text value for the given uniform, and then offsets that
29725 // value by half a texel in the overall _userUniformsTexture
29726 var uniformSamplePosition = "((" + (uniformObject.position).toFixed(1) + " + ((textIndex - ((1.0 / " + textsLength.toFixed(1) + ") / 2.0)) * " + textsLength.toFixed(1) + ")) / " + userUniformsTextureWidth + ") + " + halfPixel;
29727
29728 userUniforms.publicUniformDeclarations += glslDataType + " " + uniformName + ";\n";
29729 userUniforms.publicUniformDefinitions += " " + uniformName + " = texture2D(_userUniformsTexture, vec2(" + uniformSamplePosition + ", 0.5))." + glslSwizzle + ";\n";
29730
29731 return userUniforms;
29732 }, userUniforms);
29733
29734 fragmentSrc = [
29735
29736 Blotter.Assets.Shaders.Blending,
29737
29738 Blotter.Assets.Shaders.TextTexture,
29739
29740 // Private blotter defined uniforms.
29741 "uniform sampler2D _uSampler;",
29742 "uniform vec2 _uCanvasResolution;",
29743 "uniform sampler2D _uTextIndicesTexture;",
29744 "uniform sampler2D _uTextBoundsTexture;",
29745
29746 // Private texCoord and bounds information.
29747 "varying vec2 _vTexCoord;",
29748 "vec4 _textBounds;",
29749
29750 // Private versions of user defined and default uniform declarations
29751 "uniform sampler2D _userUniformsTexture;",
29752
29753 // Public versions of user defined and default uniform declarations
29754 userUniforms.publicUniformDeclarations,
29755
29756 "// Helper function used by user programs to retrieve texel color information within the bounds of",
29757 "// any given text. This is to be used instead of `texture2D` in the fragment sources for all Blotter materials.",
29758 "vec4 textTexture(vec2 coord) {",
29759 " vec2 adjustedFragCoord = _textBounds.xy + vec2((_textBounds.z * coord.x), (_textBounds.w * coord.y));",
29760 " vec2 uv = adjustedFragCoord.xy / _uCanvasResolution;",
29761
29762 " // If adjustedFragCoord falls outside the bounds of the current texel's text, return `vec4(0.0)`.",
29763 " if (adjustedFragCoord.x < _textBounds.x ||",
29764 " adjustedFragCoord.x > _textBounds.x + _textBounds.z ||",
29765 " adjustedFragCoord.y < _textBounds.y ||",
29766 " adjustedFragCoord.y > _textBounds.y + _textBounds.w) {",
29767 " return vec4(0.0);",
29768 " }",
29769
29770 " return texture2D(_uSampler, uv);",
29771 "}",
29772
29773 "void mainImage(out vec4 mainImage, in vec2 fragCoord);",
29774
29775 mainImageSrc,
29776
29777 "void main(void) {",
29778
29779 // Retrieve text index and text alpha for text bounds in which texel is contained.
29780 " vec4 textIndexData = texture2D(_uTextIndicesTexture, _vTexCoord);",
29781 " float textIndex = textIndexData.r;",
29782 " float textAlpha = textIndexData.a;",
29783
29784 // Make bounds for the current text globally visible.
29785 " _textBounds = texture2D(_uTextBoundsTexture, vec2(textIndex, 0.5));",
29786
29787 // Set "uniform" values visible to user.
29788 userUniforms.publicUniformDefinitions,
29789 " uResolution = _textBounds.zw;",
29790
29791 // Set fragment coordinate in respect to position within text bounds.
29792 " vec2 fragCoord = gl_FragCoord.xy - _textBounds.xy;",
29793 // Call user defined fragment function, setting outColor on return.
29794 " vec4 outColor;",
29795 " mainImage(outColor, fragCoord);",
29796
29797 // Multiply alpha by original textIndexData's fourth value."
29798 // this will be 0 for texels not within any 'text' area."
29799 " outColor.a = outColor.a * textAlpha;",
29800 " gl_FragColor = outColor;",
29801 "}"
29802
29803 ];
29804
29805 return fragmentSrc.join("\n");
29806 }
29807
29808 function _buildMappedTextsTexture (mapping, completion) {
29809 Blotter.TextTextureBuilder.build(mapping, function (texture) {
29810 completion(texture);
29811 });
29812 }
29813
29814 function _buildMappingDataTextureObjects (mapping, completion) {
29815 var buildIndicesTexture,
29816 buildBoundsTexture,
29817 mappingDataTextureObjects = [],
29818 buildStages;
29819
29820 buildIndicesTexture = function () {
29821 return function (next) {
29822 Blotter.IndicesDataTextureBuilder.build(mapping, function (texture) {
29823 mappingDataTextureObjects.push({
29824 uniformName : "_uTextIndicesTexture",
29825 texture : texture
29826 });
29827 next();
29828 });
29829 };
29830 };
29831
29832 buildBoundsTexture = function () {
29833 return function (next) {
29834 Blotter.BoundsDataTextureBuilder.build(mapping, function (texture) {
29835 mappingDataTextureObjects.push({
29836 uniformName : "_uTextBoundsTexture",
29837 texture : texture
29838 });
29839 next();
29840 });
29841 };
29842 };
29843
29844 buildStages = [
29845 buildIndicesTexture(),
29846 buildBoundsTexture()
29847 ];
29848
29849 _(buildStages).reduceRight(_.wrap, function () {
29850 completion(mappingDataTextureObjects);
29851 })();
29852 }
29853
29854 function _buildUserUniformDataTextureObjects (userUniforms, textsLength, completion) {
29855 Blotter.UniformUtils.ensureHasRequiredDefaultUniforms(userUniforms,
29856 "Blotter.MappingMaterialBuilder",
29857 "_buildUserUniformDataTextureObjects");
29858
29859 userUniforms = Blotter.UniformUtils.extractValidUniforms(userUniforms);
29860
29861 var uniformsDataLength = Object.keys(userUniforms).length * textsLength;
29862 var data = new Float32Array(uniformsDataLength * 4);
29863 var texture = new THREE.DataTexture(data, uniformsDataLength, 1, THREE.RGBAFormat, THREE.FloatType);
29864
29865 var userUniformDataTextureObjects = {
29866 data : data,
29867 texture : texture,
29868 userUniforms : {}
29869 };
29870
29871 _.reduce(userUniforms, function (memo, userUniform, uniformName) {
29872 var uniformPosition = Object.keys(userUniforms).indexOf(uniformName) * textsLength;
29873
29874 memo.userUniforms[uniformName] = {
29875 userUniform : userUniform,
29876 position : uniformPosition
29877 };
29878
29879 return memo;
29880 }, userUniformDataTextureObjects);
29881
29882 completion(userUniformDataTextureObjects);
29883 }
29884
29885 function _getUniformsForMappingDataTextureObjects (mappingDataTextureObjects) {
29886 return _.reduce(mappingDataTextureObjects, function (memo, mappingDataTextureObject) {
29887 memo[mappingDataTextureObject.uniformName] = {
29888 type : "t",
29889 value : mappingDataTextureObject.texture
29890 };
29891 return memo;
29892 }, {});
29893 }
29894
29895 function _getUniformsForUserUniformDataObjects (userUniformDataObjects) {
29896 return {
29897 _userUniformsTexture: {
29898 type : "t",
29899 value : userUniformDataObjects.texture
29900 }
29901 };
29902 }
29903
29904 function _getUniforms (width, height, mappedTextsTexture, mappingDataTextureObjects, userUniformDataTextureObjects) {
29905 var uniforms = {
29906 _uSampler : { type : "t", value : mappedTextsTexture },
29907 _uCanvasResolution : { type : "2f", value : [width, height] }
29908 };
29909
29910 _.extend(uniforms, _getUniformsForMappingDataTextureObjects(mappingDataTextureObjects));
29911 _.extend(uniforms, _getUniformsForUserUniformDataObjects(userUniformDataTextureObjects));
29912
29913 return uniforms;
29914 }
29915
29916 function _getThreeMaterial (vertexSrc, fragmentSrc, uniforms) {
29917 var threeMaterial = new THREE.ShaderMaterial({
29918 vertexShader : vertexSrc,
29919 fragmentShader : fragmentSrc,
29920 uniforms : uniforms
29921 });
29922
29923 threeMaterial.depthTest = false;
29924 threeMaterial.depthWrite = false;
29925 threeMaterial.premultipliedAlpha = false;
29926
29927 return threeMaterial;
29928 }
29929
29930 return {
29931
29932 build : function (mapping, material, completion) {
29933 var buildMappedTextsTexture,
29934 buildMappingDataTextureObjects,
29935 buildUserUniformDataAndDataTextureObjects,
29936 mappedTextsTexture,
29937 mappingDataTextureObjects,
29938 userUniformDataAndDataTextureObjects,
29939 buildStages;
29940
29941 buildMappedTextsTexture = function () {
29942 return function (next) {
29943 _buildMappedTextsTexture(mapping, function (texture) {
29944 mappedTextsTexture = texture;
29945 next();
29946 });
29947 };
29948 };
29949
29950 buildMappingDataTextureObjects = function () {
29951 return function (next) {
29952 _buildMappingDataTextureObjects(mapping, function (objects) {
29953 mappingDataTextureObjects = objects;
29954 next();
29955 });
29956 };
29957 };
29958
29959 buildUserUniformDataTextureObjects = function () {
29960 return function (next) {
29961 _buildUserUniformDataTextureObjects(material.uniforms, mapping.texts.length, function (objects) {
29962 userUniformDataTextureObjects = objects;
29963 next();
29964 });
29965 };
29966 };
29967
29968 buildStages = [
29969 buildMappedTextsTexture(),
29970 buildMappingDataTextureObjects(),
29971 buildUserUniformDataTextureObjects()
29972 ];
29973
29974 _(buildStages).reduceRight(_.wrap, function () {
29975 var uniforms = _getUniforms(
29976 mapping.width,
29977 mapping.height,
29978 mappedTextsTexture,
29979 mappingDataTextureObjects,
29980 userUniformDataTextureObjects
29981 ),
29982 userUniforms = _.omit(uniforms, "_uCanvasResolution", "_uSampler", "_uTextBoundsTexture", "_uTextIndicesTexture"),
29983 threeMaterial = _getThreeMaterial(_vertexSrc(), _fragmentSrc(userUniformDataTextureObjects, mapping.texts.length, material.mainImage), uniforms);
29984
29985 completion(new Blotter.MappingMaterial(mapping, material, threeMaterial, userUniformDataTextureObjects));
29986 })();
29987 }
29988 };
29989 })();
29990
29991})(
29992 this.Blotter, this._, this.THREE
29993);