new tagging system

This commit is contained in:
minjaesong
2021-11-25 16:46:22 +09:00
parent 4f6584ac27
commit 8641c95169
10 changed files with 194 additions and 113 deletions

View File

@@ -50,17 +50,53 @@ Rightmost vertical column (should be 20 px tall) contains the tags. Tags are def
K -, K -,
K |= Tags used by the "Keming Machine" K |= Tags used by the "Keming Machine"
K | K |
K -' ,-Nudging control bit (see below) K -' ,- Nudging Bits (see below)
N --' n --'
X -, write-on-top and centre-aligned: Align to this X pos of prev char X -,
X | (if this is zero, floorOf(width/2) will be used instead) X |= Diacritics Anchor Points (see below)
X | NOT write-on-top: nudge the texture by this pixels to the X |
X -' left (if N is unset) or right (if N is set) X -'
A -,_ 0 Align 1 Align 0 Align 1 Align before A -,_ 0 Align 1 Align 0 Align 1 Align before
A -' 0 left 0 right 1 centre 1 the glyph A -' 0 left 0 right 1 centre 1 the glyph
D --write-on-top, usually it's diatritics but not always (e.g. devanagari vowel sign O) D --write-on-top, usually it's diatritics but not always (e.g. devanagari vowel sign O)
S -,_ 0 Stack 1 Stack 0 Before 1 Up & S -,_ 0 Stack 1 Stack 0 Before 1 Up &
(MSB) S -' 0 up 0 down 1 &After 1 Down (e.g. U+0C48) (MSB) S -' 0 up 0 down 1 &After 1 Down (e.g. U+0C48)
TODO:
c - Nudging
Y - Anchor point Y for undefined, undefined, undefined
X - Anchor point X for undefined, undefined, undefined
Y - Anchor point Y for centre-aligned diacritics, undefined, undefined
X - Anchor point X for centre-aligned diacritics, undefined, undefined
* Nudging Bits encoding:
<MSB,Red> SXXXXXXX SYYYYYYY 00000000 <LSB,Blue>
Each X and Y numbers are Signed 8-Bit Integer.
X-positive: nudges towards left
Y-positive: nudges towards up
* Diacritics Anchor Point Encoding:
<MSB,Red> 1Y1Y1Y1Y 1Y2Y2Y2Y 1Y3Y3Y3Y <LSB,Blue>
<MSB,Red> 1X1X1X1X 1X2X2X2X 1X3X3X3X <LSB,Blue>
where Red is first, Green is second, Blue is the third diacritics.
MSB for each word must be set to indicate the value is being used.
-= NOTE =-
This encoding involves one HACK: using 0th diacritics' X-anchor pos as a type selector
This hack applies only when write-on-top bit is set.
Interpretation:
DIA_OVERLAY = 1
DIA_JOINER = 2
Right now, only the type-0 diacritics anchor point is used by the font.
TODO: use D-bit to give each diacritic a type
``` ```
#### Stack Up/Down #### Stack Up/Down

Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 KiB

After

Width:  |  Height:  |  Size: 320 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 140 KiB

BIN
demo.PNG

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 142 KiB

View File

@@ -1,22 +1,35 @@
package net.torvald.terrarumsansbitmap package net.torvald.terrarumsansbitmap
/**
* Created by minjaesong on 2021-11-25.
*/
data class DiacriticsAnchor(val type: Int, val x: Int, val y: Int, val xUsed: Boolean, val yUsed: Boolean)
/** /**
* Created by minjaesong on 2018-08-07. * Created by minjaesong on 2018-08-07.
*/ */
data class GlyphProps( data class GlyphProps(
val width: Int, val width: Int,
val writeOnTop: Boolean,
val alignWhere: Int, // ALIGN_LEFT..ALIGN_BEFORE val isLowheight: Boolean = false,
val alignXPos: Int, // 0..15 or DIA_OVERLAY/DIA_JOINER depends on the context
val rtl: Boolean = false, val nudgeX: Int = 0,
val nudgeY: Int = 0,
val diacriticsAnchors: Array<DiacriticsAnchor> = Array(6) { DiacriticsAnchor(it, 0, 0, false, false) },
val alignWhere: Int = 0, // ALIGN_LEFT..ALIGN_BEFORE
val writeOnTop: Boolean = false,
val stackWhere: Int = 0, // STACK_UP..STACK_UP_N_DOWN val stackWhere: Int = 0, // STACK_UP..STACK_UP_N_DOWN
var nudgeRight: Boolean = false,
var extInfo: IntArray? = null, val extInfo: IntArray = DEFAULT_EXTINFO,
val hasKernData: Boolean = false, val hasKernData: Boolean = false,
val isLowheight: Boolean = false,
val isKernYtype: Boolean = false, val isKernYtype: Boolean = false,
val kerningMask: Int = 255 val kerningMask: Int = 255,
val rtl: Boolean = false,
) { ) {
companion object { companion object {
const val ALIGN_LEFT = 0 const val ALIGN_LEFT = 0
@@ -33,9 +46,11 @@ data class GlyphProps(
const val DIA_JOINER = 2 const val DIA_JOINER = 2
private fun Boolean.toInt() = if (this) 1 else 0 private fun Boolean.toInt() = if (this) 1 else 0
val DEFAULT_EXTINFO = IntArray(15)
} }
constructor(width: Int, tags: Int) : this( /*constructor(width: Int, tags: Int) : this(
width, width,
tags.ushr(7).and(1) == 1, tags.ushr(7).and(1) == 1,
tags.ushr(5).and(3), tags.ushr(5).and(3),
@@ -59,21 +74,30 @@ data class GlyphProps(
isLowheight, isLowheight,
isKernYtype, isKernYtype,
kerningMask kerningMask
) )*/
fun isOverlay() = writeOnTop && alignXPos == 1 // fun isOverlay() = writeOnTop && alignXPos == 1
override fun hashCode(): Int { override fun hashCode(): Int {
val tags = rtl.toInt() or alignXPos.shl(1) or alignWhere.shl(5) or val tags = rtl.toInt() or alignWhere.shl(5) or
writeOnTop.toInt().shl(7) or stackWhere.shl(8) writeOnTop.toInt().shl(7) or stackWhere.shl(8)
var hash = -2128831034 var hash = -2128831034
extInfo?.forEach { extInfo.forEach {
hash = hash xor it hash = hash xor it
hash = hash * 16777619 hash = hash * 16777619
} }
diacriticsAnchors.forEach {
hash = hash xor it.type
hash = hash * 16777619
hash = hash xor (it.x or (if (it.xUsed) 128 else 0))
hash = hash * 16777619
hash = hash xor (it.y or (if (it.yUsed) 128 else 0))
hash = hash * 16777619
}
hash = hash xor tags hash = hash xor tags
hash = hash * 167677619 hash = hash * 167677619

View File

@@ -30,6 +30,7 @@ import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.* import com.badlogic.gdx.graphics.g2d.*
import com.badlogic.gdx.utils.GdxRuntimeException import com.badlogic.gdx.utils.GdxRuntimeException
import net.torvald.terrarumsansbitmap.DiacriticsAnchor
import net.torvald.terrarumsansbitmap.GlyphProps import net.torvald.terrarumsansbitmap.GlyphProps
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
import java.io.FileOutputStream import java.io.FileOutputStream
@@ -302,7 +303,7 @@ class TerrarumSansBitmap(
// make sure null char is actually null (draws nothing and has zero width) // make sure null char is actually null (draws nothing and has zero width)
sheets[SHEET_ASCII_VARW].regions[0].setColor(0) sheets[SHEET_ASCII_VARW].regions[0].setColor(0)
sheets[SHEET_ASCII_VARW].regions[0].fill() sheets[SHEET_ASCII_VARW].regions[0].fill()
glyphProps[0] = GlyphProps(0, 0) glyphProps[0] = GlyphProps(0)
} }
override fun getLineHeight(): Float = H.toFloat() override fun getLineHeight(): Float = H.toFloat()
@@ -331,7 +332,7 @@ class TerrarumSansBitmap(
private lateinit var tempLinotype: Texture private lateinit var tempLinotype: Texture
private var nullProp = GlyphProps(15, 0) private var nullProp = GlyphProps(15)
private val pixmapOffsetY = 10 private val pixmapOffsetY = 10
@@ -342,6 +343,8 @@ class TerrarumSansBitmap(
fun drawNormalised(batch: Batch, codepoints: CodepointSequence, x: Float, y: Float): GlyphLayout? { fun drawNormalised(batch: Batch, codepoints: CodepointSequence, x: Float, y: Float): GlyphLayout? {
// codepoints.forEach { dbgprn("${it.charInfo()} ${glyphProps[it]}") }
// Q&D fix for issue #12 // Q&D fix for issue #12
// When the line ends with a diacritics, the whole letter won't render // When the line ends with a diacritics, the whole letter won't render
// If the line starts with a letter-with-diacritic, it will error out // If the line starts with a letter-with-diacritic, it will error out
@@ -696,6 +699,9 @@ class TerrarumSansBitmap(
return intArrayOf(sheetX, sheetY) return intArrayOf(sheetX, sheetY)
} }
private fun Boolean.toInt() = if (this) 1 else 0
private fun Int.tagify() = if (this and 255 == 0) 0 else this
private fun buildWidthTable(pixmap: Pixmap, codeRange: Iterable<Int>, cols: Int = 16) { private fun buildWidthTable(pixmap: Pixmap, codeRange: Iterable<Int>, cols: Int = 16) {
val binaryCodeOffset = W_VAR_INIT val binaryCodeOffset = W_VAR_INIT
@@ -709,64 +715,63 @@ class TerrarumSansBitmap(
val codeStartX = cellX + binaryCodeOffset val codeStartX = cellX + binaryCodeOffset
val codeStartY = cellY val codeStartY = cellY
val tagStartY = codeStartY + 10
var width = 0 val width = (0..4).fold(0) { acc, y -> acc or ((pixmap.getPixel(codeStartX, codeStartY + y).and(255) != 0).toInt() shl y) }
var tags = 0 val isLowHeight = (pixmap.getPixel(codeStartX, codeStartY + 5).and(255) != 0)
for (y in 0..4) {
// if ALPHA is not zero, assume it's 1
if (pixmap.getPixel(codeStartX, codeStartY + y).and(0xFF) != 0) {
width = width or (1 shl y)
}
}
for (y in 0..9) {
// if ALPHA is not zero, assume it's 1
if (pixmap.getPixel(codeStartX, tagStartY + y).and(0xFF) != 0) {
tags = tags or (1 shl y)
}
}
// lowheight bit
val isLowHeight = (pixmap.getPixel(codeStartX, codeStartY + 5).and(0xFF) != 0)
// Keming machine parameters // Keming machine parameters
val kerningBit1 = pixmap.getPixel(codeStartX, codeStartY + 6) val kerningBit1 = pixmap.getPixel(codeStartX, codeStartY + 6).tagify()
val kerningBit2 = pixmap.getPixel(codeStartX, codeStartY + 7) val kerningBit2 = pixmap.getPixel(codeStartX, codeStartY + 7).tagify()
val kerningBit3 = pixmap.getPixel(codeStartX, codeStartY + 8) val kerningBit3 = pixmap.getPixel(codeStartX, codeStartY + 8).tagify()
val isKerningYtype = ((kerningBit1 and 0x80000000.toInt()) != 0) val kerningBit4 = pixmap.getPixel(codeStartX, codeStartY + 9).tagify()
val kerningMask = kerningBit1.ushr(8).and(0xFFFFFF) var isKernYtype = ((kerningBit1 and 0x80000000.toInt()) != 0)
val hasKerningBit = kerningBit1 and 255 != 0//(kerningBit1 and 255 != 0 && kerningMask != 0xFFFF) var kerningMask = kerningBit1.ushr(8).and(0xFFFFFF)
val hasKernData = kerningBit1 and 255 != 0//(kerningBit1 and 255 != 0 && kerningMask != 0xFFFF)
if (!hasKernData) {
isKernYtype = false
kerningMask = 255
}
val nudgingBits = pixmap.getPixel(codeStartX, codeStartY + 10).tagify()
val nudgeX = nudgingBits.ushr(24).toByte().toInt() // signed 8-bit int
val nudgeY = nudgingBits.ushr(16).toByte().toInt() // signed 8-bit int
//dbgprn("$code: Width $width, tags $tags") val diacriticsAnchors = (0..5).map {
if (hasKerningBit) val yPos = 11 + (it / 3) * 2
dbgprn("U+${code.toString(16).padStart(4, '0').toUpperCase()}: W $width, tags $tags, low? $isLowHeight, kern ${kerningMask.toString(16).padStart(6,'0')} (raw: ${kerningBit1.toLong().and(4294967295).toString(16).padStart(8,'0')})") val shift = (3 - (it % 3)) * 8
val yPixel = pixmap.getPixel(codeStartX, codeStartY + yPos).tagify()
val xPixel = pixmap.getPixel(codeStartX, codeStartY + yPos + 1).tagify()
val y = (yPixel ushr shift) and 127
val x = (xPixel ushr shift) and 127
val yUsed = (yPixel ushr shift) >= 128
val xUsed = (yPixel ushr shift) >= 128
/*val isDiacritics = pixmap.getPixel(codeStartX, codeStartY + H - 1).and(0xFF) != 0 DiacriticsAnchor(it, x, y, xUsed, yUsed)
if (isDiacritics) }.toTypedArray()
glyphWidth = -glyphWidth*/
glyphProps[code] = if (hasKerningBit) GlyphProps(width, tags, isLowHeight, isKerningYtype, kerningMask) else GlyphProps(width, tags) val alignWhere = (0..1).fold(0) { acc, y -> acc or ((pixmap.getPixel(codeStartX, codeStartY + y + 15).and(255) != 0).toInt() shl y) }
val writeOnTop = pixmap.getPixel(codeStartX, codeStartY + 17).and(255) != 0
val stackWhere = (0..1).fold(0) { acc, y -> acc or ((pixmap.getPixel(codeStartX, codeStartY + y + 18).and(255) != 0).toInt() shl y) }
glyphProps[code] = GlyphProps(width, isLowHeight, nudgeX, nudgeY, diacriticsAnchors, alignWhere, writeOnTop, stackWhere, GlyphProps.DEFAULT_EXTINFO, hasKernData, isKernYtype, kerningMask)
// if (nudgingBits != 0) dbgprn("${code.charInfo()} nudgeX=$nudgeX, nudgeY=$nudgeY, nudgingBits=0x${nudgingBits.toString(16)}")
// extra info // extra info
val extCount = glyphProps[code]?.requiredExtInfoCount() ?: 0 val extCount = glyphProps[code]?.requiredExtInfoCount() ?: 0
if (extCount > 0) { if (extCount > 0) {
glyphProps[code]?.extInfo = IntArray(extCount)
for (x in 0 until extCount) { for (x in 0 until extCount) {
var info = 0 var info = 0
for (y in 0..18) { for (y in 0..18) {
// if ALPHA is not zero, assume it's 1 // if ALPHA is not zero, assume it's 1
if (pixmap.getPixel(cellX + x, cellY + y).and(0xFF) != 0) { if (pixmap.getPixel(cellX + x, cellY + y).and(255) != 0) {
info = info or (1 shl y) info = info or (1 shl y)
} }
} }
glyphProps[code]!!.extInfo!![x] = info glyphProps[code]!!.extInfo[x] = info
} }
} }
@@ -775,27 +780,27 @@ class TerrarumSansBitmap(
private fun buildWidthTableFixed() { private fun buildWidthTableFixed() {
// fixed-width props // fixed-width props
codeRange[SHEET_CJK_PUNCT].forEach { glyphProps[it] = GlyphProps(W_ASIAN_PUNCT, 0) } codeRange[SHEET_CJK_PUNCT].forEach { glyphProps[it] = GlyphProps(W_ASIAN_PUNCT) }
codeRange[SHEET_CUSTOM_SYM].forEach { glyphProps[it] = GlyphProps(20, 0) } codeRange[SHEET_CUSTOM_SYM].forEach { glyphProps[it] = GlyphProps(20) }
codeRange[SHEET_FW_UNI].forEach { glyphProps[it] = GlyphProps(W_UNIHAN, 0) } codeRange[SHEET_FW_UNI].forEach { glyphProps[it] = GlyphProps(W_UNIHAN) }
codeRange[SHEET_HANGUL].forEach { glyphProps[it] = GlyphProps(W_HANGUL_BASE, 0) } codeRange[SHEET_HANGUL].forEach { glyphProps[it] = GlyphProps(W_HANGUL_BASE) }
codeRangeHangulCompat.forEach { glyphProps[it] = GlyphProps(W_HANGUL_BASE, 0) } codeRangeHangulCompat.forEach { glyphProps[it] = GlyphProps(W_HANGUL_BASE) }
codeRange[SHEET_KANA].forEach { glyphProps[it] = GlyphProps(W_KANA, 0) } codeRange[SHEET_KANA].forEach { glyphProps[it] = GlyphProps(W_KANA) }
codeRange[SHEET_RUNIC].forEach { glyphProps[it] = GlyphProps(9, 0) } codeRange[SHEET_RUNIC].forEach { glyphProps[it] = GlyphProps(9) }
codeRange[SHEET_UNIHAN].forEach { glyphProps[it] = GlyphProps(W_UNIHAN, 0) } codeRange[SHEET_UNIHAN].forEach { glyphProps[it] = GlyphProps(W_UNIHAN) }
(0xD800..0xDFFF).forEach { glyphProps[it] = GlyphProps(0, 0) } (0xD800..0xDFFF).forEach { glyphProps[it] = GlyphProps(0) }
(0x100000..0x10FFFF).forEach { glyphProps[it] = GlyphProps(0, 0) } (0x100000..0x10FFFF).forEach { glyphProps[it] = GlyphProps(0) }
(0xFFFA0..0xFFFFF).forEach { glyphProps[it] = GlyphProps(0, 0) } (0xFFFA0..0xFFFFF).forEach { glyphProps[it] = GlyphProps(0) }
// manually add width of one orphan insular letter // manually add width of one orphan insular letter
// WARNING: glyphs in 0xA770..0xA778 has invalid data, further care is required // WARNING: glyphs in 0xA770..0xA778 has invalid data, further care is required
glyphProps[0x1D79] = GlyphProps(9, 0) glyphProps[0x1D79] = GlyphProps(9)
// U+007F is DEL originally, but this font stores bitmap of Replacement Character (U+FFFD) // U+007F is DEL originally, but this font stores bitmap of Replacement Character (U+FFFD)
// to this position. String replacer will replace U+FFFD into U+007F. // to this position. String replacer will replace U+FFFD into U+007F.
glyphProps[0x7F] = GlyphProps(15, 0) glyphProps[0x7F] = GlyphProps(15)
} }
@@ -884,7 +889,7 @@ class TerrarumSansBitmap(
posXbuffer[charIndex] = posXbuffer[nonDiacriticCounter] posXbuffer[charIndex] = posXbuffer[nonDiacriticCounter]
} }
else if (!thisProp.writeOnTop) { else if (!thisProp.writeOnTop) {
posXbuffer[charIndex] = ((if (thisProp.nudgeRight) 1 else -1) * thisProp.alignXPos) + posXbuffer[charIndex] = -thisProp.nudgeX +
when (itsProp.alignWhere) { when (itsProp.alignWhere) {
GlyphProps.ALIGN_RIGHT -> GlyphProps.ALIGN_RIGHT ->
posXbuffer[nonDiacriticCounter] + W_VAR_INIT + alignmentOffset + interchar + kerning + extraWidth posXbuffer[nonDiacriticCounter] + W_VAR_INIT + alignmentOffset + interchar + kerning + extraWidth
@@ -898,9 +903,10 @@ class TerrarumSansBitmap(
stackUpwardCounter = 0 stackUpwardCounter = 0
stackDownwardCounter = 0 stackDownwardCounter = 0
extraWidth = (if (thisProp.nudgeRight) -1 else 1) * thisProp.alignXPos // NOTE: sign is flipped! extraWidth = thisProp.nudgeX // NOTE: sign is flipped!
} }
else if (thisProp.writeOnTop && thisProp.alignXPos == GlyphProps.DIA_JOINER) { // FIXME HACK: using 0th diacritics' X-anchor pos as a type selector
else if (thisProp.writeOnTop && thisProp.diacriticsAnchors[0].x == GlyphProps.DIA_JOINER) {
posXbuffer[charIndex] = when (itsProp.alignWhere) { posXbuffer[charIndex] = when (itsProp.alignWhere) {
GlyphProps.ALIGN_RIGHT -> GlyphProps.ALIGN_RIGHT ->
posXbuffer[nonDiacriticCounter] + W_VAR_INIT + alignmentOffset posXbuffer[nonDiacriticCounter] + W_VAR_INIT + alignmentOffset
@@ -919,7 +925,7 @@ class TerrarumSansBitmap(
posXbuffer[nonDiacriticCounter] - (W_VAR_INIT - itsProp.width) posXbuffer[nonDiacriticCounter] - (W_VAR_INIT - itsProp.width)
} }
GlyphProps.ALIGN_CENTRE -> { GlyphProps.ALIGN_CENTRE -> {
val alignXPos = if (itsProp.alignXPos == 0) itsProp.width.div(2) else itsProp.alignXPos val alignXPos = if (itsProp.diacriticsAnchors[0].x == 0) itsProp.width.div(2) else itsProp.diacriticsAnchors[0].x
if (itsProp.alignWhere == GlyphProps.ALIGN_RIGHT) { if (itsProp.alignWhere == GlyphProps.ALIGN_RIGHT) {
posXbuffer[nonDiacriticCounter] + alignXPos + (itsProp.width + 1).div(2) posXbuffer[nonDiacriticCounter] + alignXPos + (itsProp.width + 1).div(2)
@@ -948,7 +954,7 @@ class TerrarumSansBitmap(
//dbgprn("AAARRRRHHHH for character ${thisChar.toHex()}") //dbgprn("AAARRRRHHHH for character ${thisChar.toHex()}")
//dbgprn("lastNonDiacriticChar: ${lastNonDiacriticChar.toHex()}") //dbgprn("lastNonDiacriticChar: ${lastNonDiacriticChar.toHex()}")
//dbgprn("cond: ${thisProp.alignXPos == GlyphProps.DIA_OVERLAY}, charIndex: $charIndex") //dbgprn("cond: ${thisProp.alignXPos == GlyphProps.DIA_OVERLAY}, charIndex: $charIndex")
if (thisProp.alignXPos == GlyphProps.DIA_OVERLAY) if (thisProp.diacriticsAnchors[0].x == GlyphProps.DIA_OVERLAY)
posYbuffer[charIndex] -= H_OVERLAY_LOWERCASE_SHIFTDOWN * (!flipY).toSign() // if minus-assign doesn't work, try plus-assign posYbuffer[charIndex] -= H_OVERLAY_LOWERCASE_SHIFTDOWN * (!flipY).toSign() // if minus-assign doesn't work, try plus-assign
else else
posYbuffer[charIndex] -= H_STACKUP_LOWERCASE_SHIFTDOWN * (!flipY).toSign() // if minus-assign doesn't work, try plus-assign posYbuffer[charIndex] -= H_STACKUP_LOWERCASE_SHIFTDOWN * (!flipY).toSign() // if minus-assign doesn't work, try plus-assign
@@ -978,10 +984,10 @@ class TerrarumSansBitmap(
posXbuffer[posXbuffer.lastIndex] = 1 + posXbuffer[posXbuffer.lastIndex - 1] + // adding 1 to house the shadow posXbuffer[posXbuffer.lastIndex] = 1 + posXbuffer[posXbuffer.lastIndex - 1] + // adding 1 to house the shadow
if (lastCharProp?.writeOnTop == true) { if (lastCharProp?.writeOnTop == true) {
val realDiacriticWidth = if (lastCharProp.alignWhere == GlyphProps.ALIGN_CENTRE) { val realDiacriticWidth = if (lastCharProp.alignWhere == GlyphProps.ALIGN_CENTRE) {
(lastCharProp.width).div(2) + penultCharProp.alignXPos (lastCharProp.width).div(2) + penultCharProp.diacriticsAnchors[0].x
} }
else if (lastCharProp.alignWhere == GlyphProps.ALIGN_RIGHT) { else if (lastCharProp.alignWhere == GlyphProps.ALIGN_RIGHT) {
(lastCharProp.width) + penultCharProp.alignXPos (lastCharProp.width) + penultCharProp.diacriticsAnchors[0].x
} }
else 0 else 0

View File

@@ -7,6 +7,7 @@ import com.badlogic.gdx.graphics.g2d.Batch
import com.badlogic.gdx.graphics.g2d.BitmapFont import com.badlogic.gdx.graphics.g2d.BitmapFont
import com.badlogic.gdx.graphics.g2d.GlyphLayout import com.badlogic.gdx.graphics.g2d.GlyphLayout
import com.badlogic.gdx.utils.GdxRuntimeException import com.badlogic.gdx.utils.GdxRuntimeException
import net.torvald.terrarumsansbitmap.DiacriticsAnchor
import net.torvald.terrarumsansbitmap.GlyphProps import net.torvald.terrarumsansbitmap.GlyphProps
import net.torvald.terrarumsansbitmap.gdx.* import net.torvald.terrarumsansbitmap.gdx.*
import net.torvald.terrarumsansbitmap.gdx.CodePoint import net.torvald.terrarumsansbitmap.gdx.CodePoint
@@ -178,7 +179,7 @@ class TerrarumTypewriterBitmap(
pixmap.dispose() // you are terminated pixmap.dispose() // you are terminated
} }
glyphProps[0] = GlyphProps(0, 0) glyphProps[0] = GlyphProps(0)
} }
@@ -188,6 +189,8 @@ class TerrarumTypewriterBitmap(
intArrayOf(coff % 16, coff / 16) intArrayOf(coff % 16, coff / 16)
} }
private fun Boolean.toInt() = if (this) 1 else 0
private fun Int.tagify() = if (this and 255 == 0) 0 else this
private fun buildWidthTable(pixmap: Pixmap, codeRange: Iterable<Int>, cols: Int = 16) { private fun buildWidthTable(pixmap: Pixmap, codeRange: Iterable<Int>, cols: Int = 16) {
val binaryCodeOffset = TerrarumSansBitmap.W_VAR_INIT val binaryCodeOffset = TerrarumSansBitmap.W_VAR_INIT
@@ -202,53 +205,65 @@ class TerrarumTypewriterBitmap(
val codeStartX = cellX + binaryCodeOffset val codeStartX = cellX + binaryCodeOffset
val codeStartY = cellY val codeStartY = cellY
val tagStartY = codeStartY + 10
var width = 0 val width = (0..4).fold(0) { acc, y -> acc or ((pixmap.getPixel(codeStartX, codeStartY + y).and(255) != 0).toInt() shl y) }
var tags = 0 val isLowHeight = (pixmap.getPixel(codeStartX, codeStartY + 5).and(255) != 0)
for (y in 0..3) { // Keming machine parameters
// if ALPHA is not zero, assume it's 1 val kerningBit1 = pixmap.getPixel(codeStartX, codeStartY + 6).tagify()
if (pixmap.getPixel(codeStartX, codeStartY + y).and(0xFF) != 0) { val kerningBit2 = pixmap.getPixel(codeStartX, codeStartY + 7).tagify()
width = width or (1 shl y) val kerningBit3 = pixmap.getPixel(codeStartX, codeStartY + 8).tagify()
} val kerningBit4 = pixmap.getPixel(codeStartX, codeStartY + 9).tagify()
var isKernYtype = ((kerningBit1 and 0x80000000.toInt()) != 0)
var kerningMask = kerningBit1.ushr(8).and(0xFFFFFF)
val hasKernData = kerningBit1 and 255 != 0//(kerningBit1 and 255 != 0 && kerningMask != 0xFFFF)
if (!hasKernData) {
isKernYtype = false
kerningMask = 255
} }
for (y in 0..9) { val nudgingBits = pixmap.getPixel(codeStartX, codeStartY + 10).tagify()
// if ALPHA is not zero, assume it's 1 val nudgeX = nudgingBits.ushr(16).toByte().toInt() // signed 8-bit int
if (pixmap.getPixel(codeStartX, tagStartY + y).and(0xFF) != 0) { val nudgeY = nudgingBits.ushr(8).toByte().toInt() // signed 8-bit int
tags = tags or (1 shl y)
}
}
if (code and 127 == 67) width *= -1 // the backspace key val diacriticsAnchors = (0..5).map {
if (debug) println("${code.charInfo()}: Width $width, tags $tags") val yPos = 11 + (it / 3)
val shift = (2 - (it % 3)) * 8
val yPixel = pixmap.getPixel(codeStartX, codeStartY + yPos).tagify()
val xPixel = pixmap.getPixel(codeStartX, codeStartY + yPos + 1).tagify()
val y = (yPixel ushr shift) and 127
val x = (xPixel ushr shift) and 127
val yUsed = (yPixel ushr shift) >= 128
val xUsed = (yPixel ushr shift) >= 128
/*val isDiacritics = pixmap.getPixel(codeStartX, codeStartY + H - 1).and(0xFF) != 0 DiacriticsAnchor(it, x, y, xUsed, yUsed)
if (isDiacritics) }.toTypedArray()
glyphWidth = -glyphWidth*/
val alignWhere = (11..12).fold(0) { acc, y -> acc or ((pixmap.getPixel(codeStartX, codeStartY + y).and(255) != 0).toInt() shl y) }
glyphProps[code] = GlyphProps(width, tags) val writeOnTop = pixmap.getPixel(codeStartX, codeStartY + 13).and(255) != 0
val stackWhere = (14..15).fold(0) { acc, y -> acc or ((pixmap.getPixel(codeStartX, codeStartY + y).and(255) != 0).toInt() shl y) }
glyphProps[code] = GlyphProps(width, isLowHeight, nudgeX, nudgeY, diacriticsAnchors, alignWhere, writeOnTop, stackWhere, GlyphProps.DEFAULT_EXTINFO, hasKernData, isKernYtype, kerningMask)
// if (code < 256) dbgprn("${code.charInfo()} width: $width, tags: ${glyphProps[code]}")
// extra info // extra info
val extCount = glyphProps[code]?.requiredExtInfoCount() ?: 0 val extCount = glyphProps[code]?.requiredExtInfoCount() ?: 0
if (extCount > 0) { if (extCount > 0) {
glyphProps[code]?.extInfo = IntArray(extCount)
for (x in 0 until extCount) { for (x in 0 until extCount) {
var info = 0 var info = 0
for (y in 0..18) { for (y in 0..18) {
// if ALPHA is not zero, assume it's 1 // if ALPHA is not zero, assume it's 1
if (pixmap.getPixel(cellX + x, cellY + y).and(0xFF) != 0) { if (pixmap.getPixel(cellX + x, cellY + y).and(255) != 0) {
info = info or (1 shl y) info = info or (1 shl y)
} }
} }
glyphProps[code]!!.extInfo!![x] = info glyphProps[code]!!.extInfo[x] = info
} }
} }
} }
} }
@@ -257,7 +272,7 @@ class TerrarumTypewriterBitmap(
private var flagFirstRun = true private var flagFirstRun = true
private var textBuffer = CodepointSequence(256) private var textBuffer = CodepointSequence(256)
private lateinit var tempLinotype: Texture private lateinit var tempLinotype: Texture
private var nullProp = GlyphProps(15, 0) private var nullProp = GlyphProps(15)
fun draw(batch: Batch, codepoints: CodepointSequence, x: Float, y: Float): GlyphLayout? { fun draw(batch: Batch, codepoints: CodepointSequence, x: Float, y: Float): GlyphLayout? {
@@ -424,7 +439,7 @@ class TerrarumTypewriterBitmap(
if (!thisProp.writeOnTop) { if (!thisProp.writeOnTop) {
posXbuffer[charIndex] = ((if (thisProp.nudgeRight) 1 else -1) * thisProp.alignXPos) + posXbuffer[charIndex] = thisProp.nudgeX +
when (itsProp.alignWhere) { when (itsProp.alignWhere) {
GlyphProps.ALIGN_RIGHT -> GlyphProps.ALIGN_RIGHT ->
posXbuffer[nonDiacriticCounter] + TerrarumSansBitmap.W_VAR_INIT + alignmentOffset + interchar + kerning + extraWidth posXbuffer[nonDiacriticCounter] + TerrarumSansBitmap.W_VAR_INIT + alignmentOffset + interchar + kerning + extraWidth
@@ -438,9 +453,9 @@ class TerrarumTypewriterBitmap(
stackUpwardCounter = 0 stackUpwardCounter = 0
stackDownwardCounter = 0 stackDownwardCounter = 0
extraWidth = (if (thisProp.nudgeRight) -1 else 1) * thisProp.alignXPos // NOTE: sign is flipped! extraWidth = -thisProp.nudgeX // NOTE: sign is flipped!
} }
else if (thisProp.writeOnTop && thisProp.alignXPos == GlyphProps.DIA_JOINER) { else if (thisProp.writeOnTop && thisProp.diacriticsAnchors[0].x == GlyphProps.DIA_JOINER) {
posXbuffer[charIndex] = when (itsProp.alignWhere) { posXbuffer[charIndex] = when (itsProp.alignWhere) {
GlyphProps.ALIGN_RIGHT -> GlyphProps.ALIGN_RIGHT ->
posXbuffer[nonDiacriticCounter] + TerrarumSansBitmap.W_VAR_INIT + alignmentOffset posXbuffer[nonDiacriticCounter] + TerrarumSansBitmap.W_VAR_INIT + alignmentOffset
@@ -459,7 +474,7 @@ class TerrarumTypewriterBitmap(
posXbuffer[nonDiacriticCounter] - (TerrarumSansBitmap.W_VAR_INIT - itsProp.width) posXbuffer[nonDiacriticCounter] - (TerrarumSansBitmap.W_VAR_INIT - itsProp.width)
} }
GlyphProps.ALIGN_CENTRE -> { GlyphProps.ALIGN_CENTRE -> {
val alignXPos = if (itsProp.alignXPos == 0) itsProp.width.div(2) else itsProp.alignXPos val alignXPos = if (itsProp.diacriticsAnchors[0].x == 0) itsProp.width.div(2) else itsProp.diacriticsAnchors[0].x
if (itsProp.alignWhere == GlyphProps.ALIGN_RIGHT) { if (itsProp.alignWhere == GlyphProps.ALIGN_RIGHT) {
posXbuffer[nonDiacriticCounter] + alignXPos + (itsProp.width + 1).div(2) posXbuffer[nonDiacriticCounter] + alignXPos + (itsProp.width + 1).div(2)
@@ -516,10 +531,10 @@ class TerrarumTypewriterBitmap(
posXbuffer[posXbuffer.lastIndex] = 1 + posXbuffer[posXbuffer.lastIndex - 1] + // adding 1 to house the shadow posXbuffer[posXbuffer.lastIndex] = 1 + posXbuffer[posXbuffer.lastIndex - 1] + // adding 1 to house the shadow
if (lastCharProp?.writeOnTop == true) { if (lastCharProp?.writeOnTop == true) {
val realDiacriticWidth = if (lastCharProp.alignWhere == GlyphProps.ALIGN_CENTRE) { val realDiacriticWidth = if (lastCharProp.alignWhere == GlyphProps.ALIGN_CENTRE) {
(lastCharProp.width).div(2) + penultCharProp.alignXPos (lastCharProp.width).div(2) + penultCharProp.diacriticsAnchors[0].x
} }
else if (lastCharProp.alignWhere == GlyphProps.ALIGN_RIGHT) { else if (lastCharProp.alignWhere == GlyphProps.ALIGN_RIGHT) {
(lastCharProp.width) + penultCharProp.alignXPos (lastCharProp.width) + penultCharProp.diacriticsAnchors[0].x
} }
else 0 else 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB