@next2d/builder 0.1.7 → 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 -754
- 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 +12 -9
- package/templates/xbox/CMakeLists.txt +116 -11
- package/templates/xbox/README.md +34 -8
- package/templates/xbox/cmake/FetchDawn.cmake +47 -6
- package/templates/xbox/cmake/FindV8.cmake +15 -0
- package/templates/xbox/js/bootstrap.js +151 -28
- package/templates/xbox/js/selftest.js +740 -90
- 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 +13 -1
- package/templates/xbox/src/EventLoop.h +12 -0
- package/templates/xbox/src/bindings/Audio.cpp +211 -31
- package/templates/xbox/src/bindings/Bindings.h +10 -0
- package/templates/xbox/src/bindings/Canvas.cpp +77 -2
- package/templates/xbox/src/bindings/Canvas2D.cpp +496 -43
- package/templates/xbox/src/bindings/Console.cpp +6 -1
- package/templates/xbox/src/bindings/DomShims.cpp +143 -0
- package/templates/xbox/src/bindings/EventTarget.cpp +11 -0
- package/templates/xbox/src/bindings/Fetch.cpp +2 -8
- package/templates/xbox/src/bindings/Image.cpp +243 -15
- package/templates/xbox/src/bindings/Polyfills.cpp +1226 -0
- package/templates/xbox/src/bindings/RasterCore.h +105 -1
- package/templates/xbox/src/bindings/Video.cpp +153 -10
- package/templates/xbox/src/bindings/webgpu/WebGPU.cpp +844 -18
- package/templates/xbox/src/bindings/webgpu/WebGPUCommon.h +7 -9
- package/templates/xbox/src/bindings/webgpu/WebGPUEnums.h +32 -0
- package/templates/xbox/src/gpu/DawnContext.cpp +245 -7
- package/templates/xbox/src/gpu/DawnContext.h +18 -0
- package/templates/xbox/src/main.cpp +459 -8
- 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 +37 -6
- 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 +76 -11
- package/templates/xbox/src/v8/V8Util.h +79 -0
- package/templates/xbox/src/v8/WeakHandle.h +45 -0
- package/templates/xbox/src/worker/WorkerRuntime.cpp +432 -48
- package/templates/xbox/src/worker/WorkerRuntime.h +43 -13
- package/templates/xbox/tests/check_local.sh +7 -2
- 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
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#include "AudioDecoder.h"
|
|
2
|
+
|
|
3
|
+
// dr_mp3 / dr_wav / stb_vorbis: public domain のヘッダオンリーデコーダ (third_party/)。
|
|
4
|
+
// メモリ入力のみ使用する。実装は本 TU に集約する (ODR 一意)。
|
|
5
|
+
#define DR_MP3_IMPLEMENTATION
|
|
6
|
+
#define DR_MP3_NO_STDIO
|
|
7
|
+
#include "third_party/dr_mp3.h"
|
|
8
|
+
|
|
9
|
+
#define DR_WAV_IMPLEMENTATION
|
|
10
|
+
#define DR_WAV_NO_STDIO
|
|
11
|
+
#include "third_party/dr_wav.h"
|
|
12
|
+
|
|
13
|
+
// stb_vorbis は .c 配布のためここで取り込む (STB_VORBIS_HEADER_ONLY は使わない)。
|
|
14
|
+
#define STB_VORBIS_NO_STDIO
|
|
15
|
+
#define STB_VORBIS_NO_PUSHDATA_API
|
|
16
|
+
#include "third_party/stb_vorbis.c"
|
|
17
|
+
|
|
18
|
+
#include <cstring>
|
|
19
|
+
|
|
20
|
+
namespace next2d {
|
|
21
|
+
|
|
22
|
+
namespace {
|
|
23
|
+
|
|
24
|
+
bool DecodeMp3(const std::vector<uint8_t>& input, PcmBuffer& out)
|
|
25
|
+
{
|
|
26
|
+
drmp3_config config = {};
|
|
27
|
+
drmp3_uint64 total_frames = 0;
|
|
28
|
+
float* frames = drmp3_open_memory_and_read_pcm_frames_f32(
|
|
29
|
+
input.data(), input.size(), &config, &total_frames, nullptr);
|
|
30
|
+
if (!frames || total_frames == 0 || config.channels == 0) {
|
|
31
|
+
if (frames) {
|
|
32
|
+
drmp3_free(frames, nullptr);
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
out.channels = config.channels;
|
|
37
|
+
out.sample_rate = config.sampleRate;
|
|
38
|
+
out.samples.assign(frames, frames + total_frames * config.channels);
|
|
39
|
+
drmp3_free(frames, nullptr);
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
bool DecodeWav(const std::vector<uint8_t>& input, PcmBuffer& out)
|
|
44
|
+
{
|
|
45
|
+
unsigned int channels = 0, sample_rate = 0;
|
|
46
|
+
drwav_uint64 total_frames = 0;
|
|
47
|
+
float* frames = drwav_open_memory_and_read_pcm_frames_f32(
|
|
48
|
+
input.data(), input.size(), &channels, &sample_rate, &total_frames, nullptr);
|
|
49
|
+
if (!frames || total_frames == 0 || channels == 0) {
|
|
50
|
+
if (frames) {
|
|
51
|
+
drwav_free(frames, nullptr);
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
out.channels = channels;
|
|
56
|
+
out.sample_rate = sample_rate;
|
|
57
|
+
out.samples.assign(frames, frames + total_frames * channels);
|
|
58
|
+
drwav_free(frames, nullptr);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
bool DecodeOgg(const std::vector<uint8_t>& input, PcmBuffer& out)
|
|
63
|
+
{
|
|
64
|
+
int err = 0;
|
|
65
|
+
stb_vorbis* vorbis = stb_vorbis_open_memory(
|
|
66
|
+
input.data(), static_cast<int>(input.size()), &err, nullptr);
|
|
67
|
+
if (!vorbis) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
const stb_vorbis_info info = stb_vorbis_get_info(vorbis);
|
|
71
|
+
const unsigned int total_frames = stb_vorbis_stream_length_in_samples(vorbis);
|
|
72
|
+
if (info.channels <= 0 || total_frames == 0) {
|
|
73
|
+
stb_vorbis_close(vorbis);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
out.channels = static_cast<uint32_t>(info.channels);
|
|
77
|
+
out.sample_rate = info.sample_rate;
|
|
78
|
+
out.samples.resize(static_cast<size_t>(total_frames) * info.channels);
|
|
79
|
+
const int read = stb_vorbis_get_samples_float_interleaved(
|
|
80
|
+
vorbis, info.channels, out.samples.data(),
|
|
81
|
+
static_cast<int>(out.samples.size()));
|
|
82
|
+
stb_vorbis_close(vorbis);
|
|
83
|
+
if (read <= 0) {
|
|
84
|
+
out.samples.clear();
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
out.samples.resize(static_cast<size_t>(read) * info.channels);
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
} // namespace
|
|
92
|
+
|
|
93
|
+
bool DecodeAudio(const std::vector<uint8_t>& input, PcmBuffer& out)
|
|
94
|
+
{
|
|
95
|
+
if (input.size() < 12) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
const uint8_t* d = input.data();
|
|
99
|
+
|
|
100
|
+
// マジックナンバーで形式を判定して該当デコーダを先に試し、
|
|
101
|
+
// 外れたら残りをカスケード (誤判定・ヘッダ無し MP3 の保険)。
|
|
102
|
+
const bool looks_wav = std::memcmp(d, "RIFF", 4) == 0 && std::memcmp(d + 8, "WAVE", 4) == 0;
|
|
103
|
+
const bool looks_ogg = std::memcmp(d, "OggS", 4) == 0;
|
|
104
|
+
const bool looks_mp3 = std::memcmp(d, "ID3", 3) == 0
|
|
105
|
+
|| (d[0] == 0xFF && (d[1] & 0xE0) == 0xE0);
|
|
106
|
+
|
|
107
|
+
if (looks_wav && DecodeWav(input, out)) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
if (looks_ogg && DecodeOgg(input, out)) {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
if (looks_mp3 && DecodeMp3(input, out)) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 判定が外れた場合のカスケード
|
|
118
|
+
return DecodeWav(input, out) || DecodeOgg(input, out) || DecodeMp3(input, out);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
} // namespace next2d
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// 音声デコード (エンコード済みバイト列 -> float32 interleaved PCM)。
|
|
2
|
+
//
|
|
3
|
+
// 第一候補は dr_mp3 / dr_wav / stb_vorbis (MP3/WAV/OGG、全プラットフォーム共通、
|
|
4
|
+
// public domain)。コンソール (Game Core OS) にはデスクトップの Media Foundation が
|
|
5
|
+
// 無いため、MF 依存を第一経路から外して PC 検証と実機の挙動を一致させる。
|
|
6
|
+
// デスクトップのみ AAC 等の保険として AudioEngine::Decode 側に MF フォールバックが残る。
|
|
7
|
+
#pragma once
|
|
8
|
+
|
|
9
|
+
#include "AudioEngine.h" // PcmBuffer
|
|
10
|
+
|
|
11
|
+
#include <cstdint>
|
|
12
|
+
#include <vector>
|
|
13
|
+
|
|
14
|
+
namespace next2d {
|
|
15
|
+
|
|
16
|
+
bool DecodeAudio(const std::vector<uint8_t>& input, PcmBuffer& out);
|
|
17
|
+
|
|
18
|
+
} // namespace next2d
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
#include "AudioEngine.h"
|
|
2
|
+
#include "AudioDecoder.h"
|
|
2
3
|
|
|
3
4
|
#include <xaudio2.h>
|
|
5
|
+
#include <iostream>
|
|
6
|
+
|
|
7
|
+
// Media Foundation / shlwapi はコンソール (Game Core OS) に無いデスクトップ専用 API。
|
|
8
|
+
// 第一経路は AudioDecoder (dr_mp3/dr_wav/stb_vorbis) で、MF は AAC 等の
|
|
9
|
+
// デスクトップ限定フォールバックのみ。XAudio2 は両プラットフォームで使える。
|
|
10
|
+
#if !NEXT2D_XBOX_CONSOLE
|
|
4
11
|
#include <mfapi.h>
|
|
5
12
|
#include <mfidl.h>
|
|
6
13
|
#include <mfreadwrite.h>
|
|
7
14
|
#include <shlwapi.h>
|
|
8
15
|
#include <wrl/client.h>
|
|
9
|
-
#include <iostream>
|
|
10
16
|
|
|
11
17
|
#pragma comment(lib, "mfplat.lib")
|
|
12
18
|
#pragma comment(lib, "mfreadwrite.lib")
|
|
@@ -14,6 +20,7 @@
|
|
|
14
20
|
#pragma comment(lib, "shlwapi.lib")
|
|
15
21
|
|
|
16
22
|
using Microsoft::WRL::ComPtr;
|
|
23
|
+
#endif
|
|
17
24
|
|
|
18
25
|
namespace next2d {
|
|
19
26
|
|
|
@@ -41,6 +48,10 @@ AudioVoice::~AudioVoice()
|
|
|
41
48
|
|
|
42
49
|
void AudioVoice::Start(bool loop)
|
|
43
50
|
{
|
|
51
|
+
// 音声デバイスが無い環境 (CI 等) でも「再生開始→即終了」として扱えるよう、
|
|
52
|
+
// voice_ の有無に関わらず開始状態は記録する (IsFinished が ended 発火を導く)。
|
|
53
|
+
started_ = true;
|
|
54
|
+
looping_ = loop;
|
|
44
55
|
if (!voice_) {
|
|
45
56
|
return;
|
|
46
57
|
}
|
|
@@ -51,8 +62,6 @@ void AudioVoice::Start(bool loop)
|
|
|
51
62
|
buf.LoopCount = loop ? XAUDIO2_LOOP_INFINITE : 0;
|
|
52
63
|
voice_->SubmitSourceBuffer(&buf);
|
|
53
64
|
voice_->Start(0);
|
|
54
|
-
started_ = true;
|
|
55
|
-
looping_ = loop;
|
|
56
65
|
}
|
|
57
66
|
|
|
58
67
|
void AudioVoice::Stop()
|
|
@@ -66,9 +75,13 @@ void AudioVoice::Stop()
|
|
|
66
75
|
|
|
67
76
|
bool AudioVoice::IsFinished() const
|
|
68
77
|
{
|
|
69
|
-
if (!
|
|
78
|
+
if (!started_ || looping_) {
|
|
70
79
|
return false;
|
|
71
80
|
}
|
|
81
|
+
if (!voice_) {
|
|
82
|
+
// 実ボイスが無い (音声デバイス無し) 場合は開始と同時に終了扱い。
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
72
85
|
XAUDIO2_VOICE_STATE state = {};
|
|
73
86
|
voice_->GetState(&state);
|
|
74
87
|
return state.BuffersQueued == 0;
|
|
@@ -91,15 +104,19 @@ AudioEngine::~AudioEngine()
|
|
|
91
104
|
if (xaudio_) {
|
|
92
105
|
xaudio_->Release();
|
|
93
106
|
}
|
|
107
|
+
#if !NEXT2D_XBOX_CONSOLE
|
|
94
108
|
MFShutdown();
|
|
109
|
+
#endif
|
|
95
110
|
}
|
|
96
111
|
|
|
97
112
|
bool AudioEngine::Initialize()
|
|
98
113
|
{
|
|
114
|
+
#if !NEXT2D_XBOX_CONSOLE
|
|
99
115
|
if (FAILED(MFStartup(MF_VERSION))) {
|
|
100
116
|
std::cerr << "[Audio] MFStartup failed" << std::endl;
|
|
101
117
|
return false;
|
|
102
118
|
}
|
|
119
|
+
#endif
|
|
103
120
|
if (FAILED(XAudio2Create(&xaudio_, 0, XAUDIO2_DEFAULT_PROCESSOR))) {
|
|
104
121
|
std::cerr << "[Audio] XAudio2Create failed" << std::endl;
|
|
105
122
|
return false;
|
|
@@ -113,8 +130,21 @@ bool AudioEngine::Initialize()
|
|
|
113
130
|
|
|
114
131
|
bool AudioEngine::Decode(const std::vector<uint8_t>& input, PcmBuffer& out)
|
|
115
132
|
{
|
|
116
|
-
//
|
|
117
|
-
//
|
|
133
|
+
// 第一候補: ポータブルデコーダ (dr_mp3/dr_wav/stb_vorbis)。
|
|
134
|
+
// コンソール (Game Core) には Media Foundation が無いため、共通経路を先に
|
|
135
|
+
// 通すことで PC 検証と実機の挙動を一致させる。
|
|
136
|
+
if (DecodeAudio(input, out)) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
#if NEXT2D_XBOX_CONSOLE
|
|
141
|
+
// コンソール: MF が無いため共通デコーダで扱えない形式は失敗とする
|
|
142
|
+
// (呼び出し側の graceful degradation = 無音バッファで進行)。
|
|
143
|
+
return false;
|
|
144
|
+
#else
|
|
145
|
+
// フォールバック (デスクトップのみ): Media Foundation の SourceReader。
|
|
146
|
+
// AAC/WMA 等、MP3/WAV/OGG 以外の形式への保険。
|
|
147
|
+
// メモリストリームから 32bit float PCM へ変換して読み出す。
|
|
118
148
|
ComPtr<IStream> stream =
|
|
119
149
|
SHCreateMemStream(input.data(), static_cast<UINT>(input.size()));
|
|
120
150
|
if (!stream) {
|
|
@@ -174,6 +204,7 @@ bool AudioEngine::Decode(const std::vector<uint8_t>& input, PcmBuffer& out)
|
|
|
174
204
|
}
|
|
175
205
|
|
|
176
206
|
return !out.samples.empty();
|
|
207
|
+
#endif // NEXT2D_XBOX_CONSOLE
|
|
177
208
|
}
|
|
178
209
|
|
|
179
210
|
std::shared_ptr<AudioVoice> AudioEngine::CreateVoice(std::shared_ptr<PcmBuffer> buffer)
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#include "DecodeQueue.h"
|
|
2
|
+
|
|
3
|
+
#ifdef _WIN32
|
|
4
|
+
#include <objbase.h>
|
|
5
|
+
#endif
|
|
6
|
+
|
|
7
|
+
#include <algorithm>
|
|
8
|
+
#include <condition_variable>
|
|
9
|
+
#include <deque>
|
|
10
|
+
#include <mutex>
|
|
11
|
+
#include <thread>
|
|
12
|
+
#include <vector>
|
|
13
|
+
|
|
14
|
+
namespace next2d::decodequeue {
|
|
15
|
+
|
|
16
|
+
namespace {
|
|
17
|
+
|
|
18
|
+
struct Job {
|
|
19
|
+
std::function<void()> work;
|
|
20
|
+
std::function<void()> complete;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
struct Queue {
|
|
24
|
+
std::mutex mutex;
|
|
25
|
+
std::condition_variable cv;
|
|
26
|
+
std::deque<Job> pending; // 未処理 (プールスレッドが取る)
|
|
27
|
+
std::deque<std::function<void()>> done; // work 完了済み (Pump が実行)
|
|
28
|
+
std::vector<std::thread> threads;
|
|
29
|
+
bool stop = false;
|
|
30
|
+
|
|
31
|
+
void ThreadMain()
|
|
32
|
+
{
|
|
33
|
+
#ifdef _WIN32
|
|
34
|
+
// WIC / Media Foundation は COM を要する。プールスレッド毎に MTA で初期化する
|
|
35
|
+
// (per-call 実装なので MTA スレッド間で共有状態は無い)。
|
|
36
|
+
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
|
37
|
+
#endif
|
|
38
|
+
for (;;) {
|
|
39
|
+
Job job;
|
|
40
|
+
{
|
|
41
|
+
std::unique_lock<std::mutex> lock(mutex);
|
|
42
|
+
cv.wait(lock, [this] { return stop || !pending.empty(); });
|
|
43
|
+
if (stop) {
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
job = std::move(pending.front());
|
|
47
|
+
pending.pop_front();
|
|
48
|
+
}
|
|
49
|
+
if (job.work) {
|
|
50
|
+
job.work();
|
|
51
|
+
}
|
|
52
|
+
{
|
|
53
|
+
std::lock_guard<std::mutex> lock(mutex);
|
|
54
|
+
done.push_back(std::move(job.complete));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
#ifdef _WIN32
|
|
58
|
+
CoUninitialize();
|
|
59
|
+
#endif
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
void EnsureThreads()
|
|
63
|
+
{
|
|
64
|
+
if (!threads.empty()) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// デコードは CPU バウンド。コア数の半分 (2〜4) で遷移時のバースト
|
|
68
|
+
// (画像数十枚 + BGM) を並列処理しつつ、メイン/GC スレッドを圧迫しない。
|
|
69
|
+
const unsigned hw = std::thread::hardware_concurrency();
|
|
70
|
+
const unsigned count = std::clamp(hw / 2u, 2u, 4u);
|
|
71
|
+
threads.reserve(count);
|
|
72
|
+
for (unsigned i = 0; i < count; ++i) {
|
|
73
|
+
threads.emplace_back([this] { ThreadMain(); });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
Queue& Q()
|
|
79
|
+
{
|
|
80
|
+
static Queue q;
|
|
81
|
+
return q;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
} // namespace
|
|
85
|
+
|
|
86
|
+
void Submit(std::function<void()> work, std::function<void()> complete)
|
|
87
|
+
{
|
|
88
|
+
Queue& q = Q();
|
|
89
|
+
{
|
|
90
|
+
std::lock_guard<std::mutex> lock(q.mutex);
|
|
91
|
+
if (q.stop) {
|
|
92
|
+
return; // Shutdown 後の Submit は破棄 (終了処理中のロード要求)
|
|
93
|
+
}
|
|
94
|
+
q.EnsureThreads();
|
|
95
|
+
q.pending.push_back({std::move(work), std::move(complete)});
|
|
96
|
+
}
|
|
97
|
+
q.cv.notify_one();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
void Pump()
|
|
101
|
+
{
|
|
102
|
+
Queue& q = Q();
|
|
103
|
+
std::deque<std::function<void()>> ready;
|
|
104
|
+
{
|
|
105
|
+
std::lock_guard<std::mutex> lock(q.mutex);
|
|
106
|
+
ready.swap(q.done);
|
|
107
|
+
}
|
|
108
|
+
for (auto& complete : ready) {
|
|
109
|
+
if (complete) {
|
|
110
|
+
complete();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
void Shutdown()
|
|
116
|
+
{
|
|
117
|
+
Queue& q = Q();
|
|
118
|
+
{
|
|
119
|
+
std::lock_guard<std::mutex> lock(q.mutex);
|
|
120
|
+
q.stop = true;
|
|
121
|
+
}
|
|
122
|
+
q.cv.notify_all();
|
|
123
|
+
for (auto& t : q.threads) {
|
|
124
|
+
if (t.joinable()) {
|
|
125
|
+
t.join();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
q.threads.clear();
|
|
129
|
+
// 未実行の work / complete を破棄する。complete は v8::Global を捕捉して
|
|
130
|
+
// いるため、この関数は Isolate 破棄前に呼ばれる必要がある (main.cpp の後始末順)。
|
|
131
|
+
std::lock_guard<std::mutex> lock(q.mutex);
|
|
132
|
+
q.pending.clear();
|
|
133
|
+
q.done.clear();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
} // namespace next2d::decodequeue
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// DecodeQueue: リソースデコード用のバックグラウンドスレッドプール。
|
|
2
|
+
//
|
|
3
|
+
// 画像 (WIC) / 音声 (Media Foundation) のデコードはメインスレッドで同期実行すると
|
|
4
|
+
// 画面遷移時に 1 秒超のフレームヒッチになる (--perf 計測で特定)。work を
|
|
5
|
+
// プールスレッドへ逃がし、complete をメインループの Pump() で実行することで
|
|
6
|
+
// ヒッチを解消し、複数リソースの並列デコードでロード時間も短縮する。
|
|
7
|
+
// スレッドは Xbox で許可されている (禁止は動的コード生成のみ)。
|
|
8
|
+
//
|
|
9
|
+
// 契約:
|
|
10
|
+
// - work : プールスレッドで実行される。V8 / JS ヒープに触れてはならない。
|
|
11
|
+
// (WIC/MF は per-call 実装で COM はスレッド毎に MTA 初期化済み)
|
|
12
|
+
// - complete: work 完了後、メインスレッドの Pump() から実行される。V8 可。
|
|
13
|
+
// (v8::Global を捕捉してよい。Pump は isolate/コンテキストスコープ外で
|
|
14
|
+
// 呼ばれるため、complete 側で HandleScope/Context::Scope を張ること)
|
|
15
|
+
// - Shutdown: 全スレッドを join し、未実行の work / complete を破棄する。
|
|
16
|
+
// 捕捉された v8::Global の破棄があるため Isolate 破棄前に呼ぶこと。
|
|
17
|
+
#pragma once
|
|
18
|
+
|
|
19
|
+
#include <functional>
|
|
20
|
+
|
|
21
|
+
namespace next2d::decodequeue {
|
|
22
|
+
|
|
23
|
+
void Submit(std::function<void()> work, std::function<void()> complete);
|
|
24
|
+
void Pump();
|
|
25
|
+
void Shutdown();
|
|
26
|
+
|
|
27
|
+
} // namespace next2d::decodequeue
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#include "ImageDecoder.h"
|
|
2
|
+
|
|
3
|
+
// stb_image: public domain のヘッダオンリー画像デコーダ (third_party/)。
|
|
4
|
+
// メモリ入力のみ使用するため stdio を切る。
|
|
5
|
+
#define STB_IMAGE_IMPLEMENTATION
|
|
6
|
+
#define STBI_NO_STDIO
|
|
7
|
+
#include "third_party/stb_image.h"
|
|
8
|
+
|
|
9
|
+
#if defined(_WIN32) && !NEXT2D_XBOX_CONSOLE
|
|
10
|
+
#include "WicDecoder.h"
|
|
11
|
+
#endif
|
|
12
|
+
|
|
13
|
+
#include <cstring>
|
|
14
|
+
|
|
15
|
+
namespace next2d {
|
|
16
|
+
|
|
17
|
+
bool DecodeImage(const std::vector<uint8_t>& input, DecodedImage& out)
|
|
18
|
+
{
|
|
19
|
+
if (input.empty()) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 1) stb_image (PNG/JPEG/GIF/BMP/TGA/PSD)。コンソールでも動く共通経路。
|
|
24
|
+
int w = 0, h = 0, comp = 0;
|
|
25
|
+
stbi_uc* pixels = stbi_load_from_memory(
|
|
26
|
+
input.data(), static_cast<int>(input.size()), &w, &h, &comp, 4);
|
|
27
|
+
if (pixels) {
|
|
28
|
+
out.width = static_cast<uint32_t>(w);
|
|
29
|
+
out.height = static_cast<uint32_t>(h);
|
|
30
|
+
out.rgba.assign(pixels, pixels + static_cast<size_t>(w) * h * 4);
|
|
31
|
+
stbi_image_free(pixels);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#if defined(_WIN32) && !NEXT2D_XBOX_CONSOLE
|
|
36
|
+
// 2) デスクトップのみ: WIC フォールバック (TIFF/HEIF 等 stb 非対応形式の保険)。
|
|
37
|
+
// コンソールには WIC が無いためこの経路はコンパイルされない。
|
|
38
|
+
return DecodeImageWithWIC(input, out);
|
|
39
|
+
#else
|
|
40
|
+
return false;
|
|
41
|
+
#endif
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
} // namespace next2d
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// 画像デコード (エンコード済みバイト列 -> RGBA8)。
|
|
2
|
+
//
|
|
3
|
+
// 第一候補は stb_image (PNG/JPEG/GIF/BMP、全プラットフォーム共通)。
|
|
4
|
+
// コンソール (Game Core OS) には WIC が存在しないため、WIC 依存を第一経路から
|
|
5
|
+
// 外すことで PC 検証と実機の挙動を一致させる。デスクトップのみ、stb が扱えない
|
|
6
|
+
// 形式 (TIFF/HEIF 等) への保険として WIC フォールバックを残す。
|
|
7
|
+
#pragma once
|
|
8
|
+
|
|
9
|
+
#include "ImageTypes.h"
|
|
10
|
+
|
|
11
|
+
#include <cstdint>
|
|
12
|
+
#include <vector>
|
|
13
|
+
|
|
14
|
+
namespace next2d {
|
|
15
|
+
|
|
16
|
+
bool DecodeImage(const std::vector<uint8_t>& input, DecodedImage& out);
|
|
17
|
+
|
|
18
|
+
} // namespace next2d
|