@next2d/media 1.14.20
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/LICENSE +21 -0
- package/README.md +11 -0
- package/dist/Sound.d.ts +206 -0
- package/dist/Sound.js +501 -0
- package/dist/SoundMixer.d.ts +68 -0
- package/dist/SoundMixer.js +114 -0
- package/dist/SoundTransform.d.ts +80 -0
- package/dist/SoundTransform.js +111 -0
- package/dist/Video.d.ts +326 -0
- package/dist/Video.js +855 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/package.json +45 -0
package/dist/Video.js
ADDED
|
@@ -0,0 +1,855 @@
|
|
|
1
|
+
import { SoundMixer } from "./SoundMixer";
|
|
2
|
+
import { DisplayObject } from "@next2d/display";
|
|
3
|
+
import { VideoEvent } from "@next2d/events";
|
|
4
|
+
import { Rectangle } from "@next2d/geom";
|
|
5
|
+
import { $document, $audioContext, $currentPlayer, $isTouch, $rendererWorker } from "@next2d/util";
|
|
6
|
+
import { $Math, $cancelAnimationFrame, $requestAnimationFrame, $getBoundsObject, $boundsMatrix, $clamp, $multiplicationMatrix, $poolFloat32Array6, $MATRIX_ARRAY_IDENTITY, $OffscreenCanvas, $multiplicationColor, $poolFloat32Array8, $Infinity, $poolBoundsObject, $getFloat32Array6, $getArray, $poolArray } from "@next2d/share";
|
|
7
|
+
/**
|
|
8
|
+
* サーバーまたはローカルに保存された録画済みビデオファイルを再生する Video オブジェクトです。
|
|
9
|
+
* ビデオストリームを再生するには、attachNetStream() を使用して、ビデオを Video オブジェクトに関連付けます。
|
|
10
|
+
* 次に、addChild() を使用して、Video オブジェクトを表示リストに追加します。
|
|
11
|
+
*
|
|
12
|
+
* A Video object that plays a recorded video file stored on a server or locally.
|
|
13
|
+
* To play a video stream, use attachNetStream() to attach the video to the Video object.
|
|
14
|
+
* Then, add the Video object to the display list using addChild().
|
|
15
|
+
*
|
|
16
|
+
* @class
|
|
17
|
+
* @memberOf next2d.media
|
|
18
|
+
* @extends DisplayObject
|
|
19
|
+
*/
|
|
20
|
+
export class Video extends DisplayObject {
|
|
21
|
+
/**
|
|
22
|
+
* @param {number} [width = 0]
|
|
23
|
+
* @param {number} [height = 0]
|
|
24
|
+
*
|
|
25
|
+
* @constructor
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
constructor(width = 0, height = 0) {
|
|
29
|
+
super();
|
|
30
|
+
/**
|
|
31
|
+
* @type {boolean}
|
|
32
|
+
* @default true
|
|
33
|
+
* @private
|
|
34
|
+
*/
|
|
35
|
+
this._$smoothing = true;
|
|
36
|
+
/**
|
|
37
|
+
* @type {boolean}
|
|
38
|
+
* @default false
|
|
39
|
+
* @private
|
|
40
|
+
*/
|
|
41
|
+
this._$loop = false;
|
|
42
|
+
/**
|
|
43
|
+
* @type {boolean}
|
|
44
|
+
* @default true
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
this._$autoPlay = true;
|
|
48
|
+
/**
|
|
49
|
+
* @type {object}
|
|
50
|
+
* @private
|
|
51
|
+
*/
|
|
52
|
+
this._$bounds = $getBoundsObject(0, width, 0, height);
|
|
53
|
+
/**
|
|
54
|
+
* @type {number}
|
|
55
|
+
* @default 0
|
|
56
|
+
* @private
|
|
57
|
+
*/
|
|
58
|
+
this._$bytesLoaded = 0;
|
|
59
|
+
/**
|
|
60
|
+
* @type {number}
|
|
61
|
+
* @default 0
|
|
62
|
+
* @private
|
|
63
|
+
*/
|
|
64
|
+
this._$bytesTotal = 0;
|
|
65
|
+
/**
|
|
66
|
+
* @type {number}
|
|
67
|
+
* @default -1
|
|
68
|
+
* @private
|
|
69
|
+
*/
|
|
70
|
+
this._$timerId = -1;
|
|
71
|
+
/**
|
|
72
|
+
* @type {HTMLVideoElement}
|
|
73
|
+
* @default null
|
|
74
|
+
* @private
|
|
75
|
+
*/
|
|
76
|
+
this._$video = null;
|
|
77
|
+
/**
|
|
78
|
+
* @type {boolean}
|
|
79
|
+
* @default true
|
|
80
|
+
* @private
|
|
81
|
+
*/
|
|
82
|
+
this._$stop = true;
|
|
83
|
+
/**
|
|
84
|
+
* @type {boolean}
|
|
85
|
+
* @default false
|
|
86
|
+
* @private
|
|
87
|
+
*/
|
|
88
|
+
this._$ready = false;
|
|
89
|
+
/**
|
|
90
|
+
* @type {number}
|
|
91
|
+
* @default 1
|
|
92
|
+
* @private
|
|
93
|
+
*/
|
|
94
|
+
this._$volume = 1;
|
|
95
|
+
/**
|
|
96
|
+
* @type {CanvasRenderingContext2D}
|
|
97
|
+
* @default null
|
|
98
|
+
* @private
|
|
99
|
+
*/
|
|
100
|
+
this._$context = null;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* @description 指定されたクラスのストリングを返します。
|
|
104
|
+
* Returns the string representation of the specified class.
|
|
105
|
+
*
|
|
106
|
+
* @return {string}
|
|
107
|
+
* @default [class Video]
|
|
108
|
+
* @method
|
|
109
|
+
* @static
|
|
110
|
+
*/
|
|
111
|
+
static toString() {
|
|
112
|
+
return "[class Video]";
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* @description 指定されたクラスの空間名を返します。
|
|
116
|
+
* Returns the space name of the specified class.
|
|
117
|
+
*
|
|
118
|
+
* @return {string}
|
|
119
|
+
* @default next2d.media.Video
|
|
120
|
+
* @const
|
|
121
|
+
* @static
|
|
122
|
+
*/
|
|
123
|
+
static get namespace() {
|
|
124
|
+
return "next2d.media.Video";
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* @description 指定されたオブジェクトのストリングを返します。
|
|
128
|
+
* Returns the string representation of the specified object.
|
|
129
|
+
*
|
|
130
|
+
* @return {string}
|
|
131
|
+
* @default [object Video]
|
|
132
|
+
* @method
|
|
133
|
+
* @public
|
|
134
|
+
*/
|
|
135
|
+
toString() {
|
|
136
|
+
return "[object Video]";
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* @description 指定されたオブジェクトの空間名を返します。
|
|
140
|
+
* Returns the space name of the specified object.
|
|
141
|
+
*
|
|
142
|
+
* @return {string}
|
|
143
|
+
* @default next2d.media.Video
|
|
144
|
+
* @const
|
|
145
|
+
* @public
|
|
146
|
+
*/
|
|
147
|
+
get namespace() {
|
|
148
|
+
return "next2d.media.Video";
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* @description 既にアプリケーションにロードされているデータのバイト数です。
|
|
152
|
+
* The number of bytes of data that have been loaded into the application.
|
|
153
|
+
*
|
|
154
|
+
* @member {number}
|
|
155
|
+
* @default 0
|
|
156
|
+
* @readonly
|
|
157
|
+
* @public
|
|
158
|
+
*/
|
|
159
|
+
get bytesLoaded() {
|
|
160
|
+
return this._$bytesLoaded;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* @description アプリケーションにロードされるファイルの総バイト数。
|
|
164
|
+
* The total size in bytes of the file being loaded into the application.
|
|
165
|
+
*
|
|
166
|
+
* @member {number}
|
|
167
|
+
* @default 0
|
|
168
|
+
* @readonly
|
|
169
|
+
* @public
|
|
170
|
+
*/
|
|
171
|
+
get bytesTotal() {
|
|
172
|
+
return this._$bytesTotal;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* @description 現在のキーフレーム
|
|
176
|
+
* Current keyframe
|
|
177
|
+
*
|
|
178
|
+
*
|
|
179
|
+
* @member {number}
|
|
180
|
+
* @readonly
|
|
181
|
+
* @public
|
|
182
|
+
*/
|
|
183
|
+
get currentTime() {
|
|
184
|
+
return this._$video ? this._$video.currentTime : 0;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* @description キーフレーム総数
|
|
188
|
+
* Total number of keyframes
|
|
189
|
+
*
|
|
190
|
+
* @member {number}
|
|
191
|
+
* @readonly
|
|
192
|
+
* @public
|
|
193
|
+
*/
|
|
194
|
+
get duration() {
|
|
195
|
+
return this._$video ? this._$video.duration : 0;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* @description ビデオをループ生成するかどうかを指定します。
|
|
199
|
+
* Specifies whether to generate a video loop.
|
|
200
|
+
*
|
|
201
|
+
* @member {boolean}
|
|
202
|
+
* @default false
|
|
203
|
+
* @public
|
|
204
|
+
*/
|
|
205
|
+
get loop() {
|
|
206
|
+
return this._$loop;
|
|
207
|
+
}
|
|
208
|
+
set loop(loop) {
|
|
209
|
+
this._$loop = !!loop;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* @description ビデオの自動再生の設定。
|
|
213
|
+
* Setting up automatic video playback.
|
|
214
|
+
*
|
|
215
|
+
* @member {boolean}
|
|
216
|
+
* @default true
|
|
217
|
+
* @public
|
|
218
|
+
*/
|
|
219
|
+
get autoPlay() {
|
|
220
|
+
return this._$autoPlay;
|
|
221
|
+
}
|
|
222
|
+
set autoPlay(auto_play) {
|
|
223
|
+
this._$autoPlay = !!auto_play;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* @description ビデオを拡大 / 縮小する際にスムージング(補間)するかどうかを指定します。
|
|
227
|
+
* Specifies whether the video should be smoothed (interpolated)
|
|
228
|
+
* when it is scaled.
|
|
229
|
+
*
|
|
230
|
+
* @member {boolean}
|
|
231
|
+
* @default true
|
|
232
|
+
* @public
|
|
233
|
+
*/
|
|
234
|
+
get smoothing() {
|
|
235
|
+
return this._$smoothing;
|
|
236
|
+
}
|
|
237
|
+
set smoothing(smoothing) {
|
|
238
|
+
this._$smoothing = !!smoothing;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* @description 映像コンテンツへの URL を指定します。
|
|
242
|
+
* Specifies the URL to the video content.
|
|
243
|
+
*
|
|
244
|
+
* @member {string}
|
|
245
|
+
* @default ""
|
|
246
|
+
* @public
|
|
247
|
+
*/
|
|
248
|
+
get src() {
|
|
249
|
+
return this._$video ? this._$video.src : "";
|
|
250
|
+
}
|
|
251
|
+
set src(src) {
|
|
252
|
+
if (!this._$video) {
|
|
253
|
+
this._$video = this._$initializeVideo();
|
|
254
|
+
}
|
|
255
|
+
this._$video.src = src;
|
|
256
|
+
this._$video.load();
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* @description ビデオストリームの高さをピクセル単位で指定する整数です。
|
|
260
|
+
* An integer specifying the height of the video stream, in pixels.
|
|
261
|
+
*
|
|
262
|
+
* @member {number}
|
|
263
|
+
* @default 320
|
|
264
|
+
* @readonly
|
|
265
|
+
* @public
|
|
266
|
+
*/
|
|
267
|
+
get videoHeight() {
|
|
268
|
+
return this._$video ? this._$video.videoHeight : this._$bounds.yMax;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* @description ビデオストリームの幅をピクセル単位で指定する整数です。
|
|
272
|
+
* An integer specifying the width of the video stream, in pixels.
|
|
273
|
+
*
|
|
274
|
+
* @member {number}
|
|
275
|
+
* @default 240
|
|
276
|
+
* @readonly
|
|
277
|
+
* @public
|
|
278
|
+
*/
|
|
279
|
+
get videoWidth() {
|
|
280
|
+
return this._$video ? this._$video.videoWidth : this._$bounds.xMax;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* @description ボリュームです。範囲は 0(無音)~ 1(フルボリューム)です。
|
|
284
|
+
* The volume, ranging from 0 (silent) to 1 (full volume).
|
|
285
|
+
*
|
|
286
|
+
* @member {number}
|
|
287
|
+
* @default 1
|
|
288
|
+
* @public
|
|
289
|
+
*/
|
|
290
|
+
get volume() {
|
|
291
|
+
return this._$volume;
|
|
292
|
+
}
|
|
293
|
+
set volume(volume) {
|
|
294
|
+
this._$volume = $clamp($Math.min(SoundMixer.volume, volume), 0, 1, 1);
|
|
295
|
+
if (this._$video) {
|
|
296
|
+
this._$video.volume = this._$volume;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* @description Video オブジェクトに現在表示されているイメージ(ビデオストリームではない)をクリアします。
|
|
301
|
+
* Clears the image currently displayed
|
|
302
|
+
* in the Video object (not the video stream).
|
|
303
|
+
*
|
|
304
|
+
* @return {void}
|
|
305
|
+
* @method
|
|
306
|
+
* @public
|
|
307
|
+
*/
|
|
308
|
+
clear() {
|
|
309
|
+
if (this._$video) {
|
|
310
|
+
this._$video.pause();
|
|
311
|
+
}
|
|
312
|
+
// reset
|
|
313
|
+
this._$video = null;
|
|
314
|
+
this._$bounds.xMax = 0;
|
|
315
|
+
this._$bounds.yMax = 0;
|
|
316
|
+
this._$doChanged();
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* @description ビデオストリームの再生を一時停止します。
|
|
320
|
+
* Pauses playback of a video stream.
|
|
321
|
+
*
|
|
322
|
+
* @return {void}
|
|
323
|
+
* @method
|
|
324
|
+
* @public
|
|
325
|
+
*/
|
|
326
|
+
pause() {
|
|
327
|
+
if (this._$video && !this._$stop) {
|
|
328
|
+
this._$stop = true;
|
|
329
|
+
this._$video.pause();
|
|
330
|
+
$cancelAnimationFrame(this._$timerId);
|
|
331
|
+
this._$timerId = -1;
|
|
332
|
+
if (this.hasEventListener(VideoEvent.PAUSE)) {
|
|
333
|
+
this.dispatchEvent(new VideoEvent(VideoEvent.PAUSE, false, false, this._$bytesLoaded, this._$bytesTotal));
|
|
334
|
+
}
|
|
335
|
+
const player = $currentPlayer();
|
|
336
|
+
player._$videos.splice(player._$videos.indexOf(this), 1);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* @description ローカルディレクトリまたは Web サーバーからメディアファイルを再生します。
|
|
341
|
+
* Plays a media file from a local directory or a web server;
|
|
342
|
+
*
|
|
343
|
+
* @returns {void}
|
|
344
|
+
* @method
|
|
345
|
+
* @public
|
|
346
|
+
*/
|
|
347
|
+
play() {
|
|
348
|
+
if (this._$video && this._$stop) {
|
|
349
|
+
this._$stop = false;
|
|
350
|
+
this._$video.volume = $Math.min(this._$volume, SoundMixer.volume);
|
|
351
|
+
this
|
|
352
|
+
._$video
|
|
353
|
+
.play()
|
|
354
|
+
.then(() => {
|
|
355
|
+
this._$timerId = $requestAnimationFrame(() => {
|
|
356
|
+
this._$update();
|
|
357
|
+
});
|
|
358
|
+
if (this.hasEventListener(VideoEvent.PLAY)) {
|
|
359
|
+
this.dispatchEvent(new VideoEvent(VideoEvent.PLAY, false, false, this._$bytesLoaded, this._$bytesTotal));
|
|
360
|
+
}
|
|
361
|
+
const player = $currentPlayer();
|
|
362
|
+
if (player._$videos.indexOf(this) === -1) {
|
|
363
|
+
player._$videos.push(this);
|
|
364
|
+
}
|
|
365
|
+
this._$ready = true;
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* @description 指定された位置に最も近いキーフレームをシークします。
|
|
371
|
+
* Seeks the keyframe closest to the specified location.
|
|
372
|
+
*
|
|
373
|
+
* @param {number} offset
|
|
374
|
+
* @return {void}
|
|
375
|
+
* @method
|
|
376
|
+
* @public
|
|
377
|
+
*/
|
|
378
|
+
seek(offset) {
|
|
379
|
+
if (this._$video) {
|
|
380
|
+
this._$video.currentTime = offset;
|
|
381
|
+
if (this.hasEventListener(VideoEvent.SEEK)) {
|
|
382
|
+
this.dispatchEvent(new VideoEvent(VideoEvent.SEEK, false, false, this._$bytesLoaded, this._$bytesTotal));
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* @return {void}
|
|
388
|
+
* @method
|
|
389
|
+
* @private
|
|
390
|
+
*/
|
|
391
|
+
_$update() {
|
|
392
|
+
const player = $currentPlayer();
|
|
393
|
+
if (!this.stage || !this._$video) {
|
|
394
|
+
if (this._$video) {
|
|
395
|
+
this._$video.pause();
|
|
396
|
+
}
|
|
397
|
+
$cancelAnimationFrame(this._$timerId);
|
|
398
|
+
this._$timerId = -1;
|
|
399
|
+
player._$videos.splice(player._$videos.indexOf(this), 1);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if ($rendererWorker) {
|
|
403
|
+
this._$postProperty();
|
|
404
|
+
}
|
|
405
|
+
// update
|
|
406
|
+
this._$bytesLoaded = this._$video.currentTime;
|
|
407
|
+
if (this._$video.currentTime) {
|
|
408
|
+
if (this.hasEventListener(VideoEvent.PROGRESS)) {
|
|
409
|
+
this.dispatchEvent(new VideoEvent(VideoEvent.PROGRESS, false, false, this._$bytesLoaded, this._$bytesTotal));
|
|
410
|
+
}
|
|
411
|
+
this._$doChanged();
|
|
412
|
+
}
|
|
413
|
+
this._$timerId = $requestAnimationFrame(() => {
|
|
414
|
+
this._$update();
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* @return {void}
|
|
419
|
+
* @method
|
|
420
|
+
* @private
|
|
421
|
+
*/
|
|
422
|
+
_$start() {
|
|
423
|
+
if (!this._$video) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
this._$bounds.xMax = this._$video.videoWidth;
|
|
427
|
+
this._$bounds.yMax = this._$video.videoHeight;
|
|
428
|
+
this._$bytesTotal = this._$video.duration;
|
|
429
|
+
const player = $currentPlayer();
|
|
430
|
+
if (this._$autoPlay) {
|
|
431
|
+
this._$stop = false;
|
|
432
|
+
this
|
|
433
|
+
._$video
|
|
434
|
+
.play()
|
|
435
|
+
.then(() => {
|
|
436
|
+
if (player._$videos.indexOf(this) === -1) {
|
|
437
|
+
player._$videos.push(this);
|
|
438
|
+
}
|
|
439
|
+
if (this.hasEventListener(VideoEvent.PLAY_START)) {
|
|
440
|
+
this.dispatchEvent(new VideoEvent(VideoEvent.PLAY_START, false, false, this._$bytesLoaded, this._$bytesTotal));
|
|
441
|
+
}
|
|
442
|
+
this._$timerId = $requestAnimationFrame(() => {
|
|
443
|
+
this._$update();
|
|
444
|
+
});
|
|
445
|
+
this._$ready = true;
|
|
446
|
+
this._$doChanged();
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
this._$createContext();
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* @return {HTMLVideoElement}
|
|
453
|
+
* @method
|
|
454
|
+
* @private
|
|
455
|
+
*/
|
|
456
|
+
_$initializeVideo() {
|
|
457
|
+
const video = $document.createElement("video");
|
|
458
|
+
video.autoplay = false;
|
|
459
|
+
video.crossOrigin = "anonymous";
|
|
460
|
+
if (!$audioContext) {
|
|
461
|
+
video.muted = true;
|
|
462
|
+
}
|
|
463
|
+
if ($isTouch) {
|
|
464
|
+
video.setAttribute("playsinline", "");
|
|
465
|
+
}
|
|
466
|
+
video.addEventListener("canplaythrough", () => {
|
|
467
|
+
this._$start();
|
|
468
|
+
});
|
|
469
|
+
video.addEventListener("ended", () => {
|
|
470
|
+
if (this._$loop) {
|
|
471
|
+
video.currentTime = 0;
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
if (this.hasEventListener(VideoEvent.PLAY_END)) {
|
|
475
|
+
this.dispatchEvent(new VideoEvent(VideoEvent.PLAY_END, false, false, this._$bytesLoaded, this._$bytesTotal));
|
|
476
|
+
}
|
|
477
|
+
$cancelAnimationFrame(this._$timerId);
|
|
478
|
+
this._$timerId = -1;
|
|
479
|
+
});
|
|
480
|
+
return video;
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* @return {void}
|
|
484
|
+
* @method
|
|
485
|
+
* @private
|
|
486
|
+
*/
|
|
487
|
+
_$createContext() {
|
|
488
|
+
if ($rendererWorker) {
|
|
489
|
+
const canvas = new $OffscreenCanvas(this._$bounds.xMax, this._$bounds.yMax);
|
|
490
|
+
this._$context = canvas.getContext("2d");
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* @param {object} character
|
|
495
|
+
* @return {void}
|
|
496
|
+
* @method
|
|
497
|
+
* @private
|
|
498
|
+
*/
|
|
499
|
+
_$buildCharacter(character) {
|
|
500
|
+
if (character.buffer && !character._$buffer) {
|
|
501
|
+
character._$buffer = new Uint8Array(character.buffer);
|
|
502
|
+
character.buffer = null;
|
|
503
|
+
}
|
|
504
|
+
this._$loop = character.loop;
|
|
505
|
+
this._$autoPlay = character.autoPlay;
|
|
506
|
+
this._$bounds.xMin = character.bounds.xMin;
|
|
507
|
+
this._$bounds.yMin = character.bounds.yMin;
|
|
508
|
+
this._$bounds.xMax = character.bounds.xMax;
|
|
509
|
+
this._$bounds.yMax = character.bounds.yMax;
|
|
510
|
+
if (!this._$video) {
|
|
511
|
+
this._$video = this._$initializeVideo();
|
|
512
|
+
}
|
|
513
|
+
this._$video.src = URL.createObjectURL(new Blob([character._$buffer], { "type": "video/mp4" }));
|
|
514
|
+
// setup
|
|
515
|
+
this._$video.volume = $Math.min(character.volume, SoundMixer.volume);
|
|
516
|
+
this._$video.load();
|
|
517
|
+
if ($rendererWorker && this._$stage) {
|
|
518
|
+
this._$createWorkerInstance();
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* @param {object} character
|
|
523
|
+
* @return {void}
|
|
524
|
+
* @method
|
|
525
|
+
* @private
|
|
526
|
+
*/
|
|
527
|
+
_$sync(character) {
|
|
528
|
+
this._$buildCharacter(character);
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* @param {object} tag
|
|
532
|
+
* @param {DisplayObjectContainer} parent
|
|
533
|
+
* @return {object}
|
|
534
|
+
* @method
|
|
535
|
+
* @private
|
|
536
|
+
*/
|
|
537
|
+
_$build(tag, parent) {
|
|
538
|
+
const character = this._$baseBuild(tag, parent);
|
|
539
|
+
this._$buildCharacter(character);
|
|
540
|
+
return character;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* @param {CanvasToWebGLContext} context
|
|
544
|
+
* @param {Float32Array} matrix
|
|
545
|
+
* @returns {void}
|
|
546
|
+
* @method
|
|
547
|
+
* @private
|
|
548
|
+
*/
|
|
549
|
+
_$clip(context, matrix) {
|
|
550
|
+
const width = this._$bounds.xMax;
|
|
551
|
+
const height = this._$bounds.yMax;
|
|
552
|
+
if (!width || !height) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
let multiMatrix = matrix;
|
|
556
|
+
const rawMatrix = this._$transform._$rawMatrix();
|
|
557
|
+
if (rawMatrix[0] !== 1 || rawMatrix[1] !== 0
|
|
558
|
+
|| rawMatrix[2] !== 0 || rawMatrix[3] !== 1
|
|
559
|
+
|| rawMatrix[4] !== 0 || rawMatrix[5] !== 0) {
|
|
560
|
+
multiMatrix = $multiplicationMatrix(matrix, rawMatrix);
|
|
561
|
+
}
|
|
562
|
+
context.reset();
|
|
563
|
+
context.setTransform(multiMatrix[0], multiMatrix[1], multiMatrix[2], multiMatrix[3], multiMatrix[4], multiMatrix[5]);
|
|
564
|
+
context.beginPath();
|
|
565
|
+
context.moveTo(0, 0);
|
|
566
|
+
context.lineTo(width, 0);
|
|
567
|
+
context.lineTo(width, height);
|
|
568
|
+
context.lineTo(0, height);
|
|
569
|
+
context.lineTo(0, 0);
|
|
570
|
+
context.clip();
|
|
571
|
+
if (multiMatrix !== matrix) {
|
|
572
|
+
$poolFloat32Array6(multiMatrix);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* @param {CanvasToWebGLContext} context
|
|
577
|
+
* @param {Float32Array} matrix
|
|
578
|
+
* @param {Float32Array} color_transform
|
|
579
|
+
* @return {void}
|
|
580
|
+
* @method
|
|
581
|
+
* @private
|
|
582
|
+
*/
|
|
583
|
+
_$draw(context, matrix, color_transform) {
|
|
584
|
+
if (!this._$visible || !this._$video || !this._$ready) {
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
let multiColor = color_transform;
|
|
588
|
+
const rawColor = this._$transform._$rawColorTransform();
|
|
589
|
+
if (rawColor[0] !== 1 || rawColor[1] !== 1
|
|
590
|
+
|| rawColor[2] !== 1 || rawColor[3] !== 1
|
|
591
|
+
|| rawColor[4] !== 0 || rawColor[5] !== 0
|
|
592
|
+
|| rawColor[6] !== 0 || rawColor[7] !== 0) {
|
|
593
|
+
multiColor = $multiplicationColor(color_transform, rawColor);
|
|
594
|
+
}
|
|
595
|
+
const alpha = $clamp(multiColor[3] + multiColor[7] / 255, 0, 1, 0);
|
|
596
|
+
if (!alpha) {
|
|
597
|
+
if (multiColor !== color_transform) {
|
|
598
|
+
$poolFloat32Array8(multiColor);
|
|
599
|
+
}
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
let multiMatrix = matrix;
|
|
603
|
+
const rawMatrix = this._$transform._$rawMatrix();
|
|
604
|
+
if (rawMatrix[0] !== 1 || rawMatrix[1] !== 0
|
|
605
|
+
|| rawMatrix[2] !== 0 || rawMatrix[3] !== 1
|
|
606
|
+
|| rawMatrix[4] !== 0 || rawMatrix[5] !== 0) {
|
|
607
|
+
multiMatrix = $multiplicationMatrix(matrix, rawMatrix);
|
|
608
|
+
}
|
|
609
|
+
// default bounds
|
|
610
|
+
const bounds = $boundsMatrix(this._$bounds, multiMatrix);
|
|
611
|
+
const xMax = +bounds.xMax;
|
|
612
|
+
const xMin = +bounds.xMin;
|
|
613
|
+
const yMax = +bounds.yMax;
|
|
614
|
+
const yMin = +bounds.yMin;
|
|
615
|
+
$poolBoundsObject(bounds);
|
|
616
|
+
const width = $Math.ceil($Math.abs(xMax - xMin));
|
|
617
|
+
const height = $Math.ceil($Math.abs(yMax - yMin));
|
|
618
|
+
switch (true) {
|
|
619
|
+
case width === 0:
|
|
620
|
+
case height === 0:
|
|
621
|
+
case width === -$Infinity:
|
|
622
|
+
case height === -$Infinity:
|
|
623
|
+
case width === $Infinity:
|
|
624
|
+
case height === $Infinity:
|
|
625
|
+
return;
|
|
626
|
+
default:
|
|
627
|
+
break;
|
|
628
|
+
}
|
|
629
|
+
// cache current buffer
|
|
630
|
+
const manager = context.frameBuffer;
|
|
631
|
+
const currentAttachment = manager.currentAttachment;
|
|
632
|
+
if (!currentAttachment
|
|
633
|
+
|| xMin > currentAttachment.width
|
|
634
|
+
|| yMin > currentAttachment.height) {
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
const filters = this._$filters || this.filters;
|
|
638
|
+
if (0 > xMin + width || 0 > yMin + height) {
|
|
639
|
+
if (filters && filters.length && this._$canApply(filters)) {
|
|
640
|
+
const xScale = +$Math.sqrt(multiMatrix[0] * multiMatrix[0]
|
|
641
|
+
+ multiMatrix[1] * multiMatrix[1]);
|
|
642
|
+
const yScale = +$Math.sqrt(multiMatrix[2] * multiMatrix[2]
|
|
643
|
+
+ multiMatrix[3] * multiMatrix[3]);
|
|
644
|
+
let rect = new Rectangle(0, 0, width, height);
|
|
645
|
+
for (let idx = 0; idx < filters.length; ++idx) {
|
|
646
|
+
// @ts-ignore
|
|
647
|
+
rect = filters[idx]._$generateFilterRect(rect, xScale, yScale);
|
|
648
|
+
}
|
|
649
|
+
if (0 > rect.x + rect.width || 0 > rect.y + rect.height) {
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
const blendMode = this._$blendMode || this.blendMode;
|
|
658
|
+
let texture = manager.createTextureFromVideo(this._$video, this._$smoothing);
|
|
659
|
+
if (filters && filters.length
|
|
660
|
+
&& this._$canApply(filters)) {
|
|
661
|
+
const xScale = +$Math.sqrt(multiMatrix[0] * multiMatrix[0]
|
|
662
|
+
+ multiMatrix[1] * multiMatrix[1]);
|
|
663
|
+
const yScale = +$Math.sqrt(multiMatrix[2] * multiMatrix[2]
|
|
664
|
+
+ multiMatrix[3] * multiMatrix[3]);
|
|
665
|
+
if (xScale !== 1 || yScale !== 1) {
|
|
666
|
+
const currentAttachment = manager.currentAttachment;
|
|
667
|
+
// create cache buffer
|
|
668
|
+
const attachment = manager
|
|
669
|
+
.createCacheAttachment(width, height, false);
|
|
670
|
+
context._$bind(attachment);
|
|
671
|
+
const parentMatrix = $getFloat32Array6(xScale, 0, 0, yScale, width / 2, height / 2);
|
|
672
|
+
const baseMatrix = $getFloat32Array6(1, 0, 0, 1, -texture.width / 2, -texture.height / 2);
|
|
673
|
+
const scaleMatrix = $multiplicationMatrix(parentMatrix, baseMatrix);
|
|
674
|
+
$poolFloat32Array6(parentMatrix);
|
|
675
|
+
$poolFloat32Array6(baseMatrix);
|
|
676
|
+
context.reset();
|
|
677
|
+
context.setTransform(scaleMatrix[0], scaleMatrix[1], scaleMatrix[2], scaleMatrix[3], scaleMatrix[4], scaleMatrix[5]);
|
|
678
|
+
context.drawImage(texture, 0, 0, texture.width, texture.height);
|
|
679
|
+
manager.releaseTexture(texture);
|
|
680
|
+
$poolFloat32Array6(scaleMatrix);
|
|
681
|
+
texture = manager.getTextureFromCurrentAttachment();
|
|
682
|
+
// release buffer
|
|
683
|
+
manager.releaseAttachment(attachment, false);
|
|
684
|
+
// end draw and reset current buffer
|
|
685
|
+
context._$bind(currentAttachment);
|
|
686
|
+
}
|
|
687
|
+
// draw filter
|
|
688
|
+
texture = this._$drawFilter(context, texture, multiMatrix, filters, width, height);
|
|
689
|
+
// reset
|
|
690
|
+
context.reset();
|
|
691
|
+
// draw
|
|
692
|
+
context.globalAlpha = alpha;
|
|
693
|
+
context.imageSmoothingEnabled = this._$smoothing;
|
|
694
|
+
context.globalCompositeOperation = blendMode;
|
|
695
|
+
// size
|
|
696
|
+
const bounds = $boundsMatrix(this._$bounds, multiMatrix);
|
|
697
|
+
context.setTransform(1, 0, 0, 1, bounds.xMin - texture._$offsetX, bounds.yMin - texture._$offsetY);
|
|
698
|
+
context.drawImage(texture, 0, 0, texture.width, texture.height, multiColor);
|
|
699
|
+
// pool
|
|
700
|
+
$poolBoundsObject(bounds);
|
|
701
|
+
}
|
|
702
|
+
else {
|
|
703
|
+
// reset
|
|
704
|
+
context.reset();
|
|
705
|
+
context.setTransform(multiMatrix[0], multiMatrix[1], multiMatrix[2], multiMatrix[3], multiMatrix[4], multiMatrix[5]);
|
|
706
|
+
// draw
|
|
707
|
+
context.globalAlpha = alpha;
|
|
708
|
+
context.imageSmoothingEnabled = this._$smoothing;
|
|
709
|
+
context.globalCompositeOperation = blendMode;
|
|
710
|
+
context.drawImage(texture, 0, 0, texture.width, texture.height, multiColor);
|
|
711
|
+
manager.releaseTexture(texture);
|
|
712
|
+
}
|
|
713
|
+
if (multiMatrix !== matrix) {
|
|
714
|
+
$poolFloat32Array6(multiMatrix);
|
|
715
|
+
}
|
|
716
|
+
if (multiColor !== color_transform) {
|
|
717
|
+
$poolFloat32Array8(multiColor);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* @param {CanvasRenderingContext2D} context
|
|
722
|
+
* @param {Float32Array} matrix
|
|
723
|
+
* @param {object} options
|
|
724
|
+
* @return {boolean}
|
|
725
|
+
* @method
|
|
726
|
+
* @private
|
|
727
|
+
*/
|
|
728
|
+
_$mouseHit(context, matrix, options) {
|
|
729
|
+
if (!this._$visible) {
|
|
730
|
+
return false;
|
|
731
|
+
}
|
|
732
|
+
return this._$hit(context, matrix, options);
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* @param {CanvasRenderingContext2D} context
|
|
736
|
+
* @param {array} matrix
|
|
737
|
+
* @param {object} options
|
|
738
|
+
* @return {boolean}
|
|
739
|
+
* @method
|
|
740
|
+
* @private
|
|
741
|
+
*/
|
|
742
|
+
_$hit(context, matrix, options) {
|
|
743
|
+
let multiMatrix = matrix;
|
|
744
|
+
const rawMatrix = this._$transform._$rawMatrix();
|
|
745
|
+
if (rawMatrix !== $MATRIX_ARRAY_IDENTITY) {
|
|
746
|
+
multiMatrix = $multiplicationMatrix(matrix, rawMatrix);
|
|
747
|
+
}
|
|
748
|
+
const baseBounds = this._$getBounds(null);
|
|
749
|
+
const bounds = $boundsMatrix(baseBounds, multiMatrix);
|
|
750
|
+
const xMax = +bounds.xMax;
|
|
751
|
+
const xMin = +bounds.xMin;
|
|
752
|
+
const yMax = +bounds.yMax;
|
|
753
|
+
const yMin = +bounds.yMin;
|
|
754
|
+
$poolBoundsObject(bounds);
|
|
755
|
+
$poolBoundsObject(baseBounds);
|
|
756
|
+
const width = $Math.ceil($Math.abs(xMax - xMin));
|
|
757
|
+
const height = $Math.ceil($Math.abs(yMax - yMin));
|
|
758
|
+
context.setTransform(1, 0, 0, 1, xMin, yMin);
|
|
759
|
+
context.beginPath();
|
|
760
|
+
context.moveTo(0, 0);
|
|
761
|
+
context.lineTo(width, 0);
|
|
762
|
+
context.lineTo(width, height);
|
|
763
|
+
context.lineTo(0, height);
|
|
764
|
+
context.lineTo(0, 0);
|
|
765
|
+
if (multiMatrix !== matrix) {
|
|
766
|
+
$poolFloat32Array6(multiMatrix);
|
|
767
|
+
}
|
|
768
|
+
return context.isPointInPath(options.x, options.y);
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* @param {Float32Array} [matrix=null]
|
|
772
|
+
* @return {object}
|
|
773
|
+
* @method
|
|
774
|
+
* @private
|
|
775
|
+
*/
|
|
776
|
+
_$getBounds(matrix = null) {
|
|
777
|
+
if (matrix) {
|
|
778
|
+
let multiMatrix = matrix;
|
|
779
|
+
const rawMatrix = this._$transform._$rawMatrix();
|
|
780
|
+
if (rawMatrix !== $MATRIX_ARRAY_IDENTITY) {
|
|
781
|
+
multiMatrix = $multiplicationMatrix(matrix, rawMatrix);
|
|
782
|
+
}
|
|
783
|
+
const bounds = $boundsMatrix(this._$bounds, multiMatrix);
|
|
784
|
+
if (multiMatrix !== matrix) {
|
|
785
|
+
$poolFloat32Array6(multiMatrix);
|
|
786
|
+
}
|
|
787
|
+
return bounds;
|
|
788
|
+
}
|
|
789
|
+
return $getBoundsObject(this._$bounds.xMin, this._$bounds.xMax, this._$bounds.yMin, this._$bounds.yMax);
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* @return {void}
|
|
793
|
+
* @method
|
|
794
|
+
* @private
|
|
795
|
+
*/
|
|
796
|
+
_$createWorkerInstance() {
|
|
797
|
+
if (!$rendererWorker || this._$created) {
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
this._$created = true;
|
|
801
|
+
const message = {
|
|
802
|
+
"command": "createVideo",
|
|
803
|
+
"instanceId": this._$instanceId,
|
|
804
|
+
"parentId": this._$parent ? this._$parent._$instanceId : -1,
|
|
805
|
+
"smoothing": this._$smoothing,
|
|
806
|
+
"xMin": this._$bounds.xMin,
|
|
807
|
+
"yMin": this._$bounds.yMin,
|
|
808
|
+
"xMax": this._$bounds.xMax,
|
|
809
|
+
"yMax": this._$bounds.yMax
|
|
810
|
+
};
|
|
811
|
+
if (this._$characterId > -1) {
|
|
812
|
+
message.characterId = this._$characterId;
|
|
813
|
+
}
|
|
814
|
+
if (this._$loaderInfo) {
|
|
815
|
+
message.loaderInfoId = this._$loaderInfo._$id;
|
|
816
|
+
}
|
|
817
|
+
if (this._$scale9Grid) {
|
|
818
|
+
message.grid = {
|
|
819
|
+
"x": this._$scale9Grid.x,
|
|
820
|
+
"y": this._$scale9Grid.y,
|
|
821
|
+
"w": this._$scale9Grid.width,
|
|
822
|
+
"h": this._$scale9Grid.height
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
$rendererWorker.postMessage(message);
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* @return {void}
|
|
829
|
+
* @method
|
|
830
|
+
* @private
|
|
831
|
+
*/
|
|
832
|
+
_$postProperty() {
|
|
833
|
+
if (!$rendererWorker) {
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
const message = this._$createMessage();
|
|
837
|
+
message.smoothing = this._$smoothing;
|
|
838
|
+
const options = $getArray();
|
|
839
|
+
const context = this._$context;
|
|
840
|
+
if (context && this._$video) {
|
|
841
|
+
message.xMin = this._$bounds.xMin;
|
|
842
|
+
message.yMin = this._$bounds.yMin;
|
|
843
|
+
message.xMax = this._$bounds.xMax;
|
|
844
|
+
message.yMax = this._$bounds.yMax;
|
|
845
|
+
context.drawImage(this._$video, 0, 0);
|
|
846
|
+
const imageBitmap = context.canvas.transferToImageBitmap();
|
|
847
|
+
message.imageBitmap = imageBitmap;
|
|
848
|
+
options.push(imageBitmap);
|
|
849
|
+
}
|
|
850
|
+
$rendererWorker.postMessage(message, options);
|
|
851
|
+
$poolArray(options);
|
|
852
|
+
this._$posted = true;
|
|
853
|
+
this._$updated = false;
|
|
854
|
+
}
|
|
855
|
+
}
|