display lists for screen gui and general performance improvement in monospace font renderer (not rendering spaces, just translate)

This commit is contained in:
Florian Nücke 2013-09-20 23:34:25 +02:00
parent 20028c99ed
commit 16ec4f6acd
3 changed files with 130 additions and 52 deletions

View File

@ -5,19 +5,29 @@ import net.minecraft.client.gui.Gui
import org.lwjgl.opengl.GL11
import net.minecraft.util.ResourceLocation
import net.minecraft.client.renderer.Tessellator
import net.minecraft.client.renderer.GLAllocation
import net.minecraft.client.renderer.texture.TextureManager
/**
* This GUI shows the buffer of a single screen.
*
* The window is sized to fit the contents of the buffer. If the buffer is
* smaller than the overall available space, the window is centered. if it is
* larger, the content is scaled down to fit the available space.
*
* Text and background are cached in display lists, so updateText() must be
* called whenever the text actually changes, otherwise there will be no change
* in the text displayed in the GUI.
*/
class GuiScreen(val tileEntity: TileEntityScreen) extends net.minecraft.client.gui.GuiScreen {
tileEntity.gui = Some(this)
private val borders = new ResourceLocation("opencomputers", "textures/gui/borders.png")
private val margin = 7
private val innerMargin = 1
var (x, y, innerWidth, innerHeight, scale) = (0, 0, 0, 0, 0.0)
/** Must be called when the size of the underlying screen changes */
def setSize(w: Double, h: Double) = {
val totalMargin = (margin + innerMargin) * 2
// Re-compute sizes and positions.
val totalMargin = (GuiScreen.margin + GuiScreen.innerMargin) * 2
val bufferWidth = w * MonospaceFontRenderer.fontWidth
val bufferHeight = h * MonospaceFontRenderer.fontHeight
val bufferScaleX = ((width - totalMargin) / bufferWidth) min 1
@ -27,11 +37,19 @@ class GuiScreen(val tileEntity: TileEntityScreen) extends net.minecraft.client.g
innerHeight = (bufferHeight * scale + 1).ceil.toInt
x = (width - (innerWidth + totalMargin)) / 2
y = (height - (innerHeight + totalMargin)) / 2
// Re-build display lists.
GuiScreen.compileBackground(innerWidth, innerHeight)
GuiScreen.compileText(scale, tileEntity.component.lines)
}
/** Must be called whenever the buffer of the underlying screen changes. */
def updateText() = GuiScreen.compileText(scale, tileEntity.component.lines)
override def initGui() = {
super.initGui()
MonospaceFontRenderer.init(mc.renderEngine)
GuiScreen.init(mc.renderEngine)
val (w, h) = tileEntity.component.resolution
setSize(w, h)
}
@ -45,57 +63,100 @@ class GuiScreen(val tileEntity: TileEntityScreen) extends net.minecraft.client.g
GL11.glPushMatrix()
GL11.glTranslatef(x, y, 0)
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F)
setTexture(borders)
drawRectangle(
0, 0, 7, 7,
0, 0, 7, 7)
drawRectangle(
margin, 0, innerWidth, 7,
7, 0, 8, 7)
drawRectangle(
margin + innerWidth, 0, 7, 7,
8, 0, 15, 7)
drawRectangle(
0, margin, 7, innerHeight,
0, 7, 7, 8)
drawRectangle(
margin, margin, innerWidth, innerHeight,
7, 7, 8, 8)
drawRectangle(
margin + innerWidth, margin, 7, innerHeight,
8, 7, 15, 8)
drawRectangle(
0, margin + innerHeight, 7, 7,
0, 8, 7, 15)
drawRectangle(
margin, margin + innerHeight, innerWidth, 7,
7, 8, 8, 15)
drawRectangle(
margin + innerWidth, margin + innerHeight, 7, 7,
8, 8, 15, 15)
GL11.glTranslatef(margin + innerMargin, margin + innerMargin, 0)
GL11.glScaled(scale, scale, 1)
tileEntity.component.lines.zipWithIndex.foreach {
case (line, i) => MonospaceFontRenderer.drawString(line, 0, i * MonospaceFontRenderer.fontHeight)
}
GuiScreen.draw()
GL11.glPopMatrix()
super.drawScreen(mouseX, mouseY, dt);
}
override def doesGuiPauseGame = false
}
private def setTexture(value: ResourceLocation) =
mc.renderEngine.func_110577_a(value)
/** We cache OpenGL stuff in a singleton to avoid having to re-allocate. */
object GuiScreen {
val margin = 7
private def drawRectangle(x: Double, y: Double, w: Double, h: Double, u1: Int, v1: Int, u2: Int, v2: Int) = {
val t = Tessellator.instance
val innerMargin = 1
private val borders = new ResourceLocation("opencomputers", "textures/gui/borders.png")
private var textureManager: Option[TextureManager] = None
private var displayLists: Option[Int] = None
private var buffer: Option[java.nio.IntBuffer] = None
def init(tm: TextureManager) = if (!textureManager.isDefined) {
textureManager = Some(tm)
displayLists = Some(GLAllocation.generateDisplayLists(2))
buffer = Some(GLAllocation.createDirectIntBuffer(2))
buffer.get.put(displayLists.get)
buffer.get.put(displayLists.get + 1)
}
def draw() = if (textureManager.isDefined) {
buffer.get.rewind()
GL11.glCallLists(buffer.get)
}
private[gui] def compileBackground(innerWidth: Int, innerHeight: Int) =
if (textureManager.isDefined) {
GL11.glNewList(displayLists.get, GL11.GL_COMPILE)
setTexture(borders)
// Top border (left corner, middle bar, right corner).
drawBorder(
0, 0, 7, 7,
0, 0, 7, 7)
drawBorder(
margin, 0, innerWidth, 7,
7, 0, 8, 7)
drawBorder(
margin + innerWidth, 0, 7, 7,
8, 0, 15, 7)
// Middle area (left bar, screen background, right bar).
drawBorder(
0, margin, 7, innerHeight,
0, 7, 7, 8)
drawBorder(
margin, margin, innerWidth, innerHeight,
7, 7, 8, 8)
drawBorder(
margin + innerWidth, margin, 7, innerHeight,
8, 7, 15, 8)
// Bottom border (left corner, middle bar, right corner).
drawBorder(
0, margin + innerHeight, 7, 7,
0, 8, 7, 15)
drawBorder(
margin, margin + innerHeight, innerWidth, 7,
7, 8, 8, 15)
drawBorder(
margin + innerWidth, margin + innerHeight, 7, 7,
8, 8, 15, 15)
GL11.glEndList()
}
private[gui] def compileText(scale: Double, lines: Array[Array[Char]]) =
if (textureManager.isDefined) {
GL11.glNewList(displayLists.get + 1, GL11.GL_COMPILE)
GL11.glTranslatef(margin + innerMargin, margin + innerMargin, 0)
GL11.glScaled(scale, scale, 1)
lines.zipWithIndex.foreach {
case (line, i) => MonospaceFontRenderer.drawString(line, 0, i * MonospaceFontRenderer.fontHeight)
}
GL11.glEndList()
}
private def drawBorder(x: Double, y: Double, w: Double, h: Double, u1: Int, v1: Int, u2: Int, v2: Int) = {
val (u1d, u2d, v1d, v2d) = (u1 / 16.0, u2 / 16.0, v1 / 16.0, v2 / 16.0)
val t = Tessellator.instance
t.startDrawingQuads()
t.addVertexWithUV(x, y + h, 0, u1d, v2d)
t.addVertexWithUV(x + w, y + h, 0, u2d, v2d)
@ -103,4 +164,7 @@ class GuiScreen(val tileEntity: TileEntityScreen) extends net.minecraft.client.g
t.addVertexWithUV(x, y, 0, u1d, v1d)
t.draw()
}
private def setTexture(value: ResourceLocation) =
textureManager.get.func_110577_a(value)
}

View File

@ -41,7 +41,12 @@ object MonospaceFontRenderer {
val vOffset = vStep * 1 / 20
val vSize = vStep * 18 / 20
val t = Tessellator.instance
for (index <- (32 until 0x7F).union(0x9F until 0xFF)) {
// Special case for whitespace: just translate, don't render.
GL11.glNewList(charLists + 32, GL11.GL_COMPILE)
GL11.glTranslatef(charWidth, 0, 0)
GL11.glEndList()
// Now create lists for all printable chars.
for (index <- (33 until 0x7F).union(0x9F until 0xFF)) {
// The font texture does not contain the 0-1F range, nor the 0x7F to
// 0x9F range (control chars as per Character.isISOControl).
val textureIndex =

View File

@ -46,19 +46,28 @@ class TileEntityScreen extends TileEntityRotatable with IScreenEnvironment {
}
def onScreenSet(col: Int, row: Int, s: String) =
if (!worldObj.isRemote) {
if (worldObj.isRemote) {
gui.foreach(_.updateText())
}
else {
markAsChanged()
ServerPacketSender.sendScreenSet(this, col, row, s)
}
def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) =
if (!worldObj.isRemote) {
if (worldObj.isRemote) {
gui.foreach(_.updateText())
}
else {
markAsChanged()
ServerPacketSender.sendScreenFill(this, col, row, w, h, c)
}
def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) =
if (!worldObj.isRemote) {
if (worldObj.isRemote) {
gui.foreach(_.updateText())
}
else {
markAsChanged()
ServerPacketSender.sendScreenCopy(this, col, row, w, h, tx, ty)
}