"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildPatternAscii = void 0;
exports.uvToCanvasPixel = uvToCanvasPixel;
exports.resolveFaceTextureId = resolveFaceTextureId;
exports.resolveOverlayFaceTextureId = resolveOverlayFaceTextureId;
exports.collectFaceTextureIds = collectFaceTextureIds;
exports.collectOverlayFaceTextureIds = collectOverlayFaceTextureIds;
exports.getFaceKeys = getFaceKeys;
exports.getTextureMaterialIds = getTextureMaterialIds;
exports.collectTexturedBoxTextures = collectTexturedBoxTextures;
exports.collectTexturedBoxMaterials = collectTexturedBoxMaterials;
exports.collectTexturedBoxPatterns = collectTexturedBoxPatterns;
exports.determineTexturedBoxRenderMode = determineTexturedBoxRenderMode;
exports.collectTexturedBoxDependencies = collectTexturedBoxDependencies;
exports.collectEntityTextureLookup = collectEntityTextureLookup;
exports.collectEntityMaterialLookup = collectEntityMaterialLookup;
exports.collectEntityPatternLookup = collectEntityPatternLookup;
const FACE_FALLBACKS = {
    top: ['top', 'all', 'sides'],
    bottom: ['bottom', 'all', 'sides'],
    north: ['north', 'sides', 'all'],
    south: ['south', 'sides', 'all'],
    east: ['east', 'sides', 'all'],
    west: ['west', 'sides', 'all'],
};
const FACE_KEYS = ['top', 'bottom', 'north', 'south', 'east', 'west'];
const OVERLAY_FACE_FALLBACKS = {
    top: ['topOverlay', 'allOverlay', 'sidesOverlay'],
    bottom: ['bottomOverlay', 'allOverlay', 'sidesOverlay'],
    north: ['northOverlay', 'sidesOverlay', 'allOverlay'],
    south: ['southOverlay', 'sidesOverlay', 'allOverlay'],
    east: ['eastOverlay', 'sidesOverlay', 'allOverlay'],
    west: ['westOverlay', 'sidesOverlay', 'allOverlay'],
};
const EPSILON = 1e-6;
const clamp = (value, min, max) => {
    if (!Number.isFinite(value))
        return min;
    if (value < min)
        return min;
    if (value > max)
        return max;
    return value;
};
const toDimension = (value) => {
    if (!Number.isFinite(value) || value < 1) {
        throw new Error('texture_dimension_invalid');
    }
    return Math.floor(value);
};
function uvToCanvasPixel(u, v, width, height) {
    const w = toDimension(width);
    const h = toDimension(height);
    const clampedU = clamp(u, 0, 1);
    const clampedV = clamp(v, 0, 1);
    const x = Math.min(w - 1, Math.max(0, Math.round(clampedU * (w - 1 + EPSILON))));
    const y = Math.min(h - 1, Math.max(0, Math.round(clampedV * (h - 1 + EPSILON))));
    return { x, y };
}
const toAsciiSymbol = (value) => {
    if (value >= 0 && value <= 9)
        return value.toString();
    const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    const index = value - 10;
    if (index >= 0 && index < alphabet.length)
        return alphabet[index];
    return '?';
};
const buildPatternAscii = (pattern) => {
    const [width, height] = pattern.size;
    const lines = [];
    for (let y = 0; y < height; y += 1) {
        const start = y * width;
        const line = pattern.data.slice(start, start + width).map(toAsciiSymbol).join('');
        lines.push(line);
    }
    return lines;
};
exports.buildPatternAscii = buildPatternAscii;
function resolveFaceTextureId(box, face) {
    const order = FACE_FALLBACKS[face];
    for (const key of order) {
        const candidate = box[key];
        if (typeof candidate === 'string' && candidate.trim().length > 0) {
            return candidate;
        }
    }
    return undefined;
}
function resolveOverlayFaceTextureId(box, face) {
    const order = OVERLAY_FACE_FALLBACKS[face];
    for (const key of order) {
        const candidate = box[key];
        if (typeof candidate === 'string' && candidate.trim().length > 0) {
            return candidate;
        }
    }
    return undefined;
}
function collectFaceTextureIds(box) {
    const ids = new Set();
    FACE_KEYS.forEach(face => {
        const textureId = resolveFaceTextureId(box, face);
        if (textureId) {
            ids.add(textureId);
        }
    });
    return Array.from(ids);
}
function collectOverlayFaceTextureIds(box) {
    const ids = new Set();
    FACE_KEYS.forEach(face => {
        const textureId = resolveOverlayFaceTextureId(box, face);
        if (textureId) {
            ids.add(textureId);
        }
    });
    return Array.from(ids);
}
function getFaceKeys() {
    return [...FACE_KEYS];
}
function getTextureMaterialIds(texture) {
    return Array.isArray(texture.materials) ? [...texture.materials] : [];
}
function collectTexturedBoxTextures(box) {
    const textures = new Set();
    collectFaceTextureIds(box).forEach(id => textures.add(id));
    collectOverlayFaceTextureIds(box).forEach(id => textures.add(id));
    return textures;
}
function collectTexturedBoxMaterials(box, textureLookup) {
    const materialIds = new Set();
    const textureIds = [
        ...collectFaceTextureIds(box),
        ...collectOverlayFaceTextureIds(box),
    ];
    textureIds.forEach(textureId => {
        const texture = textureLookup.get(textureId);
        if (!texture)
            return;
        texture.materials.forEach(materialId => materialIds.add(materialId));
    });
    return materialIds;
}
function collectTexturedBoxPatterns(box, textureLookup) {
    const patternIds = new Set();
    const textureIds = [
        ...collectFaceTextureIds(box),
        ...collectOverlayFaceTextureIds(box),
    ];
    textureIds.forEach(textureId => {
        const texture = textureLookup.get(textureId);
        if (!texture)
            return;
        patternIds.add(texture.pattern);
    });
    return patternIds;
}
function buildTextureLookup(entity) {
    return new Map(entity.textures.map(texture => [texture.id, texture]));
}
function buildMaterialLookup(entity) {
    return new Map(entity.materials.map(material => [material.id, material]));
}
function determineTexturedBoxRenderMode(entity, box) {
    const textureLookup = buildTextureLookup(entity);
    const materialLookup = buildMaterialLookup(entity);
    const textureIds = new Set([
        ...collectFaceTextureIds(box),
        ...collectOverlayFaceTextureIds(box),
    ]);
    for (const textureId of textureIds) {
        const texture = textureLookup.get(textureId);
        if (!texture) {
            continue;
        }
        for (const materialId of texture.materials) {
            const material = materialLookup.get(materialId);
            if (!material) {
                continue;
            }
            const opacity = material.opacity;
            if (opacity !== undefined && Number(opacity) < 1) {
                return 'cutout';
            }
        }
    }
    return 'plain';
}
function collectTexturedBoxDependencies(box, textureLookup) {
    const textures = collectTexturedBoxTextures(box);
    const materials = new Set();
    const patterns = new Set();
    textures.forEach(textureId => {
        const texture = textureLookup.get(textureId);
        if (!texture)
            return;
        patterns.add(texture.pattern);
        texture.materials.forEach(materialId => materials.add(materialId));
    });
    return { textures, materials, patterns };
}
function collectEntityTextureLookup(entity) {
    return buildTextureLookup(entity);
}
function collectEntityMaterialLookup(entity) {
    return buildMaterialLookup(entity);
}
function collectEntityPatternLookup(entity) {
    return new Map(entity.patterns.map(pattern => [pattern.id, pattern]));
}
//# sourceMappingURL=textures.js.map