"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.scanHumanoidSource = scanHumanoidSource;
const PART_BONE_CANDIDATES = {
    torso: ['body', 'torso', 'chest'],
    head: ['head'],
    arm_left: ['leftarm', 'arm_left', 'left_arm'],
    arm_right: ['rightarm', 'arm_right', 'right_arm'],
    leg_left: ['leftleg', 'leg_left', 'left_leg'],
    leg_right: ['rightleg', 'leg_right', 'right_leg'],
};
const PART_OVERLAY_CANDIDATES = {
    head: ['hat', 'headouter', 'head_outer'],
    torso: ['jacket', 'body_outer', 'torso_outer'],
    arm_left: ['leftsleeve', 'arm_left_outer', 'left_arm_overlay'],
    arm_right: ['rightsleeve', 'arm_right_outer', 'right_arm_overlay'],
    leg_left: ['leftpants', 'leg_left_outer', 'left_leg_overlay'],
    leg_right: ['rightpants', 'leg_right_outer', 'right_leg_overlay'],
};
const normalizeName = (value) => value.trim().toLowerCase().replace(/[^a-z0-9]+/g, '');
const findBoneByCandidates = (bones, candidates) => {
    const indexed = new Map();
    bones.forEach(bone => indexed.set(normalizeName(bone.name), bone));
    for (const candidate of candidates) {
        const bone = indexed.get(normalizeName(candidate));
        if (bone) {
            return bone;
        }
    }
    return undefined;
};
const resolveUVRectFromObject = (faceValue, defaultWidth, defaultHeight) => {
    if (!faceValue || typeof faceValue !== 'object') {
        return { x: 0, y: 0, width: defaultWidth, height: defaultHeight };
    }
    const record = faceValue;
    const [u, v] = (record.uv ?? [0, 0]).map(value => Number(value));
    const [width, height] = (record.uv_size ?? [defaultWidth, defaultHeight]).map(value => Number(value));
    return { x: u, y: v, width, height };
};
const scaleValue = (value, scale) => Number.isFinite(value) ? value * scale : value;
const scaleRect = (rect, scaleX, scaleY) => ({
    x: scaleValue(rect.x, scaleX),
    y: scaleValue(rect.y, scaleY),
    width: scaleValue(rect.width, scaleX),
    height: scaleValue(rect.height, scaleY),
});
const computeFaceRects = (cube, scaleX, scaleY) => {
    const sizeX = Number(cube.size?.[0] ?? 0);
    const sizeY = Number(cube.size?.[1] ?? 0);
    const sizeZ = Number(cube.size?.[2] ?? 0);
    if (Array.isArray(cube.uv)) {
        const [u, v] = cube.uv.map(value => Number(value));
        const rects = {
            up: { x: u + sizeZ, y: v, width: sizeX, height: sizeZ },
            down: { x: u + sizeZ + sizeX, y: v, width: sizeX, height: sizeZ },
            north: { x: u + sizeZ, y: v + sizeZ, width: sizeX, height: sizeY },
            east: { x: u + sizeZ + sizeX, y: v + sizeZ, width: sizeZ, height: sizeY },
            south: { x: u + sizeZ + sizeX + sizeZ, y: v + sizeZ, width: sizeX, height: sizeY },
            west: { x: u, y: v + sizeZ, width: sizeZ, height: sizeY },
        };
        return {
            up: scaleRect(rects.up, scaleX, scaleY),
            down: scaleRect(rects.down, scaleX, scaleY),
            north: scaleRect(rects.north, scaleX, scaleY),
            east: scaleRect(rects.east, scaleX, scaleY),
            south: scaleRect(rects.south, scaleX, scaleY),
            west: scaleRect(rects.west, scaleX, scaleY),
        };
    }
    const uvObject = cube.uv;
    const rects = {
        north: resolveUVRectFromObject(uvObject?.north, sizeX, sizeY),
        south: resolveUVRectFromObject(uvObject?.south, sizeX, sizeY),
        east: resolveUVRectFromObject(uvObject?.east, sizeZ, sizeY),
        west: resolveUVRectFromObject(uvObject?.west, sizeZ, sizeY),
        up: resolveUVRectFromObject(uvObject?.up, sizeX, sizeZ),
        down: resolveUVRectFromObject(uvObject?.down, sizeX, sizeZ),
    };
    return {
        north: scaleRect(rects.north, scaleX, scaleY),
        south: scaleRect(rects.south, scaleX, scaleY),
        east: scaleRect(rects.east, scaleX, scaleY),
        west: scaleRect(rects.west, scaleX, scaleY),
        up: scaleRect(rects.up, scaleX, scaleY),
        down: scaleRect(rects.down, scaleX, scaleY),
    };
};
function scanHumanoidSource(options) {
    const { geometryId, geometry, textureWidth, textureHeight, texturePixels } = options;
    const bones = geometry.bones ?? [];
    if (bones.length === 0) {
        throw new Error(`Geometry "${geometryId}" does not contain bones`);
    }
    const baseTextureWidth = options.baseTextureWidth ?? geometry.texturewidth ?? 64;
    const baseTextureHeight = options.baseTextureHeight ?? geometry.textureheight ?? 64;
    const textureScaleX = options.textureScaleX ?? (baseTextureWidth > 0 ? textureWidth / baseTextureWidth : 1);
    const textureScaleY = options.textureScaleY ?? (baseTextureHeight > 0 ? textureHeight / baseTextureHeight : 1);
    const parts = new Map();
    Object.keys(PART_BONE_CANDIDATES).forEach(partKey => {
        const bone = findBoneByCandidates(bones, PART_BONE_CANDIDATES[partKey]);
        if (!bone) {
            throw new Error(`Geometry "${geometryId}" is missing bone for part "${partKey}"`);
        }
        if (!bone.cubes || bone.cubes.length === 0) {
            throw new Error(`Bone "${bone.name}" for part "${partKey}" has no cubes`);
        }
        const cube = bone.cubes[0];
        const base = {
            bone,
            cube,
            faces: computeFaceRects(cube, textureScaleX, textureScaleY),
        };
        let overlay;
        const overlayCandidates = PART_OVERLAY_CANDIDATES[partKey];
        if (overlayCandidates && overlayCandidates.length > 0) {
            const overlayBone = findBoneByCandidates(bones, overlayCandidates);
            if (overlayBone && overlayBone.cubes && overlayBone.cubes.length > 0) {
                const overlayCube = overlayBone.cubes[0];
                overlay = {
                    bone: overlayBone,
                    cube: overlayCube,
                    faces: computeFaceRects(overlayCube, textureScaleX, textureScaleY),
                };
            }
        }
        parts.set(partKey, { base, overlay });
    });
    return {
        geometryId,
        bones,
        parts,
        textureWidth,
        textureHeight,
        texturePixels,
        baseTextureWidth,
        baseTextureHeight,
        textureScaleX,
        textureScaleY,
    };
}
//# sourceMappingURL=scanner.js.map