{"version":3,"file":"getBitmapTextLayout.mjs","sources":["../../../../src/scene/text-bitmap/utils/getBitmapTextLayout.ts"],"sourcesContent":["import type { TextStyle } from '../../text/TextStyle';\nimport type { AbstractBitmapFont } from '../AbstractBitmapFont';\n\nexport interface BitmapTextLayoutData\n{\n    width: number;\n    height: number;\n    scale: number;\n    offsetY: number;\n    lines: {\n        width: number\n        charPositions: number[],\n        chars: string[],\n        // / spaces: number\n        spaceWidth: number\n        spacesIndex: number[]\n    }[];\n}\n\nexport function getBitmapTextLayout(chars: string[], style: TextStyle, font: AbstractBitmapFont<any>): BitmapTextLayoutData\n{\n    const layoutData: BitmapTextLayoutData = {\n        width: 0,\n        height: 0,\n        offsetY: 0,\n        scale: style.fontSize / font.baseMeasurementFontSize,\n        lines: [{\n            width: 0,\n            charPositions: [] as number[],\n            spaceWidth: 0,\n            spacesIndex: [],\n            chars: [],\n        }]\n    };\n\n    layoutData.offsetY = font.baseLineOffset;\n\n    let currentLine = layoutData.lines[0];\n\n    let previousChar: string = null;\n    let firstWord = true;\n    //    let spaceCount = 0;\n\n    const currentWord = {\n        spaceWord: false,\n        width: 0,\n        start: 0,\n        index: 0, // use index to not modify the array as we use it a lot!\n        positions: [] as number[],\n        chars: [] as string[],\n    };\n\n    const nextWord = (word: typeof currentWord) =>\n    {\n        const start = currentLine.width;\n\n        for (let j = 0; j < currentWord.index; j++)\n        {\n            const position = word.positions[j];\n\n            currentLine.chars.push(word.chars[j]);\n            currentLine.charPositions.push(position + start);\n        }\n\n        currentLine.width += word.width;\n\n        firstWord = false;\n\n        // reset the word..\n        currentWord.width = 0;\n        currentWord.index = 0;\n        currentWord.chars.length = 0;\n\n        // spaceCount = 0;\n    };\n\n    const nextLine = () =>\n    {\n        let index = currentLine.chars.length - 1;\n        let lastChar = currentLine.chars[index];\n\n        while (lastChar === ' ')\n        {\n            currentLine.width -= font.chars[lastChar].xAdvance;\n            lastChar = currentLine.chars[--index];\n        }\n\n        layoutData.width = Math.max(layoutData.width, currentLine.width);\n\n        currentLine = {\n            width: 0,\n            charPositions: [],\n            chars: [],\n            spaceWidth: 0,\n            spacesIndex: [],\n        };\n\n        firstWord = true;\n        layoutData.lines.push(currentLine);\n        layoutData.height += font.lineHeight;\n    };\n\n    const scale = font.baseMeasurementFontSize / style.fontSize;\n\n    const adjustedLetterSpacing = style.letterSpacing * scale;\n    const adjustedWordWrapWidth = style.wordWrapWidth * scale;\n\n    // loop an extra time to force a line break..\n    for (let i = 0; i < chars.length + 1; i++)\n    {\n        let char: string;\n\n        const isEnd = i === chars.length;\n\n        if (!isEnd)\n        {\n            char = chars[i];\n        }\n\n        const charData = font.chars[char] || font.chars[' '];\n\n        const isSpace = (/(?:\\s)/).test(char);\n        const isWordBreak = isSpace || char === '\\r' || char === '\\n' || isEnd;\n\n        // spaceCount++;\n        // wasSpace = isSpace;\n\n        if (isWordBreak)\n        {\n            const addWordToNextLine = !firstWord\n                && style.wordWrap\n                && (currentLine.width + currentWord.width - adjustedLetterSpacing) > adjustedWordWrapWidth;\n\n            if (addWordToNextLine)\n            {\n                nextLine();\n\n                nextWord(currentWord);\n\n                if (!isEnd)\n                {\n                    currentLine.charPositions.push(0);\n                }\n            }\n            else\n            {\n                currentWord.start = currentLine.width;\n\n                nextWord(currentWord);\n\n                if (!isEnd)\n                {\n                    currentLine.charPositions.push(0);\n                }\n            }\n\n            if (char === '\\r' || char === '\\n')\n            {\n                if (currentLine.width !== 0)\n                {\n                    nextLine();\n                }\n            }\n            else if (!isEnd)\n            {\n                const spaceWidth = charData.xAdvance + (charData.kerning[previousChar] || 0) + adjustedLetterSpacing;\n\n                currentLine.width += spaceWidth;\n\n                currentLine.spaceWidth = spaceWidth;\n                currentLine.spacesIndex.push(currentLine.charPositions.length);\n                currentLine.chars.push(char);\n\n                // spaceCount++;\n            }\n        }\n        else\n        {\n            const kerning = charData.kerning[previousChar] || 0;\n\n            const nextCharWidth = charData.xAdvance + kerning + adjustedLetterSpacing;\n\n            currentWord.positions[currentWord.index++] = currentWord.width + kerning;\n            currentWord.chars.push(char);\n\n            currentWord.width += nextCharWidth;\n        }\n\n        previousChar = char;\n        // lastChar = char;\n    }\n\n    nextLine();\n\n    if (style.align === 'center')\n    {\n        alignCenter(layoutData);\n    }\n    else if (style.align === 'right')\n    {\n        alignRight(layoutData);\n    }\n    else if (style.align === 'justify')\n    {\n        alignJustify(layoutData);\n    }\n\n    return layoutData;\n}\n\nfunction alignCenter(measurementData: BitmapTextLayoutData)\n{\n    for (let i = 0; i < measurementData.lines.length; i++)\n    {\n        const line = measurementData.lines[i];\n        const offset = ((measurementData.width / 2) - (line.width / 2));\n\n        for (let j = 0; j < line.charPositions.length; j++)\n        {\n            line.charPositions[j] += offset;\n        }\n    }\n}\n\nfunction alignRight(measurementData: BitmapTextLayoutData)\n{\n    for (let i = 0; i < measurementData.lines.length; i++)\n    {\n        const line = measurementData.lines[i];\n        const offset = ((measurementData.width) - (line.width));\n\n        for (let j = 0; j < line.charPositions.length; j++)\n        {\n            line.charPositions[j] += offset;\n        }\n    }\n}\n\nfunction alignJustify(measurementData: BitmapTextLayoutData)\n{\n    const width = measurementData.width;\n\n    for (let i = 0; i < measurementData.lines.length; i++)\n    {\n        const line = measurementData.lines[i];\n\n        let indy = 0;\n        let spaceIndex = line.spacesIndex[indy++];\n\n        let offset = 0;\n\n        const totalSpaces = line.spacesIndex.length;\n\n        const newSpaceWidth = (width - line.width) / totalSpaces;\n\n        const spaceWidth = newSpaceWidth;\n\n        for (let j = 0; j < line.charPositions.length; j++)\n        {\n            if (j === spaceIndex)\n            {\n                spaceIndex = line.spacesIndex[indy++];\n\n                offset += spaceWidth;\n            }\n\n            line.charPositions[j] += offset;\n        }\n    }\n}\n"],"names":[],"mappings":"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"}