All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.ru.casperix.multiplatform.text.impl.TextLayoutRender.kt Maven / Gradle / Ivy

There is a newer version: 1.1.1
Show newest version
package ru.casperix.multiplatform.text.impl

import ru.casperix.multiplatform.dimension
import ru.casperix.multiplatform.font.pixel.PixelFont
import ru.casperix.math.color.Color
import ru.casperix.math.color.Colors
import ru.casperix.math.quad_matrix.float32.Matrix3f
import ru.casperix.math.straight_line.float32.LineSegment2f
import ru.casperix.math.vector.float32.Vector2f
import ru.casperix.math.vector.int32.Vector2i
import ru.casperix.renderer.Renderer2D
import ru.casperix.renderer.material.SimpleMaterial
import ru.casperix.renderer.material.Texture
import ru.casperix.multiplatform.text.TextLayout
import ru.casperix.multiplatform.text.TextRenderConfig
import ru.casperix.renderer.vector.builder.VectorBuilder
import kotlin.math.roundToInt

@ExperimentalUnsignedTypes
object TextLayoutRender {

    fun drawTextLayoutMetrics(
        renderer: Renderer2D,
        matrix: Matrix3f,
        font: PixelFont,
        layout: TextLayout
    ) = renderer.run {
        val area = layout.getArea()
        drawBox(Colors.BLACK.setAlpha(0.2f), area, matrix)

        val lineThick = 1f
        val alpha = 0.6f

        layout.symbols.forEach { symbolLayout ->
            val xAxis = symbolLayout.symbol.size.xAxis.toVector2f()
            val baseLinePivot = symbolLayout.pivot

            val ascentLine = LineSegment2f.byDelta(baseLinePivot - Vector2f(0f, font.metrics.ascent), xAxis)
            val baseLine = LineSegment2f.byDelta(baseLinePivot, xAxis)
            val descentLine = LineSegment2f.byDelta(baseLinePivot + Vector2f(0f, font.metrics.descent), xAxis)
            val bottomLine = LineSegment2f.byDelta(baseLinePivot + Vector2f(0f, font.metrics.descent + font.metrics.leading), xAxis)

            drawSegment(Colors.GREEN.setAlpha(alpha), matrix.transform(ascentLine), lineThick)
            drawSegment(Colors.RED.setAlpha(alpha), matrix.transform(baseLine), lineThick)
            drawSegment(Colors.BLUE.setAlpha(alpha), matrix.transform(descentLine), lineThick)
            drawSegment(Colors.YELLOW.setAlpha(alpha), matrix.transform(bottomLine), lineThick)
        }

    }

    fun drawTextLayout(
        renderer: Renderer2D,
        matrix: Matrix3f,
        color: Color,
        layout: TextLayout
    ) {
        var lastAtlas: Texture? = null
        var lastMaterial = SimpleMaterial()

        val graphicList = layout.symbols.mapNotNull { symbolLayout ->
            val graphic = symbolLayout.symbol.graphic
            if (graphic != null) {
                Pair(symbolLayout.pivot + symbolLayout.symbol.baselineOffset.toVector2f(), graphic)
            } else null
        }

        val builder = VectorBuilder(hasPosition2 = true, hasTextureCoord = true)

        graphicList.forEachIndexed { index, (position, pixelRegion) ->
            val atlas = pixelRegion.atlas
            val atlasSize = atlas.map.dimension().toVector2f()
            val sizeFloat = pixelRegion.region.dimension.toVector2f()
            val childMatrix = Matrix3f.translate(position)
            val summaryMatrix = childMatrix * matrix

            if (TextRenderConfig.textRoundToPixel) {
                summaryMatrix.roundTranslate()
            }

            if (lastAtlas == null) {
                lastMaterial = SimpleMaterial(color, albedoMap = atlas)
                lastAtlas = atlas
            } else if (lastAtlas != atlas) {
                throw Exception("Please pack font with PixelFontPacker")
            }

            val tex00 = pixelRegion.region.min.toVector2f() / atlasSize
            val tex11 = (pixelRegion.region.max + Vector2i.ONE).toVector2f() / atlasSize
            val tex10 = Vector2f(tex11.x, tex00.y)
            val tex01 = Vector2f(tex00.x, tex11.y)

            val pos00 = summaryMatrix.transform(Vector2f.ZERO)
            val pos10 = summaryMatrix.transform(sizeFloat.xAxis)
            val pos11 = summaryMatrix.transform(sizeFloat)
            val pos01 = summaryMatrix.transform(sizeFloat.yAxis)

            builder.addQuad(pos00, pos10, pos11, pos01, tex00, tex10, tex11, tex01)
        }
        val material = lastMaterial

        renderer.drawGraphic(builder.buildGraphic(material))
    }

    private fun Matrix3f.roundTranslate() {
        data[6] = data[6].roundToInt().toFloat()
        data[7] = data[7].roundToInt().toFloat()
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy