diff --git a/FontTestGDX/src/FontTestGDX.kt b/FontTestGDX/src/FontTestGDX.kt index 3b0d6e8..f709616 100755 --- a/FontTestGDX/src/FontTestGDX.kt +++ b/FontTestGDX/src/FontTestGDX.kt @@ -1,11 +1,15 @@ import com.badlogic.gdx.* import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration +import com.badlogic.gdx.files.FileHandle import com.badlogic.gdx.graphics.* import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.glutils.FrameBuffer import com.badlogic.gdx.utils.ScreenUtils +import com.badlogic.gdx.utils.StreamUtils import net.torvald.terrarumsansbitmap.gdx.GameFontBase +import java.io.IOException +import java.io.OutputStream /** * Created by minjaesong on 2018-07-26. @@ -28,7 +32,7 @@ class FontTestGDX : Game() { private val outimageName = if (testing) "testing.PNG" else "demo.PNG" override fun create() { - font = GameFontBase("./assets", flipY = false, errorOnUnknownChar = false) // must test for two flipY cases + font = GameFontBase("./assets", flipY = false, errorOnUnknownChar = false, shadowAlpha = 0.796f) // must test for two flipY cases val inTextFile = Gdx.files.internal("./$demotextName") val reader = inTextFile.reader("UTF-8") @@ -72,16 +76,19 @@ class FontTestGDX : Game() { if (tex == null) { frameBuffer.begin() - Gdx.gl.glClearColor(.141f, .141f, .141f, 1f) + Gdx.gl.glClearColor(0f,0f,0f,0f) Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) Gdx.gl.glEnable(GL20.GL_TEXTURE_2D) Gdx.gl.glEnable(GL20.GL_BLEND) - Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA) + Gdx.gl.glBlendFuncSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE) +// Gdx.gl.glBlendFuncSeparate(GL20.GL_SRC_COLOR, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_SRC_ALPHA, GL20.GL_ONE) + +// Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA) batch.projectionMatrix = camera.combined batch.begin() - batch.color = Color(0xeeeeeeff.toInt()) + batch.color = Color(-1) inputText.forEachIndexed { index, s -> font.draw(batch, s, 10f, TEXH - 30f - index * font.lineHeight) } @@ -94,6 +101,7 @@ class FontTestGDX : Game() { val pixmap = ScreenUtils.getFrameBufferPixmap(0, 0, frameBuffer.width, frameBuffer.height) PixmapIO.writePNG(Gdx.files.local(outimageName), pixmap) +// writeTGA(Gdx.files.local(outimageName), pixmap, false) pixmap.dispose() screenshotExported = true @@ -107,6 +115,14 @@ class FontTestGDX : Game() { tex = frameBuffer.colorBufferTexture } + + Gdx.gl.glClearColor(.141f, .141f, .141f, 1f) + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) + Gdx.gl.glEnable(GL20.GL_TEXTURE_2D) + Gdx.gl.glEnable(GL20.GL_BLEND) + Gdx.gl.glBlendFuncSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE) + + batch.begin() batch.color = Color.WHITE batch.draw(tex, 0f, (TEXH.toFloat()/HEIGHT)*TEXH - scrollOffsetY, TEXW.toFloat(), -(TEXH.toFloat() / HEIGHT) * TEXH.toFloat()) @@ -155,6 +171,91 @@ class FontTestGDX : Game() { return true } } + + + @Throws(IOException::class) + private fun writeTGA(file: FileHandle, pixmap: Pixmap, flipY: Boolean) { + val output = file.write(false) + try { + _writeTGA(output, pixmap, true, flipY) + } finally { + StreamUtils.closeQuietly(output) + } + } + + @Throws(IOException::class) + private fun _writeTGA(out: OutputStream, pixmap: Pixmap, verbatim: Boolean, flipY: Boolean) { + val width: ByteArray = toShortLittle(pixmap.width) + val height: ByteArray = toShortLittle(pixmap.height) + val zero: ByteArray = toShortLittle(0) + out.write(0) // ID field: empty + out.write(0) // no colour map, but should be ignored anyway as it being unmapped RGB + out.write(2) // 2 means unmapped RGB + out.write(byteArrayOf(0, 0, 0, 0, 0)) // color map spec: empty + out.write(zero) // x origin: 0 + out.write(zero) // y origin: 0 + out.write(width) // width + out.write(height) // height + out.write(32) // image pixel size: we're writing 32-bit image (8bpp BGRA) + out.write(8) // image descriptor: dunno, Photoshop writes 8 in there + + // write actual image data + // since we're following Photoshop's conventional header, we also follows Photoshop's + // TGA saving scheme, that is: + // 1. BGRA order + // 2. Y-Flipped but not X-Flipped + if (!flipY) { + for (y in pixmap.height - 1 downTo 0) { + for (x in 0 until pixmap.width) { + writeTga(x, y, verbatim, pixmap, out) + } + } + } else { + for (y in 0 until pixmap.height) { + for (x in 0 until pixmap.width) { + writeTga(x, y, verbatim, pixmap, out) + } + } + } + + + // write footer + // 00 00 00 00 00 00 00 00 TRUEVISION-XFILE 2E 00 + out.write(byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0)) + if (verbatim) out.write("TRUEVISION-XFILE".toByteArray()) else out.write("TerrarumHappyTGA".toByteArray()) + out.write(byteArrayOf(0x2E, 0)) + out.flush() + out.close() + } + + private val zeroalpha = byteArrayOf(0, 0, 0, 0) + @Throws(IOException::class) + private fun writeTga(x: Int, y: Int, verbatim: Boolean, pixmap: Pixmap, out: OutputStream) { + val color = pixmap.getPixel(x, y) + + // if alpha == 0, write special value instead + if (verbatim && color and 0xFF == 0) { + out.write(zeroalpha) + } else { + out.write(RGBAtoBGRA(color)) + } + } + + private fun toShortLittle(i: Int): ByteArray { + return byteArrayOf( + (i and 0xFF).toByte(), + (i ushr 8 and 0xFF).toByte() + ) + } + + private fun RGBAtoBGRA(rgba: Int): ByteArray { + return byteArrayOf( + (rgba ushr 8 and 0xFF).toByte(), + (rgba ushr 16 and 0xFF).toByte(), + (rgba ushr 24 and 0xFF).toByte(), + (rgba and 0xFF).toByte() + ) + } } lateinit var appConfig: Lwjgl3ApplicationConfiguration diff --git a/src/net/torvald/terrarumsansbitmap/gdx/GameFontBase.kt b/src/net/torvald/terrarumsansbitmap/gdx/GameFontBase.kt index a4e080e..bd4f640 100755 --- a/src/net/torvald/terrarumsansbitmap/gdx/GameFontBase.kt +++ b/src/net/torvald/terrarumsansbitmap/gdx/GameFontBase.kt @@ -364,6 +364,8 @@ class GameFontBase( private val pixmapOffsetY = 10 + fun draw(batch: Batch, charSeq: CharSequence, x: Int, y: Int) = draw(batch, charSeq, x.toFloat(), y.toFloat()) + override fun draw(batch: Batch, charSeq: CharSequence, x: Float, y: Float): GlyphLayout? { if (debug) println("[TerrarumSansBitmap] max age: $textCacheCap") @@ -1155,27 +1157,23 @@ class GameFontBase( ) jobQueue.forEach { - for (y in 0 until pixmap.height) { - for (x in 0 until pixmap.width) { + for (y in (if (invertShadow) 1 else 0) until (if (invertShadow) pixmap.height else pixmap.height - 1)) { + for (x in (if (invertShadow) 1 else 0) until (if (invertShadow) pixmap.width else pixmap.width - 1)) { val pixel = pixmap.getPixel(x, y) // RGBA8888 + val newPixel = pixmap.getPixel(x + it.first, y + it.second) + val newColor = Color(pixel) + newColor.a *= shadowAlpha + /*if (shadowAlphaPremultiply) { + newColor.r *= shadowAlpha + newColor.g *= shadowAlpha + newColor.b *= shadowAlpha + }*/ // in the current version, all colour-coded glyphs are guaranteed // to be opaque - if (pixel and 0xFF == 0xFF) { - val newPixel = pixmap.getPixel(x + it.first, y + it.second) - val newColour = Color(); Color.rgba8888ToColor(newColour, pixel) - newColour.a = shadowAlpha - - if (shadowAlphaPremultiply) { - newColour.r *= shadowAlpha - newColour.g *= shadowAlpha - newColour.b *= shadowAlpha - } - - if (newPixel and 0xFF == 0) { - pixmap.drawPixel(x + it.first, y + it.second, newColour.toRGBA8888()) - } + if (pixel and 0xFF == 0xFF && newPixel and 0xFF == 0) { + pixmap.drawPixel(x + it.first, y + it.second, newColor.toRGBA8888()) } } }