50 lines
3.0 KiB
TypeScript
50 lines
3.0 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { readFileSync } from 'node:fs';
|
|
import { Mesh, MeshStandardMaterial } from 'three';
|
|
import { createBuildings } from '../src/scene/buildings.ts';
|
|
import { loadBuildingAssets, createBakedBuildings } from '../src/scene/buildingAssets.ts';
|
|
|
|
test('saved buildings load without GeoJSON and preserve geometry and lighting exactly', async (t) => {
|
|
const requested: string[] = [];
|
|
t.mock.method(globalThis, 'fetch', async (input: string) => {
|
|
requested.push(input);
|
|
const path = new URL(input, 'http://localhost').pathname;
|
|
return new Response(readFileSync(new URL(`../public${path}`, import.meta.url)));
|
|
});
|
|
const metadata = JSON.parse(readFileSync(new URL('../public/terrain/gwanaksan.json', import.meta.url), 'utf8'));
|
|
const bytes = readFileSync(new URL('../public/terrain/gwanaksan.f32', import.meta.url));
|
|
const terrain = { metadata, heights: new Float32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 4) };
|
|
const data = JSON.parse(readFileSync(new URL('../public/buildings/gwacheon.geojson', import.meta.url), 'utf8'));
|
|
const saved = await loadBuildingAssets();
|
|
assert.equal(requested.length, 2);
|
|
assert.ok(requested.every(path => !path.includes('.geojson')));
|
|
const baked = createBakedBuildings(saved, metadata);
|
|
const original = createBuildings(data, terrain);
|
|
try {
|
|
assert.deepEqual(baked.counts, original.counts);
|
|
assert.deepEqual(baked.target, original.target);
|
|
assert.equal(baked.group.children.length, original.group.children.length);
|
|
for (const [i, child] of baked.group.children.entries()) {
|
|
const actual = child as Mesh, expected = original.group.children[i] as Mesh;
|
|
assert.equal(actual.name, expected.name);
|
|
for (const name of ['position', 'normal', 'buildingLightHeight']) {
|
|
assert.deepEqual(actual.geometry.getAttribute(name).array, expected.geometry.getAttribute(name).array);
|
|
}
|
|
assert.deepEqual(actual.geometry.index!.array, expected.geometry.index!.array);
|
|
expected.geometry.computeBoundingBox(); expected.geometry.computeBoundingSphere();
|
|
assert.deepEqual(actual.geometry.boundingBox, expected.geometry.boundingBox);
|
|
assert.deepEqual(actual.geometry.boundingSphere, expected.geometry.boundingSphere);
|
|
assert.equal((actual.material as MeshStandardMaterial).color.getHex(), (expected.material as MeshStandardMaterial).color.getHex());
|
|
}
|
|
assert.deepEqual(baked.spill.texture.image.data, original.spill.texture.image.data);
|
|
assert.deepEqual(baked.spill.bounds, original.spill.bounds);
|
|
for (const altitude of [-8, 0, 6, -8]) {
|
|
baked.update(altitude); original.update(altitude);
|
|
assert.equal(baked.spill.intensity.value, original.spill.intensity.value);
|
|
}
|
|
assert.throws(() => createBakedBuildings(saved, { ...metadata, observerSurfaceElevation: metadata.observerSurfaceElevation + 1 }), /지형/);
|
|
assert.throws(() => createBakedBuildings({ ...saved, buffer: saved.buffer.slice(4) }, metadata), /건물/);
|
|
} finally { baked.dispose(); original.dispose(); }
|
|
});
|