Complete portable planetary presentation contracts

This commit is contained in:
Meta Vens 2026-07-13 02:52:13 +01:00
commit 102403efac
74 changed files with 1166 additions and 31 deletions

View file

@ -0,0 +1,21 @@
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { decodePlanetarySurfaceTile } from "./planetary-tile.ts";
if (process.argv.length !== 3) throw new Error("Expected a generated CMPT fixture path");
const bytes = await readFile(process.argv[2]);
const arrayBuffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
const tile = decodePlanetarySurfaceTile(arrayBuffer);
assert.equal(tile.header.projectionVersion, 3);
assert.equal(tile.header.layerId, 29);
assert.equal(tile.header.projectionKind, 2);
assert.equal(tile.header.interiorSize, 5);
assert.equal(tile.header.borderSize, 1);
assert.equal(tile.storageSize, 7);
assert.equal(tile.samples.length, 49);
assert.ok(tile.samples.some(sample => sample !== null));
for (const sample of tile.samples) {
if (sample === null) continue;
assert.ok(Number.isFinite(sample.radialDisplacement));
assert.ok(Number.isFinite(sample.unresolvedHeightBound));
}

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7bc397e5660d2b6448919c41983d35e8
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,39 @@
import assert from "node:assert/strict";
import { decodePlanetarySurfaceTile } from "./planetary-tile.ts";
const bytes = new ArrayBuffer(152);
const view = new DataView(bytes);
let offset = 0;
const u8 = value => view.setUint8(offset++, value);
const u32 = value => { view.setUint32(offset, value, true); offset += 4; };
const i32 = value => { view.setInt32(offset, value, true); offset += 4; };
const u64 = value => { view.setBigUint64(offset, value, true); offset += 8; };
const f32 = value => { view.setFloat32(offset, value, true); offset += 4; };
const f64 = value => { view.setFloat64(offset, value, true); offset += 8; };
for (const character of "CMPT") u8(character.charCodeAt(0));
u32(1); u64(0x1234n); u32(2); u32(17); i32(0);
f64(0); f64(0); f64(1);
i32(0); i32(0); i32(0); i32(2); i32(0);
f32(10); f32(0.5); i32(4);
u8(1);
for (const value of [1, 0, 0]) f32(value);
f32(8.4); f32(0.25);
for (const value of [0, 0.1, 0]) f32(value);
for (const value of [0.99, -0.1, 0]) f32(value);
for (const value of [0.1, 0.8, 0.2, 2.5, 0.05]) f32(value);
u8(0); u8(0); u8(0);
assert.equal(offset, bytes.byteLength);
const tile = decodePlanetarySurfaceTile(bytes);
assert.equal(tile.header.fieldVersion, 0x1234n);
assert.equal(tile.header.layerId, 17);
assert.equal(tile.storageSize, 2);
assert.equal(tile.samples.length, 4);
assert.equal(tile.samples[0]?.radialDisplacement, 0.25);
assert.equal(tile.samples[1], null);
assert.throws(() => decodePlanetarySurfaceTile(bytes.slice(0, bytes.byteLength - 1)), /Truncated/);
const trailing = new Uint8Array(bytes.byteLength + 1);
trailing.set(new Uint8Array(bytes));
assert.throws(() => decodePlanetarySurfaceTile(trailing.buffer), /trailing/);

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 04c93ecab90d465499aa3d60722e6fc3
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

89
web/planetary-tile.ts Normal file
View file

@ -0,0 +1,89 @@
export const CULTMATH_PLANETARY_TILE_VERSION = 1;
export interface PlanetaryTileHeader {
fieldVersion: bigint;
projectionVersion: number;
layerId: number;
projectionKind: number;
centerLongitude: number;
centerLatitude: number;
projectionScale: number;
level: number;
x: number;
y: number;
interiorSize: number;
borderSize: number;
footprintMeters: number;
maximumUnresolvedHeight: number;
}
export interface PlanetaryTileSample {
direction: readonly [number, number, number];
radius: number;
radialDisplacement: number;
tangentGradient: readonly [number, number, number];
surfaceNormal: readonly [number, number, number];
slope: number;
ridge: number;
gully: number;
finestResolvedWavelength: number;
unresolvedHeightBound: number;
}
export interface PlanetarySurfaceTile {
header: PlanetaryTileHeader;
storageSize: number;
samples: readonly (PlanetaryTileSample | null)[];
}
export function decodePlanetarySurfaceTile(bytes: ArrayBuffer): PlanetarySurfaceTile {
const view = new DataView(bytes);
let offset = 0;
const u8 = () => view.getUint8(offset++);
const u32 = () => { const value = view.getUint32(offset, true); offset += 4; return value; };
const i32 = () => { const value = view.getInt32(offset, true); offset += 4; return value; };
const f32 = () => { const value = view.getFloat32(offset, true); offset += 4; return value; };
const f64 = () => { const value = view.getFloat64(offset, true); offset += 8; return value; };
const u64 = () => { const value = view.getBigUint64(offset, true); offset += 8; return value; };
const vector3 = (): [number, number, number] => [f32(), f32(), f32()];
const requireRemaining = (count: number) => {
if (offset + count > view.byteLength) throw new Error("Truncated CultMath planetary tile");
};
requireRemaining(8);
if (String.fromCharCode(u8(), u8(), u8(), u8()) !== "CMPT") throw new Error("Not a CultMath planetary tile");
const version = u32();
if (version !== CULTMATH_PLANETARY_TILE_VERSION) throw new Error(`Unsupported CultMath planetary tile version ${version}`);
requireRemaining(76);
const header: PlanetaryTileHeader = {
fieldVersion: u64(),
projectionVersion: u32(),
layerId: u32(),
projectionKind: i32(),
centerLongitude: f64(),
centerLatitude: f64(),
projectionScale: f64(),
level: i32(), x: i32(), y: i32(), interiorSize: i32(), borderSize: i32(),
footprintMeters: f32(), maximumUnresolvedHeight: f32(),
};
const count = i32();
const storageSize = header.interiorSize + header.borderSize * 2;
if (count !== storageSize * storageSize) throw new Error("CultMath planetary tile sample count does not match layout");
const samples: (PlanetaryTileSample | null)[] = new Array(count);
for (let index = 0; index < count; index++) {
requireRemaining(1);
if (u8() === 0) { samples[index] = null; continue; }
requireRemaining(64);
samples[index] = {
direction: vector3(),
radius: f32(),
radialDisplacement: f32(),
tangentGradient: vector3(),
surfaceNormal: vector3(),
slope: f32(), ridge: f32(), gully: f32(),
finestResolvedWavelength: f32(), unresolvedHeightBound: f32(),
};
}
if (offset !== view.byteLength) throw new Error("CultMath planetary tile has trailing bytes");
return { header, storageSize, samples };
}

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: f284e64628320844196b7aaea76475a4
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: