const AXIS_X = [1, 0.18, 0.14, 1];
const AXIS_Y = [0.18, 0.86, 0.28, 1];
const AXIS_Z = [0.2, 0.48, 1, 1];
const DEFAULT_GRID = [0.38, 0.46, 0.58, 1];
const DEFAULT_CENTER = [0.72, 0.78, 0.86, 1];
const DEFAULT_HELPER = [1, 0.84, 0.28, 1];
export function buildAxesHelper(options = {}) {
    const size = positive(options.size ?? 1, "Axes helper size");
    const origin = options.origin ?? [0, 0, 0];
    return [
        { from: origin, to: [origin[0] + size, origin[1], origin[2]], color: AXIS_X },
        { from: origin, to: [origin[0], origin[1] + size, origin[2]], color: AXIS_Y },
        { from: origin, to: [origin[0], origin[1], origin[2] + size], color: AXIS_Z }
    ];
}
export function buildGridHelper(options = {}) {
    const size = positive(options.size ?? 10, "Grid helper size");
    const divisions = integerAtLeast(options.divisions ?? 10, 1, "Grid helper divisions");
    const y = finite(options.y ?? 0, "Grid helper y");
    const half = size / 2;
    const step = size / divisions;
    const lines = [];
    for (let index = 0; index <= divisions; index += 1) {
        const offset = -half + index * step;
        const isCenter = Math.abs(offset) < 1e-8;
        const color = isCenter ? options.centerColor ?? DEFAULT_CENTER : options.color ?? DEFAULT_GRID;
        lines.push({ from: [-half, y, offset], to: [half, y, offset], color });
        lines.push({ from: [offset, y, -half], to: [offset, y, half], color });
    }
    return lines;
}
export function buildBoundsHelper(options) {
    validateVec3(options.min, "Bounds helper min");
    validateVec3(options.max, "Bounds helper max");
    const [minX, minY, minZ] = options.min;
    const [maxX, maxY, maxZ] = options.max;
    if (maxX < minX || maxY < minY || maxZ < minZ) {
        throw new RangeError("Bounds helper max must be greater than or equal to min.");
    }
    const color = options.color ?? DEFAULT_HELPER;
    const p = [
        [minX, minY, minZ], [maxX, minY, minZ], [maxX, maxY, minZ], [minX, maxY, minZ],
        [minX, minY, maxZ], [maxX, minY, maxZ], [maxX, maxY, maxZ], [minX, maxY, maxZ]
    ];
    return edges([
        [0, 1], [1, 2], [2, 3], [3, 0],
        [4, 5], [5, 6], [6, 7], [7, 4],
        [0, 4], [1, 5], [2, 6], [3, 7]
    ], p, color);
}
export function buildCameraFrustumHelper(options) {
    const nearHalfWidth = positive(options.nearHalfWidth, "Camera frustum nearHalfWidth");
    const nearHalfHeight = positive(options.nearHalfHeight, "Camera frustum nearHalfHeight");
    const farHalfWidth = positive(options.farHalfWidth, "Camera frustum farHalfWidth");
    const farHalfHeight = positive(options.farHalfHeight, "Camera frustum farHalfHeight");
    const nearZ = finite(options.nearZ ?? -0.1, "Camera frustum nearZ");
    const farZ = finite(options.farZ ?? -1, "Camera frustum farZ");
    if (Math.abs(nearZ - farZ) < 1e-8) {
        throw new RangeError("Camera frustum nearZ and farZ must be distinct.");
    }
    const p = [
        [-nearHalfWidth, -nearHalfHeight, nearZ],
        [nearHalfWidth, -nearHalfHeight, nearZ],
        [nearHalfWidth, nearHalfHeight, nearZ],
        [-nearHalfWidth, nearHalfHeight, nearZ],
        [-farHalfWidth, -farHalfHeight, farZ],
        [farHalfWidth, -farHalfHeight, farZ],
        [farHalfWidth, farHalfHeight, farZ],
        [-farHalfWidth, farHalfHeight, farZ]
    ];
    return edges([
        [0, 1], [1, 2], [2, 3], [3, 0],
        [4, 5], [5, 6], [6, 7], [7, 4],
        [0, 4], [1, 5], [2, 6], [3, 7]
    ], p, options.color ?? DEFAULT_HELPER);
}
export function buildDirectionalLightHelper(options) {
    const origin = options.origin ?? [0, 0, 0];
    const length = positive(options.length ?? 1, "Directional light helper length");
    const direction = normalize(options.direction, "Directional light helper direction");
    const to = [
        origin[0] + direction[0] * length,
        origin[1] + direction[1] * length,
        origin[2] + direction[2] * length
    ];
    return [{ from: origin, to, color: options.color ?? DEFAULT_HELPER }];
}
export function buildSkeletonHelper(joints, color = DEFAULT_HELPER) {
    const byId = new Map();
    for (const joint of joints) {
        if (!joint.id)
            throw new Error("Skeleton helper joints require stable ids.");
        validateVec3(joint.position, `Skeleton helper joint ${joint.id}`);
        byId.set(joint.id, joint);
    }
    const lines = [];
    for (const joint of joints) {
        if (!joint.parentId)
            continue;
        const parent = byId.get(joint.parentId);
        if (!parent)
            continue;
        lines.push({ from: parent.position, to: joint.position, color });
    }
    return lines;
}
function edges(indices, points, color) {
    return indices.map(([from, to]) => ({ from: points[from], to: points[to], color }));
}
function positive(value, label) {
    if (!Number.isFinite(value) || value <= 0)
        throw new RangeError(`${label} must be finite and positive.`);
    return value;
}
function finite(value, label) {
    if (!Number.isFinite(value))
        throw new RangeError(`${label} must be finite.`);
    return value;
}
function integerAtLeast(value, minimum, label) {
    if (!Number.isInteger(value) || value < minimum)
        throw new RangeError(`${label} must be an integer >= ${minimum}.`);
    return value;
}
function validateVec3(value, label) {
    if (value.length !== 3 || value.some((component) => !Number.isFinite(component))) {
        throw new RangeError(`${label} must contain three finite values.`);
    }
}
function normalize(value, label) {
    validateVec3(value, label);
    const length = Math.hypot(value[0], value[1], value[2]);
    if (length <= 1e-8)
        throw new RangeError(`${label} must be non-zero.`);
    return [value[0] / length, value[1] / length, value[2] / length];
}
//# sourceMappingURL=SceneHelpers.js.map