From 83377b4ae023733e504db9f00f884eebd941a8f0 Mon Sep 17 00:00:00 2001 From: evg-zhabotinsky Date: Fri, 6 Jun 2014 10:04:15 +0400 Subject: [PATCH 01/10] 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 02/10] 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 03/10] 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 04/10] 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 05/10] 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 06/10] 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) From 0156408a1ef0ee0db05c74f59cb62d2bf71fa838 Mon Sep 17 00:00:00 2001 From: Vexatos Date: Tue, 10 Jun 2014 14:44:57 +0200 Subject: [PATCH 07/10] Update de_DE.lang --- .../assets/opencomputers/lang/de_DE.lang | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/resources/assets/opencomputers/lang/de_DE.lang b/src/main/resources/assets/opencomputers/lang/de_DE.lang index 74ca60cff..cc9a2d8d0 100644 --- a/src/main/resources/assets/opencomputers/lang/de_DE.lang +++ b/src/main/resources/assets/opencomputers/lang/de_DE.lang @@ -169,8 +169,8 @@ oc:tooltip.ControlUnit=Klingt wichtig, ist es auch. Man baut daraus immerhin CPU oc:tooltip.CPU=Kernstück eines jeden Computers. Die Taktrate hat einen leichten Schatten, aber was kann man von einer Taschensonnenuhr schon erwarten?[nl] Unterstützte Komponenten: §f%s§7. oc:tooltip.CuttingWire=Wird gebraucht, um Tonblöcke in Leiterplattenform zu bekommen. Vermutlich das ineffizienteste Werkzeug in der Geschichte der Menschheit, da es nach einer Verwendung kaputt geht. oc:tooltip.Disassembler=Zerlegt Gegenstände in ihre Einzelteile. §lWarnung§7: zurückgewonnene Gegenstände haben eine %s%%-ige Chance beim Extrahieren kaputt zu gehen! -oc:tooltip.Disk=Sehr einfaches Speichermedium, das verwendet werden kann, um Disketten und Festplatten bauen. -oc:tooltip.DiskDrive.CC=ComputerCraft-Disketten werden §aunterstützt§7. +oc:tooltip.Disk=Sehr einfaches Speichermedium, das verwendet werden kann, um Disketten und Festplatten zu fertigen. +oc:tooltip.DiskDrive.CC=ComputerCraft-Disketten werden §aauch unterstützt§7. oc:tooltip.DiskDrive=Erlaubt es, Disketten zu lesen und zu beschreiben. Kann in Robotern installiert werden, um später Disketten einlegen zu können. oc:tooltip.Geolyzer=Erlaubt es die Härte der Blöcke in der Umgebung abzufragen. Hilfreich um Hologramme der Gegend zu erzeugen, oder um Erze zu entdecken. oc:tooltip.GraphicsCard=Erlaubt es, den angezeigten Inhalt von Bildschirmen zu ändern.[nl] Höchstauflösung: §f%sx%s§7.[nl] Maximale Farbtiefe: §f%s§7.[nl] Operationen/Tick: §f%s§7. @@ -203,7 +203,7 @@ oc:tooltip.Robot=Im Gegensatz zu normalen Computern können sich Roboter in der # The underscore makes sure this isn't hidden with the rest of the tooltip. oc:tooltip.Robot_Level=§fStufe§7: §a%s§7. oc:tooltip.Robot_StoredEnergy=§fGespeicherte Energie§7: §a%s§7. -oc:tooltip.RobotAssembler=Erlaubt das Bauen von Robotern aus diversen anderen Computerteilen. +oc:tooltip.RobotAssembler=Erlaubt die Fertigung von Robotern aus diversen anderen Computerteilen. oc:tooltip.Router=Erlaubt es, mehrere Netzwerke miteinander zu verbinden. Leitet ausschließlich Netzwerknachrichten weiter, Komponenten "hinter" dem Switch sind nicht sichtbar. Nützlich, um Netzwerke zu trennen, jedoch nach wie vor Kommunikation zwischen den Netzwerken zu erlauben, z.b. mittels Netzwerkkarten. oc:tooltip.Screen=Zeigt Text an, gesteuert von Grafikkarten in Computern.[nl] Höchstauflösung: §f%sx%s§7.[nl] Maximale Farbtiefe: §f%s§7. oc:tooltip.Server=Ein Server kann wie ein gewöhnliches Computergehäuse mit Komponenten verbessert werden. Um den Server zu starten, muss er in einem Servergehäuse installiert werden.[nl] Anzahl unterstützter Fernbedienungen: §f%s§7. @@ -213,15 +213,15 @@ oc:tooltip.Terminal=Erlaubt es, einen Server aus der Ferne zu steuern, so lange oc:tooltip.TooLong=Halte [§f%s§7] gedrückt für mehr Infos. oc:tooltip.Transistor=Elementarer Baustein der meisten Computerkomponenten. Nicht zu verwechseln mit Steinelementaren. oc:tooltip.UpgradeAngel=Erlaubt es Robotern, Blöcke in die Luft zu setzen, selbst wenn kein Referenzblock daneben existiert. -oc:tooltip.UpgradeBattery=Erhöht die Energiespeicherkapazität eines Roboters, was ihm erlaubt länger zu arbeiten ohne erneut aufgeladen zu werden. [nl] Kapazität: §f%s§7. -oc:tooltip.UpgradeChunkloader=Wenn sich im Wald ein Roboter bewegt, und niemand da ist ihn zu sehen, bewegt er sich dann wirklich? Dieses Upgrade stellt sicher, dass dem so ist. Es hält den Chunk in dem sich der Roboter befindet geladen, verbraucht während es aktiv ist jedoch Energie. -oc:tooltip.UpgradeContainerCard=Dieses Behälter-Upgrade erlaubt es eine Karte in einem bereits zusammengebauten Roboter zu installieren und wieder zu entfernen. [nl] Maximale Stufe: §f%s§7. -oc:tooltip.UpgradeContainerUpgrade=Dieses Behälter-Upgrade erlaubt es ein Upgrade in einem bereits zusammengebauten Roboter zu installieren und wieder zu entfernen. [nl] Maximale Stufe: §f%s§7. +oc:tooltip.UpgradeBattery=Erhöht die Energiespeicherkapazität eines Roboters, was ihm erlaubt, länger zu arbeiten, ohne erneut aufgeladen werden zu müssen. [nl] Kapazität: §f%s§7. +oc:tooltip.UpgradeChunkloader=Wenn sich im Wald ein Roboter bewegt, und niemand da ist, ihn zu sehen, bewegt er sich dann wirklich? Dieses Upgrade stellt sicher, dass dem so ist. Es hält den Chunk, in dem sich der Roboter befindet, geladen, verbraucht, während es aktiv ist, jedoch Energie. +oc:tooltip.UpgradeContainerCard=Dieses Behälter-Upgrade erlaubt es, eine Karte in einem bereits zusammengebauten Roboter zu installieren und wieder zu entfernen. [nl] Maximale Stufe: §f%s§7. +oc:tooltip.UpgradeContainerUpgrade=Dieses Behälter-Upgrade erlaubt es, ein Upgrade in einem bereits zusammengebauten Roboter zu installieren und wieder zu entfernen. [nl] Maximale Stufe: §f%s§7. oc:tooltip.UpgradeCrafting=Ermöglicht Robotern, in dem oberen linken Bereich ihres Inventars Dinge zu fertigen. Gegenstände müssen so angeordnet sein, wie sie es in einer Werkbank wären. oc:tooltip.UpgradeExperience=Dieses Upgrade erlaubt es Robotern durch verschiedene Aktionen Erfahrung zu sammeln. Je mehr Erfahrung ein Roboter hat, desto mehr Energie kann er speichern, desto schneller kann er Blöcke abbauen und desto effizienter kann er mit Werkzeugen umgehen. oc:tooltip.UpgradeGenerator=Kann verwendet werden, um unterwegs Energie aus Brennstoffen zu erzeugen. Verbraucht Gegenstände über einen ihrem Brennwert gemäßen Zeitraum.[nl] §fEffizienz§7: §a%s%%§7 oc:tooltip.UpgradeInventory=Dieses Upgrade gibt Robotern ein internes Inventar. Ohne ein solches Upgrade können Roboter keine Gegenstände verwahren. -oc:tooltip.UpgradeInventoryController=Dieses Upgrade erlaubt es dem Roboter präziser mit externen Inventaren zu interagieren, und erlaubt es ihm das angelegte Werkzeug mit einem Gegenstand in seinem Inventar auszutauschen. +oc:tooltip.UpgradeInventoryController=Dieses Upgrade erlaubt es dem Roboter, präziser mit externen Inventaren zu interagieren, und erlaubt es ihm, das angelegte Werkzeug mit einem Gegenstand in seinem Inventar auszutauschen. oc:tooltip.UpgradeNavigation=Erlaubt es Robotern, ihre Position und Ausrichtung zu bestimmen. Die Position ist relativ zur Mitte der Karte, die in diesem Upgrade verbaut wurde. oc:tooltip.UpgradeSign=Erlaubt das Lesen und Schreiben von Text auf Schildern. oc:tooltip.UpgradeSolarGenerator=Kann verwendet werden, um unterwegs Energie aus Sonnenlicht zu generieren. Benötigt eine ungehinderte Sicht zum Himmel über dem Roboter. Generiert Energie mit %s%% der Geschwindigkeit eines Stirlingmotors. From 2b709eee3c0dd71e8a2a0d1b79c380bd8938c39f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 10 Jun 2014 16:54:47 +0200 Subject: [PATCH 08/10] Refactored the hologram renderer a bit (split phases into separate functions - init [create common buffer], validate [check if dirty, rebuild as needed] and publish [do the actual rendering]). Also caching the buffer used for the color data and indexes to avoid spamming the GC with instances of those (can't hurt, right?) --- .../tileentity/HologramRenderer.scala | 392 +++++++++--------- .../cil/oc/common/tileentity/Hologram.scala | 3 +- 2 files changed, 203 insertions(+), 192 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 e63bd8d34..2aa5889d2 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 @@ -13,16 +13,28 @@ import org.lwjgl.opengl.{GL15, GL11} import scala.util.Random import org.lwjgl.BufferUtils import li.cil.oc.Settings +import java.nio.IntBuffer -object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] with RemovalListener[TileEntity, Int] with ITickHandler { - val random = new Random() +object HologramRenderer extends TileEntitySpecialRenderer with Callable[(Int, IntBuffer)] with RemovalListener[TileEntity, (Int, IntBuffer)] with ITickHandler { + private val random = new Random() /** We cache the VBOs for the projectors we render for performance. */ - val cache = com.google.common.cache.CacheBuilder.newBuilder(). + private val cache = com.google.common.cache.CacheBuilder.newBuilder(). expireAfterAccess(10, TimeUnit.SECONDS). removalListener(this). - asInstanceOf[CacheBuilder[Hologram, Int]]. - build[Hologram, Int]() + asInstanceOf[CacheBuilder[Hologram, (Int, IntBuffer)]]. + build[Hologram, (Int, IntBuffer)]() + + /** + * Common for all holograms. Holds the vertex positions, texture + * coordinates and normals information. Layout is: u v nx ny nz x y z + * + * WARNING: this optimization only works if all the holograms have the + * same dimensions (in voxels). If we ever need holograms of different + * sizes we could probably just fake that by making the outer layers + * immutable (i.e. always empty). + */ + private var commonBuffer = 0 /** Used to pass the current screen along to call(). */ private var hologram: Hologram = null @@ -33,11 +45,12 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit hologram = te.asInstanceOf[Hologram] if (!hologram.hasPower) return + GL11.glPushClientAttrib(GL11.GL_ALL_CLIENT_ATTRIB_BITS) GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) RenderState.makeItBlend() GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE) - val playerDistSq = x*x + y*y + z*z + 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)) @@ -58,47 +71,50 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit // 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. + // When we don't do this the hologram will look different from different + // angles (because some faces will shine through sometimes and sometimes + // they won't), so a more... consistent look is desirable. + val (glBuffer, dataBuffer) = cache.get(hologram, this) GL11.glColorMask(false, false, false, false) GL11.glDepthMask(true) - val privateBuf = cache.get(hologram, this) - compileOrDraw(privateBuf) + draw(glBuffer, dataBuffer) GL11.glColorMask(true, true, true, true) GL11.glDepthFunc(GL11.GL_EQUAL) - compileOrDraw(privateBuf) + draw(glBuffer, dataBuffer) GL11.glPopMatrix() GL11.glPopAttrib() + GL11.glPopClientAttrib() RenderState.checkError(getClass.getName + ".renderTileEntityAt: leaving") } - 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 draw(glBuffer: Int, dataBuffer: IntBuffer) { + initialize() + validate(glBuffer, dataBuffer) + publish(glBuffer) + } - if (commonBuffer == 0) { // First run only - commonBuffer = GL15.glGenBuffers() - 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) - } - for (x <- 0 until hologram.width) { - for (z <- 0 until hologram.width) { - for (y <- 0 until hologram.height) { + private def initialize() { + // First run only, create structure information. + if (commonBuffer == 0) { + commonBuffer = GL15.glGenBuffers() + + val data = BufferUtils.createFloatBuffer(hologram.width * hologram.width * hologram.height * 24 * (2 + 3 + 3)) + def addVertex(x: Int, y: Int, z: Int, u: Int, v: Int, nx: Int, ny: Int, nz: Int) { + data.put(u) + data.put(v) + data.put(nx) + data.put(ny) + data.put(nz) + data.put(x) + data.put(y) + data.put(z) + } + + for (x <- 0 until hologram.width) { + for (z <- 0 until hologram.width) { + for (y <- 0 until hologram.height) { /* 0---1 | N | @@ -110,171 +126,159 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit */ // South - 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, 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, 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, -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, 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, 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 - } - } - } - 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) - // 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 = 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 + addVertex(x + 1, y + 1, z + 1, 0, 0, 0, 0, 1) // 5 + addVertex(x + 0, y + 1, z + 1, 1, 0, 0, 0, 1) // 4 + addVertex(x + 0, y + 0, z + 1, 1, 1, 0, 0, 1) // 7 + addVertex(x + 1, y + 0, z + 1, 0, 1, 0, 0, 1) // 6 // North - 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 + addVertex(x + 1, y + 0, z + 0, 0, 0, 0, 0, -1) // 3 + addVertex(x + 0, y + 0, z + 0, 1, 0, 0, 0, -1) // 2 + addVertex(x + 0, y + 1, z + 0, 1, 1, 0, 0, -1) // 1 + addVertex(x + 1, y + 1, z + 0, 0, 1, 0, 0, -1) // 0 // East - if (!isSolid(hx + 1, hy, hz)) { - 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 + addVertex(x + 1, y + 1, z + 1, 1, 0, 1, 0, 0) // 5 + addVertex(x + 1, y + 0, z + 1, 1, 1, 1, 0, 0) // 6 + addVertex(x + 1, y + 0, z + 0, 0, 1, 1, 0, 0) // 3 + addVertex(x + 1, y + 1, z + 0, 0, 0, 1, 0, 0) // 0 // West - if (!isSolid(hx - 1, hy, hz)) { - 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 + addVertex(x + 0, y + 0, z + 1, 1, 0, -1, 0, 0) // 7 + addVertex(x + 0, y + 1, z + 1, 1, 1, -1, 0, 0) // 4 + addVertex(x + 0, y + 1, z + 0, 0, 1, -1, 0, 0) // 1 + addVertex(x + 0, y + 0, z + 0, 0, 0, -1, 0, 0) // 2 // Up - if (!isSolid(hx, hy + 1, hz)) { - 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 + addVertex(x + 1, y + 1, z + 0, 0, 0, 0, 1, 0) // 0 + addVertex(x + 0, y + 1, z + 0, 1, 0, 0, 1, 0) // 1 + addVertex(x + 0, y + 1, z + 1, 1, 1, 0, 1, 0) // 4 + addVertex(x + 1, y + 1, z + 1, 0, 1, 0, 1, 0) // 5 // Down - if (!isSolid(hx, hy - 1, hz)) { - 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 - } else c += 24 + addVertex(x + 1, y + 0, z + 1, 0, 0, 0, -1, 0) // 6 + addVertex(x + 0, y + 0, z + 1, 1, 0, 0, -1, 0) // 7 + addVertex(x + 0, y + 0, z + 0, 1, 1, 0, -1, 0) // 2 + addVertex(x + 1, y + 0, z + 0, 0, 1, 0, -1, 0) // 3 } } } - tmpBuf.rewind() // Important! - GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, privateBuf) - GL15.glBufferData(GL15.GL_ARRAY_BUFFER, tmpBuf, GL15.GL_STATIC_DRAW) - hologram.dirty = false - } + // Important! OpenGL will start reading from the current buffer position. + data.rewind() - 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) + // This buffer never ever changes, so static is the way to go. GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, commonBuffer) - GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY) - GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY) - 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) - 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() + GL15.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STATIC_DRAW) + } } + + private def validate(glBuffer: Int, dataBuffer: IntBuffer) { + // Refresh indexes when the hologram's data changed. + if (hologram.dirty) { + 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 + + def addFace(index: Int, color: Int) { + dataBuffer.put(index) + dataBuffer.put(index + 1) + dataBuffer.put(index + 2) + dataBuffer.put(index + 3) + + dataBuffer.put(index, color) + dataBuffer.put(index + 1, color) + dataBuffer.put(index + 2, color) + dataBuffer.put(index + 3, color) + + hologram.visibleQuads += 1 + } + + // Copy color information, identify which quads to render and prepare data for glDrawElements + hologram.visibleQuads = 0 + var index = 0 + dataBuffer.position(hologram.width * hologram.width * hologram.height * 6 * 4) + for (hx <- 0 until hologram.width) { + for (hz <- 0 until hologram.width) { + for (hy <- 0 until hologram.height) { + // Do we need to draw at least one face? + if (isSolid(hx, hy, hz)) { + // Yes, get the color of the voxel. + val color = hologram.colors(value(hx, hy, hz) - 1) + + // South + if (!isSolid(hx, hy, hz + 1)) { + addFace(index, color) + } + index += 4 + // North + if (!isSolid(hx, hy, hz - 1)) { + addFace(index, color) + } + index += 4 + + // East + if (!isSolid(hx + 1, hy, hz)) { + addFace(index, color) + } + index += 4 + // West + if (!isSolid(hx - 1, hy, hz)) { + addFace(index, color) + } + index += 4 + + // Up + if (!isSolid(hx, hy + 1, hz)) { + addFace(index, color) + } + index += 4 + // Down + if (!isSolid(hx, hy - 1, hz)) { + addFace(index, color) + } + index += 4 + } + else { + // No, skip all associated indices. + index += 6 * 4 + } + } + } + } + + // Important! OpenGL will start reading from the current buffer position. + dataBuffer.rewind() + + // This buffer can be updated quite frequently, so dynamic seems sensible. + GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, glBuffer) + GL15.glBufferData(GL15.GL_ARRAY_BUFFER, dataBuffer, GL15.GL_DYNAMIC_DRAW) + + hologram.dirty = false + } + } + + private def publish(glBuffer: Int) { + bindTexture(Textures.blockHologram) + + // Normalize normals (yes, glScale scales them too). + GL11.glEnable(GL11.GL_NORMALIZE) + // evg-zhabotinsky: Because fragment processing started to slow things down + // TODO but holograms look terrible from the inside otherwise, + // and I don't see a difference in FPS anyway? Maybe a + // check for the camera position - if inside don't cull? + // GL11.glEnable(GL11.GL_CULL_FACE) + // GL11.glCullFace(GL11.GL_BACK) + + GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, commonBuffer) + GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY) + GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY) + GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY) + GL11.glInterleavedArrays(GL11.GL_T2F_N3F_V3F, 0, 0) + + GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, glBuffer) + GL11.glEnableClientState(GL11.GL_COLOR_ARRAY) + GL11.glColorPointer(3, GL11.GL_UNSIGNED_BYTE, 4, 0) + + GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, glBuffer) + GL11.glDrawElements(GL11.GL_QUADS, hologram.visibleQuads * 4, GL11.GL_UNSIGNED_INT, hologram.width * hologram.width * hologram.height * 6 * 4 * 4) } // ----------------------------------------------------------------------- // @@ -282,13 +286,19 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit // ----------------------------------------------------------------------- // def call = { - val privateBuf = GL15.glGenBuffers() - hologram.dirty = true // Force compilation. - privateBuf + val glBuffer = GL15.glGenBuffers() + val dataBuffer = BufferUtils.createIntBuffer(hologram.width * hologram.width * hologram.height * 6 * 4 * 2) + + // Force re-indexing. + hologram.dirty = true + + (glBuffer, dataBuffer) } - def onRemoval(e: RemovalNotification[TileEntity, Int]) { - GL15.glDeleteBuffers(e.getValue) + def onRemoval(e: RemovalNotification[TileEntity, (Int, IntBuffer)]) { + val (glBuffer, dataBuffer) = e.getValue + GL15.glDeleteBuffers(glBuffer) + dataBuffer.clear() } // ----------------------------------------------------------------------- // 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 d25514b08..973f45f30 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala @@ -34,7 +34,8 @@ 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 + // Store it here for convenience, this is the number of visible voxel faces + // as determined in the last VBO index update. See HologramRenderer. var visibleQuads = 0 // Interval of dirty columns. From 811300d1d81d0a627d93ca594fd97c22b7521968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 10 Jun 2014 17:05:22 +0200 Subject: [PATCH 09/10] Swapping hologram color byte order back to normal in save files for backwards compatibility. --- .../li/cil/oc/common/tileentity/Hologram.scala | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 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 973f45f30..0826305c4 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Hologram.scala @@ -50,6 +50,8 @@ class Hologram(var tier: Int) extends traits.Environment with SidedEnvironment w var hasPower = true val colorsByTier = Array(Array(0x00FF00), Array(0x0000FF, 0x00FF00, 0xFF0000)) // 0xBBGGRR for rendering convenience + + // This is a def and not a val for loading (where the tier comes from the nbt and is always 0 here). def colors = colorsByTier(tier) def getColor(x: Int, y: Int, z: Int) = { @@ -207,9 +209,8 @@ 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() - 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)) + // Colors are stored as 0xAABBGGRR for rendering convenience, so convert them. + result(convertColor(colors(index))) } @Callback(doc = """function(index:number, value:number):number -- Set the color defined for the specified value.""") @@ -220,7 +221,7 @@ class Hologram(var tier: Int) extends traits.Environment with SidedEnvironment w val oldValue = colors(index) // 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) + colors(index) = convertColor(value) ServerPacketSender.sendHologramColor(this, index, value) result(oldValue) } @@ -245,6 +246,10 @@ class Hologram(var tier: Int) extends traits.Environment with SidedEnvironment w value } + private def convertColor(color: Int) = { + ((color & 0x0000FF) << 16) | (color & 0x00FF00) | ((color & 0xFF0000) >>> 16) + } + // ----------------------------------------------------------------------- // override def canUpdate = isServer @@ -293,7 +298,7 @@ class Hologram(var tier: Int) extends traits.Environment with SidedEnvironment w tier = nbt.getByte(Settings.namespace + "tier") max 0 min 1 super.readFromNBT(nbt) nbt.getIntArray(Settings.namespace + "volume").copyToArray(volume) - nbt.getIntArray(Settings.namespace + "colors").copyToArray(colors) + nbt.getIntArray(Settings.namespace + "colors").map(convertColor).copyToArray(colors) scale = nbt.getDouble(Settings.namespace + "scale") } @@ -301,7 +306,7 @@ class Hologram(var tier: Int) extends traits.Environment with SidedEnvironment w nbt.setByte(Settings.namespace + "tier", tier.toByte) super.writeToNBT(nbt) nbt.setIntArray(Settings.namespace + "volume", volume) - nbt.setIntArray(Settings.namespace + "colors", colors) + nbt.setIntArray(Settings.namespace + "colors", colors.map(convertColor)) nbt.setDouble(Settings.namespace + "scale", scale) } From 644bb3e705486eb2fc659151ed31e4b2c3484f41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 10 Jun 2014 17:20:55 +0200 Subject: [PATCH 10/10] Added check for camera position in hologram renderer to determine whether to enable backface culling or not. --- .../tileentity/HologramRenderer.scala | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 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 2aa5889d2..62d56f46c 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 @@ -69,6 +69,24 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[(Int, In // 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) + bindTexture(Textures.blockHologram) + + // Normalize normals (yes, glScale scales them too). + GL11.glEnable(GL11.GL_NORMALIZE) + + val sx = (x + 0.5) * hologram.scale + val sy = -(y + 0.5) * hologram.scale + val sz = (z + 0.5) * hologram.scale + if (sx >= -1.5 && sx <= 1.5 && sz >= -1.5 && sz <= 1.5 && sy >= 0 && sy <= 2) { + // Camera is inside the hologram. + GL11.glDisable(GL11.GL_CULL_FACE) + } + else { + // Camera is outside the hologram. + GL11.glEnable(GL11.GL_CULL_FACE) + GL11.glCullFace(GL11.GL_BACK) + } + // 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. // When we don't do this the hologram will look different from different @@ -256,17 +274,6 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[(Int, In } private def publish(glBuffer: Int) { - bindTexture(Textures.blockHologram) - - // Normalize normals (yes, glScale scales them too). - GL11.glEnable(GL11.GL_NORMALIZE) - // evg-zhabotinsky: Because fragment processing started to slow things down - // TODO but holograms look terrible from the inside otherwise, - // and I don't see a difference in FPS anyway? Maybe a - // check for the camera position - if inside don't cull? - // GL11.glEnable(GL11.GL_CULL_FACE) - // GL11.glCullFace(GL11.GL_BACK) - GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, commonBuffer) GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY) GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY)