wtf with the premultiplying i didn't even told it to do so

This commit is contained in:
minjaesong
2021-10-21 12:19:08 +09:00
parent a7bb33c3a0
commit b40e4fcc26
2 changed files with 119 additions and 20 deletions

View File

@@ -1,11 +1,15 @@
import com.badlogic.gdx.* import com.badlogic.gdx.*
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration
import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.graphics.* import com.badlogic.gdx.graphics.*
import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.glutils.FrameBuffer import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.badlogic.gdx.utils.ScreenUtils import com.badlogic.gdx.utils.ScreenUtils
import com.badlogic.gdx.utils.StreamUtils
import net.torvald.terrarumsansbitmap.gdx.GameFontBase import net.torvald.terrarumsansbitmap.gdx.GameFontBase
import java.io.IOException
import java.io.OutputStream
/** /**
* Created by minjaesong on 2018-07-26. * Created by minjaesong on 2018-07-26.
@@ -28,7 +32,7 @@ class FontTestGDX : Game() {
private val outimageName = if (testing) "testing.PNG" else "demo.PNG" private val outimageName = if (testing) "testing.PNG" else "demo.PNG"
override fun create() { 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 inTextFile = Gdx.files.internal("./$demotextName")
val reader = inTextFile.reader("UTF-8") val reader = inTextFile.reader("UTF-8")
@@ -72,16 +76,19 @@ class FontTestGDX : Game() {
if (tex == null) { if (tex == null) {
frameBuffer.begin() 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.glClear(GL20.GL_COLOR_BUFFER_BIT)
Gdx.gl.glEnable(GL20.GL_TEXTURE_2D) Gdx.gl.glEnable(GL20.GL_TEXTURE_2D)
Gdx.gl.glEnable(GL20.GL_BLEND) 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.projectionMatrix = camera.combined
batch.begin() batch.begin()
batch.color = Color(0xeeeeeeff.toInt()) batch.color = Color(-1)
inputText.forEachIndexed { index, s -> inputText.forEachIndexed { index, s ->
font.draw(batch, s, 10f, TEXH - 30f - index * font.lineHeight) 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) val pixmap = ScreenUtils.getFrameBufferPixmap(0, 0, frameBuffer.width, frameBuffer.height)
PixmapIO.writePNG(Gdx.files.local(outimageName), pixmap) PixmapIO.writePNG(Gdx.files.local(outimageName), pixmap)
// writeTGA(Gdx.files.local(outimageName), pixmap, false)
pixmap.dispose() pixmap.dispose()
screenshotExported = true screenshotExported = true
@@ -107,6 +115,14 @@ class FontTestGDX : Game() {
tex = frameBuffer.colorBufferTexture 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.begin()
batch.color = Color.WHITE batch.color = Color.WHITE
batch.draw(tex, 0f, (TEXH.toFloat()/HEIGHT)*TEXH - scrollOffsetY, TEXW.toFloat(), -(TEXH.toFloat() / HEIGHT) * TEXH.toFloat()) 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 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 lateinit var appConfig: Lwjgl3ApplicationConfiguration

View File

@@ -364,6 +364,8 @@ class GameFontBase(
private val pixmapOffsetY = 10 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? { override fun draw(batch: Batch, charSeq: CharSequence, x: Float, y: Float): GlyphLayout? {
if (debug) if (debug)
println("[TerrarumSansBitmap] max age: $textCacheCap") println("[TerrarumSansBitmap] max age: $textCacheCap")
@@ -1155,27 +1157,23 @@ class GameFontBase(
) )
jobQueue.forEach { jobQueue.forEach {
for (y in 0 until pixmap.height) { for (y in (if (invertShadow) 1 else 0) until (if (invertShadow) pixmap.height else pixmap.height - 1)) {
for (x in 0 until pixmap.width) { 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 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 // in the current version, all colour-coded glyphs are guaranteed
// to be opaque // to be opaque
if (pixel and 0xFF == 0xFF) { if (pixel and 0xFF == 0xFF && newPixel and 0xFF == 0) {
val newPixel = pixmap.getPixel(x + it.first, y + it.second) pixmap.drawPixel(x + it.first, y + it.second, newColor.toRGBA8888())
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())
}
} }
} }
} }