etro 0.8.0 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/nodejs.yml +3 -1
- package/.github/workflows/shipjs-trigger.yml +29 -0
- package/CHANGELOG.md +36 -13
- package/CODE_OF_CONDUCT.md +5 -5
- package/CONTRIBUTING.md +22 -72
- package/README.md +2 -2
- package/dist/effect/base.d.ts +14 -1
- package/dist/etro-cjs.js +189 -230
- package/dist/etro-iife.js +189 -230
- package/dist/layer/base.d.ts +13 -0
- package/eslint.conf.js +2 -1
- package/eslint.test-conf.js +1 -0
- package/examples/application/readme-screenshot.html +4 -8
- package/examples/application/video-player.html +3 -4
- package/examples/introduction/effects.html +23 -4
- package/karma.conf.js +4 -2
- package/package.json +8 -4
- package/scripts/gen-effect-samples.html +0 -3
- package/ship.config.js +80 -0
- package/src/effect/base.ts +29 -10
- package/src/effect/gaussian-blur.ts +10 -10
- package/src/effect/pixelate.ts +1 -2
- package/src/effect/shader.ts +18 -22
- package/src/effect/stack.ts +8 -4
- package/src/effect/transform.ts +13 -14
- package/src/event.ts +8 -14
- package/src/layer/audio-source.ts +16 -14
- package/src/layer/audio.ts +1 -2
- package/src/layer/base.ts +26 -7
- package/src/layer/visual.ts +11 -6
- package/src/movie.ts +70 -64
- package/src/util.ts +50 -57
- package/docs/effect.js.html +0 -1215
- package/docs/event.js.html +0 -145
- package/docs/index.html +0 -81
- package/docs/index.js.html +0 -92
- package/docs/layer.js.html +0 -888
- package/docs/module-effect-GaussianBlurComponent.html +0 -345
- package/docs/module-effect.Brightness.html +0 -339
- package/docs/module-effect.Channels.html +0 -319
- package/docs/module-effect.ChromaKey.html +0 -611
- package/docs/module-effect.Contrast.html +0 -339
- package/docs/module-effect.EllipticalMask.html +0 -200
- package/docs/module-effect.GaussianBlur.html +0 -202
- package/docs/module-effect.GaussianBlurHorizontal.html +0 -242
- package/docs/module-effect.GaussianBlurVertical.html +0 -242
- package/docs/module-effect.Pixelate.html +0 -330
- package/docs/module-effect.Shader.html +0 -1227
- package/docs/module-effect.Stack.html +0 -406
- package/docs/module-effect.Transform.Matrix.html +0 -193
- package/docs/module-effect.Transform.html +0 -1174
- package/docs/module-effect.html +0 -148
- package/docs/module-event.html +0 -473
- package/docs/module-index.html +0 -186
- package/docs/module-layer-Media.html +0 -1116
- package/docs/module-layer-MediaMixin.html +0 -164
- package/docs/module-layer.Audio.html +0 -1188
- package/docs/module-layer.Base.html +0 -629
- package/docs/module-layer.Image.html +0 -1421
- package/docs/module-layer.Text.html +0 -1731
- package/docs/module-layer.Video.html +0 -1938
- package/docs/module-layer.Visual.html +0 -1698
- package/docs/module-layer.html +0 -137
- package/docs/module-movie.html +0 -3118
- package/docs/module-util.Color.html +0 -702
- package/docs/module-util.Font.html +0 -395
- package/docs/module-util.html +0 -845
- package/docs/movie.js.html +0 -689
- package/docs/scripts/collapse.js +0 -20
- package/docs/scripts/linenumber.js +0 -25
- package/docs/scripts/nav.js +0 -12
- package/docs/scripts/polyfill.js +0 -4
- package/docs/scripts/prettify/Apache-License-2.0.txt +0 -202
- package/docs/scripts/prettify/lang-css.js +0 -2
- package/docs/scripts/prettify/prettify.js +0 -28
- package/docs/scripts/search.js +0 -83
- package/docs/styles/jsdoc.css +0 -671
- package/docs/styles/prettify.css +0 -79
- package/docs/util.js.html +0 -503
- package/spec/assets/effect/gaussian-blur-horizontal.png +0 -0
- package/spec/assets/effect/gaussian-blur-vertical.png +0 -0
- package/spec/assets/effect/grayscale.png +0 -0
- package/spec/assets/effect/original.png +0 -0
- package/spec/assets/effect/pixelate.png +0 -0
- package/spec/assets/effect/transform/multiply.png +0 -0
- package/spec/assets/effect/transform/rotate.png +0 -0
- package/spec/assets/effect/transform/scale-fraction.png +0 -0
- package/spec/assets/effect/transform/scale.png +0 -0
- package/spec/assets/effect/transform/translate-fraction.png +0 -0
- package/spec/assets/effect/transform/translate.png +0 -0
- package/spec/assets/layer/audio.wav +0 -0
- package/spec/assets/layer/image.jpg +0 -0
- package/spec/effect.spec.js +0 -421
- package/spec/event.spec.js +0 -39
- package/spec/layer.spec.js +0 -307
- package/spec/movie.spec.js +0 -346
- package/spec/util.spec.js +0 -294
package/dist/etro-iife.js
CHANGED
|
@@ -53,14 +53,11 @@ var etro = (function () {
|
|
|
53
53
|
this._parts = id.split('.');
|
|
54
54
|
}
|
|
55
55
|
TypeId.prototype.contains = function (other) {
|
|
56
|
-
if (other._parts.length > this._parts.length)
|
|
56
|
+
if (other._parts.length > this._parts.length)
|
|
57
57
|
return false;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (other._parts[i] !== this._parts[i]) {
|
|
58
|
+
for (var i = 0; i < other._parts.length; i++)
|
|
59
|
+
if (other._parts[i] !== this._parts[i])
|
|
61
60
|
return false;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
61
|
return true;
|
|
65
62
|
};
|
|
66
63
|
TypeId.prototype.toString = function () {
|
|
@@ -77,9 +74,8 @@ var etro = (function () {
|
|
|
77
74
|
* @param listener
|
|
78
75
|
*/
|
|
79
76
|
function subscribe(target, type, listener) {
|
|
80
|
-
if (!listeners.has(target))
|
|
77
|
+
if (!listeners.has(target))
|
|
81
78
|
listeners.set(target, []);
|
|
82
|
-
}
|
|
83
79
|
listeners.get(target).push({ type: new TypeId(type), listener: listener });
|
|
84
80
|
}
|
|
85
81
|
/**
|
|
@@ -93,9 +89,8 @@ var etro = (function () {
|
|
|
93
89
|
function unsubscribe(target, listener) {
|
|
94
90
|
// Make sure `listener` has been added with `subscribe`.
|
|
95
91
|
if (!listeners.has(target) ||
|
|
96
|
-
!listeners.get(target).map(function (pair) { return pair.listener; }).includes(listener))
|
|
92
|
+
!listeners.get(target).map(function (pair) { return pair.listener; }).includes(listener))
|
|
97
93
|
throw new Error('No matching event listener to remove');
|
|
98
|
-
}
|
|
99
94
|
var removed = listeners.get(target)
|
|
100
95
|
.filter(function (pair) { return pair.listener !== listener; });
|
|
101
96
|
listeners.set(target, removed);
|
|
@@ -112,17 +107,15 @@ var etro = (function () {
|
|
|
112
107
|
event.target = target; // could be a proxy
|
|
113
108
|
event.type = type;
|
|
114
109
|
var t = new TypeId(type);
|
|
115
|
-
if (!listeners.has(target))
|
|
110
|
+
if (!listeners.has(target))
|
|
116
111
|
// No event fired
|
|
117
112
|
return null;
|
|
118
|
-
}
|
|
119
113
|
// Call event listeners for this event.
|
|
120
114
|
var listenersForType = [];
|
|
121
115
|
for (var i = 0; i < listeners.get(target).length; i++) {
|
|
122
116
|
var item = listeners.get(target)[i];
|
|
123
|
-
if (t.contains(item.type))
|
|
117
|
+
if (t.contains(item.type))
|
|
124
118
|
listenersForType.push(item.listener);
|
|
125
|
-
}
|
|
126
119
|
}
|
|
127
120
|
for (var i = 0; i < listenersForType.length; i++) {
|
|
128
121
|
var listener = listenersForType[i];
|
|
@@ -150,9 +143,8 @@ var etro = (function () {
|
|
|
150
143
|
function getPropertyDescriptor(obj, name) {
|
|
151
144
|
do {
|
|
152
145
|
var propDesc = Object.getOwnPropertyDescriptor(obj, name);
|
|
153
|
-
if (propDesc)
|
|
146
|
+
if (propDesc)
|
|
154
147
|
return propDesc;
|
|
155
|
-
}
|
|
156
148
|
obj = Object.getPrototypeOf(obj);
|
|
157
149
|
} while (obj);
|
|
158
150
|
return undefined;
|
|
@@ -167,35 +159,30 @@ var etro = (function () {
|
|
|
167
159
|
function applyOptions(options, destObj) {
|
|
168
160
|
var defaultOptions = destObj.getDefaultOptions();
|
|
169
161
|
// Validate; make sure `keys` doesn't have any extraneous items
|
|
170
|
-
for (var option in options)
|
|
162
|
+
for (var option in options)
|
|
171
163
|
// eslint-disable-next-line no-prototype-builtins
|
|
172
|
-
if (!defaultOptions.hasOwnProperty(option))
|
|
164
|
+
if (!defaultOptions.hasOwnProperty(option))
|
|
173
165
|
throw new Error("Invalid option: '" + option + "'");
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
166
|
// Merge options and defaultOptions
|
|
177
167
|
options = __assign(__assign({}, defaultOptions), options);
|
|
178
168
|
// Copy options
|
|
179
169
|
for (var option in options) {
|
|
180
170
|
var propDesc = getPropertyDescriptor(destObj, option);
|
|
181
171
|
// Update the property as long as the property has not been set (unless if it has a setter)
|
|
182
|
-
if (!propDesc || propDesc.set)
|
|
172
|
+
if (!propDesc || propDesc.set)
|
|
183
173
|
destObj[option] = options[option];
|
|
184
|
-
}
|
|
185
174
|
}
|
|
186
175
|
}
|
|
187
176
|
// This must be cleared at the start of each frame
|
|
188
177
|
var valCache = new WeakMap();
|
|
189
178
|
function cacheValue(element, path, value) {
|
|
190
179
|
// Initiate movie cache
|
|
191
|
-
if (!valCache.has(element.movie))
|
|
180
|
+
if (!valCache.has(element.movie))
|
|
192
181
|
valCache.set(element.movie, new WeakMap());
|
|
193
|
-
}
|
|
194
182
|
var movieCache = valCache.get(element.movie);
|
|
195
183
|
// Iniitate element cache
|
|
196
|
-
if (!movieCache.has(element))
|
|
184
|
+
if (!movieCache.has(element))
|
|
197
185
|
movieCache.set(element, {});
|
|
198
|
-
}
|
|
199
186
|
var elementCache = movieCache.get(element);
|
|
200
187
|
// Cache the value
|
|
201
188
|
elementCache[path] = value;
|
|
@@ -235,16 +222,13 @@ var etro = (function () {
|
|
|
235
222
|
return this;
|
|
236
223
|
};
|
|
237
224
|
KeyFrame.prototype.evaluate = function (time) {
|
|
238
|
-
if (this.value.length === 0)
|
|
225
|
+
if (this.value.length === 0)
|
|
239
226
|
throw new Error('Empty keyframe');
|
|
240
|
-
|
|
241
|
-
if (time === undefined) {
|
|
227
|
+
if (time === undefined)
|
|
242
228
|
throw new Error('|time| is undefined or null');
|
|
243
|
-
}
|
|
244
229
|
var firstTime = this.value[0][0];
|
|
245
|
-
if (time < firstTime)
|
|
230
|
+
if (time < firstTime)
|
|
246
231
|
throw new Error('No keyframe point before |time|');
|
|
247
|
-
}
|
|
248
232
|
// I think reduce are slow to do per-frame (or more)?
|
|
249
233
|
for (var i = 0; i < this.value.length; i++) {
|
|
250
234
|
var startTime = this.value[i][0];
|
|
@@ -253,7 +237,7 @@ var etro = (function () {
|
|
|
253
237
|
if (i + 1 < this.value.length) {
|
|
254
238
|
var endTime = this.value[i + 1][0];
|
|
255
239
|
var endValue = this.value[i + 1][1];
|
|
256
|
-
if (startTime <= time && time < endTime)
|
|
240
|
+
if (startTime <= time && time < endTime)
|
|
257
241
|
// No need for endValue if it is flat interpolation
|
|
258
242
|
// TODO: support custom interpolation for 'other' types?
|
|
259
243
|
if (!(typeof startValue === 'number' || typeof endValue === 'object')) {
|
|
@@ -269,7 +253,6 @@ var etro = (function () {
|
|
|
269
253
|
endValue, // eslint-disable-line @typescript-eslint/ban-types
|
|
270
254
|
percentProgress, this.interpolationKeys);
|
|
271
255
|
}
|
|
272
|
-
}
|
|
273
256
|
}
|
|
274
257
|
else {
|
|
275
258
|
// Repeat last value forever
|
|
@@ -295,28 +278,23 @@ var etro = (function () {
|
|
|
295
278
|
// TODO: Is this function efficient?
|
|
296
279
|
// TODO: Update doc @params to allow for keyframes
|
|
297
280
|
function val(element, path, time) {
|
|
298
|
-
if (hasCachedValue(element, path))
|
|
281
|
+
if (hasCachedValue(element, path))
|
|
299
282
|
return getCachedValue(element, path);
|
|
300
|
-
}
|
|
301
283
|
// Get property of element at path
|
|
302
284
|
var pathParts = path.split('.');
|
|
303
285
|
var property = element[pathParts.shift()];
|
|
304
|
-
while (pathParts.length > 0)
|
|
286
|
+
while (pathParts.length > 0)
|
|
305
287
|
property = property[pathParts.shift()];
|
|
306
|
-
}
|
|
307
288
|
// Property filter function
|
|
308
289
|
var process = element.propertyFilters[path];
|
|
309
290
|
var value;
|
|
310
|
-
if (property instanceof KeyFrame)
|
|
291
|
+
if (property instanceof KeyFrame)
|
|
311
292
|
value = property.evaluate(time);
|
|
312
|
-
|
|
313
|
-
else if (typeof property === 'function') {
|
|
293
|
+
else if (typeof property === 'function')
|
|
314
294
|
value = property(element, time); // TODO? add more args
|
|
315
|
-
|
|
316
|
-
else {
|
|
295
|
+
else
|
|
317
296
|
// Simple value
|
|
318
297
|
value = property;
|
|
319
|
-
}
|
|
320
298
|
return cacheValue(element, path, process ? process.call(element, value) : value);
|
|
321
299
|
}
|
|
322
300
|
/* export function floorInterp(x1, x2, t, objectKeys) {
|
|
@@ -327,18 +305,15 @@ var etro = (function () {
|
|
|
327
305
|
}, Object.create(Object.getPrototypeOf(x1)));
|
|
328
306
|
} */
|
|
329
307
|
function linearInterp(x1, x2, t, objectKeys) {
|
|
330
|
-
if (typeof x1 !== typeof x2)
|
|
308
|
+
if (typeof x1 !== typeof x2)
|
|
331
309
|
throw new Error('Type mismatch');
|
|
332
|
-
|
|
333
|
-
if (typeof x1 !== 'number' && typeof x1 !== 'object') {
|
|
310
|
+
if (typeof x1 !== 'number' && typeof x1 !== 'object')
|
|
334
311
|
// Flat interpolation (floor)
|
|
335
312
|
return x1;
|
|
336
|
-
}
|
|
337
313
|
if (typeof x1 === 'object') { // to work with objects (including arrays)
|
|
338
314
|
// TODO: make this code DRY
|
|
339
|
-
if (Object.getPrototypeOf(x1) !== Object.getPrototypeOf(x2))
|
|
315
|
+
if (Object.getPrototypeOf(x1) !== Object.getPrototypeOf(x2))
|
|
340
316
|
throw new Error('Prototype mismatch');
|
|
341
|
-
}
|
|
342
317
|
// Preserve prototype of objects
|
|
343
318
|
var int = Object.create(Object.getPrototypeOf(x1));
|
|
344
319
|
// Take the intersection of properties
|
|
@@ -346,9 +321,8 @@ var etro = (function () {
|
|
|
346
321
|
for (var i = 0; i < keys.length; i++) {
|
|
347
322
|
var key = keys[i];
|
|
348
323
|
// eslint-disable-next-line no-prototype-builtins
|
|
349
|
-
if (!x1.hasOwnProperty(key) || !x2.hasOwnProperty(key))
|
|
324
|
+
if (!x1.hasOwnProperty(key) || !x2.hasOwnProperty(key))
|
|
350
325
|
continue;
|
|
351
|
-
}
|
|
352
326
|
int[key] = linearInterp(x1[key], x2[key], t);
|
|
353
327
|
}
|
|
354
328
|
return int;
|
|
@@ -356,17 +330,14 @@ var etro = (function () {
|
|
|
356
330
|
return (1 - t) * x1 + t * x2;
|
|
357
331
|
}
|
|
358
332
|
function cosineInterp(x1, x2, t, objectKeys) {
|
|
359
|
-
if (typeof x1 !== typeof x2)
|
|
333
|
+
if (typeof x1 !== typeof x2)
|
|
360
334
|
throw new Error('Type mismatch');
|
|
361
|
-
|
|
362
|
-
if (typeof x1 !== 'number' && typeof x1 !== 'object') {
|
|
335
|
+
if (typeof x1 !== 'number' && typeof x1 !== 'object')
|
|
363
336
|
// Flat interpolation (floor)
|
|
364
337
|
return x1;
|
|
365
|
-
}
|
|
366
338
|
if (typeof x1 === 'object' && typeof x2 === 'object') { // to work with objects (including arrays)
|
|
367
|
-
if (Object.getPrototypeOf(x1) !== Object.getPrototypeOf(x2))
|
|
339
|
+
if (Object.getPrototypeOf(x1) !== Object.getPrototypeOf(x2))
|
|
368
340
|
throw new Error('Prototype mismatch');
|
|
369
|
-
}
|
|
370
341
|
// Preserve prototype of objects
|
|
371
342
|
var int = Object.create(Object.getPrototypeOf(x1));
|
|
372
343
|
// Take the intersection of properties
|
|
@@ -374,9 +345,8 @@ var etro = (function () {
|
|
|
374
345
|
for (var i = 0; i < keys.length; i++) {
|
|
375
346
|
var key = keys[i];
|
|
376
347
|
// eslint-disable-next-line no-prototype-builtins
|
|
377
|
-
if (!x1.hasOwnProperty(key) || !x2.hasOwnProperty(key))
|
|
348
|
+
if (!x1.hasOwnProperty(key) || !x2.hasOwnProperty(key))
|
|
378
349
|
continue;
|
|
379
|
-
}
|
|
380
350
|
int[key] = cosineInterp(x1[key], x2[key], t);
|
|
381
351
|
}
|
|
382
352
|
return int;
|
|
@@ -506,12 +476,10 @@ var etro = (function () {
|
|
|
506
476
|
width = width || canvas.width;
|
|
507
477
|
height = height || canvas.height;
|
|
508
478
|
var frame = ctx.getImageData(x, y, width, height);
|
|
509
|
-
for (var i = 0, l = frame.data.length; i < l; i += 4)
|
|
479
|
+
for (var i = 0, l = frame.data.length; i < l; i += 4)
|
|
510
480
|
mapper(frame.data, i);
|
|
511
|
-
|
|
512
|
-
if (flush) {
|
|
481
|
+
if (flush)
|
|
513
482
|
ctx.putImageData(frame, x, y);
|
|
514
|
-
}
|
|
515
483
|
}
|
|
516
484
|
/**
|
|
517
485
|
* <p>Emits "change" event when public properties updated, recursively.
|
|
@@ -528,17 +496,17 @@ var etro = (function () {
|
|
|
528
496
|
// Public API property updated, emit 'modify' event.
|
|
529
497
|
publish(proxy, target.type + ".change.modify", { property: getPath(receiver, prop), newValue: val });
|
|
530
498
|
};
|
|
531
|
-
var
|
|
499
|
+
var canWatch = function (receiver, prop) { return !prop.startsWith('_') &&
|
|
500
|
+
(receiver.publicExcludes === undefined || !receiver.publicExcludes.includes(prop)); };
|
|
532
501
|
// The path to each child property (each is a unique proxy)
|
|
533
502
|
var paths = new WeakMap();
|
|
534
503
|
var handler = {
|
|
535
504
|
set: function (obj, prop, val, receiver) {
|
|
536
505
|
// Recurse
|
|
537
|
-
if (typeof val === 'object' && val !== null && !paths.has(val) &&
|
|
506
|
+
if (typeof val === 'object' && val !== null && !paths.has(val) && canWatch(receiver, prop)) {
|
|
538
507
|
val = new Proxy(val, handler);
|
|
539
508
|
paths.set(val, getPath(receiver, prop));
|
|
540
509
|
}
|
|
541
|
-
var was = prop in obj;
|
|
542
510
|
// Set property or attribute
|
|
543
511
|
// Search prototype chain for the closest setter
|
|
544
512
|
var objProto = obj;
|
|
@@ -550,15 +518,12 @@ var etro = (function () {
|
|
|
550
518
|
break;
|
|
551
519
|
}
|
|
552
520
|
}
|
|
553
|
-
if (!objProto)
|
|
521
|
+
if (!objProto)
|
|
554
522
|
// Couldn't find setter; set value on instance
|
|
555
523
|
obj[prop] = val;
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
// on root object.
|
|
559
|
-
if (obj !== target || (was && check(prop))) {
|
|
524
|
+
// Check if the property isn't blacklisted in publicExcludes.
|
|
525
|
+
if (canWatch(receiver, prop))
|
|
560
526
|
callback(prop, val, receiver);
|
|
561
|
-
}
|
|
562
527
|
return true;
|
|
563
528
|
}
|
|
564
529
|
};
|
|
@@ -598,23 +563,20 @@ var etro = (function () {
|
|
|
598
563
|
applyOptions(options, _this);
|
|
599
564
|
var load = function () {
|
|
600
565
|
// TODO: && ?
|
|
601
|
-
if ((options.duration || (_this.source.duration - _this.sourceStartTime)) < 0)
|
|
566
|
+
if ((options.duration || (_this.source.duration - _this.sourceStartTime)) < 0)
|
|
602
567
|
throw new Error('Invalid options.duration or options.sourceStartTime');
|
|
603
|
-
}
|
|
604
568
|
_this._unstretchedDuration = options.duration || (_this.source.duration - _this.sourceStartTime);
|
|
605
569
|
_this.duration = _this._unstretchedDuration / (_this.playbackRate);
|
|
606
570
|
// onload will use `this`, and can't bind itself because it's before
|
|
607
571
|
// super()
|
|
608
572
|
onload && onload.bind(_this)(_this.source, options);
|
|
609
573
|
};
|
|
610
|
-
if (_this.source.readyState >= 2)
|
|
574
|
+
if (_this.source.readyState >= 2)
|
|
611
575
|
// this frame's data is available now
|
|
612
576
|
load();
|
|
613
|
-
|
|
614
|
-
else {
|
|
577
|
+
else
|
|
615
578
|
// when this frame's data is available
|
|
616
579
|
_this.source.addEventListener('loadedmetadata', load);
|
|
617
|
-
}
|
|
618
580
|
_this.source.addEventListener('durationchange', function () {
|
|
619
581
|
_this.duration = options.duration || (_this.source.duration - _this.sourceStartTime);
|
|
620
582
|
});
|
|
@@ -624,11 +586,9 @@ var etro = (function () {
|
|
|
624
586
|
var _this = this;
|
|
625
587
|
_super.prototype.attach.call(this, movie);
|
|
626
588
|
subscribe(movie, 'movie.seek', function () {
|
|
627
|
-
|
|
628
|
-
if (time < _this.startTime || time >= _this.startTime + _this.duration) {
|
|
589
|
+
if (_this.currentTime < 0 || _this.currentTime >= _this.duration)
|
|
629
590
|
return;
|
|
630
|
-
|
|
631
|
-
_this.source.currentTime = time - _this.startTime;
|
|
591
|
+
_this.source.currentTime = _this.currentTime + _this.sourceStartTime;
|
|
632
592
|
});
|
|
633
593
|
// TODO: on unattach?
|
|
634
594
|
subscribe(movie, 'movie.audiodestinationupdate', function (event) {
|
|
@@ -640,7 +600,7 @@ var etro = (function () {
|
|
|
640
600
|
}
|
|
641
601
|
});
|
|
642
602
|
// connect to audiocontext
|
|
643
|
-
this._audioNode = movie.actx.createMediaElementSource(this.source);
|
|
603
|
+
this._audioNode = this.audioNode || movie.actx.createMediaElementSource(this.source);
|
|
644
604
|
// Spy on connect and disconnect to remember if it connected to
|
|
645
605
|
// actx.destination (for Movie#record).
|
|
646
606
|
var oldConnect = this._audioNode.connect.bind(this.audioNode);
|
|
@@ -651,14 +611,16 @@ var etro = (function () {
|
|
|
651
611
|
var oldDisconnect = this._audioNode.disconnect.bind(this.audioNode);
|
|
652
612
|
this._audioNode.disconnect = function (destination, output, input) {
|
|
653
613
|
if (_this._connectedToDestination &&
|
|
654
|
-
destination === movie.actx.destination)
|
|
614
|
+
destination === movie.actx.destination)
|
|
655
615
|
_this._connectedToDestination = false;
|
|
656
|
-
}
|
|
657
616
|
return oldDisconnect(destination, output, input);
|
|
658
617
|
};
|
|
659
618
|
// Connect to actx.destination by default (can be rewired by user)
|
|
660
619
|
this.audioNode.connect(movie.actx.destination);
|
|
661
620
|
};
|
|
621
|
+
MixedAudioSource.prototype.detach = function () {
|
|
622
|
+
this.audioNode.disconnect(this.movie.actx.destination);
|
|
623
|
+
};
|
|
662
624
|
MixedAudioSource.prototype.start = function () {
|
|
663
625
|
this.source.currentTime = this.currentTime + this.sourceStartTime;
|
|
664
626
|
this.source.play();
|
|
@@ -690,9 +652,8 @@ var etro = (function () {
|
|
|
690
652
|
},
|
|
691
653
|
set: function (value) {
|
|
692
654
|
this._playbackRate = value;
|
|
693
|
-
if (this._unstretchedDuration !== undefined)
|
|
655
|
+
if (this._unstretchedDuration !== undefined)
|
|
694
656
|
this.duration = this._unstretchedDuration / value;
|
|
695
|
-
}
|
|
696
657
|
},
|
|
697
658
|
enumerable: false,
|
|
698
659
|
configurable: true
|
|
@@ -772,20 +733,36 @@ var etro = (function () {
|
|
|
772
733
|
});
|
|
773
734
|
return newThis;
|
|
774
735
|
}
|
|
775
|
-
|
|
736
|
+
/**
|
|
737
|
+
* Attaches this layer to `movie` if not already attached.
|
|
738
|
+
* @ignore
|
|
739
|
+
*/
|
|
740
|
+
Base.prototype.tryAttach = function (movie) {
|
|
741
|
+
if (this._occurrenceCount === 0)
|
|
742
|
+
this.attach(movie);
|
|
776
743
|
this._occurrenceCount++;
|
|
744
|
+
};
|
|
745
|
+
Base.prototype.attach = function (movie) {
|
|
777
746
|
this._movie = movie;
|
|
778
747
|
};
|
|
779
|
-
|
|
780
|
-
|
|
748
|
+
/**
|
|
749
|
+
* Dettaches this layer from its movie if the number of times `tryDetach` has
|
|
750
|
+
* been called (including this call) equals the number of times `tryAttach`
|
|
751
|
+
* has been called.
|
|
752
|
+
*
|
|
753
|
+
* @ignore
|
|
754
|
+
*/
|
|
755
|
+
Base.prototype.tryDetach = function () {
|
|
756
|
+
if (this.movie === null)
|
|
781
757
|
throw new Error('No movie to detach from');
|
|
782
|
-
}
|
|
783
758
|
this._occurrenceCount--;
|
|
784
759
|
// If this layer occurs in another place in a `layers` array, do not unset
|
|
785
760
|
// _movie. (For calling `unshift` on the `layers` proxy)
|
|
786
|
-
if (this._occurrenceCount === 0)
|
|
787
|
-
this.
|
|
788
|
-
|
|
761
|
+
if (this._occurrenceCount === 0)
|
|
762
|
+
this.detach();
|
|
763
|
+
};
|
|
764
|
+
Base.prototype.detach = function () {
|
|
765
|
+
this._movie = null;
|
|
789
766
|
};
|
|
790
767
|
/**
|
|
791
768
|
* Called when the layer is activated
|
|
@@ -874,9 +851,8 @@ var etro = (function () {
|
|
|
874
851
|
*/
|
|
875
852
|
function Audio(options) {
|
|
876
853
|
var _this = _super.call(this, options) || this;
|
|
877
|
-
if (_this.duration === undefined)
|
|
854
|
+
if (_this.duration === undefined)
|
|
878
855
|
_this.duration = (_this).source.duration - _this.sourceStartTime;
|
|
879
|
-
}
|
|
880
856
|
return _this;
|
|
881
857
|
}
|
|
882
858
|
Audio.prototype.getDefaultOptions = function () {
|
|
@@ -914,9 +890,8 @@ var etro = (function () {
|
|
|
914
890
|
set: function (target, property, value) {
|
|
915
891
|
if (!isNaN(Number(property))) {
|
|
916
892
|
// The property is a number (index)
|
|
917
|
-
if (target[property])
|
|
893
|
+
if (target[property])
|
|
918
894
|
target[property].detach();
|
|
919
|
-
}
|
|
920
895
|
value.attach(_this);
|
|
921
896
|
}
|
|
922
897
|
target[property] = value;
|
|
@@ -929,6 +904,11 @@ var etro = (function () {
|
|
|
929
904
|
* Render visual output
|
|
930
905
|
*/
|
|
931
906
|
Visual.prototype.render = function () {
|
|
907
|
+
// Prevent empty canvas errors if the width or height is 0
|
|
908
|
+
var width = val(this, 'width', this.currentTime);
|
|
909
|
+
var height = val(this, 'height', this.currentTime);
|
|
910
|
+
if (width === 0 || height === 0)
|
|
911
|
+
return;
|
|
932
912
|
this.beginRender();
|
|
933
913
|
this.doRender();
|
|
934
914
|
this.endRender();
|
|
@@ -959,18 +939,16 @@ var etro = (function () {
|
|
|
959
939
|
Visual.prototype.endRender = function () {
|
|
960
940
|
var w = val(this, 'width', this.currentTime) || val(this.movie, 'width', this.movie.currentTime);
|
|
961
941
|
var h = val(this, 'height', this.currentTime) || val(this.movie, 'height', this.movie.currentTime);
|
|
962
|
-
if (w * h > 0)
|
|
942
|
+
if (w * h > 0)
|
|
963
943
|
this._applyEffects();
|
|
964
|
-
}
|
|
965
944
|
// else InvalidStateError for drawing zero-area image in some effects, right?
|
|
966
945
|
};
|
|
967
946
|
Visual.prototype._applyEffects = function () {
|
|
968
947
|
for (var i = 0; i < this.effects.length; i++) {
|
|
969
948
|
var effect = this.effects[i];
|
|
970
|
-
if (effect.enabled)
|
|
949
|
+
if (effect && effect.enabled)
|
|
971
950
|
// Pass relative time
|
|
972
951
|
effect.apply(this, this.movie.currentTime - this.startTime);
|
|
973
|
-
}
|
|
974
952
|
}
|
|
975
953
|
};
|
|
976
954
|
/**
|
|
@@ -1214,28 +1192,43 @@ var etro = (function () {
|
|
|
1214
1192
|
newThis._target = null;
|
|
1215
1193
|
// Propogate up to target
|
|
1216
1194
|
subscribe(newThis, 'effect.change.modify', function (event) {
|
|
1217
|
-
if (!newThis._target)
|
|
1195
|
+
if (!newThis._target)
|
|
1218
1196
|
return;
|
|
1219
|
-
}
|
|
1220
1197
|
var type = newThis._target.type + ".change.effect.modify";
|
|
1221
1198
|
publish(newThis._target, type, __assign(__assign({}, event), { target: newThis._target, source: newThis, type: type }));
|
|
1222
1199
|
});
|
|
1223
1200
|
return newThis;
|
|
1224
1201
|
}
|
|
1225
|
-
|
|
1202
|
+
/**
|
|
1203
|
+
* Attaches this effect to `target` if not already attached.
|
|
1204
|
+
* @ignore
|
|
1205
|
+
*/
|
|
1206
|
+
Base.prototype.tryAttach = function (target) {
|
|
1207
|
+
if (this._occurrenceCount === 0)
|
|
1208
|
+
this.attach(target);
|
|
1226
1209
|
this._occurrenceCount++;
|
|
1227
|
-
this._target = target;
|
|
1228
1210
|
};
|
|
1229
|
-
Base.prototype.
|
|
1230
|
-
|
|
1211
|
+
Base.prototype.attach = function (movie) {
|
|
1212
|
+
this._target = movie;
|
|
1213
|
+
};
|
|
1214
|
+
/**
|
|
1215
|
+
* Dettaches this effect from its target if the number of times `tryDetach`
|
|
1216
|
+
* has been called (including this call) equals the number of times
|
|
1217
|
+
* `tryAttach` has been called.
|
|
1218
|
+
*
|
|
1219
|
+
* @ignore
|
|
1220
|
+
*/
|
|
1221
|
+
Base.prototype.tryDetach = function () {
|
|
1222
|
+
if (this._target === null)
|
|
1231
1223
|
throw new Error('No movie to detach from');
|
|
1232
|
-
}
|
|
1233
1224
|
this._occurrenceCount--;
|
|
1234
1225
|
// If this effect occurs in another place in the containing array, do not
|
|
1235
1226
|
// unset _target. (For calling `unshift` on the `layers` proxy)
|
|
1236
|
-
if (this._occurrenceCount === 0)
|
|
1237
|
-
this.
|
|
1238
|
-
|
|
1227
|
+
if (this._occurrenceCount === 0)
|
|
1228
|
+
this.detach();
|
|
1229
|
+
};
|
|
1230
|
+
Base.prototype.detach = function () {
|
|
1231
|
+
this._target = null;
|
|
1239
1232
|
};
|
|
1240
1233
|
// subclasses must implement apply
|
|
1241
1234
|
/**
|
|
@@ -1315,18 +1308,16 @@ var etro = (function () {
|
|
|
1315
1308
|
Shader.prototype._initGl = function () {
|
|
1316
1309
|
this._canvas = document.createElement('canvas');
|
|
1317
1310
|
var gl = this._canvas.getContext('webgl');
|
|
1318
|
-
if (gl === null)
|
|
1311
|
+
if (gl === null)
|
|
1319
1312
|
throw new Error('Unable to initialize WebGL. Your browser or machine may not support it.');
|
|
1320
|
-
}
|
|
1321
1313
|
this._gl = gl;
|
|
1322
1314
|
return gl;
|
|
1323
1315
|
};
|
|
1324
1316
|
Shader.prototype._initTextures = function (userUniforms, userTextures, sourceTextureOptions) {
|
|
1325
1317
|
var gl = this._gl;
|
|
1326
1318
|
var maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
|
|
1327
|
-
if (userTextures.length > maxTextures)
|
|
1319
|
+
if (userTextures.length > maxTextures)
|
|
1328
1320
|
console.warn('Too many textures!');
|
|
1329
|
-
}
|
|
1330
1321
|
this._userTextures = {};
|
|
1331
1322
|
for (var name_1 in userTextures) {
|
|
1332
1323
|
var userOptions = userTextures[name_1];
|
|
@@ -1339,9 +1330,8 @@ var etro = (function () {
|
|
|
1339
1330
|
* textures, without having to define multiple properties in the effect
|
|
1340
1331
|
* object.
|
|
1341
1332
|
*/
|
|
1342
|
-
if (userUniforms[name_1])
|
|
1333
|
+
if (userUniforms[name_1])
|
|
1343
1334
|
throw new Error("Texture - uniform naming conflict: " + name_1 + "!");
|
|
1344
|
-
}
|
|
1345
1335
|
// Add this as a "user uniform".
|
|
1346
1336
|
userUniforms[name_1] = '1i'; // texture pointer
|
|
1347
1337
|
}
|
|
@@ -1479,13 +1469,11 @@ var etro = (function () {
|
|
|
1479
1469
|
// Set the shader uniforms.
|
|
1480
1470
|
// Tell the shader we bound the texture to texture unit 0.
|
|
1481
1471
|
// All base (Shader class) uniforms are optional.
|
|
1482
|
-
if (this._uniformLocations.source)
|
|
1472
|
+
if (this._uniformLocations.source)
|
|
1483
1473
|
gl.uniform1i(this._uniformLocations.source, 0);
|
|
1484
|
-
}
|
|
1485
1474
|
// All base (Shader class) uniforms are optional.
|
|
1486
|
-
if (this._uniformLocations.size)
|
|
1475
|
+
if (this._uniformLocations.size)
|
|
1487
1476
|
gl.uniform2iv(this._uniformLocations.size, [target.canvas.width, target.canvas.height]);
|
|
1488
|
-
}
|
|
1489
1477
|
for (var unprefixed in this._userUniforms) {
|
|
1490
1478
|
var options = this._userUniforms[unprefixed];
|
|
1491
1479
|
var value = val(this, unprefixed, reltime);
|
|
@@ -1536,40 +1524,35 @@ var etro = (function () {
|
|
|
1536
1524
|
var i = 0;
|
|
1537
1525
|
for (var name_4 in this._userTextures) {
|
|
1538
1526
|
var testValue = val(this, name_4, reltime);
|
|
1539
|
-
if (value === testValue)
|
|
1527
|
+
if (value === testValue)
|
|
1540
1528
|
value = Shader.INTERNAL_TEXTURE_UNITS + i; // after the internal texture units
|
|
1541
|
-
}
|
|
1542
1529
|
i++;
|
|
1543
1530
|
}
|
|
1544
1531
|
}
|
|
1545
1532
|
if (outputType === '3fv') {
|
|
1546
1533
|
// allow 4-component vectors; TODO: why?
|
|
1547
|
-
if (Array.isArray(value) && (value.length === 3 || value.length === 4))
|
|
1534
|
+
if (Array.isArray(value) && (value.length === 3 || value.length === 4))
|
|
1548
1535
|
return value;
|
|
1549
|
-
}
|
|
1550
1536
|
// kind of loose so this can be changed if needed
|
|
1551
|
-
if (typeof value === 'object')
|
|
1537
|
+
if (typeof value === 'object')
|
|
1552
1538
|
return [
|
|
1553
1539
|
value.r !== undefined ? value.r : def,
|
|
1554
1540
|
value.g !== undefined ? value.g : def,
|
|
1555
1541
|
value.b !== undefined ? value.b : def
|
|
1556
1542
|
];
|
|
1557
|
-
}
|
|
1558
1543
|
throw new Error("Invalid type: " + outputType + " or value: " + value);
|
|
1559
1544
|
}
|
|
1560
1545
|
if (outputType === '4fv') {
|
|
1561
|
-
if (Array.isArray(value) && value.length === 4)
|
|
1546
|
+
if (Array.isArray(value) && value.length === 4)
|
|
1562
1547
|
return value;
|
|
1563
|
-
}
|
|
1564
1548
|
// kind of loose so this can be changed if needed
|
|
1565
|
-
if (typeof value === 'object')
|
|
1549
|
+
if (typeof value === 'object')
|
|
1566
1550
|
return [
|
|
1567
1551
|
value.r !== undefined ? value.r : def,
|
|
1568
1552
|
value.g !== undefined ? value.g : def,
|
|
1569
1553
|
value.b !== undefined ? value.b : def,
|
|
1570
1554
|
value.a !== undefined ? value.a : def
|
|
1571
1555
|
];
|
|
1572
|
-
}
|
|
1573
1556
|
throw new Error("Invalid type: " + outputType + " or value: " + value);
|
|
1574
1557
|
}
|
|
1575
1558
|
return value;
|
|
@@ -1663,9 +1646,8 @@ var etro = (function () {
|
|
|
1663
1646
|
else {
|
|
1664
1647
|
// No, it's not a power of 2. Turn off mips and set
|
|
1665
1648
|
// wrapping to clamp to edge
|
|
1666
|
-
if (wrapS !== gl.CLAMP_TO_EDGE || wrapT !== gl.CLAMP_TO_EDGE)
|
|
1649
|
+
if (wrapS !== gl.CLAMP_TO_EDGE || wrapT !== gl.CLAMP_TO_EDGE)
|
|
1667
1650
|
console.warn('Wrap mode is not CLAMP_TO_EDGE for a non-power-of-two texture. Defaulting to CLAMP_TO_EDGE');
|
|
1668
|
-
}
|
|
1669
1651
|
gl.texParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
1670
1652
|
gl.texParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
1671
1653
|
}
|
|
@@ -1901,6 +1883,7 @@ var etro = (function () {
|
|
|
1901
1883
|
function Stack(options) {
|
|
1902
1884
|
var _this = _super.call(this) || this;
|
|
1903
1885
|
_this._effectsBack = [];
|
|
1886
|
+
// TODO: Throw 'change' events in handlers
|
|
1904
1887
|
_this.effects = new Proxy(_this._effectsBack, {
|
|
1905
1888
|
deleteProperty: function (target, property) {
|
|
1906
1889
|
var value = target[property];
|
|
@@ -1911,9 +1894,8 @@ var etro = (function () {
|
|
|
1911
1894
|
set: function (target, property, value) {
|
|
1912
1895
|
// TODO: make sure type check works
|
|
1913
1896
|
if (!isNaN(Number(property))) { // if property is a number (index)
|
|
1914
|
-
if (target[property])
|
|
1897
|
+
if (target[property])
|
|
1915
1898
|
target[property].detach(); // Detach old effect from movie
|
|
1916
|
-
}
|
|
1917
1899
|
value.attach(this._target); // Attach effect to movie
|
|
1918
1900
|
}
|
|
1919
1901
|
target[property] = value;
|
|
@@ -1922,23 +1904,26 @@ var etro = (function () {
|
|
|
1922
1904
|
});
|
|
1923
1905
|
options.effects.forEach(function (effect) { return _this.effects.push(effect); });
|
|
1924
1906
|
return _this;
|
|
1907
|
+
// TODO: Propogate 'change' events from children up
|
|
1925
1908
|
}
|
|
1926
1909
|
Stack.prototype.attach = function (movie) {
|
|
1927
1910
|
_super.prototype.attach.call(this, movie);
|
|
1928
|
-
this.effects.forEach(function (effect) {
|
|
1911
|
+
this.effects.filter(function (effect) { return !!effect; }).forEach(function (effect) {
|
|
1929
1912
|
effect.detach();
|
|
1930
1913
|
effect.attach(movie);
|
|
1931
1914
|
});
|
|
1932
1915
|
};
|
|
1933
1916
|
Stack.prototype.detach = function () {
|
|
1934
1917
|
_super.prototype.detach.call(this);
|
|
1935
|
-
this.effects.forEach(function (effect) {
|
|
1918
|
+
this.effects.filter(function (effect) { return !!effect; }).forEach(function (effect) {
|
|
1936
1919
|
effect.detach();
|
|
1937
1920
|
});
|
|
1938
1921
|
};
|
|
1939
1922
|
Stack.prototype.apply = function (target, reltime) {
|
|
1940
1923
|
for (var i = 0; i < this.effects.length; i++) {
|
|
1941
1924
|
var effect = this.effects[i];
|
|
1925
|
+
if (!effect)
|
|
1926
|
+
continue;
|
|
1942
1927
|
effect.apply(target, reltime);
|
|
1943
1928
|
}
|
|
1944
1929
|
};
|
|
@@ -2002,10 +1987,9 @@ var etro = (function () {
|
|
|
2002
1987
|
}
|
|
2003
1988
|
GaussianBlurComponent.prototype.apply = function (target, reltime) {
|
|
2004
1989
|
var radiusVal = val(this, 'radius', reltime);
|
|
2005
|
-
if (radiusVal !== this._radiusCache)
|
|
1990
|
+
if (radiusVal !== this._radiusCache)
|
|
2006
1991
|
// Regenerate gaussian distribution canvas.
|
|
2007
1992
|
this.shape = GaussianBlurComponent._render1DKernel(GaussianBlurComponent._gen1DKernel(radiusVal));
|
|
2008
|
-
}
|
|
2009
1993
|
this._radiusCache = radiusVal;
|
|
2010
1994
|
_super.prototype.apply.call(this, target, reltime);
|
|
2011
1995
|
};
|
|
@@ -2038,27 +2022,23 @@ var etro = (function () {
|
|
|
2038
2022
|
var pascal = GaussianBlurComponent._genPascalRow(2 * radius + 1);
|
|
2039
2023
|
// don't use `reduce` and `map` (overhead?)
|
|
2040
2024
|
var sum = 0;
|
|
2041
|
-
for (var i = 0; i < pascal.length; i++)
|
|
2025
|
+
for (var i = 0; i < pascal.length; i++)
|
|
2042
2026
|
sum += pascal[i];
|
|
2043
|
-
|
|
2044
|
-
for (var i = 0; i < pascal.length; i++) {
|
|
2027
|
+
for (var i = 0; i < pascal.length; i++)
|
|
2045
2028
|
pascal[i] /= sum;
|
|
2046
|
-
}
|
|
2047
2029
|
return pascal;
|
|
2048
2030
|
};
|
|
2049
2031
|
GaussianBlurComponent._genPascalRow = function (index) {
|
|
2050
|
-
if (index < 0)
|
|
2032
|
+
if (index < 0)
|
|
2051
2033
|
throw new Error("Invalid index " + index);
|
|
2052
|
-
}
|
|
2053
2034
|
var currRow = [1];
|
|
2054
2035
|
for (var i = 1; i < index; i++) {
|
|
2055
2036
|
var nextRow = [];
|
|
2056
2037
|
nextRow.length = currRow.length + 1;
|
|
2057
2038
|
// edges are always 1's
|
|
2058
2039
|
nextRow[0] = nextRow[nextRow.length - 1] = 1;
|
|
2059
|
-
for (var j = 1; j < nextRow.length - 1; j++)
|
|
2040
|
+
for (var j = 1; j < nextRow.length - 1; j++)
|
|
2060
2041
|
nextRow[j] = currRow[j - 1] + currRow[j];
|
|
2061
|
-
}
|
|
2062
2042
|
currRow = nextRow;
|
|
2063
2043
|
}
|
|
2064
2044
|
return currRow;
|
|
@@ -2136,9 +2116,8 @@ var etro = (function () {
|
|
|
2136
2116
|
}
|
|
2137
2117
|
Pixelate.prototype.apply = function (target, reltime) {
|
|
2138
2118
|
var ps = val(this, 'pixelSize', reltime);
|
|
2139
|
-
if (ps % 1 !== 0 || ps < 0)
|
|
2119
|
+
if (ps % 1 !== 0 || ps < 0)
|
|
2140
2120
|
throw new Error('Pixel size must be a nonnegative integer');
|
|
2141
|
-
}
|
|
2142
2121
|
_super.prototype.apply.call(this, target, reltime);
|
|
2143
2122
|
};
|
|
2144
2123
|
return Pixelate;
|
|
@@ -2167,12 +2146,10 @@ var etro = (function () {
|
|
|
2167
2146
|
return _this;
|
|
2168
2147
|
}
|
|
2169
2148
|
Transform.prototype.apply = function (target, reltime) {
|
|
2170
|
-
if (target.canvas.width !== this._tmpCanvas.width)
|
|
2149
|
+
if (target.canvas.width !== this._tmpCanvas.width)
|
|
2171
2150
|
this._tmpCanvas.width = target.canvas.width;
|
|
2172
|
-
|
|
2173
|
-
if (target.canvas.height !== this._tmpCanvas.height) {
|
|
2151
|
+
if (target.canvas.height !== this._tmpCanvas.height)
|
|
2174
2152
|
this._tmpCanvas.height = target.canvas.height;
|
|
2175
|
-
}
|
|
2176
2153
|
// Use data, since that's the underlying storage
|
|
2177
2154
|
this._tmpMatrix.data = val(this, 'matrix.data', reltime);
|
|
2178
2155
|
this._tmpCtx.setTransform(this._tmpMatrix.a, this._tmpMatrix.b, this._tmpMatrix.c, this._tmpMatrix.d, this._tmpMatrix.e, this._tmpMatrix.f);
|
|
@@ -2198,9 +2175,8 @@ var etro = (function () {
|
|
|
2198
2175
|
];
|
|
2199
2176
|
}
|
|
2200
2177
|
Matrix.prototype.identity = function () {
|
|
2201
|
-
for (var i = 0; i < this.data.length; i++)
|
|
2178
|
+
for (var i = 0; i < this.data.length; i++)
|
|
2202
2179
|
this.data[i] = Matrix.IDENTITY.data[i];
|
|
2203
|
-
}
|
|
2204
2180
|
return this;
|
|
2205
2181
|
};
|
|
2206
2182
|
/**
|
|
@@ -2209,9 +2185,8 @@ var etro = (function () {
|
|
|
2209
2185
|
* @param [val]
|
|
2210
2186
|
*/
|
|
2211
2187
|
Matrix.prototype.cell = function (x, y, val) {
|
|
2212
|
-
if (val !== undefined)
|
|
2188
|
+
if (val !== undefined)
|
|
2213
2189
|
this.data[3 * y + x] = val;
|
|
2214
|
-
}
|
|
2215
2190
|
return this.data[3 * y + x];
|
|
2216
2191
|
};
|
|
2217
2192
|
Object.defineProperty(Matrix.prototype, "a", {
|
|
@@ -2263,19 +2238,16 @@ var etro = (function () {
|
|
|
2263
2238
|
*/
|
|
2264
2239
|
Matrix.prototype.multiply = function (other) {
|
|
2265
2240
|
// copy to temporary matrix to avoid modifying `this` while reading from it
|
|
2266
|
-
for (var x = 0; x < 3; x++)
|
|
2241
|
+
for (var x = 0; x < 3; x++)
|
|
2267
2242
|
for (var y = 0; y < 3; y++) {
|
|
2268
2243
|
var sum = 0;
|
|
2269
|
-
for (var i = 0; i < 3; i++)
|
|
2244
|
+
for (var i = 0; i < 3; i++)
|
|
2270
2245
|
sum += this.cell(x, i) * other.cell(i, y);
|
|
2271
|
-
}
|
|
2272
2246
|
Matrix._TMP_MATRIX.cell(x, y, sum);
|
|
2273
2247
|
}
|
|
2274
|
-
}
|
|
2275
2248
|
// copy data from TMP_MATRIX to this
|
|
2276
|
-
for (var i = 0; i < Matrix._TMP_MATRIX.data.length; i++)
|
|
2249
|
+
for (var i = 0; i < Matrix._TMP_MATRIX.data.length; i++)
|
|
2277
2250
|
this.data[i] = Matrix._TMP_MATRIX.data[i];
|
|
2278
|
-
}
|
|
2279
2251
|
return this;
|
|
2280
2252
|
};
|
|
2281
2253
|
/**
|
|
@@ -8805,7 +8777,7 @@ var etro = (function () {
|
|
|
8805
8777
|
// Refresh screen when effect is removed, if the movie isn't playing
|
|
8806
8778
|
// already.
|
|
8807
8779
|
var value = target[property];
|
|
8808
|
-
value.
|
|
8780
|
+
value.tryDetach();
|
|
8809
8781
|
delete target[property];
|
|
8810
8782
|
publish(that, 'movie.change.effect.remove', { effect: value });
|
|
8811
8783
|
return true;
|
|
@@ -8817,10 +8789,10 @@ var etro = (function () {
|
|
|
8817
8789
|
publish(that, 'movie.change.effect.remove', {
|
|
8818
8790
|
effect: target[property]
|
|
8819
8791
|
});
|
|
8820
|
-
target[property].
|
|
8792
|
+
target[property].tryDetach();
|
|
8821
8793
|
}
|
|
8822
8794
|
// Attach effect to movie
|
|
8823
|
-
value.
|
|
8795
|
+
value.tryAttach(that);
|
|
8824
8796
|
target[property] = value;
|
|
8825
8797
|
// Refresh screen when effect is set, if the movie isn't playing
|
|
8826
8798
|
// already.
|
|
@@ -8837,12 +8809,11 @@ var etro = (function () {
|
|
|
8837
8809
|
deleteProperty: function (target, property) {
|
|
8838
8810
|
var oldDuration = this.duration;
|
|
8839
8811
|
var value = target[property];
|
|
8840
|
-
value.
|
|
8812
|
+
value.tryDetach(that);
|
|
8841
8813
|
delete target[property];
|
|
8842
8814
|
var current = that.currentTime >= value.startTime && that.currentTime < value.startTime + value.duration;
|
|
8843
|
-
if (current)
|
|
8815
|
+
if (current)
|
|
8844
8816
|
publish(that, 'movie.change.layer.remove', { layer: value });
|
|
8845
|
-
}
|
|
8846
8817
|
publish(that, 'movie.change.duration', { oldDuration: oldDuration });
|
|
8847
8818
|
return true;
|
|
8848
8819
|
},
|
|
@@ -8854,16 +8825,15 @@ var etro = (function () {
|
|
|
8854
8825
|
publish(that, 'movie.change.layer.remove', {
|
|
8855
8826
|
layer: target[property]
|
|
8856
8827
|
});
|
|
8857
|
-
target[property].
|
|
8828
|
+
target[property].tryDetach();
|
|
8858
8829
|
}
|
|
8859
8830
|
// Attach layer to movie
|
|
8860
|
-
value.
|
|
8831
|
+
value.tryAttach(that);
|
|
8861
8832
|
target[property] = value;
|
|
8862
8833
|
// Refresh screen when a relevant layer is added or removed
|
|
8863
8834
|
var current = that.currentTime >= value.startTime && that.currentTime < value.startTime + value.duration;
|
|
8864
|
-
if (current)
|
|
8835
|
+
if (current)
|
|
8865
8836
|
publish(that, 'movie.change.layer.add', { layer: value });
|
|
8866
|
-
}
|
|
8867
8837
|
publish(that, 'movie.change.duration', { oldDuration: oldDuration });
|
|
8868
8838
|
}
|
|
8869
8839
|
else {
|
|
@@ -8887,14 +8857,12 @@ var etro = (function () {
|
|
|
8887
8857
|
this._lastPlayedOffset = -1;
|
|
8888
8858
|
// newThis._updateInterval = 0.1; // time in seconds between each "timeupdate" event
|
|
8889
8859
|
// newThis._lastUpdate = -1;
|
|
8890
|
-
if (newThis.autoRefresh)
|
|
8860
|
+
if (newThis.autoRefresh)
|
|
8891
8861
|
newThis.refresh(); // render single frame on creation
|
|
8892
|
-
}
|
|
8893
8862
|
// Subscribe to own event "change" (child events propogate up)
|
|
8894
8863
|
subscribe(newThis, 'movie.change', function () {
|
|
8895
|
-
if (newThis.autoRefresh && !newThis.rendering)
|
|
8864
|
+
if (newThis.autoRefresh && !newThis.rendering)
|
|
8896
8865
|
newThis.refresh();
|
|
8897
|
-
}
|
|
8898
8866
|
});
|
|
8899
8867
|
// Subscribe to own event "ended"
|
|
8900
8868
|
subscribe(newThis, 'movie.recordended', function () {
|
|
@@ -8912,16 +8880,14 @@ var etro = (function () {
|
|
|
8912
8880
|
Movie.prototype.play = function () {
|
|
8913
8881
|
var _this = this;
|
|
8914
8882
|
return new Promise(function (resolve) {
|
|
8915
|
-
if (!_this.paused)
|
|
8883
|
+
if (!_this.paused)
|
|
8916
8884
|
throw new Error('Already playing');
|
|
8917
|
-
}
|
|
8918
8885
|
_this._paused = _this._ended = false;
|
|
8919
8886
|
_this._lastPlayed = performance.now();
|
|
8920
8887
|
_this._lastPlayedOffset = _this.currentTime;
|
|
8921
|
-
if (!_this.renderingFrame)
|
|
8888
|
+
if (!_this.renderingFrame)
|
|
8922
8889
|
// Not rendering (and not playing), so play.
|
|
8923
8890
|
_this._render(true, undefined, resolve);
|
|
8924
|
-
}
|
|
8925
8891
|
// Stop rendering frame if currently doing so, because playing has higher
|
|
8926
8892
|
// priority. This will effect the next _render call.
|
|
8927
8893
|
_this._renderingFrame = false;
|
|
@@ -8945,12 +8911,13 @@ var etro = (function () {
|
|
|
8945
8911
|
// TODO: improve recording performance to increase frame rate?
|
|
8946
8912
|
Movie.prototype.record = function (options) {
|
|
8947
8913
|
var _this = this;
|
|
8948
|
-
if (options.video === false && options.audio === false)
|
|
8914
|
+
if (options.video === false && options.audio === false)
|
|
8949
8915
|
throw new Error('Both video and audio cannot be disabled');
|
|
8950
|
-
|
|
8951
|
-
if (!this.paused) {
|
|
8916
|
+
if (!this.paused)
|
|
8952
8917
|
throw new Error('Cannot record movie while already playing or recording');
|
|
8953
|
-
|
|
8918
|
+
var mimeType = options.type || 'video/webm';
|
|
8919
|
+
if (MediaRecorder && MediaRecorder.isTypeSupported && !MediaRecorder.isTypeSupported(mimeType))
|
|
8920
|
+
throw new Error('Please pass a valid MIME type for the exported video');
|
|
8954
8921
|
return new Promise(function (resolve, reject) {
|
|
8955
8922
|
var canvasCache = _this.canvas;
|
|
8956
8923
|
// Record on a temporary canvas context
|
|
@@ -8978,12 +8945,12 @@ var etro = (function () {
|
|
|
8978
8945
|
publish(_this, 'movie.audiodestinationupdate', { movie: _this, destination: audioDestination });
|
|
8979
8946
|
}
|
|
8980
8947
|
var stream = new MediaStream(tracks);
|
|
8981
|
-
var
|
|
8948
|
+
var mediaRecorderOptions = __assign(__assign({}, (options.mediaRecorderOptions || {})), { mimeType: mimeType });
|
|
8949
|
+
var mediaRecorder = new MediaRecorder(stream, mediaRecorderOptions);
|
|
8982
8950
|
mediaRecorder.ondataavailable = function (event) {
|
|
8983
8951
|
// if (this._paused) reject(new Error("Recording was interrupted"));
|
|
8984
|
-
if (event.data.size > 0)
|
|
8952
|
+
if (event.data.size > 0)
|
|
8985
8953
|
recordedChunks.push(event.data);
|
|
8986
|
-
}
|
|
8987
8954
|
};
|
|
8988
8955
|
// TODO: publish to movie, not layers
|
|
8989
8956
|
mediaRecorder.onstop = function () {
|
|
@@ -8994,7 +8961,7 @@ var etro = (function () {
|
|
|
8994
8961
|
_this._mediaRecorder = null;
|
|
8995
8962
|
// Construct the exported video out of all the frame blobs.
|
|
8996
8963
|
resolve(new Blob(recordedChunks, {
|
|
8997
|
-
type:
|
|
8964
|
+
type: mimeType
|
|
8998
8965
|
}));
|
|
8999
8966
|
};
|
|
9000
8967
|
mediaRecorder.onerror = reject;
|
|
@@ -9012,11 +8979,12 @@ var etro = (function () {
|
|
|
9012
8979
|
Movie.prototype.pause = function () {
|
|
9013
8980
|
this._paused = true;
|
|
9014
8981
|
// Deactivate all layers
|
|
9015
|
-
for (var i = 0; i < this.layers.length; i++)
|
|
9016
|
-
|
|
9017
|
-
|
|
9018
|
-
|
|
9019
|
-
|
|
8982
|
+
for (var i = 0; i < this.layers.length; i++)
|
|
8983
|
+
if (Object.prototype.hasOwnProperty.call(this.layers, i)) {
|
|
8984
|
+
var layer = this.layers[i];
|
|
8985
|
+
layer.stop();
|
|
8986
|
+
layer.active = false;
|
|
8987
|
+
}
|
|
9020
8988
|
publish(this, 'movie.pause', {});
|
|
9021
8989
|
return this;
|
|
9022
8990
|
};
|
|
@@ -9042,17 +9010,15 @@ var etro = (function () {
|
|
|
9042
9010
|
if (!this.rendering) {
|
|
9043
9011
|
// (!this.paused || this._renderingFrame) is true so it's playing or it's
|
|
9044
9012
|
// rendering a single frame.
|
|
9045
|
-
if (done)
|
|
9013
|
+
if (done)
|
|
9046
9014
|
done();
|
|
9047
|
-
}
|
|
9048
9015
|
return;
|
|
9049
9016
|
}
|
|
9050
9017
|
this._updateCurrentTime(timestamp);
|
|
9051
9018
|
var recordingEnd = this.recording ? this._recordEndTime : this.duration;
|
|
9052
9019
|
var recordingEnded = this.currentTime > recordingEnd;
|
|
9053
|
-
if (recordingEnded)
|
|
9020
|
+
if (recordingEnded)
|
|
9054
9021
|
publish(this, 'movie.recordended', { movie: this });
|
|
9055
|
-
}
|
|
9056
9022
|
// Bad for performance? (remember, it's calling Array.reduce)
|
|
9057
9023
|
var end = this.duration;
|
|
9058
9024
|
var ended = this.currentTime > end;
|
|
@@ -9067,41 +9033,38 @@ var etro = (function () {
|
|
|
9067
9033
|
if (!this.repeat || this.recording) {
|
|
9068
9034
|
this._ended = true;
|
|
9069
9035
|
// Deactivate all layers
|
|
9070
|
-
for (var i = 0; i < this.layers.length; i++)
|
|
9071
|
-
|
|
9072
|
-
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9036
|
+
for (var i = 0; i < this.layers.length; i++)
|
|
9037
|
+
if (Object.prototype.hasOwnProperty.call(this.layers, i)) {
|
|
9038
|
+
var layer = this.layers[i];
|
|
9039
|
+
// A layer that has been deleted before layers.length has been updated
|
|
9040
|
+
// (see the layers proxy in the constructor).
|
|
9041
|
+
if (!layer)
|
|
9042
|
+
continue;
|
|
9043
|
+
layer.stop();
|
|
9044
|
+
layer.active = false;
|
|
9076
9045
|
}
|
|
9077
|
-
layer.stop();
|
|
9078
|
-
layer.active = false;
|
|
9079
|
-
}
|
|
9080
9046
|
}
|
|
9081
9047
|
}
|
|
9082
9048
|
// Stop playback or recording if done
|
|
9083
9049
|
if (recordingEnded || (ended && !this.repeat)) {
|
|
9084
|
-
if (done)
|
|
9050
|
+
if (done)
|
|
9085
9051
|
done();
|
|
9086
|
-
}
|
|
9087
9052
|
return;
|
|
9088
9053
|
}
|
|
9089
9054
|
// Do render
|
|
9090
9055
|
this._renderBackground(timestamp);
|
|
9091
9056
|
var frameFullyLoaded = this._renderLayers();
|
|
9092
9057
|
this._applyEffects();
|
|
9093
|
-
if (frameFullyLoaded)
|
|
9058
|
+
if (frameFullyLoaded)
|
|
9094
9059
|
publish(this, 'movie.loadeddata', { movie: this });
|
|
9095
|
-
}
|
|
9096
9060
|
// If didn't load in this instant, repeatedly frame-render until frame is
|
|
9097
9061
|
// loaded.
|
|
9098
9062
|
// If the expression below is false, don't publish an event, just silently
|
|
9099
9063
|
// stop render loop.
|
|
9100
9064
|
if (!repeat || (this._renderingFrame && frameFullyLoaded)) {
|
|
9101
9065
|
this._renderingFrame = false;
|
|
9102
|
-
if (done)
|
|
9066
|
+
if (done)
|
|
9103
9067
|
done();
|
|
9104
|
-
}
|
|
9105
9068
|
return;
|
|
9106
9069
|
}
|
|
9107
9070
|
window.requestAnimationFrame(function (timestamp) {
|
|
@@ -9136,12 +9099,13 @@ var etro = (function () {
|
|
|
9136
9099
|
Movie.prototype._renderLayers = function () {
|
|
9137
9100
|
var frameFullyLoaded = true;
|
|
9138
9101
|
for (var i = 0; i < this.layers.length; i++) {
|
|
9102
|
+
if (!Object.prototype.hasOwnProperty.call(this.layers, i))
|
|
9103
|
+
continue;
|
|
9139
9104
|
var layer = this.layers[i];
|
|
9140
9105
|
// A layer that has been deleted before layers.length has been updated
|
|
9141
9106
|
// (see the layers proxy in the constructor).
|
|
9142
|
-
if (!layer)
|
|
9107
|
+
if (!layer)
|
|
9143
9108
|
continue;
|
|
9144
|
-
}
|
|
9145
9109
|
var reltime = this.currentTime - layer.startTime;
|
|
9146
9110
|
// Cancel operation if layer disabled or outside layer time interval
|
|
9147
9111
|
if (!val(layer, 'enabled', reltime) ||
|
|
@@ -9163,18 +9127,16 @@ var etro = (function () {
|
|
|
9163
9127
|
layer.active = true;
|
|
9164
9128
|
}
|
|
9165
9129
|
// if the layer has an input file
|
|
9166
|
-
if ('source' in layer)
|
|
9130
|
+
if ('source' in layer)
|
|
9167
9131
|
frameFullyLoaded = frameFullyLoaded && layer.source.readyState >= 2;
|
|
9168
|
-
}
|
|
9169
9132
|
layer.render();
|
|
9170
9133
|
// if the layer has visual component
|
|
9171
9134
|
if (layer instanceof Visual) {
|
|
9172
9135
|
var canvas = layer.canvas;
|
|
9173
9136
|
// layer.canvas.width and layer.canvas.height should already be interpolated
|
|
9174
9137
|
// if the layer has an area (else InvalidStateError from canvas)
|
|
9175
|
-
if (canvas.width * canvas.height > 0)
|
|
9138
|
+
if (canvas.width * canvas.height > 0)
|
|
9176
9139
|
this.cctx.drawImage(canvas, val(layer, 'x', reltime), val(layer, 'y', reltime), canvas.width, canvas.height);
|
|
9177
|
-
}
|
|
9178
9140
|
}
|
|
9179
9141
|
}
|
|
9180
9142
|
return frameFullyLoaded;
|
|
@@ -9184,9 +9146,8 @@ var etro = (function () {
|
|
|
9184
9146
|
var effect = this.effects[i];
|
|
9185
9147
|
// An effect that has been deleted before effects.length has been updated
|
|
9186
9148
|
// (see the effectsproxy in the constructor).
|
|
9187
|
-
if (!effect)
|
|
9149
|
+
if (!effect)
|
|
9188
9150
|
continue;
|
|
9189
|
-
}
|
|
9190
9151
|
effect.apply(this, this.currentTime);
|
|
9191
9152
|
}
|
|
9192
9153
|
};
|
|
@@ -9205,9 +9166,9 @@ var etro = (function () {
|
|
|
9205
9166
|
* Convienence method
|
|
9206
9167
|
*/
|
|
9207
9168
|
Movie.prototype._publishToLayers = function (type, event) {
|
|
9208
|
-
for (var i = 0; i < this.layers.length; i++)
|
|
9209
|
-
|
|
9210
|
-
|
|
9169
|
+
for (var i = 0; i < this.layers.length; i++)
|
|
9170
|
+
if (Object.prototype.hasOwnProperty.call(this.layers, i))
|
|
9171
|
+
publish(this.layers[i], type, event);
|
|
9211
9172
|
};
|
|
9212
9173
|
Object.defineProperty(Movie.prototype, "rendering", {
|
|
9213
9174
|
/**
|
|
@@ -9320,13 +9281,11 @@ var etro = (function () {
|
|
|
9320
9281
|
return new Promise(function (resolve, reject) {
|
|
9321
9282
|
_this._currentTime = time;
|
|
9322
9283
|
publish(_this, 'movie.seek', {});
|
|
9323
|
-
if (refresh)
|
|
9284
|
+
if (refresh)
|
|
9324
9285
|
// Pass promise callbacks to `refresh`
|
|
9325
9286
|
_this.refresh().then(resolve).catch(reject);
|
|
9326
|
-
|
|
9327
|
-
else {
|
|
9287
|
+
else
|
|
9328
9288
|
resolve();
|
|
9329
|
-
}
|
|
9330
9289
|
});
|
|
9331
9290
|
};
|
|
9332
9291
|
Object.defineProperty(Movie.prototype, "canvas", {
|