mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-28 07:25:35 -04:00
Merge branch 'master' of github.com:MightyPirates/OpenComputers into MC1.7
Conflicts: src/main/scala/li/cil/oc/client/renderer/tileentity/HologramRenderer.scala
This commit is contained in:
commit
2f691776ae
@ -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.
|
||||
|
@ -52,6 +52,12 @@ opencomputers {
|
||||
# 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
|
||||
|
||||
# This controls how often holograms 'flicker'. This is the chance that it
|
||||
# flickers for *each frame*, meaning if you're running at high FPS you
|
||||
# may want to lower this a bit, to avoid it flickering too much.
|
||||
|
@ -22,6 +22,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
|
||||
val hologramFlickerFrequency = config.getDouble("client.hologramFlickerFrequency") max 0
|
||||
|
||||
|
@ -160,7 +160,6 @@ object PacketHandler extends CommonPacketHandler {
|
||||
p.readTileEntity[Hologram]() match {
|
||||
case Some(t) =>
|
||||
t.scale = p.readDouble()
|
||||
t.dirty = true
|
||||
case _ => // Invalid packet.
|
||||
}
|
||||
|
||||
|
@ -8,21 +8,33 @@ 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.BufferUtils
|
||||
import li.cil.oc.Settings
|
||||
import java.nio.IntBuffer
|
||||
|
||||
object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] with RemovalListener[TileEntity, Int] {
|
||||
val random = new Random()
|
||||
object HologramRenderer extends TileEntitySpecialRenderer with Callable[(Int, IntBuffer)] with RemovalListener[TileEntity, (Int, IntBuffer)] {
|
||||
private val random = new Random()
|
||||
|
||||
/** We cache the display lists for the projectors we render for performance. */
|
||||
val cache = com.google.common.cache.CacheBuilder.newBuilder().
|
||||
expireAfterAccess(2, TimeUnit.SECONDS).
|
||||
/** We cache the VBOs for the projectors we render for performance. */
|
||||
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,10 +45,16 @@ 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 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.
|
||||
@ -48,50 +66,73 @@ 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)
|
||||
|
||||
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.
|
||||
// TODO proper transparency shader? depth peeling e.g.
|
||||
// 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 list = cache.get(hologram, this)
|
||||
compileOrDraw(list)
|
||||
draw(glBuffer, dataBuffer)
|
||||
GL11.glColorMask(true, true, true, true)
|
||||
GL11.glDepthFunc(GL11.GL_EQUAL)
|
||||
compileOrDraw(list)
|
||||
draw(glBuffer, dataBuffer)
|
||||
|
||||
GL11.glPopMatrix()
|
||||
GL11.glPopAttrib()
|
||||
GL11.glPopClientAttrib()
|
||||
|
||||
RenderState.checkError(getClass.getName + ".renderTileEntityAt: leaving")
|
||||
}
|
||||
|
||||
def compileOrDraw(list: Int) = if (hologram.dirty) {
|
||||
val doCompile = !RenderState.compilingDisplayList
|
||||
if (doCompile) {
|
||||
hologram.dirty = false
|
||||
GL11.glNewList(list, GL11.GL_COMPILE_AND_EXECUTE)
|
||||
}
|
||||
def draw(glBuffer: Int, dataBuffer: IntBuffer) {
|
||||
initialize()
|
||||
validate(glBuffer, dataBuffer)
|
||||
publish(glBuffer)
|
||||
}
|
||||
|
||||
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
|
||||
private def initialize() {
|
||||
// First run only, create structure information.
|
||||
if (commonBuffer == 0) {
|
||||
commonBuffer = GL15.glGenBuffers()
|
||||
|
||||
def isSolid(hx: Int, hy: Int, hz: Int) = value(hx, hy, hz) != 0
|
||||
|
||||
bindTexture(Textures.blockHologram)
|
||||
val t = Tessellator.instance
|
||||
t.startDrawingQuads()
|
||||
|
||||
// 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)
|
||||
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 |
|
||||
@ -103,82 +144,168 @@ object HologramRenderer extends TileEntitySpecialRenderer with Callable[Int] wit
|
||||
*/
|
||||
|
||||
// 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
|
||||
}
|
||||
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)) {
|
||||
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
|
||||
}
|
||||
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)) {
|
||||
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
|
||||
}
|
||||
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)) {
|
||||
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
|
||||
}
|
||||
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)) {
|
||||
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
|
||||
}
|
||||
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)) {
|
||||
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
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Important! OpenGL will start reading from the current buffer position.
|
||||
data.rewind()
|
||||
|
||||
// This buffer never ever changes, so static is the way to go.
|
||||
GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, commonBuffer)
|
||||
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
|
||||
}
|
||||
|
||||
t.draw()
|
||||
|
||||
if (doCompile) {
|
||||
GL11.glEndList()
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
else GL11.glCallList(list)
|
||||
|
||||
private def publish(glBuffer: Int) {
|
||||
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)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
// Cache
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
def call = {
|
||||
val list = GLAllocation.generateDisplayLists(1)
|
||||
hologram.dirty = true // Force compilation.
|
||||
list
|
||||
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]) {
|
||||
GLAllocation.deleteDisplayLists(e.getValue)
|
||||
def onRemoval(e: RemovalNotification[TileEntity, (Int, IntBuffer)]) {
|
||||
val (glBuffer, dataBuffer) = e.getValue
|
||||
GL15.glDeleteBuffers(glBuffer)
|
||||
dataBuffer.clear()
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
@ -34,6 +34,10 @@ 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, 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.
|
||||
var dirtyFromX = Int.MaxValue
|
||||
var dirtyUntilX = -1
|
||||
@ -45,7 +49,9 @@ 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
|
||||
|
||||
// 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) = {
|
||||
@ -203,7 +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()
|
||||
result(colors(index))
|
||||
// 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.""")
|
||||
@ -212,7 +219,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) = convertColor(value)
|
||||
ServerPacketSender.sendHologramColor(this, index, value)
|
||||
result(oldValue)
|
||||
}
|
||||
@ -237,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
|
||||
@ -275,6 +288,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)
|
||||
|
||||
@ -284,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")
|
||||
}
|
||||
|
||||
@ -292,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)
|
||||
}
|
||||
|
||||
@ -303,7 +317,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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user