122 lines
3.7 KiB
JavaScript
122 lines
3.7 KiB
JavaScript
import { expect } from "@esm-bundle/chai";
|
|
import { VoxelManager } from "../../src/grid/VoxelManager.js";
|
|
import { VoxelGrid } from "../../src/grid/VoxelGrid.js";
|
|
import * as THREE from "three";
|
|
|
|
describe("Phase 1: VoxelManager Rendering (WebGL)", function () {
|
|
// Increase timeout to 60s for slow WebGL initialization in headless/software mode
|
|
this.timeout(60000);
|
|
|
|
let grid;
|
|
let scene;
|
|
let manager;
|
|
let renderer;
|
|
|
|
before(function () {
|
|
// Allow extra time specifically for the first context creation
|
|
this.timeout(30000);
|
|
|
|
// 1. Setup a real WebGL Renderer (Headless)
|
|
const canvas = document.createElement("canvas");
|
|
|
|
// FORCE WebGL 2 (Required for Three.js r163+)
|
|
const context = canvas.getContext("webgl2");
|
|
|
|
if (!context) {
|
|
console.warn(
|
|
"WebGL 2 not supported in this test environment. Skipping render checks."
|
|
);
|
|
this.skip();
|
|
return;
|
|
}
|
|
|
|
renderer = new THREE.WebGLRenderer({ canvas, context });
|
|
});
|
|
|
|
after(function () {
|
|
if (renderer) {
|
|
renderer.dispose();
|
|
// Explicitly force context loss to free up resources for other test files
|
|
if (renderer.forceContextLoss) renderer.forceContextLoss();
|
|
}
|
|
});
|
|
|
|
beforeEach(() => {
|
|
grid = new VoxelGrid(4, 4, 4);
|
|
scene = new THREE.Scene();
|
|
manager = new VoxelManager(grid, scene);
|
|
});
|
|
|
|
it("CoA 1: update() should create separate InstancedMeshes for different IDs", () => {
|
|
grid.setCell(0, 0, 0, 1); // ID 1 (Stone)
|
|
grid.setCell(1, 0, 0, 2); // ID 2 (Dirt)
|
|
|
|
// In the new multi-material manager, update() handles initialization
|
|
manager.update();
|
|
|
|
// Should have 2 children in the scene (one mesh per ID) + Focus Target
|
|
// Filter to just find meshes
|
|
const meshes = scene.children.filter((c) => c.isInstancedMesh);
|
|
expect(meshes.length).to.equal(2);
|
|
});
|
|
|
|
it("CoA 2: update() should correctly position instances", () => {
|
|
grid.setCell(2, 2, 2, 1); // Specific position
|
|
manager.update();
|
|
|
|
// Find the mesh corresponding to ID 1
|
|
const mesh = scene.children.find((c) => c.isInstancedMesh);
|
|
const matrix = new THREE.Matrix4();
|
|
|
|
// Since there is only 1 voxel of ID 1, it will be at instance index 0
|
|
mesh.getMatrixAt(0, matrix);
|
|
|
|
const position = new THREE.Vector3().setFromMatrixPosition(matrix);
|
|
|
|
expect(position.x).to.equal(2);
|
|
expect(position.y).to.equal(2);
|
|
expect(position.z).to.equal(2);
|
|
});
|
|
|
|
it("CoA 3: render loop should not crash", () => {
|
|
// Verify we can actually call render() without WebGL errors
|
|
const camera = new THREE.PerspectiveCamera();
|
|
manager.update();
|
|
|
|
expect(() => renderer.render(scene, camera)).to.not.throw();
|
|
});
|
|
|
|
it("CoA 4: updateMaterials() should apply texture to material", () => {
|
|
// Mock a generated asset
|
|
const mockCanvas = document.createElement("canvas");
|
|
const assets = {
|
|
textures: {
|
|
floor: mockCanvas,
|
|
},
|
|
};
|
|
|
|
// Create a floor voxel (ID 2)
|
|
grid.setCell(0, 0, 0, 2);
|
|
|
|
manager.updateMaterials(assets);
|
|
|
|
const mesh = scene.children.find((c) => c.isInstancedMesh);
|
|
// Material could be single or array (multi-material)
|
|
// ID 2 uses an array [side, side, top, bottom, front, back]
|
|
const mat = Array.isArray(mesh.material) ? mesh.material[2] : mesh.material;
|
|
|
|
expect(mat.map).to.exist;
|
|
expect(mat.map.image).to.equal(mockCanvas);
|
|
});
|
|
|
|
it("CoA 5: Should create a Focus Target at the center of the grid", () => {
|
|
// Grid is 4x4x4. Center is roughly 2, 0, 2.
|
|
manager.update();
|
|
|
|
expect(manager.focusTarget).to.exist;
|
|
expect(manager.focusTarget.parent).to.equal(scene);
|
|
|
|
expect(manager.focusTarget.position.x).to.equal(2);
|
|
expect(manager.focusTarget.position.z).to.equal(2);
|
|
});
|
|
});
|