mirror of
https://github.com/curioustorvald/Terrarum-sans-bitmap.git
synced 2026-03-07 11:51:50 +09:00
expanding diacritics types to correctly implement thai diacritics
This commit is contained in:
@@ -7,7 +7,7 @@ Font Spritesheets are stored in ```assets/graphics/fonts``` directory. Image for
|
||||
|
||||
#### Before getting started, you did read our design goals, right? Good. Now you may continue your awesome work.
|
||||
|
||||
### Ascenders, descenders, width informations (aka Glyph Tags)
|
||||
## Ascenders, descenders, width informations (aka Glyph Tags)
|
||||
|
||||

|
||||
|
||||
@@ -26,11 +26,11 @@ Each cell is 16 px wide, and any glyph you draw **must be contained within lefts
|
||||
|
||||
|
||||
|
||||
### Font Metrics
|
||||
## Font Metrics for variable-width font sheets
|
||||
|
||||
Although the font is basically a Spritesheet, some of the sheet expects variable widths to be supported. Any sheets with ```_variable``` means it expects variable widths. Anything else expects fixed width (regular Spritesheet behaviour). ```cjkpunct``` has width of 10, ```kana``` and ```hangul_johab``` has width of 12, ```wenquanyi``` has width of 16.
|
||||
|
||||
### Parsing glyph widths for variable font sheets
|
||||
### Parsing Glyph Tags
|
||||
|
||||

|
||||
|
||||
@@ -61,26 +61,28 @@ Rightmost vertical column (should be 20 px tall) contains the tags. Tags are def
|
||||
D --Diacritics Type Bit (see below; not all diacritics are marked as one on the spritesheet)
|
||||
S -,_ 0 Stack 1 Stack 0 Before 1 Up &
|
||||
(MSB) S -' 0 up 0 down 1 &After 1 Down (e.g. U+0C48)
|
||||
```
|
||||
|
||||
|
||||
* Nudging Bits Encoding:
|
||||
#### 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:
|
||||
#### Diacritics Anchor Point Encoding
|
||||
|
||||
4 Pixels are further divided as follows:
|
||||
|
||||
(LSB)
|
||||
Y - Anchor point Y for undefined, undefined, undefined
|
||||
X - Anchor point X for undefined, undefined, undefined
|
||||
Y - Anchor point Y for (unused), undefined, undefined
|
||||
X - Anchor point X for Type-0 (centre-aligned) diacritics, undefined, undefined
|
||||
(MSB)
|
||||
| LSB | | | | |
|
||||
| ------------ | ------------ | ------------ | ------------ | ------------ |
|
||||
| Y | Anchor point Y for: | undefined | undefined | undefined |
|
||||
| X | Anchor point X for: | undefined | undefined | undefined |
|
||||
| Y | Anchor point Y for: | (unused) | (unused) | (unused) |
|
||||
| X | Anchor point X for: | Type-0 | Type-1 | Type-2 |
|
||||
| MSB | | | | |
|
||||
|
||||
<MSB,Red> 1Y1Y1Y1Y 1Y2Y2Y2Y 1Y3Y3Y3Y <LSB,Blue>
|
||||
<MSB,Red> 1X1X1X1X 1X2X2X2X 1X3X3X3X <LSB,Blue>
|
||||
@@ -89,38 +91,31 @@ where Red is first, Green is second, Blue is the third diacritics.
|
||||
MSB for each word must be set so that the pixel would appear brighter on the image editor.
|
||||
(the font program will only read low 7 bits for each RGB channel)
|
||||
|
||||
* Diacritics Type Bit Encoding:
|
||||
#### Diacritics Type Bit Encoding
|
||||
|
||||
<MSB,Red> FFFFFFFF FFFFFFFF FFFFFFFF <LSB,Blue> (For Type-0)
|
||||
<MSB,Red> TTTT0000 00000000 00000000 <LSB,Blue> (For Type-1 to Type-15)
|
||||
|
||||
Right now, only the type-0 diacritics and its anchor point is used by the font.
|
||||
Certain types of diacritics have predefined meanings:
|
||||
|
||||
* Compiler Directives:
|
||||
* Type-0: Above
|
||||
* Type-1: Below (when it should be separated from being above)
|
||||
* Type-2: Overlaid (will shift down 2 pixels for lowheight glyphs instead of the default of 4 pixels)
|
||||
|
||||
|
||||
#### Compiler Directives
|
||||
|
||||
<MSB,Red> [Opcode] [arg1] [arg2] <LSB,Blue>
|
||||
|
||||
Currently supported opcodes:
|
||||
|
||||
- 00000000: No-operation; does not use the Compiler Directive system.
|
||||
*00000000: No-operation; does not use the Compiler Directive system.
|
||||
|
||||
- 10000xxx: Replace a character with xxx subchars (yes, number 0 can be used).
|
||||
Replacement characters are encoded vertically from X-zero, bit by bit
|
||||
(colour of the pixel doesn't matter) with LSB sitting on Y-zero.
|
||||
*10000xxx: Replace a character with xxx subchars (yes, number 0 can be used).
|
||||
Replacement characters are encoded vertically from X-zero, bit by bit
|
||||
(colour of the pixel doesn't matter) with LSB sitting on Y-zero.
|
||||
|
||||
|
||||
|
||||
-= NOTE =-
|
||||
|
||||
The code has remnants of one old HACK: using 0th diacritics' X-anchor pos as a type selector
|
||||
This hack applied only when write-on-top bit is set. Relevant codes are currently commented out instead of
|
||||
being completely removed for future debugging.
|
||||
Interpretation:
|
||||
DIA_OVERLAY = 1
|
||||
DIA_JOINER = 2
|
||||
|
||||
```
|
||||
|
||||
#### Stack Up/Down
|
||||
|
||||
When the tag is stack-up, it'll be drawn 4 px lower if the underlying
|
||||
@@ -157,13 +152,13 @@ Also note that the font compiler will not "stack" these diacritics.
|
||||
|
||||
(fun fact: it was drawn on Rhodia memopad with Lamy 2000, then photographed and edited on my iPhone. Letter used is a Cherokee WE Ꮺ)
|
||||
|
||||
### Technical Limitations
|
||||
## Technical Limitations
|
||||
|
||||
- Each spritesheet is 4096x4096 maximum, which is a size of 4K Texture. However it is recommended to be smaller or equal to 1024x1024.
|
||||
- Glyphs exceeding 15px of width needs to be broken down with 2 or more characters. Wider sheets WILL NOT BE IMPLEMENTED, can't waste much pixels just for few superwide glyphs.
|
||||
- Due to how the compiler is coded, actual glyph must have alpha value of 255, the tags must have alpha values LESS THAN 255 (and obviously greater than zero). RGB plane of the TGA image doesn't do anything, keep it as #FFFFFF white.
|
||||
|
||||
### Implementing the Korean writing system
|
||||
## Implementation of the Korean writing system
|
||||
|
||||
On this font, Hangul letters are printed by assemblying two or three letter pieces. There are 10 sets of Hangul letter pieces on the font. Top 6 are initials, middle 2 are medials, and bottom 2 are finals. On the rightmost side, there's eight assembled glyphs to help you with (assuming you have basic knowledge on the writing system). Top 6 tells you how to use 6 initials, and bottom 2 tells you how to use 2 finals.
|
||||
|
||||
|
||||
BIN
assets/ascii_variable.tga
LFS
BIN
assets/ascii_variable.tga
LFS
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 131 B |
BIN
assets/ipa_ext_variable.tga
LFS
BIN
assets/ipa_ext_variable.tga
LFS
Binary file not shown.
BIN
assets/thai_variable.tga
LFS
BIN
assets/thai_variable.tga
LFS
Binary file not shown.
@@ -46,8 +46,8 @@ data class GlyphProps(
|
||||
const val STACK_BEFORE_N_AFTER = 2
|
||||
const val STACK_UP_N_DOWN = 3
|
||||
|
||||
const val DIA_OVERLAY = 1
|
||||
const val DIA_JOINER = 2
|
||||
const val DIA_OVERLAY = 2
|
||||
// const val DIA_JOINER = 2
|
||||
|
||||
private fun Boolean.toInt() = if (this) 1 else 0
|
||||
}
|
||||
|
||||
@@ -739,14 +739,14 @@ class TerrarumSansBitmap(
|
||||
val nudgeY = nudgingBits.ushr(16).toByte().toInt() // signed 8-bit int
|
||||
|
||||
val diacriticsAnchors = (0..5).map {
|
||||
val yPos = 11 + (it / 3) * 2
|
||||
val yPos = 13 - (it / 3) * 2
|
||||
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 yUsed = (yPixel ushr shift) and 128 != 0
|
||||
val xUsed = (xPixel ushr shift) and 128 != 0
|
||||
val y = if (yUsed) (yPixel ushr shift) and 127 else 0
|
||||
val x = if (xUsed) (xPixel ushr shift) and 127 else 0
|
||||
|
||||
DiacriticsAnchor(it, x, y, xUsed, yUsed)
|
||||
}.toTypedArray()
|
||||
@@ -754,18 +754,22 @@ class TerrarumSansBitmap(
|
||||
val alignWhere = (0..1).fold(0) { acc, y -> acc or ((pixmap.getPixel(codeStartX, codeStartY + y + 15).and(255) != 0).toInt() shl y) }
|
||||
|
||||
var writeOnTop = pixmap.getPixel(codeStartX, codeStartY + 17) // NO .tagify()
|
||||
if (writeOnTop and 255 == 0) writeOnTop = -1
|
||||
if (writeOnTop and 255 == 0) writeOnTop = -1 // look for the alpha channel
|
||||
else {
|
||||
writeOnTop = writeOnTop.ushr(8)
|
||||
if (writeOnTop == 0xFFFFFF) writeOnTop = 0
|
||||
if (writeOnTop.ushr(8) == 0xFFFFFF) writeOnTop = 0
|
||||
else writeOnTop = writeOnTop.ushr(28) and 15
|
||||
}
|
||||
|
||||
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, IntArray(15), hasKernData, isKernYtype, kerningMask, directiveOpcode, directiveArg1, directiveArg2)
|
||||
|
||||
|
||||
// Debug prints //
|
||||
// if (nudgingBits != 0) dbgprn("${code.charInfo()} nudgeX=$nudgeX, nudgeY=$nudgeY, nudgingBits=0x${nudgingBits.toString(16)}")
|
||||
// if (writeOnTop >= 0) dbgprn("WriteOnTop: ${code.charInfo()} (Type-${writeOnTop})")
|
||||
// if (diacriticsAnchors.any { it.xUsed || it.yUsed }) dbgprn("${code.charInfo()} ${diacriticsAnchors.filter { it.xUsed || it.yUsed }.joinToString()}")
|
||||
|
||||
|
||||
// extra info
|
||||
val extCount = glyphProps[code]?.requiredExtInfoCount() ?: 0
|
||||
@@ -834,7 +838,10 @@ class TerrarumSansBitmap(
|
||||
|
||||
|
||||
/**
|
||||
* posXbuffer's size is greater than the string, last element marks the width of entire string.
|
||||
* THE function to typeset all the letters and their diacritics
|
||||
*
|
||||
* @return Pair of X-positions and Y-positions, of which the X-position's size is greater than the string
|
||||
* and the last element marks the width of entire string.
|
||||
*/
|
||||
private fun buildPosMap(str: List<Int>): Pair<IntArray, IntArray> {
|
||||
val posXbuffer = IntArray(str.size + 1) { 0 }
|
||||
@@ -900,6 +907,7 @@ class TerrarumSansBitmap(
|
||||
if (isHangul(thisChar) && !isHangulChoseong(thisChar) && !isHangulCompat(thisChar)) {
|
||||
posXbuffer[charIndex] = posXbuffer[nonDiacriticCounter]
|
||||
}
|
||||
// is this glyph NOT a diacritic?
|
||||
else if (thisProp.writeOnTop < 0) {
|
||||
posXbuffer[charIndex] = -thisProp.nudgeX +
|
||||
when (itsProp.alignWhere) {
|
||||
@@ -929,15 +937,19 @@ class TerrarumSansBitmap(
|
||||
|
||||
}
|
||||
}*/
|
||||
// is this glyph a diacritic?
|
||||
else {
|
||||
val diacriticsType = thisProp.writeOnTop
|
||||
// set X pos according to alignment information
|
||||
posXbuffer[charIndex] = when (thisProp.alignWhere) {
|
||||
GlyphProps.ALIGN_LEFT, GlyphProps.ALIGN_BEFORE -> posXbuffer[nonDiacriticCounter]
|
||||
GlyphProps.ALIGN_RIGHT -> {
|
||||
posXbuffer[nonDiacriticCounter] - (W_VAR_INIT - itsProp.width)
|
||||
val alignXPos = if (!itsProp.diacriticsAnchors[diacriticsType].xUsed) itsProp.width else itsProp.diacriticsAnchors[diacriticsType].x
|
||||
|
||||
posXbuffer[nonDiacriticCounter] - W_VAR_INIT + alignXPos
|
||||
}
|
||||
GlyphProps.ALIGN_CENTRE -> {
|
||||
val alignXPos = if (itsProp.diacriticsAnchors[0].x == 0) itsProp.width.div(2) else itsProp.diacriticsAnchors[0].x
|
||||
val alignXPos = if (!itsProp.diacriticsAnchors[diacriticsType].xUsed) itsProp.width.div(2) else itsProp.diacriticsAnchors[diacriticsType].x
|
||||
|
||||
if (itsProp.alignWhere == GlyphProps.ALIGN_RIGHT) {
|
||||
posXbuffer[nonDiacriticCounter] + alignXPos + (itsProp.width + 1).div(2)
|
||||
@@ -966,7 +978,7 @@ class TerrarumSansBitmap(
|
||||
//dbgprn("AAARRRRHHHH for character ${thisChar.toHex()}")
|
||||
//dbgprn("lastNonDiacriticChar: ${lastNonDiacriticChar.toHex()}")
|
||||
//dbgprn("cond: ${thisProp.alignXPos == GlyphProps.DIA_OVERLAY}, charIndex: $charIndex")
|
||||
if (thisProp.diacriticsAnchors[0].x == GlyphProps.DIA_OVERLAY)
|
||||
if (diacriticsType == GlyphProps.DIA_OVERLAY)
|
||||
posYbuffer[charIndex] -= H_OVERLAY_LOWERCASE_SHIFTDOWN * (!flipY).toSign() // if minus-assign doesn't work, try plus-assign
|
||||
else
|
||||
posYbuffer[charIndex] -= H_STACKUP_LOWERCASE_SHIFTDOWN * (!flipY).toSign() // if minus-assign doesn't work, try plus-assign
|
||||
|
||||
BIN
testing.PNG
BIN
testing.PNG
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 14 KiB |
16
testtext.txt
16
testtext.txt
@@ -1,16 +1,4 @@
|
||||
ถูกตำรว
|
||||
ถูกตรว
|
||||
aำ
|
||||
แป้นพิมพ์เกษมณี แป้นพิมพ์ปัตตะโชติ
|
||||
คำเตือน-อนามัยและความปลอดภัย
|
||||
|
||||
UIJTuijt
|
||||
A ดุ ตี ปู่ พี่ ป่ ม่ ปั มั พีุ
|
||||
|
||||
দৌ ষৌ
|
||||
|
||||
Mℂ℄ℇ℀℈jℊ№℗CKℵ℡Z℥
|
||||
ℵ₀
|
||||
|
||||
🄅🄵🅅🄕🄩🄪🄭🅭🄏🄎🅯🅮🆞🆠🆐🄯🆒🆓
|
||||
|
||||
도ᄋ해 무ᄅ과 배ᄀ두사ᄂ 하느니ᄆ이 보우하사
|
||||
U̸ u̸
|
||||
BIN
work_files/ascii_variable.psd
LFS
BIN
work_files/ascii_variable.psd
LFS
Binary file not shown.
Binary file not shown.
BIN
work_files/ipa_ext_variable.psd
LFS
BIN
work_files/ipa_ext_variable.psd
LFS
Binary file not shown.
BIN
work_files/thai_variable.psd
LFS
BIN
work_files/thai_variable.psd
LFS
Binary file not shown.
Reference in New Issue
Block a user