mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-17 03:05:30 -04:00
Basic implementation for new color system (6x8x5 for 8 bit, 16 grayscale palette, pure 16 color palette for 4 bit).
This commit is contained in:
parent
f36835511a
commit
e0b35d4729
@ -270,7 +270,7 @@ class PacketHandler extends CommonPacketHandler {
|
||||
case Some(t: Rack) => t.terminals(p.readInt()).buffer
|
||||
case _ => return // Invalid packet.
|
||||
}
|
||||
buffer.depth = PackedColor.Depth(p.readInt())
|
||||
buffer.format = PackedColor.Depth.format(PackedColor.Depth(p.readInt()))
|
||||
}
|
||||
|
||||
def onScreenFill(p: PacketParser) {
|
||||
|
@ -54,7 +54,7 @@ trait Buffer extends GuiScreen {
|
||||
currentWidth = w
|
||||
currentHeight = h
|
||||
scale = changeSize(currentWidth, currentHeight)
|
||||
BufferRenderer.compileText(scale, buffer.lines, buffer.color, buffer.depth)
|
||||
BufferRenderer.compileText(scale, buffer.lines, buffer.color, buffer.format)
|
||||
}
|
||||
GL11.glPushMatrix()
|
||||
RenderState.disableLighting()
|
||||
|
@ -19,9 +19,9 @@ object MonospaceFontRenderer {
|
||||
val fontWidth = 5
|
||||
val fontHeight = 9
|
||||
|
||||
def drawString(x: Int, y: Int, value: Array[Char], color: Array[Short], depth: PackedColor.Depth.Value) = this.synchronized(instance match {
|
||||
def drawString(x: Int, y: Int, value: Array[Char], color: Array[Short], format: PackedColor.ColorFormat) = this.synchronized(instance match {
|
||||
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, format)
|
||||
})
|
||||
|
||||
private class Renderer(private val textureManager: TextureManager) {
|
||||
@ -71,7 +71,7 @@ object MonospaceFontRenderer {
|
||||
GL11.glEndList()
|
||||
}
|
||||
|
||||
def drawString(x: Int, y: Int, value: Array[Char], color: Array[Short], depth: PackedColor.Depth.Value) = {
|
||||
def drawString(x: Int, y: Int, value: Array[Char], color: Array[Short], format: PackedColor.ColorFormat) = {
|
||||
if (color.length != value.length) throw new IllegalArgumentException("Color count must match char count.")
|
||||
|
||||
if (Settings.get.textAntiAlias)
|
||||
@ -90,7 +90,7 @@ object MonospaceFontRenderer {
|
||||
var cbg = 0x000000
|
||||
var offset = 0
|
||||
var width = 0
|
||||
for (col <- color.map(PackedColor.unpackBackground(_, depth))) {
|
||||
for (col <- color.map(PackedColor.unpackBackground(_, format))) {
|
||||
if (col != cbg) {
|
||||
draw(cbg, offset, width)
|
||||
cbg = col
|
||||
@ -108,7 +108,7 @@ object MonospaceFontRenderer {
|
||||
// Foreground second. We only have to flush when the color changes, so
|
||||
// unless every char has a different color this should be quite efficient.
|
||||
var cfg = -1
|
||||
for ((ch, col) <- value.zip(color.map(PackedColor.unpackForeground(_, depth)))) {
|
||||
for ((ch, col) <- value.zip(color.map(PackedColor.unpackForeground(_, format)))) {
|
||||
val index = 1 + (chars.indexOf(ch) match {
|
||||
case -1 => chars.indexOf('?')
|
||||
case i => i
|
||||
|
@ -67,7 +67,7 @@ object BufferRenderer {
|
||||
GL11.glEndList()
|
||||
}
|
||||
|
||||
def compileText(scale: Double, lines: Array[Array[Char]], colors: Array[Array[Short]], depth: PackedColor.Depth.Value) =
|
||||
def compileText(scale: Double, lines: Array[Array[Char]], colors: Array[Array[Short]], format: PackedColor.ColorFormat) =
|
||||
if (textureManager.isDefined) {
|
||||
GL11.glNewList(displayLists + 1, GL11.GL_COMPILE)
|
||||
GL11.glPushAttrib(GL11.GL_DEPTH_BUFFER_BIT)
|
||||
@ -75,7 +75,7 @@ object BufferRenderer {
|
||||
|
||||
GL11.glScaled(scale, scale, 1)
|
||||
lines.zip(colors).zipWithIndex.foreach {
|
||||
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, format)
|
||||
}
|
||||
|
||||
GL11.glPopAttrib()
|
||||
|
@ -175,7 +175,7 @@ object ScreenRenderer extends TileEntitySpecialRenderer with Callable[Int] with
|
||||
GL11.glTranslatef(0, 0, 0.01f)
|
||||
|
||||
for (((line, color), i) <- screen.buffer.lines.zip(screen.buffer.color).zipWithIndex) {
|
||||
MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, line, color, screen.buffer.depth)
|
||||
MonospaceFontRenderer.drawString(0, i * MonospaceFontRenderer.fontHeight, line, color, screen.buffer.format)
|
||||
}
|
||||
|
||||
if (doCompile) {
|
||||
|
@ -14,7 +14,7 @@ class Buffer(val owner: Buffer.Owner) extends api.network.Environment {
|
||||
withConnector().
|
||||
create()
|
||||
|
||||
val buffer = new TextBuffer(maxResolution, maxDepth)
|
||||
val buffer = new TextBuffer(maxResolution, PackedColor.Depth.format(maxDepth))
|
||||
|
||||
def maxResolution = Settings.screenResolutionsByTier(owner.tier)
|
||||
|
||||
@ -30,13 +30,13 @@ class Buffer(val owner: Buffer.Owner) extends api.network.Environment {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
def depth = buffer.depth
|
||||
def format = buffer.format
|
||||
|
||||
def depth_=(value: PackedColor.Depth.Value) = {
|
||||
if (value > maxDepth)
|
||||
def format_=(value: PackedColor.ColorFormat) = {
|
||||
if (value.depth > maxDepth)
|
||||
throw new IllegalArgumentException("unsupported depth")
|
||||
if (buffer.depth = value) {
|
||||
owner.onScreenDepthChange(value)
|
||||
if (buffer.format = value) {
|
||||
owner.onScreenDepthChange(value.depth)
|
||||
true
|
||||
}
|
||||
else false
|
||||
|
@ -61,7 +61,7 @@ abstract class GraphicsCard extends ManagedComponent {
|
||||
val (gmw, gmh) = maxResolution
|
||||
val (smw, smh) = s.maxResolution
|
||||
s.resolution = (math.min(gmw, smw), math.min(gmh, smh))
|
||||
s.depth = PackedColor.Depth(math.min(maxDepth.id, s.maxDepth.id))
|
||||
s.format = PackedColor.Depth.format(PackedColor.Depth(math.min(maxDepth.id, s.maxDepth.id)))
|
||||
s.foreground = 0xFFFFFF
|
||||
s.background = 0x000000
|
||||
result(true)
|
||||
@ -90,15 +90,15 @@ abstract class GraphicsCard extends ManagedComponent {
|
||||
|
||||
@Callback(direct = true)
|
||||
def getDepth(context: Context, args: Arguments): Array[AnyRef] =
|
||||
screen(s => result(PackedColor.Depth.bits(s.depth)))
|
||||
screen(s => result(PackedColor.Depth.bits(s.format.depth)))
|
||||
|
||||
@Callback
|
||||
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
|
||||
screen(s => result(s.format = depth match {
|
||||
case 1 => PackedColor.Depth.format(PackedColor.Depth.OneBit)
|
||||
case 4 if maxDepth >= PackedColor.Depth.FourBit => PackedColor.Depth.format(PackedColor.Depth.FourBit)
|
||||
case 8 if maxDepth >= PackedColor.Depth.EightBit => PackedColor.Depth.format(PackedColor.Depth.EightBit)
|
||||
case _ => throw new IllegalArgumentException("unsupported depth")
|
||||
}))
|
||||
}
|
||||
@ -152,9 +152,9 @@ abstract class GraphicsCard extends ManagedComponent {
|
||||
screen(s => {
|
||||
val char = s.get(x, y)
|
||||
val color = s.color(y)(x)
|
||||
val depth = s.depth
|
||||
val foreground = PackedColor.unpackForeground(color, depth)
|
||||
val background = PackedColor.unpackBackground(color, depth)
|
||||
val format = s.format
|
||||
val foreground = PackedColor.unpackForeground(color, format)
|
||||
val background = PackedColor.unpackBackground(color, format)
|
||||
result(char, foreground, background)
|
||||
})
|
||||
}
|
||||
@ -222,7 +222,7 @@ abstract class GraphicsCard extends ManagedComponent {
|
||||
buffer.foreground = 0xFFFFFF
|
||||
message.source.host match {
|
||||
case machine: machine.Machine if machine.lastError != null =>
|
||||
if (buffer.depth > PackedColor.Depth.OneBit) buffer.background = 0x0000FF
|
||||
if (buffer.format.depth > PackedColor.Depth.OneBit) buffer.background = 0x0000FF
|
||||
else buffer.background = 0x000000
|
||||
if (buffer.buffer.fill(0, 0, w, h, ' ')) {
|
||||
buffer.owner.onScreenFill(0, 0, w, h, ' ')
|
||||
|
@ -1,5 +1,8 @@
|
||||
package li.cil.oc.util
|
||||
|
||||
import li.cil.oc.api.Persistable
|
||||
import net.minecraft.nbt.NBTTagCompound
|
||||
|
||||
object PackedColor {
|
||||
|
||||
object Depth extends Enumeration {
|
||||
@ -10,74 +13,133 @@ object PackedColor {
|
||||
case FourBit => 4
|
||||
case EightBit => 8
|
||||
}
|
||||
|
||||
def format(depth: Depth.Value) = depth match {
|
||||
case OneBit => SingleBitFormat
|
||||
case FourBit => new MutablePaletteFormat
|
||||
case EightBit => new HybridFormat
|
||||
}
|
||||
}
|
||||
|
||||
private val rMask32 = 0xFF0000
|
||||
private val gMask32 = 0x00FF00
|
||||
private val bMask32 = 0x0000FF
|
||||
private val rShift32 = 16
|
||||
private val gShift32 = 8
|
||||
private val bShift32 = 0
|
||||
|
||||
private abstract class ColorFormat {
|
||||
private def extract(value: Int) = {
|
||||
val r = (value >>> rShift32) & 0xFF
|
||||
val g = (value >>> gShift32) & 0xFF
|
||||
val b = (value >>> bShift32) & 0xFF
|
||||
(r, g, b)
|
||||
}
|
||||
|
||||
trait ColorFormat extends Persistable {
|
||||
def depth: Depth.Value
|
||||
|
||||
def inflate(value: Int): Int
|
||||
|
||||
def deflate(value: Int): Int
|
||||
|
||||
override def load(nbt: NBTTagCompound) {}
|
||||
|
||||
override def save(nbt: NBTTagCompound) {}
|
||||
}
|
||||
|
||||
private class SingleBitFormat extends ColorFormat {
|
||||
def inflate(value: Int) = if (value == 0) 0x000000 else 0xFFFFFF
|
||||
object SingleBitFormat extends ColorFormat {
|
||||
override def depth = Depth.OneBit
|
||||
|
||||
def deflate(value: Int) = if (value == 0) 0 else 1
|
||||
override def inflate(value: Int) = if (value == 0) 0x000000 else 0xFFFFFF
|
||||
|
||||
override def deflate(value: Int) = if (value == 0) 0 else 1
|
||||
}
|
||||
|
||||
private class MultiBitFormat(rBits: Int, gBits: Int, bBits: Int) extends ColorFormat {
|
||||
def mask(nBits: Int) = 0xFFFFFFFF >>> (32 - nBits)
|
||||
abstract class PaletteFormat extends ColorFormat {
|
||||
override def inflate(value: Int) = palette(math.max(0, math.min(palette.length - 1, value)))
|
||||
|
||||
private val bShift = 0
|
||||
private val gShift = bBits
|
||||
private val rShift = gShift + gBits
|
||||
override def deflate(value: Int) = palette.map(delta(value, _)).zipWithIndex.minBy(_._1)._2
|
||||
|
||||
private val bMask = mask(bBits) << bShift
|
||||
private val gMask = mask(gBits) << gShift
|
||||
private val rMask = mask(rBits) << rShift
|
||||
protected def palette: Array[Int]
|
||||
|
||||
private val bScale = 255.0 / ((1 << bBits) - 1)
|
||||
private val gScale = 255.0 / ((1 << gBits) - 1)
|
||||
private val rScale = 255.0 / ((1 << rBits) - 1)
|
||||
|
||||
def inflate(value: Int) = {
|
||||
val r = ((((value & rMask) >>> rShift) * rScale + 0.5).toInt << rShift32) & rMask32
|
||||
val g = ((((value & gMask) >>> gShift) * gScale + 0.5).toInt << gShift32) & gMask32
|
||||
val b = ((((value & bMask) >>> bShift) * bScale + 0.5).toInt << bShift32) & bMask32
|
||||
r | g | b
|
||||
}
|
||||
|
||||
def deflate(value: Int) = {
|
||||
val r = ((((value & rMask32) >>> rShift32) / rScale + 0.5).toInt << rShift) & rMask
|
||||
val g = ((((value & gMask32) >>> gShift32) / gScale + 0.5).toInt << gShift) & gMask
|
||||
val b = ((((value & bMask32) >>> bShift32) / bScale + 0.5).toInt << bShift) & bMask
|
||||
r | g | b
|
||||
protected def delta(colorA: Int, colorB: Int) = {
|
||||
val (rA, gA, bA) = extract(colorA)
|
||||
val (rB, gB, bB) = extract(colorB)
|
||||
val dr = rA - rB
|
||||
val dg = gA - gB
|
||||
val db = bA - bB
|
||||
0.2126 * dr * dr + 0.7152 * dg * dg + 0.0722 * db * db
|
||||
}
|
||||
}
|
||||
|
||||
private val formats = Map(
|
||||
Depth.OneBit -> new SingleBitFormat(),
|
||||
Depth.FourBit -> new MultiBitFormat(1, 2, 1),
|
||||
Depth.EightBit -> new MultiBitFormat(3, 3, 2))
|
||||
class MutablePaletteFormat extends PaletteFormat {
|
||||
override def depth = Depth.FourBit
|
||||
|
||||
def apply(index: Int) = palette(index)
|
||||
|
||||
def update(index: Int, value: Int) = palette(index) = value
|
||||
|
||||
protected val palette = Array(
|
||||
0x000000, 0xFF3333, 0x336600, 0x663300,
|
||||
0x333399, 0x9933CC, 0x336699, 0xCCCCCC,
|
||||
0x333333, 0xFF6699, 0x33CC33, 0xFFFF33,
|
||||
0x6699FF, 0xCC66CC, 0xFFCC33, 0xFFFFFF)
|
||||
|
||||
override def load(nbt: NBTTagCompound) {
|
||||
val loaded = nbt.getIntArray("palette")
|
||||
Array.copy(loaded, 0, palette, 0, math.min(loaded.length, palette.length))
|
||||
}
|
||||
|
||||
override def save(nbt: NBTTagCompound) {
|
||||
nbt.setIntArray("palette", palette)
|
||||
}
|
||||
}
|
||||
|
||||
class HybridFormat extends MutablePaletteFormat {
|
||||
private val reds = 6
|
||||
private val greens = 8
|
||||
private val blues = 5
|
||||
|
||||
// Initialize palette to grayscale, excluding black and white, because
|
||||
// those are already contained in the normal color cube.
|
||||
for (i <- 0 until palette.length) {
|
||||
val shade = 0xFF * (i + 1) / (palette.length + 1)
|
||||
this(i) = (shade << rShift32) | (shade << gShift32) | (shade << bShift32)
|
||||
}
|
||||
|
||||
override def depth = Depth.EightBit
|
||||
|
||||
override def inflate(value: Int) = {
|
||||
if (value < palette.length) super.inflate(value)
|
||||
else {
|
||||
val index = value - palette.length
|
||||
val idxB = index % blues
|
||||
val idxG = (index / blues) % greens
|
||||
val idxR = (index / blues / greens) % reds
|
||||
val r = (idxR * 0xFF / (reds - 1.0) + 0.5).toInt
|
||||
val g = (idxG * 0xFF / (greens - 1.0) + 0.5).toInt
|
||||
val b = (idxB * 0xFF / (blues - 1.0) + 0.5).toInt
|
||||
(r << rShift32) | (g << gShift32) | (b << bShift32)
|
||||
}
|
||||
}
|
||||
|
||||
override def deflate(value: Int) = {
|
||||
val (r, g, b) = extract(value)
|
||||
val idxR = (r * (reds - 1.0) / 0xFF + 0.5).toInt
|
||||
val idxG = (g * (greens - 1.0) / 0xFF + 0.5).toInt
|
||||
val idxB = (b * (blues - 1.0) / 0xFF + 0.5).toInt
|
||||
palette.length + idxR * greens * blues + idxG * blues + idxB
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
def pack(foreground: Int, background: Int, format: ColorFormat) = {
|
||||
((format.deflate(foreground) << fgShift) | format.deflate(background)).toShort
|
||||
}
|
||||
|
||||
def unpackForeground(color: Short, depth: Depth.Value) =
|
||||
formats(depth).inflate((color & 0xFFFF) >>> fgShift)
|
||||
def unpackForeground(color: Short, format: ColorFormat) =
|
||||
format.inflate((color & 0xFFFF) >>> fgShift)
|
||||
|
||||
def unpackBackground(color: Short, depth: Depth.Value) =
|
||||
formats(depth).inflate(color & bgMask)
|
||||
def unpackBackground(color: Short, format: ColorFormat) =
|
||||
format.inflate(color & bgMask)
|
||||
}
|
||||
|
@ -11,46 +11,46 @@ import net.minecraft.nbt._
|
||||
* relatively fast updates, given a smart algorithm (using copy()/fill()
|
||||
* instead of set()ing everything).
|
||||
*/
|
||||
class TextBuffer(var width: Int, var height: Int, initialDepth: PackedColor.Depth.Value) {
|
||||
def this(size: (Int, Int), depth: PackedColor.Depth.Value) = this(size._1, size._2, depth)
|
||||
class TextBuffer(var width: Int, var height: Int, initialFormat: PackedColor.ColorFormat) {
|
||||
def this(size: (Int, Int), format: PackedColor.ColorFormat) = this(size._1, size._2, format)
|
||||
|
||||
private var _depth = initialDepth
|
||||
private var _format = initialFormat
|
||||
|
||||
private var _foreground = 0xFFFFFF
|
||||
|
||||
private var _background = 0x000000
|
||||
|
||||
private var packed = PackedColor.pack(_foreground, _background, _depth)
|
||||
private var packed = PackedColor.pack(_foreground, _background, _format)
|
||||
|
||||
def foreground = _foreground
|
||||
|
||||
def foreground_=(value: Int) = {
|
||||
_foreground = value
|
||||
packed = PackedColor.pack(_foreground, _background, _depth)
|
||||
packed = PackedColor.pack(_foreground, _background, _format)
|
||||
}
|
||||
|
||||
def background = _background
|
||||
|
||||
def background_=(value: Int) = {
|
||||
_background = value
|
||||
packed = PackedColor.pack(_foreground, _background, _depth)
|
||||
packed = PackedColor.pack(_foreground, _background, _format)
|
||||
}
|
||||
|
||||
def depth = _depth
|
||||
def format = _format
|
||||
|
||||
def depth_=(value: PackedColor.Depth.Value) = {
|
||||
if (depth != value) {
|
||||
def format_=(value: PackedColor.ColorFormat) = {
|
||||
if (format.depth != value.depth) {
|
||||
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)
|
||||
val fg = PackedColor.unpackForeground(packed, _format)
|
||||
val bg = PackedColor.unpackBackground(packed, _format)
|
||||
rowColor(col) = PackedColor.pack(fg, bg, value)
|
||||
}
|
||||
}
|
||||
_depth = value
|
||||
packed = PackedColor.pack(_foreground, _background, _depth)
|
||||
_format = value
|
||||
packed = PackedColor.pack(_foreground, _background, _format)
|
||||
true
|
||||
}
|
||||
else false
|
||||
@ -178,7 +178,9 @@ class TextBuffer(var width: Int, var height: Int, initialDepth: PackedColor.Dept
|
||||
}
|
||||
}
|
||||
|
||||
_depth = PackedColor.Depth(nbt.getInteger("depth") max 0 min PackedColor.Depth.maxId)
|
||||
val depth = PackedColor.Depth(nbt.getInteger("depth") max 0 min PackedColor.Depth.maxId)
|
||||
_format = PackedColor.Depth.format(depth)
|
||||
_format.load(nbt)
|
||||
foreground = nbt.getInteger("foreground")
|
||||
background = nbt.getInteger("background")
|
||||
|
||||
@ -207,7 +209,8 @@ class TextBuffer(var width: Int, var height: Int, initialDepth: PackedColor.Dept
|
||||
}
|
||||
nbt.setTag("buffer", b)
|
||||
|
||||
nbt.setInteger("depth", _depth.id)
|
||||
nbt.setInteger("depth", _format.depth.id)
|
||||
_format.save(nbt)
|
||||
nbt.setInteger("foreground", _foreground)
|
||||
nbt.setInteger("background", _background)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user