@next2d/builder 0.1.8 → 0.1.10
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/dist/cli.d.ts +59 -0
- package/dist/cli.js +141 -0
- package/dist/constants.d.ts +53 -0
- package/dist/constants.js +64 -0
- package/dist/context.d.ts +29 -0
- package/dist/context.js +19 -0
- package/dist/electron.d.ts +10 -0
- package/dist/electron.js +142 -0
- package/dist/index.js +18 -790
- package/dist/native.d.ts +27 -0
- package/dist/native.js +123 -0
- package/dist/utils.d.ts +27 -0
- package/dist/utils.js +40 -0
- package/dist/web.d.ts +18 -0
- package/dist/web.js +70 -0
- package/dist/xbox.d.ts +62 -0
- package/dist/xbox.js +426 -0
- package/package.json +11 -9
- package/templates/xbox/CMakeLists.txt +47 -11
- package/templates/xbox/README.md +18 -0
- package/templates/xbox/js/bootstrap.js +120 -0
- package/templates/xbox/src/AssetLoader.cpp +115 -12
- package/templates/xbox/src/AssetLoader.h +4 -0
- package/templates/xbox/src/EmbeddedAssets.cpp +149 -0
- package/templates/xbox/src/EmbeddedAssets.h +60 -0
- package/templates/xbox/src/EventLoop.cpp +0 -15
- package/templates/xbox/src/bindings/Audio.cpp +118 -22
- package/templates/xbox/src/bindings/Canvas.cpp +32 -2
- package/templates/xbox/src/bindings/Canvas2D.cpp +495 -39
- package/templates/xbox/src/bindings/Console.cpp +6 -1
- package/templates/xbox/src/bindings/DomShims.cpp +18 -2
- package/templates/xbox/src/bindings/EventTarget.cpp +9 -0
- package/templates/xbox/src/bindings/Image.cpp +83 -57
- package/templates/xbox/src/bindings/Polyfills.cpp +671 -236
- package/templates/xbox/src/bindings/RasterCore.h +105 -1
- package/templates/xbox/src/bindings/Video.cpp +57 -3
- package/templates/xbox/src/bindings/webgpu/WebGPU.cpp +29 -3
- package/templates/xbox/src/bindings/webgpu/WebGPUCommon.h +4 -1
- package/templates/xbox/src/bindings/webgpu/WebGPUEnums.h +32 -0
- package/templates/xbox/src/gpu/DawnContext.cpp +167 -16
- package/templates/xbox/src/main.cpp +385 -16
- package/templates/xbox/src/platform/AudioDecoder.cpp +121 -0
- package/templates/xbox/src/platform/AudioDecoder.h +18 -0
- package/templates/xbox/src/platform/AudioEngine.cpp +28 -3
- package/templates/xbox/src/platform/DecodeQueue.cpp +136 -0
- package/templates/xbox/src/platform/DecodeQueue.h +27 -0
- package/templates/xbox/src/platform/ImageDecoder.cpp +44 -0
- package/templates/xbox/src/platform/ImageDecoder.h +18 -0
- package/templates/xbox/src/platform/StbTextRasterizer.cpp +324 -0
- package/templates/xbox/src/platform/StbTextRasterizer.h +37 -0
- package/templates/xbox/src/platform/TextRasterizer.cpp +32 -0
- package/templates/xbox/src/platform/WicDecoder.cpp +19 -0
- package/templates/xbox/src/v8/CodeCache.h +223 -0
- package/templates/xbox/src/v8/V8Runtime.cpp +34 -33
- package/templates/xbox/src/v8/V8Util.h +54 -4
- package/templates/xbox/src/worker/WorkerRuntime.cpp +165 -65
- package/templates/xbox/src/worker/WorkerRuntime.h +23 -3
- package/templates/xbox/tests/check_local.sh +5 -1
- package/templates/xbox/tests/gamecore_api_probe.cpp +172 -0
- package/templates/xbox/tests/raster_test.cpp +50 -0
- package/templates/xbox/tests/windows_platform_test.cpp +75 -3
- package/templates/xbox/third_party/LICENSES.md +14 -0
- package/templates/xbox/third_party/dr_mp3.h +5412 -0
- package/templates/xbox/third_party/dr_wav.h +9131 -0
- package/templates/xbox/third_party/stb_image.h +7988 -0
- package/templates/xbox/third_party/stb_truetype.h +5079 -0
- package/templates/xbox/third_party/stb_vorbis.c +5584 -0
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
#include "AssetLoader.h"
|
|
5
5
|
#include "EventTarget.h"
|
|
6
6
|
#include "platform/AudioEngine.h"
|
|
7
|
+
#include "platform/DecodeQueue.h"
|
|
7
8
|
#include "v8/V8Util.h"
|
|
8
9
|
#include "v8/WeakHandle.h"
|
|
9
10
|
|
|
10
11
|
#include <memory>
|
|
12
|
+
#include <utility>
|
|
11
13
|
#include <vector>
|
|
12
14
|
|
|
13
15
|
namespace next2d {
|
|
@@ -230,20 +232,37 @@ void PumpAudioEvents(v8::Isolate* isolate)
|
|
|
230
232
|
if (sources.empty()) return;
|
|
231
233
|
v8::HandleScope scope(isolate);
|
|
232
234
|
v8::Local<v8::Context> ctx = isolate->GetCurrentContext();
|
|
235
|
+
|
|
236
|
+
// 1) 終了した source を集めて先に登録リストから外す。ここでは JS を呼ばない。
|
|
237
|
+
// (この時点の erase による v8::Global の move は他の再入が無いので安全)
|
|
238
|
+
std::vector<v8::Global<v8::Object>> finished;
|
|
233
239
|
for (size_t i = 0; i < sources.size();) {
|
|
234
240
|
v8::Local<v8::Object> node = sources[i].Get(isolate);
|
|
235
241
|
auto voice = Get<AudioVoice>(node);
|
|
236
242
|
if (!voice || voice->IsFinished()) {
|
|
237
|
-
|
|
238
|
-
v8::Local<v8::Object> ev = v8::Object::New(isolate);
|
|
239
|
-
ev->Set(ctx, Str(isolate, "type"), Str(isolate, "ended")).Check();
|
|
240
|
-
DispatchEvent(isolate, node, ev);
|
|
241
|
-
}
|
|
243
|
+
finished.push_back(std::move(sources[i]));
|
|
242
244
|
sources.erase(sources.begin() + i);
|
|
243
245
|
} else {
|
|
244
246
|
++i;
|
|
245
247
|
}
|
|
246
248
|
}
|
|
249
|
+
|
|
250
|
+
// 2) リストが安定した状態で "ended" を配送する。
|
|
251
|
+
// "ended" ハンドラは source.disconnect() や新規再生で PlayingSources を
|
|
252
|
+
// 再入的に変更しうる。以前は配送と erase を同一ループで行っていたため、
|
|
253
|
+
// 配送中にベクタが変更されると直後の erase 中の v8::Global move が壊れ
|
|
254
|
+
// GlobalHandles::MoveGlobal でアクセス違反していた。独立した finished を
|
|
255
|
+
// 走査することで再入変更から隔離する。
|
|
256
|
+
for (auto& g : finished) {
|
|
257
|
+
v8::Local<v8::Object> node = g.Get(isolate);
|
|
258
|
+
auto voice = Get<AudioVoice>(node);
|
|
259
|
+
if (voice) {
|
|
260
|
+
v8::Local<v8::Object> ev = v8::Object::New(isolate);
|
|
261
|
+
ev->Set(ctx, Str(isolate, "type"), Str(isolate, "ended")).Check();
|
|
262
|
+
DispatchEvent(isolate, node, ev);
|
|
263
|
+
}
|
|
264
|
+
g.Reset();
|
|
265
|
+
}
|
|
247
266
|
}
|
|
248
267
|
|
|
249
268
|
namespace {
|
|
@@ -266,21 +285,49 @@ void DecodeAudioData(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
|
266
285
|
static_cast<uint8_t*>(store->Data()) + store->ByteLength());
|
|
267
286
|
}
|
|
268
287
|
|
|
288
|
+
// Media Foundation デコードはバックグラウンドスレッドへ (Promise なので元々
|
|
289
|
+
// 非同期契約)。BGM の同期デコードは画面遷移時の数百 ms ヒッチになっていた。
|
|
290
|
+
auto resolver_ref =
|
|
291
|
+
std::make_shared<v8::Global<v8::Promise::Resolver>>(isolate, resolver);
|
|
269
292
|
auto pcm = std::make_shared<PcmBuffer>();
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
293
|
+
auto decoded = std::make_shared<bool>(false);
|
|
294
|
+
|
|
295
|
+
decodequeue::Submit(
|
|
296
|
+
[input = std::move(input), pcm, decoded]() {
|
|
297
|
+
*decoded = !input.empty() && AudioEngine::Decode(input, *pcm);
|
|
298
|
+
},
|
|
299
|
+
[isolate, resolver_ref, pcm, decoded]() {
|
|
300
|
+
v8::HandleScope hs(isolate);
|
|
301
|
+
v8::Local<v8::Promise::Resolver> r = resolver_ref->Get(isolate);
|
|
302
|
+
v8::Local<v8::Context> c = r->GetCreationContextChecked();
|
|
303
|
+
v8::Context::Scope cs(c);
|
|
304
|
+
|
|
305
|
+
// 重要: デコード失敗でも Reject しない。@next2d/media の SoundDecodeService は
|
|
306
|
+
// decodeAudioData の reject を catch して先頭バイトをスキップし再帰リトライするが、
|
|
307
|
+
// そのループ条件 (`idx > byteLength`) が常に false のため同一バッファで無限再帰し、
|
|
308
|
+
// マイクロタスクが枯渇してフレームワークのローディング画面ごとフリーズする。
|
|
309
|
+
// ここで無音の空バッファを resolve すれば、そのサウンドは無音になるだけでアプリは
|
|
310
|
+
// 進行できる (graceful degradation)。実データが壊れているか MF 非対応かは上のログで判別。
|
|
311
|
+
if (!*decoded) {
|
|
312
|
+
pcm->samples.clear(); // 0 サンプル = 無音
|
|
313
|
+
pcm->channels = pcm->channels ? pcm->channels : 2;
|
|
314
|
+
pcm->sample_rate = pcm->sample_rate ? pcm->sample_rate : 48000;
|
|
315
|
+
}
|
|
274
316
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
317
|
+
v8::Local<v8::Object> buffer =
|
|
318
|
+
InternalTemplate(isolate)->NewInstance(c).ToLocalChecked();
|
|
319
|
+
Attach<PcmBuffer>(isolate, buffer, pcm);
|
|
320
|
+
v8util::SetValue(isolate, buffer, "sampleRate",
|
|
321
|
+
v8::Number::New(isolate, pcm->sample_rate));
|
|
322
|
+
v8util::SetValue(isolate, buffer, "numberOfChannels",
|
|
323
|
+
v8::Integer::New(isolate, pcm->channels));
|
|
324
|
+
v8util::SetValue(isolate, buffer, "duration",
|
|
325
|
+
v8::Number::New(isolate, pcm->channels
|
|
326
|
+
? static_cast<double>(pcm->samples.size()) / pcm->channels / pcm->sample_rate
|
|
327
|
+
: 0.0));
|
|
328
|
+
r->Resolve(c, buffer).Check();
|
|
329
|
+
resolver_ref->Reset();
|
|
330
|
+
});
|
|
284
331
|
}
|
|
285
332
|
|
|
286
333
|
// --- Audio (HTMLAudioElement 最小実装) -------------------------------------
|
|
@@ -335,17 +382,49 @@ void AudioElementConstructor(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
|
335
382
|
v8::Local<v8::Object> self = args.This();
|
|
336
383
|
Attach<AudioVoice>(isolate, self, nullptr);
|
|
337
384
|
|
|
338
|
-
// URL
|
|
385
|
+
// URL 指定があればロードし、デコードはバックグラウンドスレッドへ (失敗時は
|
|
386
|
+
// 無音の no-op)。デコード完了前に play() が呼ばれていた場合 (paused=false) は
|
|
387
|
+
// 完了時に再生を開始する (同期デコード時代の「即時再生」挙動を維持)。
|
|
339
388
|
if (args.Length() > 0 && args[0]->IsString()) {
|
|
340
389
|
const std::string src = ToStdString(isolate, args[0]);
|
|
341
390
|
v8util::SetValue(isolate, self, "src", args[0]);
|
|
342
391
|
HostContext* host = HostContext::From(isolate);
|
|
343
392
|
auto bytes = host->assets->ReadBinary(src);
|
|
344
393
|
if (bytes) {
|
|
394
|
+
auto self_ref = std::make_shared<v8::Global<v8::Object>>(isolate, self);
|
|
345
395
|
auto pcm = std::make_shared<PcmBuffer>();
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
396
|
+
auto decoded = std::make_shared<bool>(false);
|
|
397
|
+
decodequeue::Submit(
|
|
398
|
+
[input = std::move(*bytes), pcm, decoded]() {
|
|
399
|
+
*decoded = AudioEngine::Decode(input, *pcm);
|
|
400
|
+
},
|
|
401
|
+
[isolate, self_ref, pcm, decoded, host]() {
|
|
402
|
+
v8::HandleScope hs(isolate);
|
|
403
|
+
v8::Local<v8::Object> el = self_ref->Get(isolate);
|
|
404
|
+
v8::Local<v8::Context> c = el->GetCreationContextChecked();
|
|
405
|
+
v8::Context::Scope cs(c);
|
|
406
|
+
if (*decoded) {
|
|
407
|
+
auto voice = host->audio->CreateVoice(pcm);
|
|
408
|
+
Attach<AudioVoice>(isolate, el, voice);
|
|
409
|
+
// デコード中に play() 済みなら開始する
|
|
410
|
+
v8::Local<v8::Value> paused_v, loop_v, vol_v;
|
|
411
|
+
const bool paused =
|
|
412
|
+
!el->Get(c, Str(isolate, "paused")).ToLocal(&paused_v) ||
|
|
413
|
+
paused_v->BooleanValue(isolate);
|
|
414
|
+
if (!paused && voice) {
|
|
415
|
+
if (el->Get(c, Str(isolate, "volume")).ToLocal(&vol_v) &&
|
|
416
|
+
vol_v->IsNumber()) {
|
|
417
|
+
voice->SetVolume(static_cast<float>(
|
|
418
|
+
vol_v.As<v8::Number>()->Value()));
|
|
419
|
+
}
|
|
420
|
+
const bool loop =
|
|
421
|
+
el->Get(c, Str(isolate, "loop")).ToLocal(&loop_v) &&
|
|
422
|
+
loop_v->BooleanValue(isolate);
|
|
423
|
+
voice->Start(loop);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
self_ref->Reset();
|
|
427
|
+
});
|
|
349
428
|
}
|
|
350
429
|
}
|
|
351
430
|
|
|
@@ -374,6 +453,23 @@ void AudioContextConstructor(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
|
374
453
|
v8util::SetMethod(isolate, self, "createBufferSource", CreateBufferSource);
|
|
375
454
|
v8util::SetMethod(isolate, self, "createGain", CreateGain);
|
|
376
455
|
v8util::SetMethod(isolate, self, "decodeAudioData", DecodeAudioData);
|
|
456
|
+
|
|
457
|
+
// state / resume / suspend / close: ブラウザの AudioContext はユーザージェスチャまで
|
|
458
|
+
// suspended だが、ホストの XAudio2 は常に有効なので "running" 固定。player の音声
|
|
459
|
+
// アンロック (初回 pointerup で ctx.resume()) が未実装だと TypeError で throw し、
|
|
460
|
+
// そのハンドラ(ミュート解除等)以降が中断する。解決済み Promise を返す no-op にする。
|
|
461
|
+
v8util::SetValue(isolate, self, "state", v8util::Str(isolate, "running"));
|
|
462
|
+
auto resolvedPromise = [](const v8::FunctionCallbackInfo<v8::Value>& a) {
|
|
463
|
+
v8::Isolate* iso = a.GetIsolate();
|
|
464
|
+
v8::Local<v8::Context> c = iso->GetCurrentContext();
|
|
465
|
+
auto r = v8::Promise::Resolver::New(c).ToLocalChecked();
|
|
466
|
+
(void) r->Resolve(c, v8::Undefined(iso));
|
|
467
|
+
a.GetReturnValue().Set(r->GetPromise());
|
|
468
|
+
};
|
|
469
|
+
v8util::SetMethod(isolate, self, "resume", resolvedPromise);
|
|
470
|
+
v8util::SetMethod(isolate, self, "suspend", resolvedPromise);
|
|
471
|
+
v8util::SetMethod(isolate, self, "close", resolvedPromise);
|
|
472
|
+
|
|
377
473
|
args.GetReturnValue().Set(self);
|
|
378
474
|
}
|
|
379
475
|
|
|
@@ -105,6 +105,16 @@ void TransferControlToOffscreen(const v8::FunctionCallbackInfo<v8::Value>& args)
|
|
|
105
105
|
if (args.This()->Get(ctx, Str(isolate, "height")).ToLocal(&hv) && hv->IsNumber()) {
|
|
106
106
|
height = static_cast<int>(hv.As<v8::Number>()->Value());
|
|
107
107
|
}
|
|
108
|
+
|
|
109
|
+
// このソース canvas (args.This()) こそがプレイヤーの主表示 canvas。
|
|
110
|
+
// player は「document.createElement('canvas') → pointer リスナ登録 → その canvas を
|
|
111
|
+
// transferControlToOffscreen()」の順で主 canvas を作る (input と描画で同一要素)。
|
|
112
|
+
// 一方 createElement は毎回 main_canvas を上書きするため、後続のヒットテスト用
|
|
113
|
+
// Canvas2D 生成 (getContext('2d') 用に 7 個も作る) で main_canvas が別要素に化け、
|
|
114
|
+
// WndProc の入力配送先とリスナ登録先がズレて「ボタンが全く反応しない」状態になる。
|
|
115
|
+
// transferControlToOffscreen が呼ばれる唯一の canvas = 正しい入力要素なので確定させる。
|
|
116
|
+
host->main_canvas.Reset(isolate, args.This());
|
|
117
|
+
|
|
108
118
|
args.GetReturnValue().Set(CreateOffscreenCanvas(isolate, host, width, height));
|
|
109
119
|
}
|
|
110
120
|
|
|
@@ -147,6 +157,18 @@ v8::Local<v8::Object> CreateCanvasElement(v8::Isolate* isolate, HostContext* hos
|
|
|
147
157
|
SetValue(isolate, canvas, "style", v8::Object::New(isolate));
|
|
148
158
|
SetMethod(isolate, canvas, "getContext", Canvas_GetContext);
|
|
149
159
|
SetMethod(isolate, canvas, "transferControlToOffscreen", TransferControlToOffscreen);
|
|
160
|
+
// Pointer capture: player の pointerdown ハンドラは t.setPointerCapture(pointerId) を
|
|
161
|
+
// 呼ぶ。未実装だと TypeError で DispatchEvent の TryCatch に飲まれ、以降の座標解決
|
|
162
|
+
// (dl) に到達せずボタンが反応しない。no-op として実装する (単一ウィンドウでは
|
|
163
|
+
// capture の有無で挙動は変わらない)。hasPointerCapture は false を返す。
|
|
164
|
+
SetMethod(isolate, canvas, "setPointerCapture",
|
|
165
|
+
[](const v8::FunctionCallbackInfo<v8::Value>&) {});
|
|
166
|
+
SetMethod(isolate, canvas, "releasePointerCapture",
|
|
167
|
+
[](const v8::FunctionCallbackInfo<v8::Value>&) {});
|
|
168
|
+
SetMethod(isolate, canvas, "hasPointerCapture",
|
|
169
|
+
[](const v8::FunctionCallbackInfo<v8::Value>& a) {
|
|
170
|
+
a.GetReturnValue().Set(false);
|
|
171
|
+
});
|
|
150
172
|
InstallEventTarget(isolate, canvas); // pointer/wheel リスナを保持
|
|
151
173
|
SetMethod(isolate, canvas, "getBoundingClientRect", GetBoundingClientRect);
|
|
152
174
|
|
|
@@ -191,8 +213,16 @@ v8::Local<v8::Object> CreateCanvasElement(v8::Isolate* isolate, HostContext* hos
|
|
|
191
213
|
(void) attrs.As<v8::Object>()->Delete(c, a[0]);
|
|
192
214
|
}
|
|
193
215
|
});
|
|
194
|
-
// 主要 canvas
|
|
195
|
-
|
|
216
|
+
// 主要 canvas の記録 (WndProc の入力配送先)。
|
|
217
|
+
// 確定は transferControlToOffscreen 側で行う (player が input を張る主 canvas はそちら)。
|
|
218
|
+
// ここでは「まだ未設定なら暫定で最初の canvas を採用」するフォールバックに留め、
|
|
219
|
+
// 後続の Canvas2D 生成で上書きしない (上書きすると入力配送先がヒットテスト用 canvas に化ける)。
|
|
220
|
+
{
|
|
221
|
+
HostContext* host = HostContext::From(isolate);
|
|
222
|
+
if (host->main_canvas.IsEmpty()) {
|
|
223
|
+
host->main_canvas.Reset(isolate, canvas);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
196
226
|
return canvas;
|
|
197
227
|
}
|
|
198
228
|
|