more color screen stuff; made advanced screen 4 bit, pro screen 8 bit (which is actually pretty much for a pseudo computer in a game with 16x16 textures...); depth can be dynamically changed; colors are always provided as 32bit rgb from the lua side to make things easier, so it's ok to call these even on a color-less gpu+screen; added vertical gap between chars in char texture to avoid bleeding when interpolating due to downscaling; made some programs use colors (sh, lua and ls); screw scanlines, aliasing is too much of a pain

This commit is contained in:
Florian Nücke 2013-11-11 00:51:23 +01:00
parent 4ee76b146d
commit 0c8347df62
20 changed files with 384 additions and 156 deletions

View File

@ -13,7 +13,19 @@ for i = 1, #dirs do
if not list then if not list then
print(reason) print(reason)
else else
local function setColor(c)
if component.gpu.getForeground() ~= c then
component.gpu.setForeground(c)
end
end
for f in list do for f in list do
if f:sub(-1) == "/" then
setColor(0x99CCFF)
elseif f:sub(-4) == ".lua" then
setColor(0x00FF00)
else
setColor(0xFFFFFF)
end
if options.a or f:sub(1, 1) ~= "." then if options.a or f:sub(1, 1) ~= "." then
if options.l then if options.l then
print(f, fs.size(fs.concat(path, f))) print(f, fs.size(fs.concat(path, f)))
@ -22,6 +34,7 @@ for i = 1, #dirs do
end end
end end
end end
setColor(0xFFFFFF)
if not options.l then if not options.l then
print() print()
end end

View File

@ -2,7 +2,9 @@ print("Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio")
local history = {} local history = {}
local env = setmetatable({}, {__index=_ENV}) local env = setmetatable({}, {__index=_ENV})
while term.isAvailable() do while term.isAvailable() do
local foreground = component.gpu.setForeground(0x00FF00)
term.write("lua> ") term.write("lua> ")
component.gpu.setForeground(foreground)
local command = term.read(history) local command = term.read(history)
if command == nil then -- eof if command == nil then -- eof
return return

View File

@ -16,7 +16,9 @@ while true do
end end
end end
while term.isAvailable() do while term.isAvailable() do
local foreground = component.gpu.setForeground(0xFF0000)
term.write("# ") term.write("# ")
component.gpu.setForeground(foreground)
local command = term.read(history) local command = term.read(history)
if not command then if not command then
print("exit") print("exit")

View File

@ -4,8 +4,6 @@ local function onComponentAvailable(_, componentType)
then then
local gpu = component.primary("gpu") local gpu = component.primary("gpu")
gpu.bind(component.primary("screen").address) gpu.bind(component.primary("screen").address)
local maxX, maxY = gpu.maxResolution()
gpu.setResolution(maxX, maxY)
end end
end end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,6 +1,7 @@
package li.cil.oc package li.cil.oc
import java.io.File import java.io.File
import li.cil.oc.util.PackedColor
object Config { object Config {
val resourceDomain = "opencomputers" val resourceDomain = "opencomputers"
@ -10,6 +11,7 @@ object Config {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
val screenResolutionsByTier = Array((50, 16), (80, 25), (160, 50)) val screenResolutionsByTier = Array((50, 16), (80, 25), (160, 50))
val screenDepthsByTier = Array(PackedColor.Depth.OneBit, PackedColor.Depth.FourBit, PackedColor.Depth.EightBit)
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@ -39,6 +41,7 @@ object Config {
var maxScreenTextRenderDistance = 10.0 var maxScreenTextRenderDistance = 10.0
var screenTextFadeStartDistance = 8.0 var screenTextFadeStartDistance = 8.0
var textLinearFiltering = false
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@ -97,6 +100,15 @@ object Config {
"instantly disappear when moving away from the screen displaying it."). "instantly disappear when moving away from the screen displaying it.").
getDouble(screenTextFadeStartDistance) getDouble(screenTextFadeStartDistance)
textLinearFiltering = config.get("client", "textLinearFiltering", textLinearFiltering, "" +
"Whether to apply linear filtering for text displayed on screens when the\n" +
"screen has to be scaled down - i.e. the text is rendered at a resolution\n" +
"lower than their native one, e.g. when the GUI scale is less than one or\n" +
"when looking at a far away screen. This leads to smoother text for scaled\n" +
"down text but results in characters not perfectly connecting anymore (for\n" +
"example for box drawing characters. Look it up on Wikipedia.)").
getBoolean(textLinearFiltering)
// --------------------------------------------------------------------- // // --------------------------------------------------------------------- //
config.getCategory("power"). config.getCategory("power").

View File

@ -5,6 +5,7 @@ import li.cil.oc.common.PacketType
import li.cil.oc.common.tileentity.{PowerDistributor, Computer, Rotatable, Screen} import li.cil.oc.common.tileentity.{PowerDistributor, Computer, Rotatable, Screen}
import li.cil.oc.common.{PacketHandler => CommonPacketHandler} import li.cil.oc.common.{PacketHandler => CommonPacketHandler}
import li.cil.oc.server.component.Redstone import li.cil.oc.server.component.Redstone
import li.cil.oc.util.PackedColor
import net.minecraft.client.gui.GuiScreen import net.minecraft.client.gui.GuiScreen
import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayer
import net.minecraft.tileentity.TileEntity import net.minecraft.tileentity.TileEntity
@ -25,7 +26,9 @@ class PacketHandler extends CommonPacketHandler {
case PacketType.RedstoneStateResponse => onRedstoneStateResponse(p) case PacketType.RedstoneStateResponse => onRedstoneStateResponse(p)
case PacketType.RotatableStateResponse => onRotatableStateResponse(p) case PacketType.RotatableStateResponse => onRotatableStateResponse(p)
case PacketType.ScreenBufferResponse => onScreenBufferResponse(p) case PacketType.ScreenBufferResponse => onScreenBufferResponse(p)
case PacketType.ScreenColorChange => onScreenColorChange(p)
case PacketType.ScreenCopy => onScreenCopy(p) case PacketType.ScreenCopy => onScreenCopy(p)
case PacketType.ScreenDepthChange => onScreenDepthChange(p)
case PacketType.ScreenFill => onScreenFill(p) case PacketType.ScreenFill => onScreenFill(p)
case PacketType.ScreenResolutionChange => onScreenResolutionChange(p) case PacketType.ScreenResolutionChange => onScreenResolutionChange(p)
case PacketType.ScreenSet => onScreenSet(p) case PacketType.ScreenSet => onScreenSet(p)
@ -74,12 +77,31 @@ class PacketHandler extends CommonPacketHandler {
def onScreenBufferResponse(p: PacketParser) = def onScreenBufferResponse(p: PacketParser) =
p.readTileEntity[Screen]() match { p.readTileEntity[Screen]() match {
case Some(t) => case Some(t) =>
val screen = t.instance
val w = p.readInt() val w = p.readInt()
val h = p.readInt() val h = p.readInt()
t.instance.resolution = (w, h) screen.resolution = (w, h)
p.readUTF.split('\n').zipWithIndex.foreach { p.readUTF.split('\n').zipWithIndex.foreach {
case (line, i) => t.instance.set(0, i, line) case (line, i) => screen.set(0, i, line)
} }
screen.depth = PackedColor.Depth(p.readInt())
screen.foreground = p.readInt()
screen.background = p.readInt()
for (row <- 0 until h) {
val rowColor = screen.colors(row)
for (col <- 0 until w) {
rowColor(col) = p.readShort()
}
}
case _ => // Invalid packet.
}
def onScreenColorChange(p: PacketParser) =
p.readTileEntity[Screen]() match {
case Some(t) => {
t.instance.foreground = p.readInt()
t.instance.background = p.readInt()
}
case _ => // Invalid packet. case _ => // Invalid packet.
} }
@ -97,6 +119,14 @@ class PacketHandler extends CommonPacketHandler {
case _ => // Invalid packet. case _ => // Invalid packet.
} }
def onScreenDepthChange(p: PacketParser) =
p.readTileEntity[Screen]() match {
case Some(t) => {
t.instance.depth = PackedColor.Depth(p.readInt())
}
case _ => // Invalid packet.
}
def onScreenFill(p: PacketParser) = def onScreenFill(p: PacketParser) =
p.readTileEntity[Screen]() match { p.readTileEntity[Screen]() match {
case Some(t) => { case Some(t) => {

View File

@ -4,6 +4,7 @@ import li.cil.oc.Config
import li.cil.oc.client.PacketSender import li.cil.oc.client.PacketSender
import li.cil.oc.client.renderer.MonospaceFontRenderer import li.cil.oc.client.renderer.MonospaceFontRenderer
import li.cil.oc.common.tileentity import li.cil.oc.common.tileentity
import li.cil.oc.util.PackedColor
import net.minecraft.client.gui.{GuiScreen => MCGuiScreen} import net.minecraft.client.gui.{GuiScreen => MCGuiScreen}
import net.minecraft.client.renderer.GLAllocation import net.minecraft.client.renderer.GLAllocation
import net.minecraft.client.renderer.Tessellator import net.minecraft.client.renderer.Tessellator
@ -12,7 +13,6 @@ import net.minecraft.util.ResourceLocation
import org.lwjgl.input.Keyboard import org.lwjgl.input.Keyboard
import org.lwjgl.opengl.GL11 import org.lwjgl.opengl.GL11
import scala.collection.mutable import scala.collection.mutable
import li.cil.oc.util.PackedColor
/** /**
* This GUI shows the buffer of a single screen. * This GUI shows the buffer of a single screen.
@ -184,9 +184,11 @@ object Screen {
GL11.glEndList() GL11.glEndList()
} }
private[gui] def compileText(scale: Double, lines: Array[Array[Char]], colors:Array[Array[Int]], depth: PackedColor.Depth.Value) = private[gui] def compileText(scale: Double, lines: Array[Array[Char]], colors: Array[Array[Short]], depth: PackedColor.Depth.Value) =
if (textureManager.isDefined) { if (textureManager.isDefined) {
GL11.glNewList(displayLists.get + 1, GL11.GL_COMPILE) GL11.glNewList(displayLists.get + 1, GL11.GL_COMPILE)
GL11.glPushAttrib(GL11.GL_DEPTH_BUFFER_BIT)
GL11.glDepthMask(false)
GL11.glTranslatef(margin + innerMargin, margin + innerMargin, 0) GL11.glTranslatef(margin + innerMargin, margin + innerMargin, 0)
GL11.glScaled(scale, scale, 1) GL11.glScaled(scale, scale, 1)
@ -194,6 +196,7 @@ object Screen {
case ((line, color), i) => MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, line, color, depth) case ((line, color), i) => MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, line, color, depth)
} }
GL11.glPopAttrib()
GL11.glEndList() GL11.glEndList()
} }

View File

@ -1,6 +1,6 @@
package li.cil.oc.client.renderer package li.cil.oc.client.renderer
import li.cil.oc.util.{RenderState, PackedColor} import li.cil.oc.util.PackedColor
import li.cil.oc.{OpenComputers, Config} import li.cil.oc.{OpenComputers, Config}
import net.minecraft.client.renderer.GLAllocation import net.minecraft.client.renderer.GLAllocation
import net.minecraft.client.renderer.Tessellator import net.minecraft.client.renderer.Tessellator
@ -10,7 +10,7 @@ import org.lwjgl.opengl.GL11
import scala.io.Source import scala.io.Source
object MonospaceFontRenderer { object MonospaceFontRenderer {
private val font = new ResourceLocation(Config.resourceDomain, "textures/font/chars.png") val font = new ResourceLocation(Config.resourceDomain, "textures/font/chars.png")
private val chars = Source.fromInputStream(MonospaceFontRenderer.getClass.getResourceAsStream("/assets/" + Config.resourceDomain + "/textures/font/chars.txt")).mkString private val chars = Source.fromInputStream(MonospaceFontRenderer.getClass.getResourceAsStream("/assets/" + Config.resourceDomain + "/textures/font/chars.txt")).mkString
@ -21,7 +21,7 @@ object MonospaceFontRenderer {
val (fontWidth, fontHeight) = (5, 9) val (fontWidth, fontHeight) = (5, 9)
def drawString(x: Int, y: Int, value: Array[Char], color: Array[Int], depth: PackedColor.Depth.Value) = instance match { def drawString(x: Int, y: Int, value: Array[Char], color: Array[Short], depth: PackedColor.Depth.Value) = instance match {
case None => OpenComputers.log.warning("Trying to render string with uninitialized MonospaceFontRenderer.") case None => OpenComputers.log.warning("Trying to render string with uninitialized MonospaceFontRenderer.")
case Some(renderer) => renderer.drawString(x, y, value, color, depth) case Some(renderer) => renderer.drawString(x, y, value, color, depth)
} }
@ -36,7 +36,9 @@ object MonospaceFontRenderer {
private val (charWidth, charHeight) = (MonospaceFontRenderer.fontWidth * 2, MonospaceFontRenderer.fontHeight * 2) private val (charWidth, charHeight) = (MonospaceFontRenderer.fontWidth * 2, MonospaceFontRenderer.fontHeight * 2)
private val cols = 256 / charWidth private val cols = 256 / charWidth
private val uStep = charWidth / 256.0 private val uStep = charWidth / 256.0
private val vStep = charHeight / 256.0 private val uSize = uStep
private val vStep = (charHeight + 1) / 256.0
private val vSize = charHeight / 256.0
// Set up the display lists. // Set up the display lists.
{ {
@ -49,9 +51,9 @@ object MonospaceFontRenderer {
val v = y * vStep val v = y * vStep
GL11.glNewList(charLists + index, GL11.GL_COMPILE) GL11.glNewList(charLists + index, GL11.GL_COMPILE)
t.startDrawingQuads() t.startDrawingQuads()
t.addVertexWithUV(0, charHeight, 0, u, v + vStep) t.addVertexWithUV(0, charHeight, 0, u, v + vSize)
t.addVertexWithUV(charWidth, charHeight, 0, u + uStep, v + vStep) t.addVertexWithUV(charWidth, charHeight, 0, u + uSize, v + vSize)
t.addVertexWithUV(charWidth, 0, 0, u + uStep, v) t.addVertexWithUV(charWidth, 0, 0, u + uSize, v)
t.addVertexWithUV(0, 0, 0, u, v) t.addVertexWithUV(0, 0, 0, u, v)
t.draw() t.draw()
GL11.glTranslatef(charWidth, 0, 0) GL11.glTranslatef(charWidth, 0, 0)
@ -63,35 +65,39 @@ object MonospaceFontRenderer {
GL11.glEndList() GL11.glEndList()
} }
def drawString(x: Int, y: Int, value: Array[Char], color: Array[Int], depth: PackedColor.Depth.Value) = { def drawString(x: Int, y: Int, value: Array[Char], color: Array[Short], depth: PackedColor.Depth.Value) = {
if (color.length != value.length) throw new IllegalArgumentException("Color count must match char count.") if (color.length != value.length) throw new IllegalArgumentException("Color count must match char count.")
textureManager.bindTexture(MonospaceFontRenderer.font) textureManager.bindTexture(MonospaceFontRenderer.font)
GL11.glPushMatrix() GL11.glPushMatrix()
GL11.glPushAttrib(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT) GL11.glPushAttrib(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_TEXTURE_BIT)
GL11.glTranslatef(x, y, 0) GL11.glTranslatef(x, y, 0)
GL11.glScalef(0.5f, 0.5f, 1) GL11.glScalef(0.5f, 0.5f, 1)
GL11.glDepthMask(false) GL11.glDepthMask(false)
RenderState.makeItBlend()
// Background first. We try to merge adjacent backgrounds of the same // Background first. We try to merge adjacent backgrounds of the same
// color to reduce the number of quads we have to draw. // color to reduce the number of quads we have to draw.
var cbg = 0x000000 var cbg = 0x000000
var offset = 0
var width = 0 var width = 0
for (col <- color.map(PackedColor.unpackBackground(_, depth))) { for (col <- color.map(PackedColor.unpackBackground(_, depth))) {
if (col != cbg) { if (col != cbg) {
draw(cbg, width) draw(cbg, offset, width)
cbg = col cbg = col
offset += width
width = 0 width = 0
} }
width = width + 1 width = width + 1
} }
draw(cbg, width) draw(cbg, offset, width)
if (Config.textLinearFiltering) {
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR)
}
// Foreground second. We only have to flush when the color changes, so // Foreground second. We only have to flush when the color changes, so
// unless every char has a different color this should be quite efficient. // unless every char has a different color this should be quite efficient.
var cfg = 0x000000 var cfg = -1
GL11.glColor3f(0, 0, 0)
for ((ch, col) <- value.zip(color.map(PackedColor.unpackForeground(_, depth)))) { for ((ch, col) <- value.zip(color.map(PackedColor.unpackForeground(_, depth)))) {
val index = 1 + chars.indexOf(ch) match { val index = 1 + chars.indexOf(ch) match {
case -1 => chars.indexOf('?') case -1 => chars.indexOf('?')
@ -102,9 +108,9 @@ object MonospaceFontRenderer {
flush() flush()
cfg = col cfg = col
GL11.glColor3ub( GL11.glColor3ub(
(cfg & 0xFF0000 >> 16).toByte, ((cfg & 0xFF0000) >> 16).toByte,
(cfg & 0x00FF00 >> 8).toByte, ((cfg & 0x00FF00) >> 8).toByte,
(cfg & 0x0000FF).toByte) ((cfg & 0x0000FF) >> 0).toByte)
} }
listBuffer.put(charLists + index) listBuffer.put(charLists + index)
if (listBuffer.remaining == 0) if (listBuffer.remaining == 0)
@ -116,18 +122,23 @@ object MonospaceFontRenderer {
GL11.glPopMatrix() GL11.glPopMatrix()
} }
private def draw(color: Int, width: Int) = if (color != 0 && width > 0) { private val bgu1 = 254.0 / 256.0
private val bgu2 = 255.0 / 256.0
private val bgv1 = 255.0 / 256.0
private val bgv2 = 256.0 / 256.0
private def draw(color: Int, offset: Int, width: Int) = if (color != 0 && width > 0) {
val t = Tessellator.instance val t = Tessellator.instance
t.startDrawingQuads() t.startDrawingQuads()
t.setColorOpaque_I(color) t.setColorOpaque_I(color)
t.addVertexWithUV(0, charHeight, 0, 0, vStep) t.addVertexWithUV(charWidth * offset, charHeight, 0, bgu1, bgv2)
t.addVertexWithUV(charWidth, charHeight, 0, width * uStep, vStep) t.addVertexWithUV(charWidth * (offset + width), charHeight, 0, bgu2, bgv2)
t.addVertexWithUV(charWidth, 0, 0, width * uStep, 0) t.addVertexWithUV(charWidth * (offset + width), 0, 0, bgu2, bgv1)
t.addVertexWithUV(0, 0, 0, 0, 0) t.addVertexWithUV(charWidth * offset, 0, 0, bgu1, bgv1)
t.draw() t.draw()
} }
private def flush() = { private def flush() = if (listBuffer.position > 0) {
listBuffer.flip() listBuffer.flip()
GL11.glCallLists(listBuffer) GL11.glCallLists(listBuffer)
listBuffer.clear() listBuffer.clear()

View File

@ -34,7 +34,9 @@ object PacketType extends Enumeration {
val ScreenBufferResponse = Value("ScreenBufferResponse") val ScreenBufferResponse = Value("ScreenBufferResponse")
/** These are sent from the server to the client for partial updates. */ /** These are sent from the server to the client for partial updates. */
val ScreenColorChange = Value("ScreenColorChange")
val ScreenCopy = Value("ScreenCopy") val ScreenCopy = Value("ScreenCopy")
val ScreenDepthChange = Value("ScreenDepthChange")
val ScreenFill = Value("ScreenFill") val ScreenFill = Value("ScreenFill")
val ScreenResolutionChange = Value("ScreenResolutionChange") val ScreenResolutionChange = Value("ScreenResolutionChange")
val ScreenSet = Value("ScreenSet") val ScreenSet = Value("ScreenSet")

View File

@ -7,7 +7,7 @@ import li.cil.oc.util.{PackedColor, TextBuffer}
import li.cil.oc.{Config, util, api} import li.cil.oc.{Config, util, api}
import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagCompound
class Screen(val owner: Screen.Environment, val maxResolution: (Int, Int)) extends Persistable { class Screen(val owner: Screen.Environment, val maxResolution: (Int, Int), val maxDepth: PackedColor.Depth.Value) extends Persistable {
private val buffer = new TextBuffer(maxResolution, PackedColor.Depth.OneBit) private val buffer = new TextBuffer(maxResolution, PackedColor.Depth.OneBit)
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@ -20,12 +20,48 @@ class Screen(val owner: Screen.Environment, val maxResolution: (Int, Int)) exten
def depth = buffer.depth def depth = buffer.depth
def depth_=(value: PackedColor.Depth.Value) = {
if (value > maxDepth)
throw new IllegalArgumentException("unsupported depth")
if (buffer.depth = value) {
owner.onScreenDepthChange(value)
true
}
else false
}
def foreground = buffer.foreground
def foreground_=(value: Int) = {
if (buffer.foreground != value) {
val result = buffer.foreground
buffer.foreground = value
owner.onScreenColorChange(foreground, background)
result
}
else value
}
def background = buffer.background
def background_=(value: Int) = {
if (buffer.background != value) {
val result = buffer.background
buffer.background = value
owner.onScreenColorChange(foreground, background)
result
}
else value
}
def resolution = buffer.size def resolution = buffer.size
def resolution_=(value: (Int, Int)) = { def resolution_=(value: (Int, Int)) = {
val (w, h) = value val (w, h) = value
val (mw, mh) = maxResolution val (mw, mh) = maxResolution
if (w <= mw && h <= mh && (buffer.size = value)) { if (w < 1 || w > mw || h < 1 || h > mh)
throw new IllegalArgumentException("unsupported resolution")
if (buffer.size = value) {
owner.onScreenResolutionChange(w, h) owner.onScreenResolutionChange(w, h)
true true
} }
@ -58,12 +94,12 @@ class Screen(val owner: Screen.Environment, val maxResolution: (Int, Int)) exten
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override def load(nbt: NBTTagCompound) = { override def load(nbt: NBTTagCompound) = {
buffer.readFromNBT(nbt.getCompoundTag("oc.screen")) buffer.load(nbt.getCompoundTag("oc.screen"))
} }
override def save(nbt: NBTTagCompound) = { override def save(nbt: NBTTagCompound) = {
val screenNbt = new NBTTagCompound val screenNbt = new NBTTagCompound
buffer.writeToNBT(screenNbt) buffer.save(screenNbt)
nbt.setCompoundTag("oc.screen", screenNbt) nbt.setCompoundTag("oc.screen", screenNbt)
} }
@ -81,7 +117,7 @@ object Screen {
withConnector(Config.bufferScreen * (tier + 1)). withConnector(Config.bufferScreen * (tier + 1)).
create() create()
final val instance = new component.Screen(this, Config.screenResolutionsByTier(tier)) final val instance = new component.Screen(this, Config.screenResolutionsByTier(tier), Config.screenDepthsByTier(tier))
protected def tier: Int protected def tier: Int
@ -101,8 +137,12 @@ object Screen {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
def onScreenColorChange(foreground: Int, background: Int) {}
def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) {} def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) {}
def onScreenDepthChange(depth: PackedColor.Depth.Value) {}
def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) {} def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) {}
def onScreenResolutionChange(w: Int, h: Int) { def onScreenResolutionChange(w: Int, h: Int) {

View File

@ -8,6 +8,8 @@ class GraphicsCard(val parent: Delegator, val tier: Int) extends Delegate {
val maxResolution = Config.screenResolutionsByTier(tier) val maxResolution = Config.screenResolutionsByTier(tier)
val maxDepth = Config.screenDepthsByTier(tier)
override def registerIcons(iconRegister: IconRegister) { override def registerIcons(iconRegister: IconRegister) {
super.registerIcons(iconRegister) super.registerIcons(iconRegister)

View File

@ -7,11 +7,12 @@ import li.cil.oc.client.gui
import li.cil.oc.client.{PacketSender => ClientPacketSender} import li.cil.oc.client.{PacketSender => ClientPacketSender}
import li.cil.oc.common.component.Screen.{Environment => ScreenEnvironment} import li.cil.oc.common.component.Screen.{Environment => ScreenEnvironment}
import li.cil.oc.server.{PacketSender => ServerPacketSender} import li.cil.oc.server.{PacketSender => ServerPacketSender}
import li.cil.oc.util.PackedColor
import net.minecraft.client.Minecraft
import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.AxisAlignedBB import net.minecraft.util.AxisAlignedBB
import net.minecraftforge.common.ForgeDirection import net.minecraftforge.common.ForgeDirection
import scala.collection.mutable import scala.collection.mutable
import net.minecraft.client.Minecraft
class ScreenTier1 extends Screen { class ScreenTier1 extends Screen {
protected def tier = 0 protected def tier = 0
@ -225,6 +226,46 @@ abstract class Screen extends Rotatable with ScreenEnvironment {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
override def onScreenColorChange(foreground: Int, background: Int) {
super.onScreenColorChange(foreground, background)
if (!worldObj.isRemote) {
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
ServerPacketSender.sendScreenColorChange(this, foreground, background)
}
}
override def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) = {
super.onScreenCopy(col, row, w, h, tx, ty)
if (worldObj.isRemote) {
currentGui.foreach(_.updateText())
hasChanged = true
}
else {
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
ServerPacketSender.sendScreenCopy(this, col, row, w, h, tx, ty)
}
}
override def onScreenDepthChange(depth: PackedColor.Depth.Value) {
super.onScreenDepthChange(depth)
if (!worldObj.isRemote) {
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
ServerPacketSender.sendScreenDepthChange(this, depth)
}
}
override def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) = {
super.onScreenFill(col, row, w, h, c)
if (worldObj.isRemote) {
currentGui.foreach(_.updateText())
hasChanged = true
}
else {
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
ServerPacketSender.sendScreenFill(this, col, row, w, h, c)
}
}
override def onScreenResolutionChange(w: Int, h: Int) = { override def onScreenResolutionChange(w: Int, h: Int) = {
super.onScreenResolutionChange(w, h) super.onScreenResolutionChange(w, h)
if (worldObj.isRemote) { if (worldObj.isRemote) {
@ -248,28 +289,4 @@ abstract class Screen extends Rotatable with ScreenEnvironment {
ServerPacketSender.sendScreenSet(this, col, row, s) ServerPacketSender.sendScreenSet(this, col, row, s)
} }
} }
override def onScreenFill(col: Int, row: Int, w: Int, h: Int, c: Char) = {
super.onScreenFill(col, row, w, h, c)
if (worldObj.isRemote) {
currentGui.foreach(_.updateText())
hasChanged = true
}
else {
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
ServerPacketSender.sendScreenFill(this, col, row, w, h, c)
}
}
override def onScreenCopy(col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) = {
super.onScreenCopy(col, row, w, h, tx, ty)
if (worldObj.isRemote) {
currentGui.foreach(_.updateText())
hasChanged = true
}
else {
worldObj.markTileEntityChunkModified(xCoord, yCoord, zCoord, this)
ServerPacketSender.sendScreenCopy(this, col, row, w, h, tx, ty)
}
}
} }

View File

@ -52,9 +52,7 @@ class PacketHandler extends CommonPacketHandler {
def onScreenBufferRequest(p: PacketParser) = def onScreenBufferRequest(p: PacketParser) =
p.readTileEntity[tileentity.Screen]() match { p.readTileEntity[tileentity.Screen]() match {
case Some(t) => case Some(t) => PacketSender.sendScreenBufferState(t, Option(p.player))
val (w, h) = t.instance.resolution
PacketSender.sendScreenBufferState(t, w, h, t.instance.text, Option(p.player))
case _ => // Invalid packet. case _ => // Invalid packet.
} }

View File

@ -3,8 +3,10 @@ package li.cil.oc.server
import cpw.mods.fml.common.network.Player import cpw.mods.fml.common.network.Player
import li.cil.oc.common.PacketBuilder import li.cil.oc.common.PacketBuilder
import li.cil.oc.common.PacketType import li.cil.oc.common.PacketType
import li.cil.oc.common.component.Screen
import li.cil.oc.common.tileentity.{PowerDistributor, Rotatable} import li.cil.oc.common.tileentity.{PowerDistributor, Rotatable}
import li.cil.oc.server.component.Redstone import li.cil.oc.server.component.Redstone
import li.cil.oc.util.PackedColor
import net.minecraft.tileentity.TileEntity import net.minecraft.tileentity.TileEntity
import net.minecraftforge.common.ForgeDirection import net.minecraftforge.common.ForgeDirection
@ -70,13 +72,20 @@ object PacketSender {
} }
} }
def sendScreenBufferState(t: TileEntity, w: Int, h: Int, text: String, player: Option[Player] = None) { def sendScreenBufferState(t: TileEntity with Screen.Environment, player: Option[Player] = None) {
val pb = new PacketBuilder(PacketType.ScreenBufferResponse) val pb = new PacketBuilder(PacketType.ScreenBufferResponse)
pb.writeTileEntity(t) pb.writeTileEntity(t)
val screen = t.instance
val (w, h) = screen.resolution
pb.writeInt(w) pb.writeInt(w)
pb.writeInt(h) pb.writeInt(h)
pb.writeUTF(text) pb.writeUTF(screen.text)
pb.writeInt(screen.depth.id)
pb.writeInt(screen.foreground)
pb.writeInt(screen.background)
for (cs <- screen.colors) for (c <- cs) pb.writeShort(c)
player match { player match {
case Some(p) => pb.sendToPlayer(p) case Some(p) => pb.sendToPlayer(p)
@ -84,6 +93,16 @@ object PacketSender {
} }
} }
def sendScreenColorChange(t: TileEntity, foreground: Int, background: Int) {
val pb = new PacketBuilder(PacketType.ScreenColorChange)
pb.writeTileEntity(t)
pb.writeInt(foreground)
pb.writeInt(background)
pb.sendToAllPlayers()
}
def sendScreenCopy(t: TileEntity, col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) { def sendScreenCopy(t: TileEntity, col: Int, row: Int, w: Int, h: Int, tx: Int, ty: Int) {
val pb = new PacketBuilder(PacketType.ScreenCopy) val pb = new PacketBuilder(PacketType.ScreenCopy)
@ -98,6 +117,15 @@ object PacketSender {
pb.sendToAllPlayers() pb.sendToAllPlayers()
} }
def sendScreenDepthChange(t: TileEntity, value: PackedColor.Depth.Value) {
val pb = new PacketBuilder(PacketType.ScreenDepthChange)
pb.writeTileEntity(t)
pb.writeInt(value.id)
pb.sendToAllPlayers()
}
def sendScreenFill(t: TileEntity, col: Int, row: Int, w: Int, h: Int, c: Char) { def sendScreenFill(t: TileEntity, col: Int, row: Int, w: Int, h: Int, c: Char) {
val pb = new PacketBuilder(PacketType.ScreenFill) val pb = new PacketBuilder(PacketType.ScreenFill)

View File

@ -3,10 +3,11 @@ package li.cil.oc.server.component
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.api.network._ import li.cil.oc.api.network._
import li.cil.oc.common.component.Screen import li.cil.oc.common.component.Screen
import li.cil.oc.util.PackedColor
import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagCompound
import scala.Some import scala.Some
class GraphicsCard(val maxResolution: (Int, Int)) extends ManagedComponent { class GraphicsCard(val maxResolution: (Int, Int), val maxDepth: PackedColor.Depth.Value) extends ManagedComponent {
val node = api.Network.newNode(this, Visibility.Neighbors). val node = api.Network.newNode(this, Visibility.Neighbors).
withComponent("gpu"). withComponent("gpu").
create() create()
@ -15,7 +16,7 @@ class GraphicsCard(val maxResolution: (Int, Int)) extends ManagedComponent {
private var screenInstance: Option[Screen] = None private var screenInstance: Option[Screen] = None
private def screen(f: (Screen) => Array[AnyRef]) = { private def screen(f: (Screen) => Array[AnyRef]) = this.synchronized {
if (screenInstance.isEmpty && screenAddress.isDefined) { if (screenInstance.isEmpty && screenAddress.isDefined) {
Option(node.network.node(screenAddress.get)) match { Option(node.network.node(screenAddress.get)) match {
case Some(node: Node) if node.host.isInstanceOf[Screen.Environment] => case Some(node: Node) if node.host.isInstanceOf[Screen.Environment] =>
@ -38,18 +39,73 @@ class GraphicsCard(val maxResolution: (Int, Int)) extends ManagedComponent {
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //
@LuaCallback("bind") @LuaCallback("bind")
def bind(context: Context, args: Arguments): Array[AnyRef] = { def bind(context: Context, args: Arguments): Array[AnyRef] = this.synchronized {
val address = args.checkString(0) val address = args.checkString(0)
node.network.node(address) match { node.network.node(address) match {
case null => Array(Unit, "invalid address") case null => Array(Unit, "invalid address")
case node: Node if node.host.isInstanceOf[Screen.Environment] => case node: Node if node.host.isInstanceOf[Screen.Environment] =>
screenAddress = Option(address) screenAddress = Option(address)
screenInstance = None screenInstance = None
result(true) screen(s => {
val (gmw, gmh) = maxResolution
val (smw, smh) = s.maxResolution
s.resolution = (gmw min smw, gmh min smh)
s.depth = PackedColor.Depth(maxDepth.id min s.maxDepth.id)
s.foreground = 0xFFFFFF
s.background = 0x000000
result(true)
})
case _ => Array(Unit, "not a screen") case _ => Array(Unit, "not a screen")
} }
} }
@LuaCallback(value = "getBackground", direct = true)
def getBackground(context: Context, args: Arguments): Array[AnyRef] =
screen(s => result(s.background))
@LuaCallback("setBackground")
def setBackground(context: Context, args: Arguments): Array[AnyRef] = {
val color = args.checkInteger(0)
screen(s => result(s.background = color))
}
@LuaCallback(value = "getForeground", direct = true)
def getForeground(context: Context, args: Arguments): Array[AnyRef] =
screen(s => result(s.foreground))
@LuaCallback("setForeground")
def setForeground(context: Context, args: Arguments): Array[AnyRef] = {
val color = args.checkInteger(0)
screen(s => result(s.foreground = color))
}
@LuaCallback(value = "getDepth", direct = true)
def getDepth(context: Context, args: Arguments): Array[AnyRef] =
screen(s => result(s.depth match {
case PackedColor.Depth.OneBit => 1
case PackedColor.Depth.FourBit => 4
case PackedColor.Depth.EightBit => 8
}))
@LuaCallback("setDepth")
def setDepth(context: Context, args: Arguments): Array[AnyRef] = {
val depth = args.checkInteger(0)
screen(s => result(s.depth = depth match {
case 1 => PackedColor.Depth.OneBit
case 4 if maxDepth >= PackedColor.Depth.FourBit => PackedColor.Depth.FourBit
case 8 if maxDepth >= PackedColor.Depth.EightBit => PackedColor.Depth.EightBit
case _ => throw new IllegalArgumentException("unsupported depth")
}))
}
@LuaCallback(value = "maxDepth", direct = true)
def maxDepth(context: Context, args: Arguments): Array[AnyRef] =
screen(s => result(PackedColor.Depth(maxDepth.id min s.maxDepth.id) match {
case PackedColor.Depth.OneBit => 1
case PackedColor.Depth.FourBit => 4
case PackedColor.Depth.EightBit => 8
}))
@LuaCallback(value = "getResolution", direct = true) @LuaCallback(value = "getResolution", direct = true)
def getResolution(context: Context, args: Arguments): Array[AnyRef] = def getResolution(context: Context, args: Arguments): Array[AnyRef] =
screen(s => { screen(s => {
@ -62,10 +118,8 @@ class GraphicsCard(val maxResolution: (Int, Int)) extends ManagedComponent {
val w = args.checkInteger(0) val w = args.checkInteger(0)
val h = args.checkInteger(1) val h = args.checkInteger(1)
val (mw, mh) = maxResolution val (mw, mh) = maxResolution
if (w > 0 && h > 0 && w <= mw && h <= mh) if (w > 0 && h > 0 && w <= mw && h <= mh) screen(s => result(s.resolution = (w, h)))
screen(s => result(s.resolution = (w, h))) else throw new IllegalArgumentException("unsupported resolution")
else
Array(Unit, "unsupported resolution")
} }
@LuaCallback(value = "maxResolution", direct = true) @LuaCallback(value = "maxResolution", direct = true)

View File

@ -12,7 +12,7 @@ object GraphicsCard extends Item {
override def createEnvironment(item: ItemStack, container: AnyRef) = override def createEnvironment(item: ItemStack, container: AnyRef) =
Items.multi.subItem(item) match { Items.multi.subItem(item) match {
case Some(gpu: common.item.GraphicsCard) => case Some(gpu: common.item.GraphicsCard) =>
new component.GraphicsCard(gpu.maxResolution) new component.GraphicsCard(gpu.maxResolution, gpu.maxDepth)
case _ => null case _ => null
} }

View File

@ -3,7 +3,7 @@ package li.cil.oc.util
object PackedColor { object PackedColor {
object Depth extends Enumeration { object Depth extends Enumeration {
val OneBit, EightBit, SixteenBit = Value val OneBit, FourBit, EightBit = Value
} }
private val rMask32 = 0xFF0000 private val rMask32 = 0xFF0000
@ -13,88 +13,65 @@ object PackedColor {
private val gShift32 = 8 private val gShift32 = 8
private val bShift32 = 0 private val bShift32 = 0
// 7 6 5 4 3 2 1 0 private abstract class ColorFormat {
// r r r g g g b b : 3.3.2 def inflate(value: Int): Int
private val rMask8 = Integer.parseInt("11100000", 2)
private val gMask8 = Integer.parseInt("00011100", 2)
private val bMask8 = Integer.parseInt("00000011", 2)
private val rShift8 = 5
private val gShift8 = 2
private val bShift8 = 0
private val rScale8 = 255.0 / 0x7
private val gScale8 = 255.0 / 0x7
private val bScale8 = 255.0 / 0x3
// 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 def deflate(value: Int): Int
// r r r r r g g g g g g b b b b b : 5.6.5
private val rMask16 = Integer.parseInt("1111100000000000", 2)
private val gMask16 = Integer.parseInt("0000011111100000", 2)
private val bMask16 = Integer.parseInt("0000000000011111", 2)
private val rShift16 = 11
private val gShift16 = 5
private val bShift16 = 0
private val rScale16 = 255.0 / 0x1F
private val gScale16 = 255.0 / 0x3F
private val bScale16 = 255.0 / 0x1F
private def extractFrom1Bit(c: Short) = if (c == 0) 0x000000 else 0xFFFFFF
private def compressTo1Bit(c: Int) = (if (c == 0) 0 else 1).toShort
private def extractFrom8Bit(c: Short) = {
val r = ((((c & rMask8) >>> rShift8) * rScale8).toInt << rShift32) & rMask32
val g = ((((c & gMask8) >>> gShift8) * gScale8).toInt << gShift32) & gMask32
val b = ((((c & bMask8) >>> bShift8) * bScale8).toInt << bShift32) & bMask32
r | g | b
} }
private def compressTo8Bit(c: Int) = { private class SingleBitFormat extends ColorFormat {
val r = ((((c & rMask32) >>> rShift32) / rScale8).toInt << rShift8) & rMask8 def inflate(value: Int) = if (value == 0) 0x000000 else 0xFFFFFF
val g = ((((c & gMask32) >>> gShift32) / gScale8).toInt << gShift8) & gMask8
val b = ((((c & bMask32) >>> bShift32) / bScale8).toInt << bShift8) & bMask8 def deflate(value: Int) = if (value == 0) 0 else 1
(r | g | b).toShort
} }
private def extractFrom16Bit(c: Short) = { private class MultiBitFormat(rBits: Int, gBits: Int, bBits: Int) extends ColorFormat {
val r = ((((c & rMask16) >>> rShift16) * rScale16).toInt << rShift32) & rMask32 def mask(nBits: Int) = 0xFFFFFFFF >>> (32 - nBits)
val g = ((((c & gMask16) >>> gShift16) * gScale16).toInt << gShift32) & gMask32
val b = ((((c & bMask16) >>> bShift16) * bScale16).toInt << bShift32) & bMask32
r | g | b
}
private def compressTo16Bit(c: Int) = { private val bShift = 0
val r = ((((c & rMask32) >>> rShift32) / rScale16).toInt << rShift16) & rMask16 private val gShift = bBits
val g = ((((c & gMask32) >>> gShift32) / gScale16).toInt << gShift16) & gMask16 private val rShift = gShift + gBits
val b = ((((c & bMask32) >>> bShift32) / bScale16).toInt << bShift16) & bMask16
(r | g | b).toShort
}
// Colors are packed: 0xFFFFBBBB (F = foreground, B = background) private val bMask = mask(bBits) << bShift
private val fgShift = 16 private val gMask = mask(gBits) << gShift
private val bgShift = 0 private val rMask = mask(rBits) << rShift
def pack(foreground: Int, background: Int, depth: Depth.Value) = private val bScale = 255.0 / ((1 << bBits) - 1)
depth match { private val gScale = 255.0 / ((1 << gBits) - 1)
case Depth.OneBit => (compressTo1Bit(foreground) << fgShift) | (compressTo1Bit(background) << bgShift) private val rScale = 255.0 / ((1 << rBits) - 1)
case Depth.EightBit => (compressTo8Bit(foreground) << fgShift) | (compressTo8Bit(background) << bgShift)
case Depth.SixteenBit => (compressTo16Bit(foreground) << fgShift) | (compressTo16Bit(background) << bgShift) def inflate(value: Int) = {
val r = ((((value & rMask) >>> rShift) * rScale).toInt << rShift32) & rMask32
val g = ((((value & gMask) >>> gShift) * gScale).toInt << gShift32) & gMask32
val b = ((((value & bMask) >>> bShift) * bScale).toInt << bShift32) & bMask32
r | g | b
} }
def unpackForeground(color: Int, depth: Depth.Value) = { def deflate(value: Int) = {
val c = (color >>> fgShift).toShort val r = ((((value & rMask32) >>> rShift32) / rScale).toInt << rShift) & rMask
depth match { val g = ((((value & gMask32) >>> gShift32) / gScale).toInt << gShift) & gMask
case Depth.OneBit => extractFrom1Bit(c) val b = ((((value & bMask32) >>> bShift32) / bScale).toInt << bShift) & bMask
case Depth.EightBit => extractFrom8Bit(c) r | g | b
case Depth.SixteenBit => extractFrom16Bit(c)
} }
} }
def unpackBackground(color: Int, depth: Depth.Value) = { private val formats = Map(
val c = (color >>> bgShift).toShort Depth.OneBit -> new SingleBitFormat(),
depth match { Depth.FourBit -> new MultiBitFormat(1, 2, 1),
case Depth.OneBit => extractFrom1Bit(c) Depth.EightBit -> new MultiBitFormat(3, 3, 2))
case Depth.EightBit => extractFrom8Bit(c)
case Depth.SixteenBit => extractFrom16Bit(c) // Colors are packed: 0xFFBB (F = foreground, B = background)
} private val fgShift = 8
private val bgMask = 0x000000FF
def pack(foreground: Int, background: Int, depth: Depth.Value) = {
val format = formats(depth)
((format.deflate(foreground) << fgShift) | format.deflate(background)).toShort
} }
def unpackForeground(color: Short, depth: Depth.Value) =
formats(depth).inflate((color & 0xFFFF) >>> fgShift)
def unpackBackground(color: Short, depth: Depth.Value) =
formats(depth).inflate(color & bgMask)
} }

View File

@ -24,7 +24,7 @@ object RenderState {
def makeItBlend() { def makeItBlend() {
GL11.glEnable(GL11.GL_BLEND) GL11.glEnable(GL11.GL_BLEND)
GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_COLOR) GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA)
GL11.glDepthFunc(GL11.GL_LEQUAL) GL11.glDepthFunc(GL11.GL_LEQUAL)
} }

View File

@ -1,6 +1,6 @@
package li.cil.oc.util package li.cil.oc.util
import net.minecraft.nbt.{NBTTagIntArray, NBTTagCompound, NBTTagList, NBTTagString} import net.minecraft.nbt._
/** /**
* This stores chars in a 2D-Array and provides some manipulation functions. * This stores chars in a 2D-Array and provides some manipulation functions.
@ -10,27 +10,49 @@ import net.minecraft.nbt.{NBTTagIntArray, NBTTagCompound, NBTTagList, NBTTagStri
* relatively fast updates, given a smart algorithm (using copy()/fill() * relatively fast updates, given a smart algorithm (using copy()/fill()
* instead of set()ing everything). * instead of set()ing everything).
*/ */
class TextBuffer(var width: Int, var height: Int, val depth: PackedColor.Depth.Value) { class TextBuffer(var width: Int, var height: Int, initialDepth: PackedColor.Depth.Value) extends Persistable {
def this(size: (Int, Int), depth: PackedColor.Depth.Value) = this(size._1, size._2, depth) def this(size: (Int, Int), depth: PackedColor.Depth.Value) = this(size._1, size._2, depth)
private var depth_ = initialDepth
private var foreground_ = 0xFFFFFF private var foreground_ = 0xFFFFFF
private var background_ = 0x000000 private var background_ = 0x000000
private var packed = PackedColor.pack(foreground_, background_, depth) private var packed = PackedColor.pack(foreground_, background_, depth_)
def foreground = foreground_ def foreground = foreground_
def foreground_=(value: Int) = { def foreground_=(value: Int) = {
foreground_ = value foreground_ = value
packed = PackedColor.pack(foreground_, background_, depth) packed = PackedColor.pack(foreground_, background_, depth_)
} }
def background = background_ def background = background_
def background_=(value: Int) = { def background_=(value: Int) = {
background_ = value background_ = value
packed = PackedColor.pack(foreground_, background_, depth) packed = PackedColor.pack(foreground_, background_, depth_)
}
def depth = depth_
def depth_=(value: PackedColor.Depth.Value) = {
if (depth != value) {
for (row <- 0 until height) {
val rowColor = color(row)
for (col <- 0 until width) {
val packed = rowColor(col)
val fg = PackedColor.unpackForeground(packed, depth_)
val bg = PackedColor.unpackBackground(packed, depth_)
rowColor(col) = PackedColor.pack(fg, bg, value)
}
}
depth_ = value
packed = PackedColor.pack(foreground_, background_, depth_)
true
}
else false
} }
var color = Array.fill(height, width)(packed) var color = Array.fill(height, width)(packed)
@ -143,33 +165,50 @@ class TextBuffer(var width: Int, var height: Int, val depth: PackedColor.Depth.V
changed changed
} }
def readFromNBT(nbt: NBTTagCompound): Unit = { override def load(nbt: NBTTagCompound): Unit = {
val w = nbt.getInteger("width") val w = nbt.getInteger("width")
val h = nbt.getInteger("height") val h = nbt.getInteger("height")
size = (w, h) size = (w, h)
val b = nbt.getTagList("buffer") val b = nbt.getTagList("buffer")
for (i <- 0 until (h min b.tagCount)) { for (i <- 0 until (h min b.tagCount)) {
val line = b.tagAt(i).asInstanceOf[NBTTagString].data val line = b.tagAt(i).asInstanceOf[NBTTagString].data
set(0, i, line) set(0, i, line)
} }
depth_ = PackedColor.Depth(nbt.getInteger("depth"))
foreground = nbt.getInteger("foreground")
background = nbt.getInteger("background")
val c = nbt.getTagList("color") val c = nbt.getTagList("color")
for (i <- 0 until (h min c.tagCount)) { for (i <- 0 until h) {
val line = c.tagAt(i).asInstanceOf[NBTTagIntArray].intArray val rowColor = color(i)
Array.copy(line, 0, color(i), 0, line.length min width) for (j <- 0 until w) {
rowColor(j) = c.tagAt(j + i * w).asInstanceOf[NBTTagShort].data
}
} }
} }
def writeToNBT(nbt: NBTTagCompound): Unit = { override def save(nbt: NBTTagCompound): Unit = {
nbt.setInteger("width", width) nbt.setInteger("width", width)
nbt.setInteger("height", height) nbt.setInteger("height", height)
val b = new NBTTagList() val b = new NBTTagList()
for (i <- 0 until height) { for (i <- 0 until height) {
b.appendTag(new NBTTagString(null, String.valueOf(buffer(i)))) b.appendTag(new NBTTagString(null, String.valueOf(buffer(i))))
} }
nbt.setTag("buffer", b) nbt.setTag("buffer", b)
nbt.setInteger("depth", depth_.id)
nbt.setInteger("foreground", foreground_)
nbt.setInteger("background", background_)
val c = new NBTTagList() val c = new NBTTagList()
for (i <- 0 until height) { for (i <- 0 until height) {
c.appendTag(new NBTTagIntArray(null, color(i))) val rowColor = color(i)
for (j <- 0 until width) {
c.appendTag(new NBTTagShort(null, rowColor(j)))
}
} }
nbt.setTag("color", c) nbt.setTag("color", c)
} }