@next2d/builder 0.1.4 → 0.1.6
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/README.md +11 -0
- package/dist/index.js +247 -3
- package/package.json +11 -9
- package/templates/xbox/CMakeLists.txt +121 -0
- package/templates/xbox/MicrosoftGame.config +36 -0
- package/templates/xbox/README.md +319 -0
- package/templates/xbox/cmake/FetchDawn.cmake +42 -0
- package/templates/xbox/cmake/FindV8.cmake +62 -0
- package/templates/xbox/js/bootstrap.js +143 -0
- package/templates/xbox/js/selftest.js +515 -0
- package/templates/xbox/src/AssetLoader.cpp +106 -0
- package/templates/xbox/src/AssetLoader.h +35 -0
- package/templates/xbox/src/EventLoop.cpp +162 -0
- package/templates/xbox/src/EventLoop.h +73 -0
- package/templates/xbox/src/HostContext.h +58 -0
- package/templates/xbox/src/bindings/Audio.cpp +320 -0
- package/templates/xbox/src/bindings/Bindings.h +75 -0
- package/templates/xbox/src/bindings/Canvas.cpp +171 -0
- package/templates/xbox/src/bindings/Canvas2D.cpp +462 -0
- package/templates/xbox/src/bindings/Console.cpp +52 -0
- package/templates/xbox/src/bindings/DomShims.cpp +221 -0
- package/templates/xbox/src/bindings/EventTarget.cpp +127 -0
- package/templates/xbox/src/bindings/EventTarget.h +17 -0
- package/templates/xbox/src/bindings/Fetch.cpp +149 -0
- package/templates/xbox/src/bindings/Gamepad.cpp +79 -0
- package/templates/xbox/src/bindings/Image.cpp +160 -0
- package/templates/xbox/src/bindings/ImageSource.h +26 -0
- package/templates/xbox/src/bindings/Network.cpp +303 -0
- package/templates/xbox/src/bindings/RasterCore.h +265 -0
- package/templates/xbox/src/bindings/Timers.cpp +87 -0
- package/templates/xbox/src/bindings/Video.cpp +235 -0
- package/templates/xbox/src/bindings/webgpu/WebGPU.cpp +1318 -0
- package/templates/xbox/src/bindings/webgpu/WebGPUCommon.h +119 -0
- package/templates/xbox/src/bindings/webgpu/WebGPUEnums.h +245 -0
- package/templates/xbox/src/gpu/DawnContext.cpp +170 -0
- package/templates/xbox/src/gpu/DawnContext.h +64 -0
- package/templates/xbox/src/main.cpp +368 -0
- package/templates/xbox/src/platform/AudioEngine.cpp +184 -0
- package/templates/xbox/src/platform/AudioEngine.h +65 -0
- package/templates/xbox/src/platform/GamepadManager.cpp +83 -0
- package/templates/xbox/src/platform/GamepadManager.h +40 -0
- package/templates/xbox/src/platform/ImageTypes.h +17 -0
- package/templates/xbox/src/platform/TextRasterizer.cpp +183 -0
- package/templates/xbox/src/platform/TextRasterizer.h +35 -0
- package/templates/xbox/src/platform/WicDecoder.cpp +63 -0
- package/templates/xbox/src/platform/WicDecoder.h +16 -0
- package/templates/xbox/src/v8/V8Runtime.cpp +284 -0
- package/templates/xbox/src/v8/V8Runtime.h +68 -0
- package/templates/xbox/src/v8/V8Util.h +56 -0
- package/templates/xbox/src/worker/WorkerRuntime.cpp +453 -0
- package/templates/xbox/src/worker/WorkerRuntime.h +108 -0
- package/templates/xbox/tests/check_local.sh +56 -0
- package/templates/xbox/tests/raster_test.bin +0 -0
- package/templates/xbox/tests/raster_test.cpp +279 -0
- package/templates/xbox/tests/windows_platform_test.cpp +187 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# macOS / Linux で Windows 実機なしに実行できる検証をまとめて回す。
|
|
3
|
+
# 1. RasterCore 単体テスト (実行)
|
|
4
|
+
# 2. RasterCore 単体テスト (ASan/UBSan)
|
|
5
|
+
# 3. V8 依存ソースの構文チェック (実 V8 ヘッダに対して。Windows API 非依存の12ファイル)
|
|
6
|
+
#
|
|
7
|
+
# 使い方:
|
|
8
|
+
# tests/check_local.sh [V8_INCLUDE_DIR]
|
|
9
|
+
# V8_INCLUDE_DIR 省略時は ./.v8_headers/include へ sparse clone する。
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
cd "$(dirname "$0")/.."
|
|
12
|
+
|
|
13
|
+
V8_TAG="13.6.233.17"
|
|
14
|
+
V8INC="${1:-}"
|
|
15
|
+
|
|
16
|
+
echo "== 1/3 RasterCore unit tests =="
|
|
17
|
+
c++ -std=c++17 -Wall -Wextra -O1 -o /tmp/next2d_raster_test tests/raster_test.cpp
|
|
18
|
+
/tmp/next2d_raster_test
|
|
19
|
+
|
|
20
|
+
echo "== 2/3 RasterCore unit tests (ASan/UBSan) =="
|
|
21
|
+
c++ -std=c++17 -g -fsanitize=address,undefined -fno-omit-frame-pointer \
|
|
22
|
+
-o /tmp/next2d_raster_test_asan tests/raster_test.cpp
|
|
23
|
+
/tmp/next2d_raster_test_asan
|
|
24
|
+
|
|
25
|
+
echo "== 3/3 V8-dependent sources syntax check (V8 ${V8_TAG}) =="
|
|
26
|
+
if [ -z "${V8INC}" ]; then
|
|
27
|
+
if [ ! -d ".v8_headers/include" ]; then
|
|
28
|
+
git clone --depth 1 --branch "${V8_TAG}" --filter=blob:none --sparse \
|
|
29
|
+
https://github.com/v8/v8.git .v8_headers
|
|
30
|
+
(cd .v8_headers && git sparse-checkout set include)
|
|
31
|
+
fi
|
|
32
|
+
V8INC=".v8_headers/include"
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# Windows API に依存しない V8 バインディング (Windows 依存分は CI の windows-latest で検証)
|
|
36
|
+
FILES=(
|
|
37
|
+
src/EventLoop.cpp
|
|
38
|
+
src/AssetLoader.cpp
|
|
39
|
+
src/v8/V8Runtime.cpp
|
|
40
|
+
src/worker/WorkerRuntime.cpp
|
|
41
|
+
src/bindings/Console.cpp
|
|
42
|
+
src/bindings/Timers.cpp
|
|
43
|
+
src/bindings/EventTarget.cpp
|
|
44
|
+
src/bindings/Network.cpp
|
|
45
|
+
src/bindings/Fetch.cpp
|
|
46
|
+
src/bindings/Canvas.cpp
|
|
47
|
+
src/bindings/Audio.cpp
|
|
48
|
+
src/bindings/Gamepad.cpp
|
|
49
|
+
)
|
|
50
|
+
for f in "${FILES[@]}"; do
|
|
51
|
+
c++ -fsyntax-only -std=c++20 -Isrc -isystem "${V8INC}" \
|
|
52
|
+
-DV8_COMPRESS_POINTERS -DV8_ENABLE_SANDBOX "$f"
|
|
53
|
+
echo "OK $f"
|
|
54
|
+
done
|
|
55
|
+
|
|
56
|
+
echo "all checks passed"
|
|
Binary file
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
// RasterCore.h (Canvas2D ソフトラスタライザ純ロジック) の単体テスト。
|
|
2
|
+
// V8 / Windows 不要。macOS/Linux では:
|
|
3
|
+
// c++ -std=c++17 -O1 -o raster_test tests/raster_test.cpp && ./raster_test
|
|
4
|
+
// Windows (MSVC) では:
|
|
5
|
+
// cl /std:c++17 /EHsc tests\raster_test.cpp && raster_test.exe
|
|
6
|
+
#include "../src/bindings/RasterCore.h"
|
|
7
|
+
|
|
8
|
+
#include <cmath>
|
|
9
|
+
#include <cstdio>
|
|
10
|
+
|
|
11
|
+
using namespace next2d::raster;
|
|
12
|
+
|
|
13
|
+
static int failures = 0;
|
|
14
|
+
static int checks = 0;
|
|
15
|
+
|
|
16
|
+
#define CHECK(cond) do { ++checks; if (!(cond)) { \
|
|
17
|
+
++failures; std::printf("not ok - %s:%d: %s\n", __FILE__, __LINE__, #cond); } } while (0)
|
|
18
|
+
|
|
19
|
+
#define CHECK_NEAR(a, b, eps) do { ++checks; if (std::fabs((a) - (b)) > (eps)) { \
|
|
20
|
+
++failures; std::printf("not ok - %s:%d: %s=%f != %s=%f\n", \
|
|
21
|
+
__FILE__, __LINE__, #a, static_cast<double>(a), #b, static_cast<double>(b)); } } while (0)
|
|
22
|
+
|
|
23
|
+
// (x,y) のピクセルを取得
|
|
24
|
+
static RGBA Px(const Surface& s, int x, int y)
|
|
25
|
+
{
|
|
26
|
+
size_t i = (static_cast<size_t>(y) * s.width + x) * 4;
|
|
27
|
+
return { s.pixels[i], s.pixels[i+1], s.pixels[i+2], s.pixels[i+3] };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static SubPath MakeRectPath(double x, double y, double w, double h, bool reverse = false)
|
|
31
|
+
{
|
|
32
|
+
SubPath sp;
|
|
33
|
+
if (!reverse) {
|
|
34
|
+
sp.pts = { {x,y}, {x+w,y}, {x+w,y+h}, {x,y+h} };
|
|
35
|
+
} else {
|
|
36
|
+
sp.pts = { {x,y}, {x,y+h}, {x+w,y+h}, {x+w,y} };
|
|
37
|
+
}
|
|
38
|
+
sp.closed = true;
|
|
39
|
+
return sp;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static void TestParseColor()
|
|
43
|
+
{
|
|
44
|
+
RGBA c = ParseColor("#fff");
|
|
45
|
+
CHECK(c.r == 255 && c.g == 255 && c.b == 255 && c.a == 255);
|
|
46
|
+
c = ParseColor("#ff8000");
|
|
47
|
+
CHECK(c.r == 255 && c.g == 128 && c.b == 0);
|
|
48
|
+
c = ParseColor("rgb(10, 20, 30)");
|
|
49
|
+
CHECK(c.r == 10 && c.g == 20 && c.b == 30 && c.a == 255);
|
|
50
|
+
c = ParseColor("rgba(10, 20, 30, 0.5)");
|
|
51
|
+
CHECK(c.r == 10 && c.g == 20 && c.b == 30 && c.a == 127);
|
|
52
|
+
c = ParseColor("");
|
|
53
|
+
CHECK(c.r == 0 && c.g == 0 && c.b == 0 && c.a == 255);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static void TestFontPixelSize()
|
|
57
|
+
{
|
|
58
|
+
CHECK_NEAR(FontPixelSize("10px sans-serif"), 10.0, 1e-9);
|
|
59
|
+
CHECK_NEAR(FontPixelSize("bold 24px Arial"), 24.0, 1e-9);
|
|
60
|
+
CHECK_NEAR(FontPixelSize("italic 1.5px x"), 1.5, 1e-9);
|
|
61
|
+
CHECK_NEAR(FontPixelSize("no-size"), 10.0, 1e-9);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static void TestMatrix()
|
|
65
|
+
{
|
|
66
|
+
// translate(10,0) してから scale(2,2): Canvas と同じく後から掛けた変換が先に適用される
|
|
67
|
+
Mat m;
|
|
68
|
+
m = Multiply(m, {1,0,0,1,10,0});
|
|
69
|
+
m = Multiply(m, {2,0,0,2,0,0});
|
|
70
|
+
Point p = Apply(m, 1, 1);
|
|
71
|
+
CHECK_NEAR(p.x, 12.0, 1e-9);
|
|
72
|
+
CHECK_NEAR(p.y, 2.0, 1e-9);
|
|
73
|
+
|
|
74
|
+
// 90 度回転 (a=cos,b=sin,c=-sin,d=cos)
|
|
75
|
+
const double r = kPi / 2;
|
|
76
|
+
Mat rot = { std::cos(r), std::sin(r), -std::sin(r), std::cos(r), 0, 0 };
|
|
77
|
+
Point q = Apply(rot, 1, 0);
|
|
78
|
+
CHECK_NEAR(q.x, 0.0, 1e-9);
|
|
79
|
+
CHECK_NEAR(q.y, 1.0, 1e-9);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static void TestFillRectPath()
|
|
83
|
+
{
|
|
84
|
+
Surface s(100, 100);
|
|
85
|
+
ClipRect clip;
|
|
86
|
+
std::vector<SubPath> path = { MakeRectPath(10, 10, 10, 10) };
|
|
87
|
+
FillPath(s, clip, path, {255, 0, 0, 255}, 1.0);
|
|
88
|
+
CHECK(Px(s, 15, 15).r == 255 && Px(s, 15, 15).a == 255); // 内側
|
|
89
|
+
CHECK(Px(s, 5, 15).a == 0); // 左外
|
|
90
|
+
CHECK(Px(s, 25, 15).a == 0); // 右外
|
|
91
|
+
CHECK(Px(s, 15, 25).a == 0); // 下外
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
static void TestFillImplicitClose()
|
|
95
|
+
{
|
|
96
|
+
// 未クローズの三角形 (moveTo/lineTo のみ) — Canvas 仕様では fill 時に暗黙クローズ
|
|
97
|
+
Surface s(100, 100);
|
|
98
|
+
ClipRect clip;
|
|
99
|
+
SubPath tri;
|
|
100
|
+
tri.pts = { {10,10}, {50,10}, {30,40} };
|
|
101
|
+
tri.closed = false;
|
|
102
|
+
std::vector<SubPath> path = { tri };
|
|
103
|
+
FillPath(s, clip, path, {0, 255, 0, 255}, 1.0);
|
|
104
|
+
CHECK(Px(s, 30, 20).g == 255); // 重心付近は塗られる
|
|
105
|
+
CHECK(Px(s, 12, 35).a == 0); // 三角形の外
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
static void TestNonzeroWindingDonut()
|
|
109
|
+
{
|
|
110
|
+
// 外周 CW + 内周 CCW → 穴には塗らない (nonzero)
|
|
111
|
+
Surface s(100, 100);
|
|
112
|
+
ClipRect clip;
|
|
113
|
+
std::vector<SubPath> path = {
|
|
114
|
+
MakeRectPath(10, 10, 50, 50, false), // 外周
|
|
115
|
+
MakeRectPath(20, 20, 30, 30, true), // 内周 (逆回り)
|
|
116
|
+
};
|
|
117
|
+
FillPath(s, clip, path, {0, 0, 255, 255}, 1.0);
|
|
118
|
+
CHECK(Px(s, 15, 35).b == 255); // リング部
|
|
119
|
+
CHECK(Px(s, 35, 35).a == 0); // 穴
|
|
120
|
+
|
|
121
|
+
// isPointInPath も同じ nonzero 判定
|
|
122
|
+
CHECK(PointInPath(path, 15, 35));
|
|
123
|
+
CHECK(!PointInPath(path, 35, 35));
|
|
124
|
+
CHECK(!PointInPath(path, 90, 90));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static void TestClip()
|
|
128
|
+
{
|
|
129
|
+
Surface s(100, 100);
|
|
130
|
+
ClipRect clip;
|
|
131
|
+
IntersectClip(clip, 10, 10, 20, 20);
|
|
132
|
+
CHECK(clip.active);
|
|
133
|
+
|
|
134
|
+
std::vector<SubPath> path = { MakeRectPath(0, 0, 100, 100) };
|
|
135
|
+
FillPath(s, clip, path, {255, 0, 0, 255}, 1.0);
|
|
136
|
+
CHECK(Px(s, 15, 15).r == 255); // クリップ内
|
|
137
|
+
CHECK(Px(s, 25, 15).a == 0); // クリップ外 (右)
|
|
138
|
+
CHECK(Px(s, 5, 5).a == 0); // クリップ外 (左上)
|
|
139
|
+
|
|
140
|
+
// 2 回目の clip は積集合
|
|
141
|
+
IntersectClip(clip, 0, 0, 15, 100);
|
|
142
|
+
CHECK_NEAR(clip.x0, 10.0, 1e-9);
|
|
143
|
+
CHECK_NEAR(clip.x1, 15.0, 1e-9);
|
|
144
|
+
Surface s2(100, 100);
|
|
145
|
+
FillPath(s2, clip, path, {255, 0, 0, 255}, 1.0);
|
|
146
|
+
CHECK(Px(s2, 12, 15).r == 255);
|
|
147
|
+
CHECK(Px(s2, 17, 15).a == 0); // 積集合で除外
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
static void TestClearRect()
|
|
151
|
+
{
|
|
152
|
+
Surface s(50, 50);
|
|
153
|
+
ClipRect clip;
|
|
154
|
+
std::vector<SubPath> path = { MakeRectPath(0, 0, 50, 50) };
|
|
155
|
+
FillPath(s, clip, path, {255, 255, 255, 255}, 1.0);
|
|
156
|
+
ClearRect(s, 10, 10, 10, 10);
|
|
157
|
+
CHECK(Px(s, 15, 15).a == 0); // クリア済み
|
|
158
|
+
CHECK(Px(s, 25, 25).r == 255); // クリア外は残る
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
static void TestStroke()
|
|
162
|
+
{
|
|
163
|
+
Surface s(50, 50);
|
|
164
|
+
ClipRect clip;
|
|
165
|
+
SubPath line;
|
|
166
|
+
line.pts = { {5, 10}, {40, 10} };
|
|
167
|
+
line.closed = false;
|
|
168
|
+
std::vector<SubPath> path = { line };
|
|
169
|
+
StrokePath(s, clip, path, {255, 0, 255, 255}, 1.0);
|
|
170
|
+
CHECK(Px(s, 20, 10).r == 255 && Px(s, 20, 10).b == 255);
|
|
171
|
+
CHECK(Px(s, 20, 20).a == 0);
|
|
172
|
+
// 未クローズなので終点→始点の辺は描かれない (stroke は暗黙クローズしない)
|
|
173
|
+
CHECK(Px(s, 45, 10).a == 0);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
static void TestBlendAlpha()
|
|
177
|
+
{
|
|
178
|
+
Surface s(4, 4);
|
|
179
|
+
ClipRect clip;
|
|
180
|
+
// 下地: 白
|
|
181
|
+
Blend(s, clip, 1, 1, {255, 255, 255, 255}, 1.0);
|
|
182
|
+
// 50% の赤を重ねる
|
|
183
|
+
Blend(s, clip, 1, 1, {255, 0, 0, 255}, 0.5);
|
|
184
|
+
RGBA p = Px(s, 1, 1);
|
|
185
|
+
CHECK(p.r == 255);
|
|
186
|
+
CHECK(p.g >= 126 && p.g <= 128);
|
|
187
|
+
CHECK(p.b >= 126 && p.b <= 128);
|
|
188
|
+
|
|
189
|
+
// クリップ外は書き込まれない
|
|
190
|
+
IntersectClip(clip, 0, 0, 1, 1);
|
|
191
|
+
Blend(s, clip, 2, 2, {255, 0, 0, 255}, 1.0);
|
|
192
|
+
CHECK(Px(s, 2, 2).a == 0);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
static void TestFlattenCurves()
|
|
196
|
+
{
|
|
197
|
+
// 2次ベジェ: 終点が p2 に一致
|
|
198
|
+
std::vector<Point> out;
|
|
199
|
+
FlattenQuadratic(out, {0,0}, {5,10}, {10,0});
|
|
200
|
+
CHECK(!out.empty());
|
|
201
|
+
CHECK_NEAR(out.back().x, 10.0, 1e-9);
|
|
202
|
+
CHECK_NEAR(out.back().y, 0.0, 1e-9);
|
|
203
|
+
|
|
204
|
+
// 3次ベジェ: 終点が p3 に一致
|
|
205
|
+
out.clear();
|
|
206
|
+
FlattenCubic(out, {0,0}, {0,10}, {10,10}, {10,0});
|
|
207
|
+
CHECK_NEAR(out.back().x, 10.0, 1e-9);
|
|
208
|
+
CHECK_NEAR(out.back().y, 0.0, 1e-9);
|
|
209
|
+
|
|
210
|
+
// 全周円: 始点と終点が一致し半径を保つ
|
|
211
|
+
out.clear();
|
|
212
|
+
Mat identity;
|
|
213
|
+
FlattenArc(out, identity, 50, 50, 10, 0, 2 * kPi, false);
|
|
214
|
+
CHECK(out.size() == 33);
|
|
215
|
+
CHECK_NEAR(out.front().x, out.back().x, 1e-6);
|
|
216
|
+
CHECK_NEAR(out.front().y, out.back().y, 1e-6);
|
|
217
|
+
for (auto& p : out) {
|
|
218
|
+
CHECK_NEAR(std::hypot(p.x - 50, p.y - 50), 10.0, 1e-6);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ccw で end > start の場合は 2π 巻き戻す (過去に壊れていた経路)
|
|
222
|
+
out.clear();
|
|
223
|
+
FlattenArc(out, identity, 0, 0, 1, 0, kPi / 2, true);
|
|
224
|
+
// 終点は角度 π/2 - 2π = -3π/2 → (cos,sin) = (0, 1)
|
|
225
|
+
CHECK_NEAR(out.back().x, 0.0, 1e-6);
|
|
226
|
+
CHECK_NEAR(out.back().y, 1.0, 1e-6);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
static void TestPathBounds()
|
|
230
|
+
{
|
|
231
|
+
std::vector<SubPath> path = { MakeRectPath(5, 7, 10, 20) };
|
|
232
|
+
double x0, y0, x1, y1;
|
|
233
|
+
CHECK(PathBounds(path, &x0, &y0, &x1, &y1));
|
|
234
|
+
CHECK_NEAR(x0, 5.0, 1e-9);
|
|
235
|
+
CHECK_NEAR(y0, 7.0, 1e-9);
|
|
236
|
+
CHECK_NEAR(x1, 15.0, 1e-9);
|
|
237
|
+
CHECK_NEAR(y1, 27.0, 1e-9);
|
|
238
|
+
|
|
239
|
+
std::vector<SubPath> empty;
|
|
240
|
+
CHECK(!PathBounds(empty, &x0, &y0, &x1, &y1));
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
static void TestTransformedFill()
|
|
244
|
+
{
|
|
245
|
+
// setTransform(2,0,0,2,10,10) で組んだ 5x5 矩形 → デバイス座標 20..30
|
|
246
|
+
Surface s(64, 64);
|
|
247
|
+
ClipRect clip;
|
|
248
|
+
Mat m = {2, 0, 0, 2, 10, 10};
|
|
249
|
+
SubPath sp;
|
|
250
|
+
const double corners[4][2] = { {5,5}, {10,5}, {10,10}, {5,10} };
|
|
251
|
+
for (auto& c : corners) sp.pts.push_back(Apply(m, c[0], c[1]));
|
|
252
|
+
sp.closed = true;
|
|
253
|
+
std::vector<SubPath> path = { sp };
|
|
254
|
+
FillPath(s, clip, path, {255, 128, 0, 255}, 1.0);
|
|
255
|
+
CHECK(Px(s, 25, 25).r == 255);
|
|
256
|
+
CHECK(Px(s, 15, 15).a == 0);
|
|
257
|
+
CHECK(Px(s, 33, 25).a == 0);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
int main()
|
|
261
|
+
{
|
|
262
|
+
TestParseColor();
|
|
263
|
+
TestFontPixelSize();
|
|
264
|
+
TestMatrix();
|
|
265
|
+
TestFillRectPath();
|
|
266
|
+
TestFillImplicitClose();
|
|
267
|
+
TestNonzeroWindingDonut();
|
|
268
|
+
TestClip();
|
|
269
|
+
TestClearRect();
|
|
270
|
+
TestStroke();
|
|
271
|
+
TestBlendAlpha();
|
|
272
|
+
TestFlattenCurves();
|
|
273
|
+
TestPathBounds();
|
|
274
|
+
TestTransformedFill();
|
|
275
|
+
|
|
276
|
+
std::printf("%s: %d checks, %d failures\n",
|
|
277
|
+
failures ? "FAILED" : "ok", checks, failures);
|
|
278
|
+
return failures ? 1 : 0;
|
|
279
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// Windows 実 API (WIC / DirectWrite / Media Foundation / XAudio2) の smoke テスト。
|
|
2
|
+
// V8 / Dawn / GDK 不要 — Windows SDK だけでビルドでき、GitHub Actions の
|
|
3
|
+
// windows-latest ランナーで実行して「Windows 上で実際に動く」ことを検証する。
|
|
4
|
+
//
|
|
5
|
+
// ビルド (Developer Command Prompt / CI):
|
|
6
|
+
// cl /std:c++17 /EHsc /Isrc tests\windows_platform_test.cpp ^
|
|
7
|
+
// src\platform\WicDecoder.cpp src\platform\TextRasterizer.cpp ^
|
|
8
|
+
// src\platform\AudioEngine.cpp ^
|
|
9
|
+
// ole32.lib windowscodecs.lib d2d1.lib dwrite.lib ^
|
|
10
|
+
// mfplat.lib mfreadwrite.lib mfuuid.lib xaudio2.lib shlwapi.lib
|
|
11
|
+
//
|
|
12
|
+
// XAudio2 の CreateMasteringVoice はヘッドレス環境 (音声デバイス無し) では失敗し得る
|
|
13
|
+
// ため warn 扱い。WIC / DirectWrite / MF デコードは必ず成功すべきで、失敗はエラー。
|
|
14
|
+
#ifndef NOMINMAX
|
|
15
|
+
#define NOMINMAX
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
#include "../src/platform/WicDecoder.h"
|
|
19
|
+
#include "../src/platform/TextRasterizer.h"
|
|
20
|
+
#include "../src/platform/AudioEngine.h"
|
|
21
|
+
|
|
22
|
+
#include <Windows.h>
|
|
23
|
+
#include <mfapi.h>
|
|
24
|
+
|
|
25
|
+
#include <algorithm>
|
|
26
|
+
#include <cmath>
|
|
27
|
+
#include <cstdio>
|
|
28
|
+
#include <memory>
|
|
29
|
+
#include <vector>
|
|
30
|
+
|
|
31
|
+
#pragma comment(lib, "ole32.lib")
|
|
32
|
+
#pragma comment(lib, "windowscodecs.lib")
|
|
33
|
+
#pragma comment(lib, "mfplat.lib")
|
|
34
|
+
#pragma comment(lib, "shlwapi.lib")
|
|
35
|
+
|
|
36
|
+
static int failures = 0;
|
|
37
|
+
static int checks = 0;
|
|
38
|
+
|
|
39
|
+
#define CHECK(cond) do { ++checks; if (!(cond)) { \
|
|
40
|
+
++failures; std::printf("not ok - %s:%d: %s\n", __FILE__, __LINE__, #cond); } } while (0)
|
|
41
|
+
|
|
42
|
+
// 2x2 PNG: (0,0)=赤 (1,0)=緑 (0,1)=青 (1,1)=半透明白
|
|
43
|
+
static const unsigned char kTestPng[] = {
|
|
44
|
+
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
|
|
45
|
+
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02,
|
|
46
|
+
0x08, 0x06, 0x00, 0x00, 0x00, 0x72, 0xb6, 0x0d, 0x24, 0x00, 0x00, 0x00,
|
|
47
|
+
0x13, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0x63, 0xf8, 0xcf, 0xc0, 0xf0,
|
|
48
|
+
0x1f, 0x0c, 0x81, 0x34, 0x08, 0x34, 0x00, 0x00, 0x49, 0x49, 0x09, 0x78,
|
|
49
|
+
0x28, 0xa0, 0xdb, 0x77, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44,
|
|
50
|
+
0xae, 0x42, 0x60, 0x82
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// 48kHz mono 16bit PCM WAV (0.5 振幅の矩形波 48 サンプル)
|
|
54
|
+
static const unsigned char kTestWav[] = {
|
|
55
|
+
0x52, 0x49, 0x46, 0x46, 0x84, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45,
|
|
56
|
+
0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
|
|
57
|
+
0x80, 0xbb, 0x00, 0x00, 0x00, 0x77, 0x01, 0x00, 0x02, 0x00, 0x10, 0x00,
|
|
58
|
+
0x64, 0x61, 0x74, 0x61, 0x60, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40,
|
|
59
|
+
0x00, 0x40, 0x00, 0x40, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0,
|
|
60
|
+
0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xc0, 0x00, 0xc0,
|
|
61
|
+
0x00, 0xc0, 0x00, 0xc0, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40,
|
|
62
|
+
0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0x40, 0x00, 0x40,
|
|
63
|
+
0x00, 0x40, 0x00, 0x40, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0,
|
|
64
|
+
0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xc0, 0x00, 0xc0,
|
|
65
|
+
0x00, 0xc0, 0x00, 0xc0, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40,
|
|
66
|
+
0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// --- WIC: PNG デコード (createImageBitmap / Image.src の実体) ---------------
|
|
70
|
+
static void TestWicDecode()
|
|
71
|
+
{
|
|
72
|
+
std::vector<uint8_t> png(kTestPng, kTestPng + sizeof(kTestPng));
|
|
73
|
+
next2d::DecodedImage img;
|
|
74
|
+
CHECK(next2d::DecodeImageWithWIC(png, img));
|
|
75
|
+
CHECK(img.width == 2 && img.height == 2);
|
|
76
|
+
CHECK(img.rgba.size() == 16);
|
|
77
|
+
// (0,0)=赤
|
|
78
|
+
CHECK(img.rgba[0] == 255 && img.rgba[1] == 0 && img.rgba[2] == 0 && img.rgba[3] == 255);
|
|
79
|
+
// (1,0)=緑
|
|
80
|
+
CHECK(img.rgba[4] == 0 && img.rgba[5] == 255 && img.rgba[6] == 0);
|
|
81
|
+
// (0,1)=青
|
|
82
|
+
CHECK(img.rgba[8] == 0 && img.rgba[9] == 0 && img.rgba[10] == 255);
|
|
83
|
+
// (1,1)=半透明 (alpha=128)
|
|
84
|
+
CHECK(img.rgba[15] == 128);
|
|
85
|
+
|
|
86
|
+
// 壊れた入力は false
|
|
87
|
+
std::vector<uint8_t> garbage(32, 0xAB);
|
|
88
|
+
next2d::DecodedImage bad;
|
|
89
|
+
CHECK(!next2d::DecodeImageWithWIC(garbage, bad));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// --- DirectWrite: メトリクスとグリフラスタライズ (fillText の実体) ----------
|
|
93
|
+
static void TestTextRasterizer()
|
|
94
|
+
{
|
|
95
|
+
next2d::TextMetricsInfo m;
|
|
96
|
+
CHECK(next2d::MeasureTextWithDWrite("24px Segoe UI", L"Hello", m));
|
|
97
|
+
CHECK(m.width > 10.0);
|
|
98
|
+
CHECK(m.ascent > 5.0 && m.ascent < 40.0);
|
|
99
|
+
CHECK(m.descent > 0.0 && m.descent < 20.0);
|
|
100
|
+
|
|
101
|
+
// bold は同サイズの normal より広い (フォントメトリクスの妥当性)
|
|
102
|
+
next2d::TextMetricsInfo mb;
|
|
103
|
+
CHECK(next2d::MeasureTextWithDWrite("bold 24px Segoe UI", L"Hello", mb));
|
|
104
|
+
CHECK(mb.width >= m.width);
|
|
105
|
+
|
|
106
|
+
next2d::TextBitmap bmp;
|
|
107
|
+
CHECK(next2d::RasterizeTextWithDWrite("24px Segoe UI", L"A", 255, 0, 0, bmp));
|
|
108
|
+
CHECK(bmp.width > 0 && bmp.height > 0);
|
|
109
|
+
CHECK(bmp.baseline > 0.0);
|
|
110
|
+
// 何らかの不透明ピクセルがあり、色は赤
|
|
111
|
+
int opaque = 0;
|
|
112
|
+
bool red_ok = true;
|
|
113
|
+
for (size_t i = 0; i + 3 < bmp.rgba.size(); i += 4) {
|
|
114
|
+
if (bmp.rgba[i + 3] > 200) {
|
|
115
|
+
++opaque;
|
|
116
|
+
if (bmp.rgba[i] < 200 || bmp.rgba[i + 1] > 60 || bmp.rgba[i + 2] > 60) red_ok = false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
CHECK(opaque > 5);
|
|
120
|
+
CHECK(red_ok);
|
|
121
|
+
|
|
122
|
+
// 日本語グリフもラスタライズできる
|
|
123
|
+
next2d::TextBitmap jp;
|
|
124
|
+
CHECK(next2d::RasterizeTextWithDWrite("24px Yu Gothic", L"あ", 0, 0, 0, jp)); // あ
|
|
125
|
+
int jp_opaque = 0;
|
|
126
|
+
for (size_t i = 3; i < jp.rgba.size(); i += 4) if (jp.rgba[i] > 200) ++jp_opaque;
|
|
127
|
+
CHECK(jp_opaque > 5);
|
|
128
|
+
|
|
129
|
+
// 空文字は false
|
|
130
|
+
next2d::TextBitmap empty;
|
|
131
|
+
CHECK(!next2d::RasterizeTextWithDWrite("24px Segoe UI", L"", 0, 0, 0, empty));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// --- Media Foundation: 音声デコード (decodeAudioData の実体) -----------------
|
|
135
|
+
static void TestAudioDecode()
|
|
136
|
+
{
|
|
137
|
+
std::vector<uint8_t> wav(kTestWav, kTestWav + sizeof(kTestWav));
|
|
138
|
+
next2d::PcmBuffer pcm;
|
|
139
|
+
CHECK(next2d::AudioEngine::Decode(wav, pcm));
|
|
140
|
+
CHECK(pcm.sample_rate == 48000);
|
|
141
|
+
CHECK(pcm.channels == 1);
|
|
142
|
+
CHECK(pcm.samples.size() >= 40); // 48 サンプル前後 (MF は端数調整あり)
|
|
143
|
+
// 振幅 0.5 の矩形波 → ピーク絶対値が 0.4〜0.6
|
|
144
|
+
float peak = 0;
|
|
145
|
+
for (float s : pcm.samples) peak = std::max(peak, std::fabs(s));
|
|
146
|
+
CHECK(peak > 0.4f && peak < 0.6f);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// --- XAudio2: 初期化 (ヘッドレス CI では音声デバイスが無く失敗し得る → warn) --
|
|
150
|
+
static void TestAudioEngineInit()
|
|
151
|
+
{
|
|
152
|
+
next2d::AudioEngine engine;
|
|
153
|
+
if (!engine.Initialize()) {
|
|
154
|
+
std::printf("warn - XAudio2 init failed (headless runner? not counted as failure)\n");
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
std::printf("ok - XAudio2 initialized\n");
|
|
158
|
+
// ボイス生成 + 音量設定 + 即停止 (クラッシュしないこと)
|
|
159
|
+
auto pcm = std::make_shared<next2d::PcmBuffer>();
|
|
160
|
+
pcm->sample_rate = 48000;
|
|
161
|
+
pcm->channels = 1;
|
|
162
|
+
pcm->samples.assign(480, 0.1f);
|
|
163
|
+
auto voice = engine.CreateVoice(pcm);
|
|
164
|
+
CHECK(voice != nullptr);
|
|
165
|
+
voice->SetVolume(0.5f);
|
|
166
|
+
voice->Start(false);
|
|
167
|
+
CHECK(!voice->IsFinished() || true); // 状態取得がクラッシュしないこと
|
|
168
|
+
voice->Stop();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
int main()
|
|
172
|
+
{
|
|
173
|
+
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
|
174
|
+
// AudioEngine::Decode は MF を使う (AudioEngine::Initialize を通さない場合は自前で起動)
|
|
175
|
+
MFStartup(MF_VERSION);
|
|
176
|
+
|
|
177
|
+
TestWicDecode();
|
|
178
|
+
TestTextRasterizer();
|
|
179
|
+
TestAudioDecode();
|
|
180
|
+
TestAudioEngineInit();
|
|
181
|
+
|
|
182
|
+
MFShutdown();
|
|
183
|
+
|
|
184
|
+
std::printf("%s: %d checks, %d failures\n",
|
|
185
|
+
failures ? "FAILED" : "ok", checks, failures);
|
|
186
|
+
return failures ? 1 : 0;
|
|
187
|
+
}
|