Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
36486a7
#263 マスク処理後のフィルター適用のバグを改修、不要なコードやファイルを削除
ienaga Mar 13, 2026
f83c2eb
#263 不要なファイルを削除
ienaga Mar 13, 2026
a1f3733
#260 webgpu版のリファクタリング
ienaga Mar 13, 2026
8c29809
#260 webgpu版のリファクタリング
ienaga Mar 13, 2026
9252019
#260 テストケースを追加
ienaga Mar 13, 2026
2b1cfa4
#265 update packages
ienaga Mar 26, 2026
5f5a846
#265 利用していないライブラリを削除
ienaga Mar 26, 2026
b9f84ba
#265 エラーハンドリングを追加
ienaga Mar 26, 2026
996cd54
#265 zip解凍だけに特化した処理に変更
ienaga Mar 26, 2026
3384c88
#266 htmlTextの出力結果をe2eテストとして追加
ienaga Mar 26, 2026
f8131be
#266 htmlTextのパース処理を高速化
ienaga Mar 26, 2026
a19809c
refactor(webgpu): add JSDoc and convert camelCase params to snake_cas…
ienaga Mar 26, 2026
c595e24
#267 WebGPUのリファクタリング
ienaga Mar 26, 2026
afe740e
#267 WebGPUのリファクタリング
ienaga Mar 26, 2026
9c30887
#260 e2eテストを追加
ienaga Mar 27, 2026
adbdffb
#260 テストケースを追加
ienaga Mar 27, 2026
214f465
#260 cacheAsBitmapの機能を追加
ienaga Mar 27, 2026
27bcfe4
fix: cacheAsBitmap cache reuse + bitmap-like drawing path
ienaga Mar 27, 2026
1ca4db6
#260 必要なタイミングで計算ロジックを実行する
ienaga Mar 27, 2026
1e346ab
feat: make cacheAsBitmap Matrix scale 1.0-based relative to own scale…
ienaga Mar 27, 2026
961e47e
#260 cacheAsBitmapで設定したMatrixをDisplayObjectのmatrixに加算
ienaga Mar 27, 2026
cb7f81a
#260 update e2eテスト
ienaga Mar 27, 2026
087a256
#269 e2eテストを追加
ienaga Mar 29, 2026
3d1e266
#269 ドキュメントを更新
ienaga Mar 29, 2026
077aad3
#269 DisplayObjectContainerのcacheAsBitmapを実装
ienaga Mar 29, 2026
63725ea
#269 ドキュメントを更新
ienaga Mar 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 55 additions & 21 deletions e2e/pages/mask/sprite-mask.html
Original file line number Diff line number Diff line change
Expand Up @@ -592,32 +592,66 @@
container15.addChild(triangleMask);
videoWrapper3.mask = triangleMask;

// 全ビデオの読み込みと再生開始を待機
// 全ビデオのcompleteイベントを待機
const allVideos = [video1, video2, video3];
const waitForVideos = () => {
await Promise.all(allVideos.map(video => {
return new Promise((resolve) => {
const checkLoaded = () => {
// loadedかつ再生中(paused=false)を確認
if (allVideos.every(v => v.loaded && !v.paused)) {
// フレーム描画を待つために複数フレーム待機
let frameCount = 0;
const waitFrames = () => {
frameCount++;
if (frameCount >= 10) {
setTimeout(resolve, 1000);
} else {
requestAnimationFrame(waitFrames);
}
};
requestAnimationFrame(waitFrames);
} else {
requestAnimationFrame(checkLoaded);
}
if (video.loaded && !video.paused) {
resolve();
} else {
video.addEventListener("complete", () => resolve());
}
});
}));

// 固定フレームのためにシークして一時停止
const SEEK_TIME = 1.0;
await Promise.all(allVideos.map(video => {
return new Promise((resolve) => {
if (!video.$videoElement) {
resolve();
return;
}

const onSeeked = () => {
video.$videoElement.removeEventListener("seeked", onSeeked);
video.pause();
resolve();
};
checkLoaded();

video.$videoElement.addEventListener("seeked", onSeeked);
video.seek(SEEK_TIME);
});
}));

// changedフラグを更新してレンダリングを強制
const applyChanges = (displayObject) => {
displayObject.changed = true;
let parent = displayObject.parent;
while (parent && !parent.changed) {
parent.changed = true;
parent = parent.parent;
}
};
await waitForVideos();

// レンダリング安定化のため数フレーム待機
await new Promise((resolve) => {
let frameCount = 0;
const waitFrames = () => {
allVideos.forEach((video) => {
if (video.$videoElement && video.$videoElement.readyState >= 2) {
applyChanges(video);
}
});
frameCount++;
if (frameCount >= 10) {
resolve();
} else {
requestAnimationFrame(waitFrames);
}
};
requestAnimationFrame(waitFrames);
});

window.__E2E_RENDER_COMPLETE__ = true;
});
Expand Down
161 changes: 161 additions & 0 deletions e2e/pages/shape/cache-as-bitmap.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Next2D E2E - Shape cacheAsBitmap</title>
<script defer type="module" src="/src/index.ts"></script>
<style>
body { margin: 0; padding: 0; background: #333333; }
</style>
</head>
<body>
<script type="module">
window.addEventListener("DOMContentLoaded", async () => {
const root = await next2d.createRootMovieClip(600, 500, 60);
const { Shape, Sprite } = next2d.display;
const { Matrix } = next2d.geom;

// ===== 1. 基本: cacheAsBitmap=Matrix(1,0,0,1) で等倍キャッシュ =====
const shape1 = new Shape();
shape1.graphics
.beginFill(0xFF0000, 1.0)
.drawCircle(60, 60, 50)
.endFill();
shape1.cacheAsBitmap = new Matrix(1, 0, 0, 1, 0, 0);
root.addChild(shape1);

// ===== 2. cacheAsBitmap=Matrix(2,0,0,2) で2倍キャッシュ =====
const shape2 = new Shape();
shape2.graphics
.beginFill(0x00FF00, 1.0)
.drawCircle(60, 60, 50)
.endFill();
shape2.x = 140;
shape2.cacheAsBitmap = new Matrix(2, 0, 0, 2, 0, 0);
root.addChild(shape2);

// ===== 3. 先祖のスケールの影響を受けないことを確認 =====
// 親Spriteを2倍にしても、キャッシュ品質はcacheAsBitmapのMatrixで固定
const container1 = new Sprite();
container1.scaleX = 2;
container1.scaleY = 2;
container1.x = 280;
root.addChild(container1);

const shape3 = new Shape();
shape3.graphics
.beginFill(0x0000FF, 1.0)
.drawRect(0, 0, 50, 50)
.endFill();
shape3.cacheAsBitmap = new Matrix(1, 0, 0, 1, 0, 0);
container1.addChild(shape3);

// ===== 4. 比較用: cacheAsBitmapなし(親スケール2倍) =====
const container2 = new Sprite();
container2.scaleX = 2;
container2.scaleY = 2;
container2.x = 420;
root.addChild(container2);

const shape4 = new Shape();
shape4.graphics
.beginFill(0x0000FF, 1.0)
.drawRect(0, 0, 50, 50)
.endFill();
// cacheAsBitmapなし
container2.addChild(shape4);

// ===== 5. 回転した親の中でcacheAsBitmap =====
const container3 = new Sprite();
container3.x = 100;
container3.y = 250;
container3.rotation = 30;
root.addChild(container3);

const shape5 = new Shape();
shape5.graphics
.beginFill(0xFF00FF, 1.0)
.drawRoundRect(0, 0, 80, 60, 10)
.endFill();
shape5.cacheAsBitmap = new Matrix(1, 0, 0, 1, 0, 0);
container3.addChild(shape5);

// ===== 6. 比較用: cacheAsBitmapなし(回転親) =====
const container4 = new Sprite();
container4.x = 280;
container4.y = 250;
container4.rotation = 30;
root.addChild(container4);

const shape6 = new Shape();
shape6.graphics
.beginFill(0xFF00FF, 1.0)
.drawRoundRect(0, 0, 80, 60, 10)
.endFill();
// cacheAsBitmapなし
container4.addChild(shape6);

// ===== 7. 複雑な図形でcacheAsBitmap =====
const shape7 = new Shape();
shape7.graphics
.beginFill(0xFFFF00, 1.0)
.drawCircle(40, 40, 30)
.endFill()
.beginFill(0xFF8800, 1.0)
.drawRect(20, 20, 40, 40)
.endFill();
shape7.x = 20;
shape7.y = 360;
shape7.cacheAsBitmap = new Matrix(2, 0, 0, 2, 0, 0);
root.addChild(shape7);

// ===== 8. 線付き図形のcacheAsBitmap =====
const shape8 = new Shape();
shape8.graphics
.lineStyle(3, 0xFFFFFF, 1.0)
.beginFill(0x00FFFF, 0.8)
.drawEllipse(0, 0, 100, 60)
.endFill();
shape8.x = 150;
shape8.y = 360;
shape8.cacheAsBitmap = new Matrix(1, 0, 0, 1, 0, 0);
root.addChild(shape8);

// ===== 9. 深いネスト: 祖父母→親→子すべてにスケール =====
const grandParent = new Sprite();
grandParent.scaleX = 1.5;
grandParent.scaleY = 1.5;
grandParent.x = 350;
grandParent.y = 300;
root.addChild(grandParent);

const parent9 = new Sprite();
parent9.scaleX = 1.5;
parent9.scaleY = 1.5;
grandParent.addChild(parent9);

const shape9 = new Shape();
shape9.graphics
.beginFill(0x88FF88, 1.0)
.drawCircle(20, 20, 20)
.endFill();
shape9.cacheAsBitmap = new Matrix(1, 0, 0, 1, 0, 0);
parent9.addChild(shape9);

// ===== 10. cacheAsBitmap=null(デフォルト動作確認) =====
const shape10 = new Shape();
shape10.graphics
.beginFill(0xFFFFFF, 1.0)
.drawRect(0, 0, 40, 40)
.endFill();
shape10.x = 500;
shape10.y = 360;
shape10.cacheAsBitmap = null;
root.addChild(shape10);

window.__E2E_RENDER_COMPLETE__ = true;
});
</script>
</body>
</html>
104 changes: 104 additions & 0 deletions e2e/pages/sprite/cache-as-bitmap-hit.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Next2D E2E - Sprite cacheAsBitmap cache HIT test</title>
<script defer type="module" src="/src/index.ts"></script>
<style>
body { margin: 0; padding: 0; background: #333333; }
</style>
</head>
<body>
<script type="module">
window.addEventListener("DOMContentLoaded", async () => {
const root = await next2d.createRootMovieClip(800, 600, 60);
const { Shape, Sprite } = next2d.display;
const { Matrix } = next2d.geom;

// Sprite内に複数子要素を配置するヘルパー
const createTestSprite = (x, y) => {
const sprite = new Sprite();
sprite.x = x;
sprite.y = y;

const rect = new Shape();
rect.graphics
.beginFill(0xFF0000, 1.0)
.drawRect(0, 0, 100, 80)
.endFill();
sprite.addChild(rect);

const circle = new Shape();
circle.graphics
.beginFill(0x00FF00, 1.0)
.drawCircle(50, 40, 30)
.endFill();
sprite.addChild(circle);

const small = new Shape();
small.graphics
.beginFill(0x0000FF, 1.0)
.drawRect(60, 10, 30, 30)
.endFill();
sprite.addChild(small);

return sprite;
};

// ===== cacheAsBitmapなし(参照用)=====
const noCache = createTestSprite(30, 30);
root.addChild(noCache);

// ===== cacheAsBitmap(等倍、単位行列)=====
const cached1x = createTestSprite(180, 30);
cached1x.cacheAsBitmap = new Matrix(1, 0, 0, 1, 0, 0);
root.addChild(cached1x);

// ===== cacheAsBitmap + 親スケール =====
const cachedScaled = createTestSprite(30, 180);
cachedScaled.scaleX = 1.5;
cachedScaled.scaleY = 1.5;
cachedScaled.cacheAsBitmap = new Matrix(1, 0, 0, 1, 0, 0);
root.addChild(cachedScaled);

// ===== cacheAsBitmap + 回転 =====
const cachedRotated = createTestSprite(280, 180);
cachedRotated.rotation = 30;
cachedRotated.cacheAsBitmap = new Matrix(1, 0, 0, 1, 0, 0);
root.addChild(cachedRotated);

// ===== ネストされたSprite + cacheAsBitmap =====
const outer = new Sprite();
outer.x = 480;
outer.y = 180;
const inner = createTestSprite(0, 0);
inner.cacheAsBitmap = new Matrix(1, 0, 0, 1, 0, 0);
outer.addChild(inner);
root.addChild(outer);

// 最初のフレームが描画されるまで待機(cache miss)
// その後、兄弟要素を追加して再描画をトリガー(cache hit を検証)
let frameCount = 0;
root.addEventListener("enterFrame", () => {
frameCount++;
if (frameCount === 5) {
// cache hit をトリガーするため、兄弟の Shape を追加
const trigger = new Shape();
trigger.graphics
.beginFill(0xFFFF00, 1.0)
.drawRect(0, 0, 40, 40)
.endFill();
trigger.x = 700;
trigger.y = 500;
root.addChild(trigger);
}
if (frameCount >= 10) {
// 十分なフレーム経過後に完了フラグ
window.__E2E_RENDER_COMPLETE__ = true;
}
});
});
</script>
</body>
</html>
Loading
Loading