diff --git a/FontTestGDX/lib/TerrarumSansBitmap.jar b/FontTestGDX/lib/TerrarumSansBitmap.jar index 920abb1..593e459 100644 Binary files a/FontTestGDX/lib/TerrarumSansBitmap.jar and b/FontTestGDX/lib/TerrarumSansBitmap.jar differ diff --git a/assets/hangul_johab.tga b/assets/hangul_johab.tga index 5e6237b..765936b 100644 Binary files a/assets/hangul_johab.tga and b/assets/hangul_johab.tga differ diff --git a/src/net/torvald/terrarumsansbitmap/gdx/GameFontBase.kt b/src/net/torvald/terrarumsansbitmap/gdx/GameFontBase.kt index 766e84c..58973a9 100755 --- a/src/net/torvald/terrarumsansbitmap/gdx/GameFontBase.kt +++ b/src/net/torvald/terrarumsansbitmap/gdx/GameFontBase.kt @@ -37,7 +37,6 @@ import java.security.MessageDigest import java.util.* import java.util.zip.CRC32 import java.util.zip.GZIPInputStream -import kotlin.NullPointerException import kotlin.math.roundToInt import kotlin.math.sign @@ -106,218 +105,7 @@ class GameFontBase( val debug: Boolean = false ) : BitmapFont() { - // Hangul Implementation Specific // - private fun getWanseongHanChoseong(hanIndex: Int) = hanIndex / (JUNG_COUNT * JONG_COUNT) - private fun getWanseongHanJungseong(hanIndex: Int) = hanIndex / JONG_COUNT % JUNG_COUNT - private fun getWanseongHanJongseong(hanIndex: Int) = hanIndex % JONG_COUNT - - // ㅗ ㅛ ㅜ ㅠ ㅡ etc - private val jungseongWide: Array = arrayOf(9,13,14,18,19,34,35,39,45,51,53,54,62,64,66,80,83) - // ㅘ ㅙ ㅚ etc - private val jungseongComplex: Array = arrayOf(10,11,12,15,16,17,20) + (22..33).toList() + arrayOf(36,37,38) + (40..44).toList() + arrayOf(46,47,48,49,50,52) + (55..60).toList() + arrayOf(63,65) + (67..79).toList() + arrayOf(81,82) + (84..93).toList() - // ㅓ ㅔ ㅕ etc - private val jungseongRightie: Array = arrayOf(2,4,6,8,11,16,32,33,37,42,44,48,50,71,72,75,78,79,83,86,87,88,94) - - private fun isJungseongWide(hanIndex: Int) = jungseongWide.binarySearch(hanIndex) >= 0 - private fun isJungseongComplex(hanIndex: Int) = jungseongComplex.binarySearch(hanIndex) >= 0 - private fun isJungseongRighie(hanIndex: Int) = jungseongRightie.binarySearch(hanIndex) >= 0 - - /** - * @param i Initial (Choseong) - * @param p Peak (Jungseong) - * @param f Final (Jongseong) - */ - private fun getHanInitialRow(i: Int, p: Int, f: Int): Int { - val ret = - if (isJungseongWide(p)) 3 - else if (isJungseongComplex(p)) 5 - else 1 - - return if (f == 0) ret else ret + 1 - } - - private fun getHanMedialRow(i: Int, p: Int, f: Int) = if (f == 0) 7 else 8 - - private fun getHanFinalRow(i: Int, p: Int, f: Int): Int { - - return if (isJungseongRighie(p)) - 10 - else - 9 - } - - private fun isHangulChoseong(c: CodePoint) = c in (0x1100..0x115F) || c in (0xA960..0xA97F) - private fun isHangulJungseong(c: CodePoint) = c in (0x1160..0x11A7) || c in (0xD7B0..0xD7C6) - private fun isHangulJongseong(c: CodePoint) = c in (0x11A8..0x11FF) || c in (0xD7CB..0xD7FB) - - private fun toHangulChoseongIndex(c: CodePoint) = - if (!isHangulChoseong(c)) throw IllegalArgumentException("This Hangul sequence does not begin with Choseong (${c.toHex()})") - else if (c in 0x1100..0x115F) c - 0x1100 - else c - 0xA960 + 96 - private fun toHangulJungseongIndex(c: CodePoint) = - if (!isHangulJungseong(c)) 0 - else if (c in 0x1160..0x11A7) c - 0x1160 - else c - 0xD7B0 + 72 - private fun toHangulJongseongIndex(c: CodePoint) = - if (!isHangulJongseong(c)) 0 - else if (c in 0x11A8..0x11FF) c - 0x11A8 + 1 - else c - 0xD7CB + 88 + 1 - - /** - * X-position in the spritesheet - * - * @param iCP Code point for Initial (Choseong) - * @param pCP Code point for Peak (Jungseong) - * @param fCP Code point for Final (Jongseong) - */ - private fun toHangulIndex(iCP: CodePoint, pCP: CodePoint, fCP: CodePoint): IntArray { - val indexI = toHangulChoseongIndex(iCP) - val indexP = toHangulJungseongIndex(pCP) - val indexF = toHangulJongseongIndex(fCP) - - return intArrayOf(indexI, indexP, indexF) - } - - /** - * @param iCP 0x1100..0x115F, 0xA960..0xA97F, 0x3130..0x318F - * @param pCP 0x00, 0x1160..0x11A7, 0xD7B0..0xD7CA - * @param fCP 0x00, 0x11A8..0x11FF, 0xD7BB..0xD7FF - * - * @return IntArray pair representing Hangul indices and rows (in this order) - */ - private fun toHangulIndexAndRow(iCP: CodePoint, pCP: CodePoint, fCP: CodePoint): Pair { - if (isHangulCompat(iCP)) { - return intArrayOf(iCP - 0x3130, 0, 0) to intArrayOf(0, 7, 9) - } - else { - val (indexI, indexP, indexF) = toHangulIndex(iCP, pCP, fCP) - - val rowI = getHanInitialRow(indexI, indexP, indexF) - val rowP = getHanMedialRow(indexI, indexP, indexF) - val rowF = getHanFinalRow(indexI, indexP, indexF) - - return intArrayOf(indexI, indexP, indexF) to intArrayOf(rowI, rowP, rowF) - } - } - - - // END Hangul // - - private fun isHangul(c: CodePoint) = c in codeRange[SHEET_HANGUL] || c in 0x3130..0x318F - private fun isAscii(c: CodePoint) = c in codeRange[SHEET_ASCII_VARW] - private fun isRunic(c: CodePoint) = c in codeRange[SHEET_RUNIC] - private fun isExtA(c: CodePoint) = c in codeRange[SHEET_EXTA_VARW] - private fun isExtB(c: CodePoint) = c in codeRange[SHEET_EXTB_VARW] - private fun isKana(c: CodePoint) = c in codeRange[SHEET_KANA] - private fun isCJKPunct(c: CodePoint) = c in codeRange[SHEET_CJK_PUNCT] - private fun isUniHan(c: CodePoint) = c in codeRange[SHEET_UNIHAN] - private fun isCyrilic(c: CodePoint) = c in codeRange[SHEET_CYRILIC_VARW] - private fun isFullwidthUni(c: CodePoint) = c in codeRange[SHEET_FW_UNI] - private fun isUniPunct(c: CodePoint) = c in codeRange[SHEET_UNI_PUNCT_VARW] - private fun isGreek(c: CodePoint) = c in codeRange[SHEET_GREEK_VARW] - private fun isThai(c: CodePoint) = c in codeRange[SHEET_THAI_VARW] - /*private fun isDiacritics(c: CodePoint) = c in 0xE34..0xE3A - || c in 0xE47..0xE4E - || c == 0xE31*/ - private fun isCustomSym(c: CodePoint) = c in codeRange[SHEET_CUSTOM_SYM] - private fun isArmenian(c: CodePoint) = c in codeRange[SHEET_HAYEREN_VARW] - private fun isKartvelian(c: CodePoint) = c in codeRange[SHEET_KARTULI_VARW] - private fun isIPA(c: CodePoint) = c in codeRange[SHEET_IPA_VARW] - private fun isLatinExtAdd(c: CodePoint) = c in 0x1E00..0x1EFF - private fun isBulgarian(c: CodePoint) = c in 0x400..0x45F - private fun isColourCode(c: CodePoint) = c == 0x100000 || c in 0x10F000..0x10FFFF - private fun isCharsetOverride(c: CodePoint) = c in 0xFFFC0..0xFFFFF - private fun isCherokee(c: CodePoint) = c in codeRange[SHEET_TSALAGI_VARW] - private fun isInsular(c: CodePoint) = c == 0x1D79 - private fun isNagariBengali(c: CodePoint) = c in codeRange[SHEET_NAGARI_BENGALI_VARW] - private fun isKartvelianCaps(c: CodePoint) = c in codeRange[SHEET_KARTULI_CAPS_VARW] - private fun isDiacriticalMarks(c: CodePoint) = c in codeRange[SHEET_DIACRITICAL_MARKS_VARW] - private fun isPolytonicGreek(c: CodePoint) = c in codeRange[SHEET_GREEK_POLY_VARW] - private fun isExtC(c: CodePoint) = c in codeRange[SHEET_EXTC_VARW] - private fun isExtD(c: CodePoint) = c in codeRange[SHEET_EXTD_VARW] - private fun isHangulCompat(c: CodePoint) = c in codeRangeHangulCompat - - // underscored name: not a charset - private fun _isCaps(c: CodePoint) = Character.isUpperCase(c) || isKartvelianCaps(c) - - - private fun extAindexX(c: CodePoint) = (c - 0x100) % 16 - private fun extAindexY(c: CodePoint) = (c - 0x100) / 16 - - private fun extBindexX(c: CodePoint) = (c - 0x180) % 16 - private fun extBindexY(c: CodePoint) = (c - 0x180) / 16 - - private fun runicIndexX(c: CodePoint) = (c - 0x16A0) % 16 - private fun runicIndexY(c: CodePoint) = (c - 0x16A0) / 16 - - private fun kanaIndexX(c: CodePoint) = (c - 0x3040) % 16 - private fun kanaIndexY(c: CodePoint) = - if (c in 0x31F0..0x31FF) 12 - else if (c in 0x1B000..0x1B00F) 13 - else (c - 0x3040) / 16 - - private fun cjkPunctIndexX(c: CodePoint) = (c - 0x3000) % 16 - private fun cjkPunctIndexY(c: CodePoint) = (c - 0x3000) / 16 - - private fun cyrilicIndexX(c: CodePoint) = (c - 0x400) % 16 - private fun cyrilicIndexY(c: CodePoint) = (c - 0x400) / 16 - - private fun fullwidthUniIndexX(c: CodePoint) = (c - 0xFF00) % 16 - private fun fullwidthUniIndexY(c: CodePoint) = (c - 0xFF00) / 16 - - private fun uniPunctIndexX(c: CodePoint) = (c - 0x2000) % 16 - private fun uniPunctIndexY(c: CodePoint) = (c - 0x2000) / 16 - - private fun unihanIndexX(c: CodePoint) = (c - 0x3400) % 256 - private fun unihanIndexY(c: CodePoint) = (c - 0x3400) / 256 - - private fun greekIndexX(c: CodePoint) = (c - 0x370) % 16 - private fun greekIndexY(c: CodePoint) = (c - 0x370) / 16 - - private fun thaiIndexX(c: CodePoint) = (c - 0xE00) % 16 - private fun thaiIndexY(c: CodePoint) = (c - 0xE00) / 16 - - private fun symbolIndexX(c: CodePoint) = (c - 0xE000) % 16 - private fun symbolIndexY(c: CodePoint) = (c - 0xE000) / 16 - - private fun armenianIndexX(c: CodePoint) = (c - 0x530) % 16 - private fun armenianIndexY(c: CodePoint) = (c - 0x530) / 16 - - private fun kartvelianIndexX(c: CodePoint) = (c - 0x10D0) % 16 - private fun kartvelianIndexY(c: CodePoint) = (c - 0x10D0) / 16 - - private fun ipaIndexX(c: CodePoint) = (c - 0x250) % 16 - private fun ipaIndexY(c: CodePoint) = (c - 0x250) / 16 - - private fun latinExtAddX(c: CodePoint) = (c - 0x1E00) % 16 - private fun latinExtAddY(c: CodePoint) = (c - 0x1E00) / 16 - - private fun cherokeeIndexX(c: CodePoint) = (c - 0x13A0) % 16 - private fun cherokeeIndexY(c: CodePoint) = (c - 0x13A0) / 16 - - private fun insularIndexX(c: CodePoint) = - if (c == 0x1D79) 0 else (c - 0xA770) % 16 - private fun insularIndexY(c: CodePoint) = - if (c == 0x1D79) 0 else (c - 0xA770) / 16 - - private fun nagariIndexX(c: CodePoint) = (c - 0x900) % 16 - private fun nagariIndexY(c: CodePoint) = (c - 0x900) / 16 - - private fun kartvelianCapsIndexX(c: CodePoint) = (c - 0x1C90) % 16 - private fun kartvelianCapsIndexY(c: CodePoint) = (c - 0x1C90) / 16 - - private fun diacriticalMarksIndexX(c: CodePoint) = (c - 0x300) % 16 - private fun diacriticalMarksIndexY(c: CodePoint) = (c - 0x300) / 16 - - private fun polytonicGreekIndexX(c: CodePoint) = (c - 0x1F00) % 16 - private fun polytonicGreekIndexY(c: CodePoint) = (c - 0x1F00) / 16 - - private fun extCIndexX(c: CodePoint) = (c - 0x2C60) % 16 - private fun extCIndexY(c: CodePoint) = (c - 0x2C60) / 16 - - private fun extDIndexX(c: CodePoint) = (c - 0xA720) % 16 - private fun extDIndexY(c: CodePoint) = (c - 0xA720) / 16 /** @@ -437,101 +225,11 @@ class GameFontBase( return col } + private val colourBuffer = HashMap() - - private val unihanWidthSheets = arrayOf( - SHEET_UNIHAN, - SHEET_FW_UNI - ) - private val variableWidthSheets = arrayOf( - SHEET_ASCII_VARW, - SHEET_EXTA_VARW, - SHEET_EXTB_VARW, - SHEET_CYRILIC_VARW, - SHEET_UNI_PUNCT_VARW, - SHEET_GREEK_VARW, - SHEET_THAI_VARW, - SHEET_HAYEREN_VARW, - SHEET_KARTULI_VARW, - SHEET_IPA_VARW, - SHEET_LATIN_EXT_ADD_VARW, - SHEET_BULGARIAN_VARW, - SHEET_SERBIAN_VARW, - SHEET_TSALAGI_VARW, - SHEET_INSUAR_VARW, - SHEET_NAGARI_BENGALI_VARW, - SHEET_KARTULI_CAPS_VARW, - SHEET_DIACRITICAL_MARKS_VARW, - SHEET_GREEK_POLY_VARW, - SHEET_EXTC_VARW, - SHEET_EXTD_VARW - ) - private val autoShiftDownOnLowercase = arrayOf( - SHEET_DIACRITICAL_MARKS_VARW - ) - private val fontParentDir = if (fontDir.endsWith('/') || fontDir.endsWith('\\')) fontDir else "$fontDir/" - private val fileList = arrayOf( // MUST BE MATCHING WITH SHEET INDICES!! - "ascii_variable.tga", - "hangul_johab.tga", - "latinExtA_variable.tga", - "latinExtB_variable.tga", - "kana.tga", - "cjkpunct.tga", - "wenquanyi.tga.gz", - "cyrilic_variable.tga", - "fullwidth_forms.tga", - "unipunct_variable.tga", - "greek_variable.tga", - "thai_variable.tga", - "hayeren_variable.tga", - "kartuli_variable.tga", - "ipa_ext_variable.tga", - "futhark.tga", - "latinExt_additional_variable.tga", - "puae000-e0ff.tga", - "cyrilic_bulgarian_variable.tga", - "cyrilic_serbian_variable.tga", - "tsalagi_variable.tga", - "insular_variable.tga", - "devanagari_bengali_variable.tga", - "kartuli_allcaps_variable.tga", - "diacritical_marks_variable.tga", - "greek_polytonic_xyswap_variable.tga", - "latinExtC_variable.tga", - "latinExtD_variable.tga" - ) - private val codeRange = arrayOf( // MUST BE MATCHING WITH SHEET INDICES!! - 0..0xFF, // SHEET_ASCII_VARW - (0x1100..0x11FF) + (0xA960..0xA97F) + (0xD7B0..0xD7FF), // SHEET_HANGUL, because Hangul Syllables are disassembled prior to the render - 0x100..0x17F, // SHEET_EXTA_VARW - 0x180..0x24F, // SHEET_EXTB_VARW - (0x3040..0x30FF) + (0x31F0..0x31FF) + (0x1B000..0x1B001), // SHEET_KANA - 0x3000..0x303F, // SHEET_CJK_PUNCT - 0x3400..0x9FFF, // SHEET_UNIHAN - 0x400..0x52F, // SHEET_CYRILIC_VARW - 0xFF00..0xFF1F, // SHEET_FW_UNI - 0x2000..0x209F, // SHEET_UNI_PUNCT_VARW - 0x370..0x3CE, // SHEET_GREEK_VARW - 0xE00..0xE5F, // SHEET_THAI_VARW - 0x530..0x58F, // SHEET_HAYEREN_VARW - 0x10D0..0x10FF, // SHEET_KARTULI_VARW - 0x250..0x2FF, // SHEET_IPA_VARW - 0x16A0..0x16FF, // SHEET_RUNIC - 0x1E00..0x1EFF, // SHEET_LATIN_EXT_ADD_VARW - 0xE000..0xE0FF, // SHEET_CUSTOM_SYM - 0xF00000..0xF0005F, // SHEET_BULGARIAN_VARW; assign them to PUA - 0xF00060..0xF000BF, // SHEET_SERBIAN_VARW; assign them to PUA - 0x13A0..0x13F5, // SHEET_TSALAGI_VARW - 0xA770..0xA787, // SHEET_INSULAR_VARW; if it work, don't fix it (yet--wait until Latin Extended C) - 0x900..0x9FF, // SHEET_NAGARI_BENGALI_VARW - 0x1C90..0x1CBF, // SHEET_KARTULI_CAPS_VARW - 0x300..0x36F, // SHEET_DIACRITICAL_MARKS_VARW - 0x1F00..0x1FFF, // SHEET_GREEK_POLY_VARW - 0x2C60..0x2C7F, // SHEET_EXTC_VARW - 0xA720..0xA7FF // SHEET_EXTD_VARW - ) - private val codeRangeHangulCompat = 0x3130..0x318F + + /** Props of all printable Unicode points. */ private val glyphProps: HashMap = HashMap() private val sheets: Array @@ -1150,14 +848,14 @@ class GameFontBase( fun buildWidthTableFixed() { // fixed-width props - this.codeRange[SHEET_CJK_PUNCT].forEach { glyphProps[it] = GlyphProps(W_ASIAN_PUNCT, 0) } - this.codeRange[SHEET_CUSTOM_SYM].forEach { glyphProps[it] = GlyphProps(20, 0) } - this.codeRange[SHEET_FW_UNI].forEach { glyphProps[it] = GlyphProps(W_UNIHAN, 0) } - this.codeRange[SHEET_HANGUL].forEach { glyphProps[it] = GlyphProps(W_HANGUL, 0) } + codeRange[SHEET_CJK_PUNCT].forEach { glyphProps[it] = GlyphProps(W_ASIAN_PUNCT, 0) } + codeRange[SHEET_CUSTOM_SYM].forEach { glyphProps[it] = GlyphProps(20, 0) } + codeRange[SHEET_FW_UNI].forEach { glyphProps[it] = GlyphProps(W_UNIHAN, 0) } + codeRange[SHEET_HANGUL].forEach { glyphProps[it] = GlyphProps(W_HANGUL, 0) } codeRangeHangulCompat.forEach { glyphProps[it] = GlyphProps(W_HANGUL, 0) } - this.codeRange[SHEET_KANA].forEach { glyphProps[it] = GlyphProps(W_KANA, 0) } - this.codeRange[SHEET_RUNIC].forEach { glyphProps[it] = GlyphProps(9, 0) } - this.codeRange[SHEET_UNIHAN].forEach { glyphProps[it] = GlyphProps(W_UNIHAN, 0) } + codeRange[SHEET_KANA].forEach { glyphProps[it] = GlyphProps(W_KANA, 0) } + codeRange[SHEET_RUNIC].forEach { glyphProps[it] = GlyphProps(9, 0) } + codeRange[SHEET_UNIHAN].forEach { glyphProps[it] = GlyphProps(W_UNIHAN, 0) } (0xD800..0xDFFF).forEach { glyphProps[it] = GlyphProps(0, 0) } (0x100000..0x10FFFF).forEach { glyphProps[it] = GlyphProps(0, 0) } (0xFFFA0..0xFFFFF).forEach { glyphProps[it] = GlyphProps(0, 0) } @@ -1634,7 +1332,6 @@ class GameFontBase( } - private fun Int.toHex() = "U+${this.toString(16).padStart(4, '0').toUpperCase()}" private fun CharSequence.sha256(): ByteArray { val digest = MessageDigest.getInstance("SHA-256") @@ -1728,6 +1425,330 @@ class GameFontBase( internal val CHARSET_OVERRIDE_SR_SR = 0xFFFC2 + private val unihanWidthSheets = arrayOf( + SHEET_UNIHAN, + SHEET_FW_UNI + ) + private val variableWidthSheets = arrayOf( + SHEET_ASCII_VARW, + SHEET_EXTA_VARW, + SHEET_EXTB_VARW, + SHEET_CYRILIC_VARW, + SHEET_UNI_PUNCT_VARW, + SHEET_GREEK_VARW, + SHEET_THAI_VARW, + SHEET_HAYEREN_VARW, + SHEET_KARTULI_VARW, + SHEET_IPA_VARW, + SHEET_LATIN_EXT_ADD_VARW, + SHEET_BULGARIAN_VARW, + SHEET_SERBIAN_VARW, + SHEET_TSALAGI_VARW, + SHEET_INSUAR_VARW, + SHEET_NAGARI_BENGALI_VARW, + SHEET_KARTULI_CAPS_VARW, + SHEET_DIACRITICAL_MARKS_VARW, + SHEET_GREEK_POLY_VARW, + SHEET_EXTC_VARW, + SHEET_EXTD_VARW + ) + private val autoShiftDownOnLowercase = arrayOf( + SHEET_DIACRITICAL_MARKS_VARW + ) + + private val fileList = arrayOf( // MUST BE MATCHING WITH SHEET INDICES!! + "ascii_variable.tga", + "hangul_johab.tga", + "latinExtA_variable.tga", + "latinExtB_variable.tga", + "kana.tga", + "cjkpunct.tga", + "wenquanyi.tga.gz", + "cyrilic_variable.tga", + "fullwidth_forms.tga", + "unipunct_variable.tga", + "greek_variable.tga", + "thai_variable.tga", + "hayeren_variable.tga", + "kartuli_variable.tga", + "ipa_ext_variable.tga", + "futhark.tga", + "latinExt_additional_variable.tga", + "puae000-e0ff.tga", + "cyrilic_bulgarian_variable.tga", + "cyrilic_serbian_variable.tga", + "tsalagi_variable.tga", + "insular_variable.tga", + "devanagari_bengali_variable.tga", + "kartuli_allcaps_variable.tga", + "diacritical_marks_variable.tga", + "greek_polytonic_xyswap_variable.tga", + "latinExtC_variable.tga", + "latinExtD_variable.tga" + ) + private val codeRange = arrayOf( // MUST BE MATCHING WITH SHEET INDICES!! + 0..0xFF, // SHEET_ASCII_VARW + (0x1100..0x11FF) + (0xA960..0xA97F) + (0xD7B0..0xD7FF), // SHEET_HANGUL, because Hangul Syllables are disassembled prior to the render + 0x100..0x17F, // SHEET_EXTA_VARW + 0x180..0x24F, // SHEET_EXTB_VARW + (0x3040..0x30FF) + (0x31F0..0x31FF) + (0x1B000..0x1B001), // SHEET_KANA + 0x3000..0x303F, // SHEET_CJK_PUNCT + 0x3400..0x9FFF, // SHEET_UNIHAN + 0x400..0x52F, // SHEET_CYRILIC_VARW + 0xFF00..0xFF1F, // SHEET_FW_UNI + 0x2000..0x209F, // SHEET_UNI_PUNCT_VARW + 0x370..0x3CE, // SHEET_GREEK_VARW + 0xE00..0xE5F, // SHEET_THAI_VARW + 0x530..0x58F, // SHEET_HAYEREN_VARW + 0x10D0..0x10FF, // SHEET_KARTULI_VARW + 0x250..0x2FF, // SHEET_IPA_VARW + 0x16A0..0x16FF, // SHEET_RUNIC + 0x1E00..0x1EFF, // SHEET_LATIN_EXT_ADD_VARW + 0xE000..0xE0FF, // SHEET_CUSTOM_SYM + 0xF00000..0xF0005F, // SHEET_BULGARIAN_VARW; assign them to PUA + 0xF00060..0xF000BF, // SHEET_SERBIAN_VARW; assign them to PUA + 0x13A0..0x13F5, // SHEET_TSALAGI_VARW + 0xA770..0xA787, // SHEET_INSULAR_VARW; if it work, don't fix it (yet--wait until Latin Extended C) + 0x900..0x9FF, // SHEET_NAGARI_BENGALI_VARW + 0x1C90..0x1CBF, // SHEET_KARTULI_CAPS_VARW + 0x300..0x36F, // SHEET_DIACRITICAL_MARKS_VARW + 0x1F00..0x1FFF, // SHEET_GREEK_POLY_VARW + 0x2C60..0x2C7F, // SHEET_EXTC_VARW + 0xA720..0xA7FF // SHEET_EXTD_VARW + ) + private val codeRangeHangulCompat = 0x3130..0x318F + + private fun Int.toHex() = "U+${this.toString(16).padStart(4, '0').toUpperCase()}" + + // Hangul Implementation Specific // + + private fun getWanseongHanChoseong(hanIndex: Int) = hanIndex / (JUNG_COUNT * JONG_COUNT) + private fun getWanseongHanJungseong(hanIndex: Int) = hanIndex / JONG_COUNT % JUNG_COUNT + private fun getWanseongHanJongseong(hanIndex: Int) = hanIndex % JONG_COUNT + + // ㅣ + private val jungseongI: Array = arrayOf(21,61) + // ㅗ ㅛ ㅜ ㅠ + private val jungseongOU: Array = arrayOf(9,13,14,18,34,35,39,45,51,53,54,64,80,83) + // ㅘ ㅙ ㅝ ㅞ + private val jungseongOUComplex: Array = arrayOf(10,11,15,16) + (22..33).toList() + arrayOf(36,37,38) + (41..44).toList() + arrayOf(46,47,48,49,50) + (56..59).toList() + arrayOf(63) + (67..79).toList() + arrayOf(81,82) + (84..93).toList() + // ㅐ ㅒ ㅔ ㅖ etc + private val jungseongRightie: Array = arrayOf(2,4,6,8,11,16,32,33,37,42,44,48,50,71,72,75,78,79,83,86,87,88,94) + // ㅚ ㅟ + private val jungseongOEWI: Array = arrayOf(12,17,40,52,55,89,90,91) + // ㅡ + private val jungseongEU: Array = arrayOf(19,62,66) + // ㅢ + private val jungseongYI: Array = arrayOf(20,60,65) + + private fun isJungseongI(hanIndex: Int) = jungseongI.binarySearch(hanIndex) >= 0 + private fun isJungseongOU(hanIndex: Int) = jungseongOU.binarySearch(hanIndex) >= 0 + private fun isJungseongOUComplex(hanIndex: Int) = jungseongOUComplex.binarySearch(hanIndex) >= 0 + private fun isJungseongRighie(hanIndex: Int) = jungseongRightie.binarySearch(hanIndex) >= 0 + private fun isJungseongOEWI(hanIndex: Int) = jungseongOEWI.binarySearch(hanIndex) >= 0 + private fun isJungseongEU(hanIndex: Int) = jungseongEU.binarySearch(hanIndex) >= 0 + private fun isJungseongYI(hanIndex: Int) = jungseongYI.binarySearch(hanIndex) >= 0 + + + /** + * @param i Initial (Choseong) + * @param p Peak (Jungseong) + * @param f Final (Jongseong) + */ + private fun getHanInitialRow(i: Int, p: Int, f: Int): Int { + val ret = + if (isJungseongI(p)) 3 + else if (isJungseongOUComplex(p)) 7 + else if (isJungseongOEWI(p)) 11 + else if (isJungseongOU(p)) 5 + else if (isJungseongEU(p)) 9 + else if (isJungseongYI(p)) 13 + else 1 + + return if (f == 0) ret else ret + 1 + } + + private fun getHanMedialRow(i: Int, p: Int, f: Int) = if (f == 0) 15 else 16 + + private fun getHanFinalRow(i: Int, p: Int, f: Int): Int { + + return if (!isJungseongRighie(p)) + 17 + else + 18 + } + + private fun isHangulChoseong(c: CodePoint) = c in (0x1100..0x115F) || c in (0xA960..0xA97F) + private fun isHangulJungseong(c: CodePoint) = c in (0x1160..0x11A7) || c in (0xD7B0..0xD7C6) + private fun isHangulJongseong(c: CodePoint) = c in (0x11A8..0x11FF) || c in (0xD7CB..0xD7FB) + + private fun toHangulChoseongIndex(c: CodePoint) = + if (!isHangulChoseong(c)) throw IllegalArgumentException("This Hangul sequence does not begin with Choseong (${c.toHex()})") + else if (c in 0x1100..0x115F) c - 0x1100 + else c - 0xA960 + 96 + private fun toHangulJungseongIndex(c: CodePoint) = + if (!isHangulJungseong(c)) 0 + else if (c in 0x1160..0x11A7) c - 0x1160 + else c - 0xD7B0 + 72 + private fun toHangulJongseongIndex(c: CodePoint) = + if (!isHangulJongseong(c)) 0 + else if (c in 0x11A8..0x11FF) c - 0x11A8 + 1 + else c - 0xD7CB + 88 + 1 + + /** + * X-position in the spritesheet + * + * @param iCP Code point for Initial (Choseong) + * @param pCP Code point for Peak (Jungseong) + * @param fCP Code point for Final (Jongseong) + */ + private fun toHangulIndex(iCP: CodePoint, pCP: CodePoint, fCP: CodePoint): IntArray { + val indexI = toHangulChoseongIndex(iCP) + val indexP = toHangulJungseongIndex(pCP) + val indexF = toHangulJongseongIndex(fCP) + + return intArrayOf(indexI, indexP, indexF) + } + + /** + * @param iCP 0x1100..0x115F, 0xA960..0xA97F, 0x3130..0x318F + * @param pCP 0x00, 0x1160..0x11A7, 0xD7B0..0xD7CA + * @param fCP 0x00, 0x11A8..0x11FF, 0xD7BB..0xD7FF + * + * @return IntArray pair representing Hangul indices and rows (in this order) + */ + private fun toHangulIndexAndRow(iCP: CodePoint, pCP: CodePoint, fCP: CodePoint): Pair { + if (isHangulCompat(iCP)) { + return intArrayOf(iCP - 0x3130, 0, 0) to intArrayOf(0, 15, 17) + } + else { + val (indexI, indexP, indexF) = toHangulIndex(iCP, pCP, fCP) + + val rowI = getHanInitialRow(indexI, indexP, indexF) + val rowP = getHanMedialRow(indexI, indexP, indexF) + val rowF = getHanFinalRow(indexI, indexP, indexF) + + return intArrayOf(indexI, indexP, indexF) to intArrayOf(rowI, rowP, rowF) + } + } + + + // END Hangul // + + private fun isHangul(c: CodePoint) = c in codeRange[SHEET_HANGUL] || c in 0x3130..0x318F + private fun isAscii(c: CodePoint) = c in codeRange[SHEET_ASCII_VARW] + private fun isRunic(c: CodePoint) = c in codeRange[SHEET_RUNIC] + private fun isExtA(c: CodePoint) = c in codeRange[SHEET_EXTA_VARW] + private fun isExtB(c: CodePoint) = c in codeRange[SHEET_EXTB_VARW] + private fun isKana(c: CodePoint) = c in codeRange[SHEET_KANA] + private fun isCJKPunct(c: CodePoint) = c in codeRange[SHEET_CJK_PUNCT] + private fun isUniHan(c: CodePoint) = c in codeRange[SHEET_UNIHAN] + private fun isCyrilic(c: CodePoint) = c in codeRange[SHEET_CYRILIC_VARW] + private fun isFullwidthUni(c: CodePoint) = c in codeRange[SHEET_FW_UNI] + private fun isUniPunct(c: CodePoint) = c in codeRange[SHEET_UNI_PUNCT_VARW] + private fun isGreek(c: CodePoint) = c in codeRange[SHEET_GREEK_VARW] + private fun isThai(c: CodePoint) = c in codeRange[SHEET_THAI_VARW] + /*private fun isDiacritics(c: CodePoint) = c in 0xE34..0xE3A + || c in 0xE47..0xE4E + || c == 0xE31*/ + private fun isCustomSym(c: CodePoint) = c in codeRange[SHEET_CUSTOM_SYM] + private fun isArmenian(c: CodePoint) = c in codeRange[SHEET_HAYEREN_VARW] + private fun isKartvelian(c: CodePoint) = c in codeRange[SHEET_KARTULI_VARW] + private fun isIPA(c: CodePoint) = c in codeRange[SHEET_IPA_VARW] + private fun isLatinExtAdd(c: CodePoint) = c in 0x1E00..0x1EFF + private fun isBulgarian(c: CodePoint) = c in 0x400..0x45F + private fun isColourCode(c: CodePoint) = c == 0x100000 || c in 0x10F000..0x10FFFF + private fun isCharsetOverride(c: CodePoint) = c in 0xFFFC0..0xFFFFF + private fun isCherokee(c: CodePoint) = c in codeRange[SHEET_TSALAGI_VARW] + private fun isInsular(c: CodePoint) = c == 0x1D79 + private fun isNagariBengali(c: CodePoint) = c in codeRange[SHEET_NAGARI_BENGALI_VARW] + private fun isKartvelianCaps(c: CodePoint) = c in codeRange[SHEET_KARTULI_CAPS_VARW] + private fun isDiacriticalMarks(c: CodePoint) = c in codeRange[SHEET_DIACRITICAL_MARKS_VARW] + private fun isPolytonicGreek(c: CodePoint) = c in codeRange[SHEET_GREEK_POLY_VARW] + private fun isExtC(c: CodePoint) = c in codeRange[SHEET_EXTC_VARW] + private fun isExtD(c: CodePoint) = c in codeRange[SHEET_EXTD_VARW] + private fun isHangulCompat(c: CodePoint) = c in codeRangeHangulCompat + + // underscored name: not a charset + private fun _isCaps(c: CodePoint) = Character.isUpperCase(c) || isKartvelianCaps(c) + + + private fun extAindexX(c: CodePoint) = (c - 0x100) % 16 + private fun extAindexY(c: CodePoint) = (c - 0x100) / 16 + + private fun extBindexX(c: CodePoint) = (c - 0x180) % 16 + private fun extBindexY(c: CodePoint) = (c - 0x180) / 16 + + private fun runicIndexX(c: CodePoint) = (c - 0x16A0) % 16 + private fun runicIndexY(c: CodePoint) = (c - 0x16A0) / 16 + + private fun kanaIndexX(c: CodePoint) = (c - 0x3040) % 16 + private fun kanaIndexY(c: CodePoint) = + if (c in 0x31F0..0x31FF) 12 + else if (c in 0x1B000..0x1B00F) 13 + else (c - 0x3040) / 16 + + private fun cjkPunctIndexX(c: CodePoint) = (c - 0x3000) % 16 + private fun cjkPunctIndexY(c: CodePoint) = (c - 0x3000) / 16 + + private fun cyrilicIndexX(c: CodePoint) = (c - 0x400) % 16 + private fun cyrilicIndexY(c: CodePoint) = (c - 0x400) / 16 + + private fun fullwidthUniIndexX(c: CodePoint) = (c - 0xFF00) % 16 + private fun fullwidthUniIndexY(c: CodePoint) = (c - 0xFF00) / 16 + + private fun uniPunctIndexX(c: CodePoint) = (c - 0x2000) % 16 + private fun uniPunctIndexY(c: CodePoint) = (c - 0x2000) / 16 + + private fun unihanIndexX(c: CodePoint) = (c - 0x3400) % 256 + private fun unihanIndexY(c: CodePoint) = (c - 0x3400) / 256 + + private fun greekIndexX(c: CodePoint) = (c - 0x370) % 16 + private fun greekIndexY(c: CodePoint) = (c - 0x370) / 16 + + private fun thaiIndexX(c: CodePoint) = (c - 0xE00) % 16 + private fun thaiIndexY(c: CodePoint) = (c - 0xE00) / 16 + + private fun symbolIndexX(c: CodePoint) = (c - 0xE000) % 16 + private fun symbolIndexY(c: CodePoint) = (c - 0xE000) / 16 + + private fun armenianIndexX(c: CodePoint) = (c - 0x530) % 16 + private fun armenianIndexY(c: CodePoint) = (c - 0x530) / 16 + + private fun kartvelianIndexX(c: CodePoint) = (c - 0x10D0) % 16 + private fun kartvelianIndexY(c: CodePoint) = (c - 0x10D0) / 16 + + private fun ipaIndexX(c: CodePoint) = (c - 0x250) % 16 + private fun ipaIndexY(c: CodePoint) = (c - 0x250) / 16 + + private fun latinExtAddX(c: CodePoint) = (c - 0x1E00) % 16 + private fun latinExtAddY(c: CodePoint) = (c - 0x1E00) / 16 + + private fun cherokeeIndexX(c: CodePoint) = (c - 0x13A0) % 16 + private fun cherokeeIndexY(c: CodePoint) = (c - 0x13A0) / 16 + + private fun insularIndexX(c: CodePoint) = + if (c == 0x1D79) 0 else (c - 0xA770) % 16 + private fun insularIndexY(c: CodePoint) = + if (c == 0x1D79) 0 else (c - 0xA770) / 16 + + private fun nagariIndexX(c: CodePoint) = (c - 0x900) % 16 + private fun nagariIndexY(c: CodePoint) = (c - 0x900) / 16 + + private fun kartvelianCapsIndexX(c: CodePoint) = (c - 0x1C90) % 16 + private fun kartvelianCapsIndexY(c: CodePoint) = (c - 0x1C90) / 16 + + private fun diacriticalMarksIndexX(c: CodePoint) = (c - 0x300) % 16 + private fun diacriticalMarksIndexY(c: CodePoint) = (c - 0x300) / 16 + + private fun polytonicGreekIndexX(c: CodePoint) = (c - 0x1F00) % 16 + private fun polytonicGreekIndexY(c: CodePoint) = (c - 0x1F00) / 16 + + private fun extCIndexX(c: CodePoint) = (c - 0x2C60) % 16 + private fun extCIndexY(c: CodePoint) = (c - 0x2C60) / 16 + + private fun extDIndexX(c: CodePoint) = (c - 0xA720) % 16 + private fun extDIndexY(c: CodePoint) = (c - 0xA720) / 16 /* #!/usr/bin/python3 @@ -1737,9 +1758,7 @@ s = "charseq" for c in s: #print(ord(c)) print("0x{0:x}".format(ord(c))) - */ - - // acegijmnopqrsuvwxyzɱɳʙɾɽʒʂʐʋɹɻɥɟɡɢʛȵɲŋɴʀɕʑçʝxɣχʁʜʍɰʟɨʉɯuʊøɘɵɤəɛœɜɞʌɔæɐɶɑɒɚɝɩɪʅʈʏʞⱥⱦⱱⱳⱴⱶⱷⱸⱺⱻꜥꜩꜫꜭꜯꜰꜱꜳꜵꜷꜹꜻꜽꜿꝋꝍꝏꝑꝓꝕꝗꝙꝛꝝꝟꝡꝫꝯꝳꝴꝵꝶꝷꝺꝼꝿꞁꞃꞅꞇꞑꞓꞔꞛꞝꞟꞡꞥꞧꞩꞮꞷꟺ\uA7AF\uA7B9\uA7C3\uA7CA + */ // acegijmnopqrsuvwxyzɱɳʙɾɽʒʂʐʋɹɻɥɟɡɢʛȵɲŋɴʀɕʑçʝxɣχʁʜʍɰʟɨʉɯuʊøɘɵɤəɛœɜɞʌɔæɐɶɑɒɚɝɩɪʅʈʏʞⱥⱦⱱⱳⱴⱶⱷⱸⱺⱻꜥꜩꜫꜭꜯꜰꜱꜳꜵꜷꜹꜻꜽꜿꝋꝍꝏꝑꝓꝕꝗꝙꝛꝝꝟꝡꝫꝯꝳꝴꝵꝶꝷꝺꝼꝿꞁꞃꞅꞇꞑꞓꞔꞛꞝꞟꞡꞥꞧꞩꞮꞷꟺ\uA7AF\uA7B9\uA7C3\uA7CA private val lowHeightLetters = intArrayOf(0x61,0x63,0x65,0x67,0x69,0x6a,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x75,0x76,0x77,0x78,0x79,0x7a,0x271,0x273,0x299,0x27e,0x27d,0x292,0x282,0x290,0x28b,0x279,0x27b,0x265,0x25f,0x261,0x262,0x29b,0x235,0x272,0x14b,0x274,0x280,0x255,0x291,0xe7,0x29d,0x78,0x263,0x3c7,0x281,0x29c,0x28d,0x270,0x29f,0x268,0x289,0x26f,0x75,0x28a,0xf8,0x258,0x275,0x264,0x259,0x25b,0x153,0x25c,0x25e,0x28c,0x254,0xe6,0x250,0x276,0x251,0x252,0x25a,0x25d,0x269,0x26a,0x285,0x288,0x28f,0x29e,0x2c65,0x2c66,0x2c71,0x2c73,0x2c74,0x2c76,0x2c77,0x2c78,0x2c7a,0x2c7b,0xa725,0xa729,0xa72b,0xa72d,0xa72f,0xa730,0xa731,0xa733,0xa735,0xa737,0xa739,0xa73b,0xa73d,0xa73f,0xa74b,0xa74d,0xa74f,0xa751,0xa753,0xa755,0xa757,0xa759,0xa75b,0xa75d,0xa75f,0xa761,0xa76b,0xa76f,0xa773,0xa774,0xa775,0xa776,0xa777,0xa77a,0xa77c,0xa77f,0xa781,0xa783,0xa785,0xa787,0xa791,0xa793,0xa794,0xa79b,0xa79d,0xa79f,0xa7a1,0xa7a5,0xa7a7,0xa7a9,0xa7ae,0xa7b7,0xa7fa,0xa7af,0xa7b9,0xa7c3,0xa7ca).toSortedSet() // TŢŤƬƮȚͲΤТҬᛏṪṬṮṰⲦϮϯⴶꚌꚐᎢᛠꓔ private val kernTees = intArrayOf(0x54,0x162,0x164,0x1ac,0x1ae,0x21a,0x372,0x3a4,0x422,0x4ac,0x16cf,0x1e6a,0x1e6c,0x1e6e,0x1e70,0x2ca6,0x3ee,0x3ef,0x2d36,0xa68c,0xa690,0x13a2,0x16e0,0xa4d4).toSortedSet() diff --git a/testing.PNG b/testing.PNG index 2599d5f..fb5d6a7 100755 Binary files a/testing.PNG and b/testing.PNG differ diff --git a/testtext.txt b/testtext.txt index 24f0de5..ae02e45 100755 --- a/testtext.txt +++ b/testtext.txt @@ -16,21 +16,34 @@ OOO 바람결에 실려온 당신의 nostalgia와 어지러이 섞인 regret의 memories -x86 또는 80x86은 인텔이 개발한 마이크로프로세서 계열을 부르는 말이자, 이들과 호환되는 프로세서들에서 사용한 명령어 집합 -구조들을 통칭하는 말이다. x86 아키텍처는 데스크톱 컴퓨터 시장에서 매우 널리 쓰이며, PowerPC 같이 좀 더 근대적인 아키텍처를 -사용한 프로세서들이 x86과 경쟁했으나 그다지 많은 시장 점유율을 확보하지는 못했다. +x86 또는 80x86은 인텔이 개발한 마이크로프로세서 계열을 부르는 말이자, 이들과 호환되는 프로세서들에서 사용한 +명령어 집합 구조들을 통칭하는 말이다. x86 아키텍처는 데스크톱 컴퓨터 시장에서 매우 널리 쓰이며, PowerPC +같이 좀 더 근대적인 아키텍처를 사용한 프로세서들이 x86과 경쟁했으나 그다지 많은 시장 점유율을 확보하지는 못했다. -x86 또는 80x86이라는 이름은 여기에 속하는 초기의 프로세서들 이름이 모두 80으로 시작해서 86으로 끝났기 때문에 붙여졌다. -여기에는 8086, 80186, 80286, 386, 486이 포함되며, 숫자로 상표를 등록할 수 없었기 때문에 그 뒤로는 펜티엄과 같은 별도의 -이름을 사용하게 되었다. 그러나 586, 686과 같은 이름은 아직까지도 (비공식적으로) 사용되며, 전체 아키텍처를 나타내는 말에도 -그 흔적이 남아 있다. +x86 또는 80x86이라는 이름은 여기에 속하는 초기의 프로세서들 이름이 모두 80으로 시작해서 86으로 끝났기 때문에 +붙여졌다. 여기에는 8086, 80186, 80286, 386, 486이 포함되며, 숫자로 상표를 등록할 수 없었기 때문에 그 +뒤로는 펜티엄과 같은 별도의 이름을 사용하게 되었다. 그러나 586, 686과 같은 이름은 아직까지도 (비공식적으로) +사용되며, 전체 아키텍처를 나타내는 말에도 그 흔적이 남아 있다. -x86 아키텍처를 사용하는 최초의 프로세서는 1978년에 발표된 인텔 8086으로, 이전 프로세서인 인텔 8080과 어셈블리어 단에서 -호환되도록 설계되었다. 인텔 8086은 3년 후에 IBM PC의 표준 프로세서로 채택되었다. IBM PC는 그 후로 계속 성장하여 개인용 컴퓨터 업계의 표준이 되었으며, 그에 따라 x86 아키텍처는 매우 성공적인 명령 집합 아키텍처가 되었다. 사이릭스, 일본 -전기 주식회사(NEC), IBM, 트랜스메타 등의 회사들이 x86 아키텍처를 사용하는 프로세서를 생산했으며, 그중 AMD의 애슬론 계열 -프로세서들은 펜티엄에 미치지는 못 하지만 상당한 시장 점유율을 차지하고 있다. +x86 아키텍처를 사용하는 최초의 프로세서는 1978년에 발표된 인텔 8086으로, 이전 프로세서인 인텔 8080과 +어셈블리어 단에서 호환되도록 설계되었다. 인텔 8086은 3년 후에 IBM PC의 표준 프로세서로 채택되었다. IBM PC는 +그 후로 계속 성장하여 개인용 컴퓨터 업계의 표준이 되었으며, 그에 따라 x86 아키텍처는 매우 성공적인 명령 집합 +아키텍처가 되었다. 사이릭스, 일본 전기 주식회사(NEC), IBM, 트랜스메타 등의 회사들이 x86 아키텍처를 사용하는 +프로세서를 생산했으며, 그중 AMD의 애슬론 계열 프로세서들은 펜티엄에 미치지는 못 하지만 상당한 시장 점유율을 +차지하고 있다. -x86 아키텍처는 가변 길이 명령을 쓰는 CISC 설계를 채용했으며, 하위 호환성에 중점을 두고 있다. x86 아키텍처는 다른 아키텍처와 -같이 워드 경계에 맞춰서 메모리를 읽는 것이 효율적이긴 하지만, 워드 경계에 걸치는 메모리도 한 번에 접근할 수 있다. 워드들은 -최하위 바이트부터 최상위 바이트까지 순서대로 (리틀 엔디안) 저장된다. 현재의 x86 프로세서들은 명령들을 내부적으로 더 작은 -단위로 쪼개서 RISC와 비슷한 내부 아키텍처에서 수행한다. \ No newline at end of file +x86 아키텍처는 가변 길이 명령을 쓰는 CISC 설계를 채용했으며, 하위 호환성에 중점을 두고 있다. x86 아키텍처는 +다른 아키텍처와 같이 워드 경계에 맞춰서 메모리를 읽는 것이 효율적이긴 하지만, 워드 경계에 걸치는 메모리도 한 +번에 접근할 수 있다. 워드들은 최하위 바이트부터 최상위 바이트까지 순서대로 (리틀 엔디안) 저장된다. 현재의 +x86 프로세서들은 명령들을 내부적으로 더 작은 단위로 쪼개서 RISC와 비슷한 내부 아키텍처에서 수행한다. + +EVE Online 전문가 펀지 사망했습니다! ㅗㅜㅑ +AVA 고인물 DXFunz 펀즈펀즈파누털 ㅍㅈㅍㅈㅍㄴㅌ + +씬춘 썅쑝쑈를 썅그릴라 호텔테서 연 씬찐 썅쑝 가수 쏭쌍썽씨가 쩌끼 쩌 미트 쏘씨찌 쏘쓰 쓰파게티는 깐쑈쌔우 크림 +쏘쓰 쏘씨찌 쏘쓰 쓰테이크보다 비싸다며 단식에 들어가 호텔의 빈축을 사고 있습니다 +헌 상품을 새 쌍품으로 만들애내는 쌍장사가 저기 가능 쌍짱싸가 쌔 쌍 쌍짱싸냐 헌 쌍 쌍짱싸냐고 쏘릴 질러 찌나가던 +씬씬얘씨가 쏘쓰라치게 놀랐다고 합니다 +쓰티븐 씨걸씨의 쏘울메이트로 알려진 쑸싸씀이 맨해튼에 쎈쎄이쎤을 쑾쏙을 쌑쌑이 + +왵 윁 왰 웼 \ No newline at end of file