diff --git a/gradle.properties b/gradle.properties index d2ef271..f36e2ec 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,15 +1,15 @@ -korgePluginVersion=2.0.6.0 - -web.bind.port=8080 - -org.gradle.jvmargs=-Xmx3g -org.gradle.parallel=true -org.gradle.parallel.intra=true -org.gradle.configureondemand=true -kotlin.mpp.stability.nowarn=true - -korge.enable.desktop=true -korge.enable.android.indirect=true -#korge.enable.android.direct=true -korge.enable.ios=true -korge.enable.js=true +korgePluginVersion=2.0.7.0 + +web.bind.port=8080 + +org.gradle.jvmargs=-Xmx3g +org.gradle.parallel=true +org.gradle.parallel.intra=true +org.gradle.configureondemand=true +kotlin.mpp.stability.nowarn=true + +korge.enable.desktop=true +korge.enable.android.indirect=true +#korge.enable.android.direct=true +korge.enable.ios=true +korge.enable.js=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 62d4c05..e708b1c 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 28ff446..2a56324 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index fbd7c51..4f906e0 100755 --- a/gradlew +++ b/gradlew @@ -130,7 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath diff --git a/gradlew.bat b/gradlew.bat index a9f778a..ac1b06f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,21 +64,6 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line @@ -86,7 +71,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/sample/bunnymark/src/commonMain/kotlin/main.kt b/sample/bunnymark/src/commonMain/kotlin/main.kt index 78aa097..e333b9f 100644 --- a/sample/bunnymark/src/commonMain/kotlin/main.kt +++ b/sample/bunnymark/src/commonMain/kotlin/main.kt @@ -32,7 +32,9 @@ class Bunny(tex: BmpSlice) : FastSprite(tex) { // bunnymark ported from PIXI.js // https://www.goodboydigital.com/pixijs/bunnymark/ // https://www.goodboydigital.com/pixijs/bunnymark/js/bunnyBenchMark.js -suspend fun main() = Korge(width = 800, height = 600, bgcolor = Colors["#2b2b9b"]) { +suspend fun main() = Korge(width = 800, height = 600, bgcolor = Colors["#2b2b9b"], batchMaxQuads = com.soywiz.korge.render.BatchBuilder2D.MAX_BATCH_QUADS) { +//suspend fun main() = Korge(width = 800, height = 600, bgcolor = Colors["#2b2b9b"], batchMaxQuads = com.soywiz.korge.render.BatchBuilder2D.MAX_BATCH_QUADS, debug = true) { +//suspend fun main() = Korge(width = 800, height = 600, bgcolor = Colors["#2b2b9b"], debug = true) { val wabbitTexture = resourcesVfs["bunnys.png"].readBitmap() val bunny1 = wabbitTexture.sliceWithSize(2, 47, 26, 37) @@ -42,6 +44,9 @@ suspend fun main() = Korge(width = 800, height = 600, bgcolor = Colors["#2b2b9b" val bunny5 = wabbitTexture.sliceWithSize(2, 2, 26, 37) val startBunnyCount = 2 + //val startBunnyCount = 400_003 + //val startBunnyCount = 200_000 + //val startBunnyCount = 250_000 //val startBunnyCount = 1_000_000 //val startBunnyCount = 200_000 val bunnyTextures = listOf(bunny1, bunny2, bunny3, bunny4, bunny5) diff --git a/sample/sprites10k/src/commonMain/kotlin/Main.kt b/sample/sprites10k/src/commonMain/kotlin/Main.kt index 8a5df3e..897ee91 100644 --- a/sample/sprites10k/src/commonMain/kotlin/Main.kt +++ b/sample/sprites10k/src/commonMain/kotlin/Main.kt @@ -5,7 +5,7 @@ import com.soywiz.korim.bitmap.* import com.soywiz.korim.format.* import com.soywiz.korio.file.std.* -suspend fun main() = Korge(width = 1600, height = 1200) { +suspend fun main() = Korge(width = 1600, height = 1200, batchMaxQuads = com.soywiz.korge.render.BatchBuilder2D.MAX_BATCH_QUADS) { val numberOfGreen = 5000 //val numberOfGreen = 20000 diff --git a/sample/text-metrics/.gitignore b/sample/text-metrics/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/sample/text-metrics/.gitignore @@ -0,0 +1 @@ +/build diff --git a/sample/text-metrics/build.gradle.kts b/sample/text-metrics/build.gradle.kts new file mode 100644 index 0000000..7722c57 --- /dev/null +++ b/sample/text-metrics/build.gradle.kts @@ -0,0 +1,13 @@ +import com.soywiz.korge.gradle.* + +apply() + +korge { + id = "com.soywiz.samples.textmetrics" + name = "Text2" + description = "Shows show text metrics" + orientation = com.soywiz.korge.gradle.Orientation.LANDSCAPE + jvmMainClassName = "MainKt" + + targetDefault() +} diff --git a/sample/text-metrics/src/commonMain/kotlin/main.kt b/sample/text-metrics/src/commonMain/kotlin/main.kt new file mode 100644 index 0000000..c35ae0e --- /dev/null +++ b/sample/text-metrics/src/commonMain/kotlin/main.kt @@ -0,0 +1,196 @@ +import com.soywiz.korev.* +import com.soywiz.korge.* +import com.soywiz.korge.scene.* +import com.soywiz.korge.ui.* +import com.soywiz.korge.view.* +import com.soywiz.korgw.* +import com.soywiz.korim.bitmap.effect.* +import com.soywiz.korim.vector.* +import com.soywiz.korim.color.* +import com.soywiz.korim.font.* +import com.soywiz.korim.text.* +import com.soywiz.korio.async.* +import com.soywiz.korio.file.std.* +import com.soywiz.korma.geom.* +import com.soywiz.korma.geom.vector.* +import com.soywiz.korui.* +import com.soywiz.korui.layout.* +import kotlin.reflect.* + +val DEFAULT_BG = Colors["#2b2b2b"] + +suspend fun main() { + //GLOBAL_CHECK_GL = true + Korge(width = 960, height = 720, bgcolor = DEFAULT_BG, clipBorders = false, scaleAnchor = Anchor.TOP_LEFT) { + val font0 = resourcesVfs["clear_sans.fnt"].readFont() + val font1 = debugBmpFont + val font2 = DefaultTtfFont + val font3 = BitmapFont(DefaultTtfFont, 64.0) + val font4 = BitmapFont(DefaultTtfFont, 64.0, paint = Colors.BLUEVIOLET, effect = BitmapEffect( + blurRadius = 0, + dropShadowX = 2, + dropShadowY = 2, + dropShadowColor = Colors.GREEN, + dropShadowRadius = 1, + //borderSize = 1, + //borderColor = Colors.RED, + )) + val font5 = resourcesVfs["Pacifico.ttf"].readFont() + lateinit var text1: Text + + val textStrs = mapOf( + "simple" to "01xXhjgÁEñÑ", + "UPPER" to "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "lower" to "abcdefghijklmnopqrstuvwxyz", + "number" to "0123456789", + "fox" to "The quick brown fox jumps over the lazy dog. 1234567890", + ) + val fontSizes = listOf(8, 16, 32, 64, 128, 175) + val verticalAlignments = VerticalAlign.values().toList() + val horizontalAlignments = HorizontalAlign.values().toList() + + val fonts = mapOf( + "DebugBMP" to font1, + "BMPFile" to font0, + "ExternalTTF" to font5, + "DefaultTTF" to font2, + "TTFtoBMP" to font3, + "TTFtoBMPEffect" to font4, + ) + + container { + xy(0, 500) + val leftPadding = 50 + text1 = text(textStrs["simple"]!!, 175.0, Colors.WHITE, font2, alignment = TextAlignment.BASELINE_LEFT, autoScaling = true).xy(leftPadding, 0) + val gbounds = graphics {}.xy(leftPadding, 0) + + val baseLineLine = solidRect(960 + 1200, 1, Colors.ORANGE) + val baseAscent = solidRect(960 + 1200, 1, Colors.BLUE) + val baseDescent = solidRect(960 + 1200, 1, Colors.PURPLE) + + var cachedBounds: Rectangle? = null + fun updateBounds() { + val currentBounds = text1.getLocalBounds() + if (cachedBounds != currentBounds) { + cachedBounds = currentBounds + gbounds.clear() + gbounds.stroke(Colors.RED, StrokeInfo(2.0)) { + rect(text1.getLocalBounds()) + } + gbounds.stroke(Colors.BLUE, StrokeInfo(2.0)) { + line(-5, 0, +5, 0) + line(0, -5, 0, +5) + } + val metrics = text1.font.getOrNull()!!.getFontMetrics(text1.fontSize) + baseLineLine.xy(0.0, -metrics.baseline) + baseAscent.xy(0.0, -metrics.ascent) + baseDescent.xy(0.0, -metrics.descent) + } + } + + addUpdater { + updateBounds() + } + updateBounds() + + } + + data class SecInfo( + val name: String, + val prop: KMutableProperty0, + val items: List, + val convert: (T) -> String = { it.toString().toLowerCase().capitalize() } + ) + + korui(width, 200) { + for (info in listOf( + SecInfo("Vertical", text1::verticalAlign, verticalAlignments), + SecInfo("Horizontal", text1::horizontalAlign, horizontalAlignments), + SecInfo("Size", text1::textSize, fontSizes.map { it.toDouble() }) { "${it.toInt()}" }, + )) { + @Suppress("UNCHECKED_CAST") val rinfo = (info as SecInfo) + horizontal { + label("${info.name}:") + val prop = ObservableProperty(info.prop) + @Suppress("UNCHECKED_CAST") val rprop = (prop as ObservableProperty) + for (item in info.items) { + toggleButton(rinfo.convert(item)) { + prop.observeStart { this.pressed = (it == item) } + onClick { + rprop.value = item + } + } + } + } + } + val fontProp = ObservableProperty(text1.font.getOrNull()!!).observeStart { text1.font = it } + horizontal { + label("Font:") + gameWindow.onDragAndDropFileEvent { + when (it.type) { + DropFileEvent.Type.START -> { + views.clearColor = DEFAULT_BG.interpolateWith(0.2, Colors.RED) + } + DropFileEvent.Type.END -> { + views.clearColor = DEFAULT_BG + } + DropFileEvent.Type.DROP -> { + try { + val file = it.files?.firstOrNull()?.jailParent() + val font = file?.readFont() + if (font != null) { + fontProp.value = font + } + } catch (e: Throwable) { + gameWindow.alertError(e) + throw e + } + } + } + } + for ((key, value) in fonts) { + toggleButton(key) { + fontProp.observeStart { this.pressed = (it == value) } + onClick { fontProp.value = value } + } + } + } + horizontal { + label("Text:") + val prop = ObservableProperty(textStrs.values.first()).observeStart { text1.text = it } + for ((key, value) in textStrs) { + toggleButton(key) { + prop.observeStart { this.pressed = (it == value) } + onClick { prop.value = value } + } + } + } + horizontal { + checkBox("Autoscale") { + checked = text1.autoScaling + onChange { text1.autoScaling = it } + } + checkBox("Smooth") { + checked = text1.smoothing + onChange { text1.smoothing = it } + } + checkBox("Native Render") { + checked = text1.useNativeRendering + onChange { text1.useNativeRendering = it } + } + } + horizontal { + button("Select file...") { + onClick { + launchImmediately { + val file = gameWindow.openFileDialog().firstOrNull() + if (file != null) { + fontProp.value = file.readFont() + } + } + } + } + } + } + } +} diff --git a/sample/text-metrics/src/commonMain/resources/Pacifico.ttf b/sample/text-metrics/src/commonMain/resources/Pacifico.ttf new file mode 100644 index 0000000..6d47cdc Binary files /dev/null and b/sample/text-metrics/src/commonMain/resources/Pacifico.ttf differ diff --git a/sample/text-metrics/src/commonMain/resources/clear_sans.fnt b/sample/text-metrics/src/commonMain/resources/clear_sans.fnt new file mode 100644 index 0000000..268c7be --- /dev/null +++ b/sample/text-metrics/src/commonMain/resources/clear_sans.fnt @@ -0,0 +1,99 @@ +info face="Clear Sans" size=64 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 outline=0 +common lineHeight=62 base=48 scaleW=256 scaleH=256 pages=1 packed=0 alphaChnl=0 redChnl=4 greenChnl=4 blueChnl=4 +page id=0 file="clear_sans.png" +chars count=95 +char id=32 x=100 y=41 width=1 height=1 xoffset=0 yoffset=0 xadvance=12 page=0 chnl=15 +char id=33 x=128 y=173 width=7 height=31 xoffset=2 yoffset=17 xadvance=12 page=0 chnl=15 +char id=34 x=95 y=230 width=13 height=13 xoffset=4 yoffset=17 xadvance=20 page=0 chnl=15 +char id=35 x=67 y=77 width=28 height=31 xoffset=2 yoffset=17 xadvance=32 page=0 chnl=15 +char id=36 x=221 y=0 width=21 height=34 xoffset=3 yoffset=17 xadvance=28 page=0 chnl=15 +char id=37 x=189 y=39 width=43 height=32 xoffset=1 yoffset=16 xadvance=46 page=0 chnl=15 +char id=38 x=124 y=75 width=27 height=31 xoffset=2 yoffset=17 xadvance=31 page=0 chnl=15 +char id=39 x=109 y=230 width=5 height=13 xoffset=4 yoffset=17 xadvance=12 page=0 chnl=15 +char id=40 x=38 y=0 width=14 height=42 xoffset=2 yoffset=15 xadvance=18 page=0 chnl=15 +char id=41 x=53 y=0 width=14 height=42 xoffset=1 yoffset=15 xadvance=18 page=0 chnl=15 +char id=42 x=50 y=230 width=18 height=16 xoffset=1 yoffset=15 xadvance=21 page=0 chnl=15 +char id=43 x=160 y=171 width=25 height=25 xoffset=3 yoffset=23 xadvance=31 page=0 chnl=15 +char id=44 x=115 y=230 width=7 height=12 xoffset=2 yoffset=43 xadvance=12 page=0 chnl=15 +char id=45 x=233 y=99 width=15 height=4 xoffset=1 yoffset=35 xadvance=18 page=0 chnl=15 +char id=46 x=160 y=222 width=7 height=5 xoffset=2 yoffset=43 xadvance=12 page=0 chnl=15 +char id=47 x=122 y=0 width=20 height=40 xoffset=0 yoffset=15 xadvance=22 page=0 chnl=15 +char id=48 x=96 y=141 width=23 height=31 xoffset=2 yoffset=17 xadvance=28 page=0 chnl=15 +char id=49 x=115 y=173 width=12 height=31 xoffset=6 yoffset=17 xadvance=28 page=0 chnl=15 +char id=50 x=167 y=139 width=22 height=31 xoffset=2 yoffset=17 xadvance=26 page=0 chnl=15 +char id=51 x=0 y=173 width=21 height=31 xoffset=1 yoffset=17 xadvance=26 page=0 chnl=15 +char id=52 x=27 y=109 width=26 height=31 xoffset=0 yoffset=17 xadvance=28 page=0 chnl=15 +char id=53 x=144 y=139 width=22 height=31 xoffset=1 yoffset=17 xadvance=26 page=0 chnl=15 +char id=54 x=233 y=35 width=22 height=31 xoffset=2 yoffset=17 xadvance=26 page=0 chnl=15 +char id=55 x=24 y=141 width=23 height=31 xoffset=2 yoffset=17 xadvance=28 page=0 chnl=15 +char id=56 x=48 y=141 width=23 height=31 xoffset=1 yoffset=17 xadvance=26 page=0 chnl=15 +char id=57 x=120 y=141 width=23 height=31 xoffset=1 yoffset=17 xadvance=26 page=0 chnl=15 +char id=58 x=19 y=230 width=7 height=23 xoffset=2 yoffset=25 xadvance=12 page=0 chnl=15 +char id=59 x=152 y=171 width=7 height=30 xoffset=2 yoffset=25 xadvance=12 page=0 chnl=15 +char id=60 x=0 y=205 width=26 height=24 xoffset=3 yoffset=24 xadvance=31 page=0 chnl=15 +char id=61 x=69 y=230 width=25 height=14 xoffset=3 yoffset=28 xadvance=31 page=0 chnl=15 +char id=62 x=27 y=205 width=25 height=24 xoffset=2 yoffset=24 xadvance=31 page=0 chnl=15 +char id=63 x=235 y=136 width=20 height=31 xoffset=1 yoffset=17 xadvance=23 page=0 chnl=15 +char id=64 x=156 y=0 width=38 height=38 xoffset=2 yoffset=17 xadvance=43 page=0 chnl=15 +char id=65 x=96 y=77 width=27 height=31 xoffset=0 yoffset=17 xadvance=28 page=0 chnl=15 +char id=66 x=190 y=137 width=22 height=31 xoffset=3 yoffset=17 xadvance=28 page=0 chnl=15 +char id=67 x=80 y=109 width=25 height=31 xoffset=2 yoffset=17 xadvance=29 page=0 chnl=15 +char id=68 x=233 y=67 width=22 height=31 xoffset=3 yoffset=17 xadvance=28 page=0 chnl=15 +char id=69 x=22 y=173 width=20 height=31 xoffset=3 yoffset=17 xadvance=25 page=0 chnl=15 +char id=70 x=43 y=173 width=20 height=31 xoffset=3 yoffset=17 xadvance=24 page=0 chnl=15 +char id=71 x=179 y=73 width=26 height=31 xoffset=2 yoffset=17 xadvance=31 page=0 chnl=15 +char id=72 x=132 y=107 width=24 height=31 xoffset=3 yoffset=17 xadvance=30 page=0 chnl=15 +char id=73 x=100 y=173 width=14 height=31 xoffset=1 yoffset=17 xadvance=17 page=0 chnl=15 +char id=74 x=84 y=173 width=15 height=31 xoffset=0 yoffset=17 xadvance=19 page=0 chnl=15 +char id=75 x=182 y=105 width=24 height=31 xoffset=3 yoffset=17 xadvance=28 page=0 chnl=15 +char id=76 x=64 y=173 width=19 height=31 xoffset=3 yoffset=17 xadvance=23 page=0 chnl=15 +char id=77 x=38 y=77 width=28 height=31 xoffset=3 yoffset=17 xadvance=35 page=0 chnl=15 +char id=78 x=232 y=104 width=23 height=31 xoffset=3 yoffset=17 xadvance=30 page=0 chnl=15 +char id=79 x=54 y=109 width=25 height=31 xoffset=2 yoffset=17 xadvance=30 page=0 chnl=15 +char id=80 x=213 y=136 width=21 height=31 xoffset=3 yoffset=17 xadvance=26 page=0 chnl=15 +char id=81 x=195 y=0 width=25 height=38 xoffset=2 yoffset=17 xadvance=30 page=0 chnl=15 +char id=82 x=72 y=141 width=23 height=31 xoffset=3 yoffset=17 xadvance=27 page=0 chnl=15 +char id=83 x=157 y=107 width=24 height=31 xoffset=1 yoffset=17 xadvance=27 page=0 chnl=15 +char id=84 x=152 y=75 width=26 height=31 xoffset=0 yoffset=17 xadvance=26 page=0 chnl=15 +char id=85 x=106 y=109 width=25 height=31 xoffset=3 yoffset=17 xadvance=31 page=0 chnl=15 +char id=86 x=206 y=72 width=26 height=31 xoffset=0 yoffset=17 xadvance=27 page=0 chnl=15 +char id=87 x=0 y=77 width=37 height=31 xoffset=1 yoffset=17 xadvance=39 page=0 chnl=15 +char id=88 x=0 y=109 width=26 height=31 xoffset=0 yoffset=17 xadvance=27 page=0 chnl=15 +char id=89 x=207 y=104 width=24 height=31 xoffset=0 yoffset=17 xadvance=25 page=0 chnl=15 +char id=90 x=0 y=141 width=23 height=31 xoffset=1 yoffset=17 xadvance=26 page=0 chnl=15 +char id=91 x=81 y=0 width=12 height=42 xoffset=3 yoffset=15 xadvance=18 page=0 chnl=15 +char id=92 x=100 y=0 width=21 height=40 xoffset=1 yoffset=15 xadvance=22 page=0 chnl=15 +char id=93 x=68 y=0 width=12 height=42 xoffset=2 yoffset=15 xadvance=18 page=0 chnl=15 +char id=94 x=27 y=230 width=22 height=19 xoffset=2 yoffset=17 xadvance=27 page=0 chnl=15 +char id=95 x=168 y=222 width=23 height=4 xoffset=0 yoffset=50 xadvance=23 page=0 chnl=15 +char id=96 x=123 y=230 width=10 height=9 xoffset=5 yoffset=14 xadvance=24 page=0 chnl=15 +char id=97 x=160 y=197 width=20 height=24 xoffset=1 yoffset=24 xadvance=24 page=0 chnl=15 +char id=98 x=89 y=43 width=20 height=33 xoffset=3 yoffset=15 xadvance=26 page=0 chnl=15 +char id=99 x=181 y=197 width=19 height=24 xoffset=2 yoffset=24 xadvance=23 page=0 chnl=15 +char id=100 x=67 y=43 width=21 height=33 xoffset=2 yoffset=15 xadvance=26 page=0 chnl=15 +char id=101 x=97 y=205 width=20 height=24 xoffset=2 yoffset=24 xadvance=24 page=0 chnl=15 +char id=102 x=172 y=39 width=16 height=33 xoffset=0 yoffset=15 xadvance=14 page=0 chnl=15 +char id=103 x=45 y=43 width=21 height=33 xoffset=2 yoffset=24 xadvance=26 page=0 chnl=15 +char id=104 x=131 y=41 width=20 height=33 xoffset=3 yoffset=15 xadvance=26 page=0 chnl=15 +char id=105 x=249 y=0 width=6 height=31 xoffset=2 yoffset=17 xadvance=11 page=0 chnl=15 +char id=106 x=143 y=0 width=12 height=40 xoffset=-3 yoffset=17 xadvance=12 page=0 chnl=15 +char id=107 x=152 y=41 width=19 height=33 xoffset=3 yoffset=15 xadvance=23 page=0 chnl=15 +char id=108 x=243 y=0 width=5 height=33 xoffset=3 yoffset=15 xadvance=12 page=0 chnl=15 +char id=109 x=186 y=171 width=32 height=24 xoffset=3 yoffset=24 xadvance=38 page=0 chnl=15 +char id=110 x=118 y=205 width=20 height=24 xoffset=3 yoffset=24 xadvance=26 page=0 chnl=15 +char id=111 x=139 y=204 width=20 height=24 xoffset=2 yoffset=24 xadvance=25 page=0 chnl=15 +char id=112 x=110 y=41 width=20 height=33 xoffset=3 yoffset=24 xadvance=26 page=0 chnl=15 +char id=113 x=23 y=43 width=21 height=33 xoffset=2 yoffset=24 xadvance=26 page=0 chnl=15 +char id=114 x=241 y=193 width=14 height=24 xoffset=3 yoffset=24 xadvance=18 page=0 chnl=15 +char id=115 x=0 y=230 width=18 height=24 xoffset=1 yoffset=24 xadvance=22 page=0 chnl=15 +char id=116 x=136 y=173 width=15 height=30 xoffset=0 yoffset=18 xadvance=16 page=0 chnl=15 +char id=117 x=201 y=196 width=19 height=24 xoffset=3 yoffset=24 xadvance=26 page=0 chnl=15 +char id=118 x=53 y=205 width=21 height=24 xoffset=0 yoffset=24 xadvance=22 page=0 chnl=15 +char id=119 x=219 y=168 width=31 height=24 xoffset=0 yoffset=24 xadvance=32 page=0 chnl=15 +char id=120 x=75 y=205 width=21 height=24 xoffset=0 yoffset=24 xadvance=22 page=0 chnl=15 +char id=121 x=0 y=43 width=22 height=33 xoffset=0 yoffset=24 xadvance=23 page=0 chnl=15 +char id=122 x=221 y=193 width=19 height=24 xoffset=1 yoffset=24 xadvance=21 page=0 chnl=15 +char id=123 x=0 y=0 width=19 height=42 xoffset=1 yoffset=15 xadvance=21 page=0 chnl=15 +char id=124 x=94 y=0 width=5 height=42 xoffset=7 yoffset=15 xadvance=19 page=0 chnl=15 +char id=125 x=20 y=0 width=17 height=42 xoffset=2 yoffset=15 xadvance=21 page=0 chnl=15 +char id=126 x=134 y=230 width=25 height=7 xoffset=3 yoffset=29 xadvance=31 page=0 chnl=15 diff --git a/sample/text-metrics/src/commonMain/resources/clear_sans.png b/sample/text-metrics/src/commonMain/resources/clear_sans.png new file mode 100644 index 0000000..f5f331d Binary files /dev/null and b/sample/text-metrics/src/commonMain/resources/clear_sans.png differ