From 83377b4ae023733e504db9f00f884eebd941a8f0 Mon Sep 17 00:00:00 2001 From: evg-zhabotinsky Date: Fri, 6 Jun 2014 10:04:15 +0400 Subject: [PATCH 1/6] Rewrite hologram renderer using VBOs for better performance (issue #259) --- .../li/cil/oc/client/PacketHandler.scala | 1 - .../tileentity/HologramRenderer.scala | 287 ++++++++++++------ .../cil/oc/common/tileentity/Hologram.scala | 3 + 3 files changed, 189 insertions(+), 102 deletions(-) diff --git a/src/main/scala/li/cil/oc/client/PacketHandler.scala b/src/main/scala/li/cil/oc/client/PacketHandler.scala index 109f6d1da..1ec0604bf 100644 --- a/src/main/scala/li/cil/oc/client/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/client/PacketHandler.scala @@ -153,7 +153,6 @@ class PacketHandler extends CommonPacketHandler { p.readTileEntity[Hologram]() match { case Some(t) => t.scale = p.readDouble() - t.dirty = true case _ => // Invalid packet. } diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala index 6c85741cc..6a16e61f7 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala @@ -8,16 +8,15 @@ import li.cil.oc.client.Textures import li.cil.oc.common.tileentity.Hologram import li.cil.oc.util.RenderState import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer -import net.minecraft.client.renderer.{GLAllocation, Tessellator} import net.minecraft.tileentity.TileEntity -import org.lwjgl.opengl.GL11 +import org.lwjgl.opengl.{GL15, GL11} import scala.util.Random -import org.lwjgl.input.Keyboard +import org.lwjgl.BufferUtils object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] with RemovalListener[TileEntity, Int] with ITickHandler { val random = new Random() - /** We cache the display lists for the projectors we render for performance. */ + /** We cache the VBOs for the projectors we render for performance. */ val cache = com.google.common.cache.CacheBuilder.newBuilder(). expireAfterAccess(2, TimeUnit.SECONDS). removalListener(this). @@ -46,135 +45,221 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit GL11.glTranslated(random.nextGaussian() * 0.01, random.nextGaussian() * 0.01, random.nextGaussian() * 0.01) } + // After the below scaling, hologram is drawn inside a [0..48]x[0..32]x[0..48] box + GL11.glScaled(hologram.scale / 16f, hologram.scale / 16f, hologram.scale / 16f) + // We do two passes here to avoid weird transparency effects: in the first // pass we find the front-most fragment, in the second we actually draw it. // TODO proper transparency shader? depth peeling e.g. + // evg-zhabotinsky: I'd rather not do it. Anyway it won't work for multiple holograms. + // Also I commented out the first pass to see what it will look like and I prefer it the way it is now. GL11.glColorMask(false, false, false, false) GL11.glDepthMask(true) - val list = cache.get(hologram, this) - compileOrDraw(list) + val privateBuf = cache.get(hologram, this) + compileOrDraw(privateBuf) GL11.glColorMask(true, true, true, true) GL11.glDepthFunc(GL11.GL_EQUAL) - compileOrDraw(list) + compileOrDraw(privateBuf) GL11.glPopMatrix() GL11.glPopAttrib() } - def compileOrDraw(list: Int) = if (hologram.dirty) { - val doCompile = !RenderState.compilingDisplayList - if (doCompile) { - hologram.dirty = false - GL11.glNewList(list, GL11.GL_COMPILE_AND_EXECUTE) - } + val compileOrDraw = { + // WARNING works only if all the holograms have the same dimensions (in voxels) + var commonBuffer = 0 // Common for all holograms (a-la static variable) + (privateBuf: Int) => { + // Save current state (don't forget to restore) + GL11.glPushClientAttrib(GL11.GL_ALL_CLIENT_ATTRIB_BITS) + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) - def value(hx: Int, hy: Int, hz: Int) = if (hx >= 0 && hy >= 0 && hz >= 0 && hx < hologram.width && hy < hologram.height && hz < hologram.width) hologram.getColor(hx, hy, hz) else 0 + if (commonBuffer == 0) { // First run only + commonBuffer = GL15.glGenBuffers() + var tmpBuf = BufferUtils.createFloatBuffer(hologram.width * hologram.width * hologram.height * 24 * (3 + 2)) + def newVert = (x: Int, y: Int, z: Int, u: Int, v: Int) => { // Dirty hack to avoid rewriting :) + tmpBuf.put(u) + tmpBuf.put(v) + tmpBuf.put(x) + tmpBuf.put(y) + tmpBuf.put(z) + } + for (x <- 0 until hologram.width) { + for (z <- 0 until hologram.width) { + for (y <- 0 until hologram.height) { + /* + 0---1 + | N | + 0---3---2---1---0 + | W | U | E | D | + 5---6---7---4---5 + | S | + 5---4 + */ - def isSolid(hx: Int, hy: Int, hz: Int) = value(hx, hy, hz) != 0 + // South + newVert(x + 1, y + 1, z + 1, 0, 0) // 5 + newVert(x + 0, y + 1, z + 1, 1, 0) // 4 + newVert(x + 0, y + 0, z + 1, 1, 1) // 7 + newVert(x + 1, y + 0, z + 1, 0, 1) // 6 + // North + newVert(x + 1, y + 0, z + 0, 0, 0) // 3 + newVert(x + 0, y + 0, z + 0, 1, 0) // 2 + newVert(x + 0, y + 1, z + 0, 1, 1) // 1 + newVert(x + 1, y + 1, z + 0, 0, 1) // 0 - bindTexture(Textures.blockHologram) - val t = Tessellator.instance - t.startDrawingQuads() + // East + newVert(x + 1, y + 1, z + 1, 1, 0) // 5 + newVert(x + 1, y + 0, z + 1, 1, 1) // 6 + newVert(x + 1, y + 0, z + 0, 0, 1) // 3 + newVert(x + 1, y + 1, z + 0, 0, 0) // 0 + // West + newVert(x + 0, y + 0, z + 1, 1, 0) // 7 + newVert(x + 0, y + 1, z + 1, 1, 1) // 4 + newVert(x + 0, y + 1, z + 0, 0, 1) // 1 + newVert(x + 0, y + 0, z + 0, 0, 0) // 2 - // TODO merge quads for better rendering performance - val s = 1f / 16f * hologram.scale - for (hx <- 0 until hologram.width) { - val wx = hx * s - for (hz <- 0 until hologram.width) { - val wz = hz * s - for (hy <- 0 until hologram.height) { - val wy = hy * s - - if (isSolid(hx, hy, hz)) { - t.setColorRGBA_I(hologram.colors(value(hx, hy, hz) - 1), 192) - - /* - 0---1 - | N | - 0---3---2---1---0 - | W | U | E | D | - 5---6---7---4---5 - | S | - 5---4 - */ - - // South - if (!isSolid(hx, hy, hz + 1)) { - t.setNormal(0, 0, 1) - t.addVertexWithUV(wx + s, wy + s, wz + s, 0, 0) // 5 - t.addVertexWithUV(wx + 0, wy + s, wz + s, 1, 0) // 4 - t.addVertexWithUV(wx + 0, wy + 0, wz + s, 1, 1) // 7 - t.addVertexWithUV(wx + s, wy + 0, wz + s, 0, 1) // 6 - } - // North - if (!isSolid(hx, hy, hz - 1)) { - t.setNormal(0, 0, -1) - t.addVertexWithUV(wx + s, wy + 0, wz + 0, 0, 0) // 3 - t.addVertexWithUV(wx + 0, wy + 0, wz + 0, 1, 0) // 2 - t.addVertexWithUV(wx + 0, wy + s, wz + 0, 1, 1) // 1 - t.addVertexWithUV(wx + s, wy + s, wz + 0, 0, 1) // 0 - } - - // East - if (!isSolid(hx + 1, hy, hz)) { - t.setNormal(1, 0, 0) - t.addVertexWithUV(wx + s, wy + s, wz + s, 1, 0) // 5 - t.addVertexWithUV(wx + s, wy + 0, wz + s, 1, 1) // 6 - t.addVertexWithUV(wx + s, wy + 0, wz + 0, 0, 1) // 3 - t.addVertexWithUV(wx + s, wy + s, wz + 0, 0, 0) // 0 - } - // West - if (!isSolid(hx - 1, hy, hz)) { - t.setNormal(-1, 0, 0) - t.addVertexWithUV(wx + 0, wy + 0, wz + s, 1, 0) // 7 - t.addVertexWithUV(wx + 0, wy + s, wz + s, 1, 1) // 4 - t.addVertexWithUV(wx + 0, wy + s, wz + 0, 0, 1) // 1 - t.addVertexWithUV(wx + 0, wy + 0, wz + 0, 0, 0) // 2 - } - - // Up - if (!isSolid(hx, hy + 1, hz)) { - t.setNormal(0, 1, 0) - t.addVertexWithUV(wx + s, wy + s, wz + 0, 0, 0) // 0 - t.addVertexWithUV(wx + 0, wy + s, wz + 0, 1, 0) // 1 - t.addVertexWithUV(wx + 0, wy + s, wz + s, 1, 1) // 4 - t.addVertexWithUV(wx + s, wy + s, wz + s, 0, 1) // 5 - } - // Down - if (!isSolid(hx, hy - 1, hz)) { - t.setNormal(0, -1, 0) - t.addVertexWithUV(wx + s, wy + 0, wz + s, 0, 0) // 6 - t.addVertexWithUV(wx + 0, wy + 0, wz + s, 1, 0) // 7 - t.addVertexWithUV(wx + 0, wy + 0, wz + 0, 1, 1) // 2 - t.addVertexWithUV(wx + s, wy + 0, wz + 0, 0, 1) // 3 + // Up + newVert(x + 1, y + 1, z + 0, 0, 0) // 0 + newVert(x + 0, y + 1, z + 0, 1, 0) // 1 + newVert(x + 0, y + 1, z + 1, 1, 1) // 4 + newVert(x + 1, y + 1, z + 1, 0, 1) // 5 + // Down + newVert(x + 1, y + 0, z + 1, 0, 0) // 6 + newVert(x + 0, y + 0, z + 1, 1, 0) // 7 + newVert(x + 0, y + 0, z + 0, 1, 1) // 2 + newVert(x + 1, y + 0, z + 0, 0, 1) // 3 } } } + tmpBuf.rewind() // Important! + GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, commonBuffer) + GL15.glBufferData(GL15.GL_ARRAY_BUFFER, tmpBuf, GL15.GL_STATIC_DRAW) } + + if (hologram.dirty) { // Refresh hologram + def value(hx: Int, hy: Int, hz: Int) = if (hx >= 0 && hy >= 0 && hz >= 0 && hx < hologram.width && hy < hologram.height && hz < hologram.width) hologram.getColor(hx, hy, hz) else 0 + + def isSolid(hx: Int, hy: Int, hz: Int) = value(hx, hy, hz) != 0 + + var tmpBuf = BufferUtils.createIntBuffer(hologram.width * hologram.width * hologram.height * 24 * 2) + // First copy color information + for (x <- 0 until hologram.width) { + for (z <- 0 until hologram.width) { + for (y <- 0 until hologram.height) { + val v: Int = if (isSolid(x, y, z)) (192 << 24) + hologram.colors(value(x, y, z) - 1) else 0 + for (t <- 0 until 24) { + tmpBuf.put(v) + } + } + } + } + // Then identify which quads to render and prepare data for glDrawElements + hologram.visibleQuads = 0; + var c = 0 + for (hx <- 0 until hologram.width) { + for (hz <- 0 until hologram.width) { + for (hy <- 0 until hologram.height) { + if (isSolid(hx, hy, hz)) { + // South + if (!isSolid(hx, hy, hz + 1)) { + tmpBuf.put(c) + tmpBuf.put(c + 1) + tmpBuf.put(c + 2) + tmpBuf.put(c + 3) + hologram.visibleQuads += 1 + } + c += 4 + // North + if (!isSolid(hx, hy, hz - 1)) { + tmpBuf.put(c) + tmpBuf.put(c + 1) + tmpBuf.put(c + 2) + tmpBuf.put(c + 3) + hologram.visibleQuads += 1 + } + c += 4 + + // East + if (!isSolid(hx + 1, hy, hz)) { + tmpBuf.put(c) + tmpBuf.put(c + 1) + tmpBuf.put(c + 2) + tmpBuf.put(c + 3) + hologram.visibleQuads += 1 + } + c += 4 + // West + if (!isSolid(hx - 1, hy, hz)) { + tmpBuf.put(c) + tmpBuf.put(c + 1) + tmpBuf.put(c + 2) + tmpBuf.put(c + 3) + hologram.visibleQuads += 1 + } + c += 4 + + // Up + if (!isSolid(hx, hy + 1, hz)) { + tmpBuf.put(c) + tmpBuf.put(c + 1) + tmpBuf.put(c + 2) + tmpBuf.put(c + 3) + hologram.visibleQuads += 1 + } + c += 4 + // Down + if (!isSolid(hx, hy - 1, hz)) { + tmpBuf.put(c) + tmpBuf.put(c + 1) + tmpBuf.put(c + 2) + tmpBuf.put(c + 3) + hologram.visibleQuads += 1 + } + c += 4 + } else c += 24 + } + } + } + tmpBuf.rewind() // Important! + GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, privateBuf) + GL15.glBufferData(GL15.GL_ARRAY_BUFFER, tmpBuf, GL15.GL_STATIC_DRAW) + + hologram.dirty = false + } + + GL11.glDisable(GL11.GL_LIGHTING) // Hologram that reflects light... It would be awesome! But... + GL11.glEnable(GL11.GL_CULL_FACE) + GL11.glCullFace(GL11.GL_BACK) // Because fragment processing started to slow things down + bindTexture(Textures.blockHologram) + GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, commonBuffer) + GL11.glEnable(GL11.GL_VERTEX_ARRAY) + GL11.glEnable(GL11.GL_TEXTURE_COORD_ARRAY) + GL11.glInterleavedArrays(GL11.GL_T2F_V3F, 0, 0) + GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, privateBuf) + GL11.glEnable(GL11.GL_COLOR_ARRAY) + GL11.glColorPointer(4, GL11.GL_UNSIGNED_BYTE, 0, 0) + GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, privateBuf) + + GL11.glDrawElements(GL11.GL_QUADS, hologram.visibleQuads * 4, GL11.GL_UNSIGNED_INT, hologram.width * hologram.width * hologram.height * 24 * 4) + + // Restore original state + GL11.glPopAttrib() + GL11.glPopClientAttrib() } - - t.draw() - - if (doCompile) { - GL11.glEndList() - } - - true } - else GL11.glCallList(list) // ----------------------------------------------------------------------- // // Cache // ----------------------------------------------------------------------- // def call = { - val list = GLAllocation.generateDisplayLists(1) + val privateBuf = GL15.glGenBuffers() hologram.dirty = true // Force compilation. - list + privateBuf } def onRemoval(e: RemovalNotification[TileEntity, Int]) { - GLAllocation.deleteDisplayLists(e.getValue) + GL15.glDeleteBuffers(e.getValue) } // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala b/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala index 38dda0071..d508f11b6 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala @@ -34,6 +34,9 @@ class Hologram(var tier: Int) extends traits.Environment with SidedEnvironment w // Whether we need to send an update packet/recompile our display list. var dirty = false + // Store it here for convenience + var visibleQuads = 0 + // Interval of dirty columns. var dirtyFromX = Int.MaxValue var dirtyUntilX = -1 From 5e64a27a0db517688a46e497b65378e2f2239619 Mon Sep 17 00:00:00 2001 From: evg-zhabotinsky Date: Fri, 6 Jun 2014 21:18:14 +0400 Subject: [PATCH 2/6] Now it really works. Need to read documentation more carefully. (#259) --- .../oc/client/renderer/tileentity/HologramRenderer.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala index 6a16e61f7..997d1c187 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala @@ -232,11 +232,11 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit GL11.glCullFace(GL11.GL_BACK) // Because fragment processing started to slow things down bindTexture(Textures.blockHologram) GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, commonBuffer) - GL11.glEnable(GL11.GL_VERTEX_ARRAY) - GL11.glEnable(GL11.GL_TEXTURE_COORD_ARRAY) + GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY) + GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY) GL11.glInterleavedArrays(GL11.GL_T2F_V3F, 0, 0) GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, privateBuf) - GL11.glEnable(GL11.GL_COLOR_ARRAY) + GL11.glEnableClientState(GL11.GL_COLOR_ARRAY) GL11.glColorPointer(4, GL11.GL_UNSIGNED_BYTE, 0, 0) GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, privateBuf) From c4105d5197e958488748251a22dad08970781a85 Mon Sep 17 00:00:00 2001 From: evg-zhabotinsky Date: Sat, 7 Jun 2014 00:02:46 +0400 Subject: [PATCH 3/6] Compact hologram update code (decrease Java overhead). Also remove `dirty=true` on NBT read since privateBuf caching already takes care of it. (I hope so) That is, d99bc5815c680198dfa7cd94eede40e5b4e66296 no longer affects hologram performance. --- .../tileentity/HologramRenderer.scala | 41 +++++++++++++------ .../cil/oc/common/tileentity/Hologram.scala | 1 - 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala index 997d1c187..4518ea941 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala @@ -18,7 +18,7 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit /** We cache the VBOs for the projectors we render for performance. */ val cache = com.google.common.cache.CacheBuilder.newBuilder(). - expireAfterAccess(2, TimeUnit.SECONDS). + expireAfterAccess(10, TimeUnit.SECONDS). removalListener(this). asInstanceOf[CacheBuilder[Hologram, Int]]. build[Hologram, Int]() @@ -142,30 +142,25 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit def isSolid(hx: Int, hy: Int, hz: Int) = value(hx, hy, hz) != 0 var tmpBuf = BufferUtils.createIntBuffer(hologram.width * hologram.width * hologram.height * 24 * 2) - // First copy color information - for (x <- 0 until hologram.width) { - for (z <- 0 until hologram.width) { - for (y <- 0 until hologram.height) { - val v: Int = if (isSolid(x, y, z)) (192 << 24) + hologram.colors(value(x, y, z) - 1) else 0 - for (t <- 0 until 24) { - tmpBuf.put(v) - } - } - } - } - // Then identify which quads to render and prepare data for glDrawElements + // Copy color information, identify which quads to render and prepare data for glDrawElements hologram.visibleQuads = 0; var c = 0 + tmpBuf.position(hologram.width * hologram.width * hologram.height * 24) for (hx <- 0 until hologram.width) { for (hz <- 0 until hologram.width) { for (hy <- 0 until hologram.height) { if (isSolid(hx, hy, hz)) { + val v: Int = (192 << 24) + hologram.colors(value(hx, hy, hz) - 1) // South if (!isSolid(hx, hy, hz + 1)) { tmpBuf.put(c) tmpBuf.put(c + 1) tmpBuf.put(c + 2) tmpBuf.put(c + 3) + tmpBuf.put(c, v) + tmpBuf.put(c + 1, v) + tmpBuf.put(c + 2, v) + tmpBuf.put(c + 3, v) hologram.visibleQuads += 1 } c += 4 @@ -175,6 +170,10 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit tmpBuf.put(c + 1) tmpBuf.put(c + 2) tmpBuf.put(c + 3) + tmpBuf.put(c, v) + tmpBuf.put(c + 1, v) + tmpBuf.put(c + 2, v) + tmpBuf.put(c + 3, v) hologram.visibleQuads += 1 } c += 4 @@ -185,6 +184,10 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit tmpBuf.put(c + 1) tmpBuf.put(c + 2) tmpBuf.put(c + 3) + tmpBuf.put(c, v) + tmpBuf.put(c + 1, v) + tmpBuf.put(c + 2, v) + tmpBuf.put(c + 3, v) hologram.visibleQuads += 1 } c += 4 @@ -194,6 +197,10 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit tmpBuf.put(c + 1) tmpBuf.put(c + 2) tmpBuf.put(c + 3) + tmpBuf.put(c, v) + tmpBuf.put(c + 1, v) + tmpBuf.put(c + 2, v) + tmpBuf.put(c + 3, v) hologram.visibleQuads += 1 } c += 4 @@ -204,6 +211,10 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit tmpBuf.put(c + 1) tmpBuf.put(c + 2) tmpBuf.put(c + 3) + tmpBuf.put(c, v) + tmpBuf.put(c + 1, v) + tmpBuf.put(c + 2, v) + tmpBuf.put(c + 3, v) hologram.visibleQuads += 1 } c += 4 @@ -213,6 +224,10 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit tmpBuf.put(c + 1) tmpBuf.put(c + 2) tmpBuf.put(c + 3) + tmpBuf.put(c, v) + tmpBuf.put(c + 1, v) + tmpBuf.put(c + 2, v) + tmpBuf.put(c + 3, v) hologram.visibleQuads += 1 } c += 4 diff --git a/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala b/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala index d508f11b6..33f832aff 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala @@ -306,7 +306,6 @@ class Hologram(var tier: Int) extends traits.Environment with SidedEnvironment w nbt.getIntArray("colors").copyToArray(colors) scale = nbt.getDouble("scale") hasPower = nbt.getBoolean("hasPower") - dirty = true } override def writeToNBTForClient(nbt: NBTTagCompound) { From ebbd3c2ea6f8ebf4eab6b4883de77a6810681b8b Mon Sep 17 00:00:00 2001 From: evg-zhabotinsky Date: Sat, 7 Jun 2014 02:36:04 +0400 Subject: [PATCH 4/6] Mimic screen text fading for holograms. Performance might be affected (definitely improved but I can't notice it) --- src/main/resources/reference.conf | 6 ++++++ src/main/scala/li/cil/oc/Settings.scala | 1 + .../oc/client/renderer/tileentity/HologramRenderer.scala | 9 +++++++-- .../scala/li/cil/oc/common/tileentity/Hologram.scala | 1 + 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf index 76939ec69..9d4d9fd10 100644 --- a/src/main/resources/reference.conf +++ b/src/main/resources/reference.conf @@ -66,6 +66,12 @@ opencomputers { # hologram projector when at maximum scale. Render distance is scaled # down with the actual scale of the hologram. hologramRenderDistance: 64 + + # The distance at which to start fading out the hologram (as with + # hologramRenderDistance). This is purely cosmetic, to avoid image + # disappearing instantly when moving too far away from a projector. + # It does not affect performance. Holograms are transparent anyway. + hologramFadeStartDistance: 48 } # Computer related settings, concerns server performance and security. diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index 38df2498d..a7cb84d69 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -31,6 +31,7 @@ class Settings(config: Config) { val robotLabels = config.getBoolean("client.robotLabels") val soundVolume = config.getDouble("client.soundVolume").toFloat max 0 min 2 val fontCharScale = config.getDouble("client.fontCharScale") max 0.5 min 2 + val hologramFadeStartDistance = config.getDouble("client.hologramFadeStartDistance") max 0 val hologramRenderDistance = config.getDouble("client.hologramRenderDistance") max 0 // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala index 4518ea941..fcb31626c 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala @@ -34,6 +34,11 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit RenderState.makeItBlend() GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE) + val playerDistSq = x*x + y*y + z*z + val maxDistSq = hologram.getMaxRenderDistanceSquared + val fadeDistSq = hologram.getFadeStartDistanceSquared + RenderState.setBlendAlpha(0.75f * (if (playerDistSq > fadeDistSq) math.max(0, 1 - ((playerDistSq - fadeDistSq) / (maxDistSq - fadeDistSq)).toFloat) else 1)) + GL11.glPushMatrix() GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5) GL11.glScaled(1.001, 1.001, 1.001) // Avoid z-fighting with other blocks. @@ -150,7 +155,7 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit for (hz <- 0 until hologram.width) { for (hy <- 0 until hologram.height) { if (isSolid(hx, hy, hz)) { - val v: Int = (192 << 24) + hologram.colors(value(hx, hy, hz) - 1) + val v: Int = hologram.colors(value(hx, hy, hz) - 1) // South if (!isSolid(hx, hy, hz + 1)) { tmpBuf.put(c) @@ -252,7 +257,7 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit GL11.glInterleavedArrays(GL11.GL_T2F_V3F, 0, 0) GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, privateBuf) GL11.glEnableClientState(GL11.GL_COLOR_ARRAY) - GL11.glColorPointer(4, GL11.GL_UNSIGNED_BYTE, 0, 0) + GL11.glColorPointer(3, GL11.GL_UNSIGNED_BYTE, 4, 0) GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, privateBuf) GL11.glDrawElements(GL11.GL_QUADS, hologram.visibleQuads * 4, GL11.GL_UNSIGNED_INT, hologram.width * hologram.width * hologram.height * 24 * 4) diff --git a/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala b/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala index 33f832aff..3663f6ff1 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala @@ -278,6 +278,7 @@ class Hologram(var tier: Int) extends traits.Environment with SidedEnvironment w override def shouldRenderInPass(pass: Int) = pass == 1 override def getMaxRenderDistanceSquared = scale / Settings.hologramMaxScaleByTier.max * Settings.get.hologramRenderDistance * Settings.get.hologramRenderDistance + def getFadeStartDistanceSquared = scale / Settings.hologramMaxScaleByTier.max * Settings.get.hologramFadeStartDistance * Settings.get.hologramFadeStartDistance override def getRenderBoundingBox = AxisAlignedBB.getAABBPool.getAABB(xCoord + 0.5 - 1.5 * scale, yCoord, zCoord - scale, xCoord + 0.5 + 1.5 * scale, yCoord + 0.25 + 2 * scale, zCoord + 0.5 + 1.5 * scale) From 29fdc074103bd0e315b86a41e5d1d4275374c2b8 Mon Sep 17 00:00:00 2001 From: evg-zhabotinsky Date: Sun, 8 Jun 2014 14:25:44 +0400 Subject: [PATCH 5/6] Fix "reverse" color component order for holograms. It is 0xRRGGBB again. --- .../scala/li/cil/oc/common/tileentity/Hologram.scala | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala b/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala index 3663f6ff1..d25514b08 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala @@ -48,7 +48,7 @@ class Hologram(var tier: Int) extends traits.Environment with SidedEnvironment w var hasPower = true - val colorsByTier = Array(Array(0x00FF00), Array(0xFF0000, 0x00FF00, 0x0000FF)) + val colorsByTier = Array(Array(0x00FF00), Array(0x0000FF, 0x00FF00, 0xFF0000)) // 0xBBGGRR for rendering convenience def colors = colorsByTier(tier) def getColor(x: Int, y: Int, z: Int) = { @@ -206,7 +206,9 @@ class Hologram(var tier: Int) extends traits.Environment with SidedEnvironment w def getPaletteColor(computer: Context, args: Arguments): Array[AnyRef] = { val index = args.checkInteger(0) if (index < 0 || index >= colors.length) throw new ArrayIndexOutOfBoundsException() - result(colors(index)) + var col = colors(index) + // Colors are stored as 0xAABBGGRR for rendering convenience, so convert them back here + result(((col & 0xFF) << 16) | (col & 0xFF00) | ((col >>> 16) & 0xFF)) } @Callback(doc = """function(index:number, value:number):number -- Set the color defined for the specified value.""") @@ -215,7 +217,9 @@ class Hologram(var tier: Int) extends traits.Environment with SidedEnvironment w if (index < 0 || index >= colors.length) throw new ArrayIndexOutOfBoundsException() val value = args.checkInteger(1) val oldValue = colors(index) - colors(index) = value & 0xFFFFFF + // Change byte order here to allow passing stored color to OpenGL "as-is" + // (as whole Int, i.e. 0xAABBGGRR, alpha is unused but present for alignment) + colors(index) = ((value & 0xFF) << 16) | (value & 0xFF00) | ((value >>> 16) & 0xFF) ServerPacketSender.sendHologramColor(this, index, value) result(oldValue) } From f480dca78d97cc96ae045aeddf57379b64788bd1 Mon Sep 17 00:00:00 2001 From: evg-zhabotinsky Date: Tue, 10 Jun 2014 03:40:26 +0400 Subject: [PATCH 6/6] Reenable hologram lighting --- .../tileentity/HologramRenderer.scala | 62 ++++++++++--------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala index fcb31626c..ece8d84f9 100644 --- a/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala @@ -80,10 +80,13 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit if (commonBuffer == 0) { // First run only commonBuffer = GL15.glGenBuffers() - var tmpBuf = BufferUtils.createFloatBuffer(hologram.width * hologram.width * hologram.height * 24 * (3 + 2)) - def newVert = (x: Int, y: Int, z: Int, u: Int, v: Int) => { // Dirty hack to avoid rewriting :) + var tmpBuf = BufferUtils.createFloatBuffer(hologram.width * hologram.width * hologram.height * 24 * (2 + 3 + 3)) + def newVert = (x: Int, y: Int, z: Int, u: Int, v: Int, nx: Int, ny: Int, nz: Int) => { tmpBuf.put(u) tmpBuf.put(v) + tmpBuf.put(nx) + tmpBuf.put(ny) + tmpBuf.put(nz) tmpBuf.put(x) tmpBuf.put(y) tmpBuf.put(z) @@ -102,37 +105,37 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit */ // South - newVert(x + 1, y + 1, z + 1, 0, 0) // 5 - newVert(x + 0, y + 1, z + 1, 1, 0) // 4 - newVert(x + 0, y + 0, z + 1, 1, 1) // 7 - newVert(x + 1, y + 0, z + 1, 0, 1) // 6 + newVert(x + 1, y + 1, z + 1, 0, 0, 0, 0, 1) // 5 + newVert(x + 0, y + 1, z + 1, 1, 0, 0, 0, 1) // 4 + newVert(x + 0, y + 0, z + 1, 1, 1, 0, 0, 1) // 7 + newVert(x + 1, y + 0, z + 1, 0, 1, 0, 0, 1) // 6 // North - newVert(x + 1, y + 0, z + 0, 0, 0) // 3 - newVert(x + 0, y + 0, z + 0, 1, 0) // 2 - newVert(x + 0, y + 1, z + 0, 1, 1) // 1 - newVert(x + 1, y + 1, z + 0, 0, 1) // 0 + newVert(x + 1, y + 0, z + 0, 0, 0, 0, 0, -1) // 3 + newVert(x + 0, y + 0, z + 0, 1, 0, 0, 0, -1) // 2 + newVert(x + 0, y + 1, z + 0, 1, 1, 0, 0, -1) // 1 + newVert(x + 1, y + 1, z + 0, 0, 1, 0, 0, -1) // 0 // East - newVert(x + 1, y + 1, z + 1, 1, 0) // 5 - newVert(x + 1, y + 0, z + 1, 1, 1) // 6 - newVert(x + 1, y + 0, z + 0, 0, 1) // 3 - newVert(x + 1, y + 1, z + 0, 0, 0) // 0 + newVert(x + 1, y + 1, z + 1, 1, 0, 1, 0, 0) // 5 + newVert(x + 1, y + 0, z + 1, 1, 1, 1, 0, 0) // 6 + newVert(x + 1, y + 0, z + 0, 0, 1, 1, 0, 0) // 3 + newVert(x + 1, y + 1, z + 0, 0, 0, 1, 0, 0) // 0 // West - newVert(x + 0, y + 0, z + 1, 1, 0) // 7 - newVert(x + 0, y + 1, z + 1, 1, 1) // 4 - newVert(x + 0, y + 1, z + 0, 0, 1) // 1 - newVert(x + 0, y + 0, z + 0, 0, 0) // 2 + newVert(x + 0, y + 0, z + 1, 1, 0, -1, 0, 0) // 7 + newVert(x + 0, y + 1, z + 1, 1, 1, -1, 0, 0) // 4 + newVert(x + 0, y + 1, z + 0, 0, 1, -1, 0, 0) // 1 + newVert(x + 0, y + 0, z + 0, 0, 0, -1, 0, 0) // 2 // Up - newVert(x + 1, y + 1, z + 0, 0, 0) // 0 - newVert(x + 0, y + 1, z + 0, 1, 0) // 1 - newVert(x + 0, y + 1, z + 1, 1, 1) // 4 - newVert(x + 1, y + 1, z + 1, 0, 1) // 5 + newVert(x + 1, y + 1, z + 0, 0, 0, 0, 1, 0) // 0 + newVert(x + 0, y + 1, z + 0, 1, 0, 0, 1, 0) // 1 + newVert(x + 0, y + 1, z + 1, 1, 1, 0, 1, 0) // 4 + newVert(x + 1, y + 1, z + 1, 0, 1, 0, 1, 0) // 5 // Down - newVert(x + 1, y + 0, z + 1, 0, 0) // 6 - newVert(x + 0, y + 0, z + 1, 1, 0) // 7 - newVert(x + 0, y + 0, z + 0, 1, 1) // 2 - newVert(x + 1, y + 0, z + 0, 0, 1) // 3 + newVert(x + 1, y + 0, z + 1, 0, 0, 0, -1, 0) // 6 + newVert(x + 0, y + 0, z + 1, 1, 0, 0, -1, 0) // 7 + newVert(x + 0, y + 0, z + 0, 1, 1, 0, -1, 0) // 2 + newVert(x + 1, y + 0, z + 0, 0, 1, 0, -1, 0) // 3 } } } @@ -148,7 +151,7 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit var tmpBuf = BufferUtils.createIntBuffer(hologram.width * hologram.width * hologram.height * 24 * 2) // Copy color information, identify which quads to render and prepare data for glDrawElements - hologram.visibleQuads = 0; + hologram.visibleQuads = 0 var c = 0 tmpBuf.position(hologram.width * hologram.width * hologram.height * 24) for (hx <- 0 until hologram.width) { @@ -247,14 +250,15 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit hologram.dirty = false } - GL11.glDisable(GL11.GL_LIGHTING) // Hologram that reflects light... It would be awesome! But... + GL11.glEnable(GL11.GL_NORMALIZE) // Normalize normals!!! (Yes, glScale scales them too!) GL11.glEnable(GL11.GL_CULL_FACE) GL11.glCullFace(GL11.GL_BACK) // Because fragment processing started to slow things down bindTexture(Textures.blockHologram) GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, commonBuffer) GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY) GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY) - GL11.glInterleavedArrays(GL11.GL_T2F_V3F, 0, 0) + GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY) + GL11.glInterleavedArrays(GL11.GL_T2F_N3F_V3F, 0, 0) GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, privateBuf) GL11.glEnableClientState(GL11.GL_COLOR_ARRAY) GL11.glColorPointer(3, GL11.GL_UNSIGNED_BYTE, 4, 0)