[enhancement] Use mipmaps for KamiMoji

closes #1825
This commit is contained in:
Xiaro 2021-01-08 19:21:43 -05:00
parent 9c0c237650
commit 3f2e0c486d
No known key found for this signature in database
GPG Key ID: 996D265D6E155377
5 changed files with 86 additions and 60 deletions

View File

@ -12,10 +12,11 @@ import kotlinx.coroutines.launch
import me.zeroeightsix.kami.KamiMod
import me.zeroeightsix.kami.manager.Manager
import me.zeroeightsix.kami.util.Wrapper
import me.zeroeightsix.kami.util.graphics.TextureUtils
import me.zeroeightsix.kami.util.threads.mainScope
import me.zeroeightsix.kami.util.threads.onMainThreadW
import net.minecraft.client.renderer.texture.DynamicTexture
import net.minecraft.util.ResourceLocation
import org.lwjgl.opengl.GL11.GL_RGBA
import java.io.File
import java.io.FileInputStream
import java.io.IOException
@ -125,7 +126,7 @@ object KamiMojiManager : Manager {
val image = ImageIO.read(file)
onMainThreadW(5000L) {
val dynamicTexture = DynamicTexture(image)
val dynamicTexture = TextureUtils.genTextureWithMipmaps(image, 3, GL_RGBA)
val resourceLocation = Wrapper.minecraft.textureManager.getDynamicTextureLocation(name, dynamicTexture)
emojiMap[name] = resourceLocation
}

View File

@ -22,12 +22,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
public abstract class MixinFontRenderer {
@Shadow public int FONT_HEIGHT;
@Shadow public float alpha;
@Shadow public float posX;
@Shadow public float posY;
@Shadow public float red;
@Shadow public float green;
@Shadow public float blue;
@Shadow private float alpha;
@Shadow protected float posX;
@Shadow protected float posY;
@Shadow private float red;
@Shadow private float green;
@Shadow private float blue;
@Shadow
protected abstract void renderStringAtPos(String text, boolean shadow);
@ -38,7 +38,7 @@ public abstract class MixinFontRenderer {
@Redirect(method = "renderString", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/FontRenderer;renderStringAtPos(Ljava/lang/String;Z)V"))
private void renderStringAtPos(FontRenderer fontRenderer, String text, boolean shadow) {
if (KamiMoji.INSTANCE.isEnabled() && text.contains(":")) {
text = KamiMoji.getText(text, FONT_HEIGHT, shadow, posX, posY, alpha);
text = KamiMoji.renderText(text, FONT_HEIGHT, shadow, posX, posY, alpha);
}
GlStateManager.color(red, blue, green, alpha); // Big Mojang meme :monkey:

View File

@ -1,7 +1,6 @@
package me.zeroeightsix.kami.module.modules.chat
import me.zeroeightsix.kami.manager.managers.KamiMojiManager.getEmoji
import me.zeroeightsix.kami.manager.managers.KamiMojiManager.isEmoji
import me.zeroeightsix.kami.manager.managers.KamiMojiManager
import me.zeroeightsix.kami.module.Module
import me.zeroeightsix.kami.util.graphics.GlStateUtils.resetTexParam
import net.minecraft.client.renderer.GlStateManager
@ -9,7 +8,9 @@ import net.minecraft.client.renderer.Tessellator
import net.minecraft.client.renderer.vertex.DefaultVertexFormats
import net.minecraft.util.ResourceLocation
import org.kamiblue.commons.extension.ceilToInt
import org.lwjgl.opengl.GL11
import org.lwjgl.opengl.GL11.*
import org.lwjgl.opengl.GL12.GL_CLAMP_TO_EDGE
import org.lwjgl.opengl.GL14.GL_TEXTURE_LOD_BIAS
object KamiMoji : Module(
name = "KamiMoji",
@ -17,18 +18,18 @@ object KamiMoji : Module(
category = Category.CHAT
) {
@JvmStatic
fun getText(inputText: String, fontHeight: Int, shadow: Boolean, posX: Float, posY: Float, alpha: Float): String {
fun renderText(inputText: String, fontHeight: Int, shadow: Boolean, posX: Float, posY: Float, alpha: Float): String {
var text = inputText
for (possible in text.split(":").toTypedArray()) {
if (isEmoji(possible)) {
if (KamiMojiManager.isEmoji(possible)) {
val emojiText = ":$possible:"
if (!shadow) {
val index = text.indexOf(emojiText)
if (index == -1) continue
val x = mc.fontRenderer.getStringWidth(text.substring(0, index)) + fontHeight / 4
drawEmoji(getEmoji(possible), (posX + x).toDouble(), posY.toDouble(), fontHeight.toFloat(), alpha)
drawEmoji(KamiMojiManager.getEmoji(possible), (posX + x).toDouble(), posY.toDouble(), fontHeight.toFloat(), alpha)
}
text = text.replaceFirst(emojiText, getReplacement(fontHeight))
@ -44,7 +45,7 @@ object KamiMoji : Module(
var reducedWidth = inputWidth
for (possible in text.split(":")) {
if (isEmoji(possible)) {
if (KamiMojiManager.isEmoji(possible)) {
val emojiText = ":$possible:"
val emojiTextWidth = emojiText.sumBy { mc.fontRenderer.getCharWidth(it) }
reducedWidth -= emojiTextWidth
@ -68,8 +69,15 @@ object KamiMoji : Module(
val bufBuilder = tessellator.buffer
mc.textureManager.bindTexture(emojiTexture)
GlStateManager.color(1f, 1f, 1f, alpha)
GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR)
GlStateManager.color(1.0f, 1.0f, 1.0f, alpha)
GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.0f)
bufBuilder.begin(7, DefaultVertexFormats.POSITION_TEX)
bufBuilder.pos(x, y + size, 0.0).tex(0.0, 1.0).endVertex()
@ -79,5 +87,6 @@ object KamiMoji : Module(
tessellator.draw()
resetTexParam()
GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
}
}

View File

@ -0,0 +1,55 @@
package me.zeroeightsix.kami.util.graphics
import net.minecraft.client.renderer.GlStateManager
import net.minecraft.client.renderer.texture.DynamicTexture
import net.minecraft.client.renderer.texture.TextureUtil
import org.lwjgl.opengl.GL11.*
import org.lwjgl.opengl.GL12.*
import org.lwjgl.opengl.GL14.*
import java.awt.image.BufferedImage
import java.nio.ByteBuffer
object TextureUtils {
fun genTextureWithMipmaps(bufferedImage: BufferedImage, level: Int, textureFormat: Int) : DynamicTexture {
val dynamicTexture = DynamicTexture(bufferedImage)
val textureId = dynamicTexture.glTextureId
val depth = glGetBoolean(GL_DEPTH_TEST)
val blend = glGetBoolean(GL_BLEND)
GlStateUtils.depth(false)
GlStateUtils.blend(true)
GlStateManager.tryBlendFuncSeparate(GL_ONE, GL_ZERO, GL_SRC_ALPHA, GL_ZERO)
// Tells Gl that our texture isn't a repeating texture (edges are not connecting to each others)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
// Setup texture filters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST)
// Setup mipmap parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, level)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.0f)
GlStateManager.bindTexture(textureId)
for (mipmapLevel in 0..level) {
// GL_ALPHA means that the texture is a grayscale texture (black & white and alpha only)
glTexImage2D(GL_TEXTURE_2D, mipmapLevel, textureFormat, bufferedImage.width shr mipmapLevel, bufferedImage.height shr mipmapLevel, 0, textureFormat, GL_UNSIGNED_BYTE, null as ByteBuffer?)
}
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1)
TextureUtil.uploadTextureImageSub(textureId, bufferedImage, 0, 0, true, true)
GlStateUtils.resetTexParam()
GlStateUtils.depth(depth)
GlStateUtils.blend(blend)
GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
return dynamicTexture
}
}

View File

@ -1,21 +1,15 @@
package me.zeroeightsix.kami.util.graphics.font
import me.zeroeightsix.kami.KamiMod
import me.zeroeightsix.kami.util.Wrapper
import me.zeroeightsix.kami.util.graphics.GlStateUtils
import net.minecraft.client.renderer.GlStateManager
import me.zeroeightsix.kami.util.graphics.TextureUtils
import net.minecraft.client.renderer.texture.DynamicTexture
import net.minecraft.client.renderer.texture.TextureUtil
import org.kamiblue.commons.utils.MathUtils
import org.lwjgl.opengl.GL11.*
import org.lwjgl.opengl.GL12.*
import org.lwjgl.opengl.GL14.*
import org.lwjgl.opengl.GL11.GL_ALPHA
import java.awt.Color
import java.awt.Font
import java.awt.Graphics2D
import java.awt.RenderingHints
import java.awt.image.BufferedImage
import java.nio.ByteBuffer
import kotlin.math.max
import kotlin.math.min
@ -178,40 +172,7 @@ class FontGlyphs(val style: Style, private val font: Font, private val fallbackF
private fun createTexture(bufferedImage: BufferedImage): DynamicTexture? {
return try {
val dynamicTexture = DynamicTexture(bufferedImage)
dynamicTexture.loadTexture(Wrapper.minecraft.resourceManager)
val textureId = dynamicTexture.glTextureId
// Tells Gl that our texture isn't a repeating texture (edges are not connecting to each others)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
// Setup texture filters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST)
// Setup mipmap parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0f)
GlStateManager.bindTexture(textureId)
// We only need 4 levels of mipmaps for 64 sized font
// 0: 64 x 64, 1: 32 x 32, 2: 16 x 16, 3: 8 x 8, 4: 4 x 4
for (mipmapLevel in 0..4) {
// GL_ALPHA means that the texture is a grayscale texture (black & white and alpha only)
glTexImage2D(GL_TEXTURE_2D, mipmapLevel, GL_ALPHA, bufferedImage.width shr mipmapLevel, bufferedImage.height shr mipmapLevel, 0, GL_ALPHA, GL_UNSIGNED_BYTE, null as ByteBuffer?)
}
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1)
TextureUtil.uploadTextureImageSub(textureId, bufferedImage, 0, 0, true, true)
GlStateUtils.resetTexParam()
dynamicTexture
TextureUtils.genTextureWithMipmaps(bufferedImage, 4, GL_ALPHA)
} catch (e: Exception) {
KamiMod.LOG.error("Failed to create font texture.")
e.printStackTrace()