diff --git a/MISC_FEATURES.md b/MISC_FEATURES.md index 7f78af1bc..fde97d3a9 100644 --- a/MISC_FEATURES.md +++ b/MISC_FEATURES.md @@ -39,3 +39,8 @@ Connect two or more tracker head to play the array of trackers play simultaneous - Include a valid way of obtaining Aimhack (possessed weapon shit?) - Implement it on ```.primaryUse(gc, delta)``` + + +## Computers ## + +Instead of single box with bunch of parts, make computers occupy several blocks -- processor unit, core memory unit, storage unit (RAMAC!), I/O unit, etc., like old PDPs. Powerful computer == more space. Plus portable units like TRS-80 Model 100. \ No newline at end of file diff --git a/src/net/torvald/terrarum/StateGraphicComputerTest.kt b/src/net/torvald/terrarum/StateGraphicComputerTest.kt new file mode 100644 index 000000000..c71925cae --- /dev/null +++ b/src/net/torvald/terrarum/StateGraphicComputerTest.kt @@ -0,0 +1,73 @@ +package net.torvald.terrarum + +import net.torvald.random.HQRNG +import net.torvald.terrarum.gameactors.roundInt +import net.torvald.terrarum.virtualcomputer.computer.BaseTerrarumComputer +import net.torvald.terrarum.virtualcomputer.peripheral.PeripheralVideoCard +import net.torvald.terrarum.virtualcomputer.terminal.GraphicsTerminal +import org.lwjgl.opengl.GL11 +import org.newdawn.slick.GameContainer +import org.newdawn.slick.Graphics +import org.newdawn.slick.state.BasicGameState +import org.newdawn.slick.state.StateBasedGame +import java.util.* + +/** + * Created by SKYHi14 on 2017-02-23. + */ +class StateGraphicComputerTest : BasicGameState() { + val computer = BaseTerrarumComputer(8) + val monitor = GraphicsTerminal(computer) + + init { + val videocard = PeripheralVideoCard() + monitor.attachVideoCard(videocard) + + computer.attachTerminal(monitor) + computer.attachPeripheral(videocard) + } + + override fun init(container: GameContainer?, game: StateBasedGame?) { + val sprite = (computer.getPeripheral("ppu") as PeripheralVideoCard).vram.sprites[0] + + sprite.setLine(0, intArrayOf(1,1,0,0,0,0,3,3)) + sprite.setLine(1, intArrayOf(1,1,0,0,0,0,3,3)) + sprite.setLine(2, intArrayOf(1,1,0,0,0,0,1,1)) + sprite.setLine(3, intArrayOf(1,1,1,1,1,1,1,1)) + sprite.setLine(4, intArrayOf(1,1,1,1,1,1,1,1)) + sprite.setLine(5, intArrayOf(0,0,0,0,0,0,1,1)) + sprite.setLine(6, intArrayOf(2,2,0,0,0,0,1,1)) + sprite.setLine(7, intArrayOf(2,2,0,0,0,0,1,1)) + + } + + var angle = 0.0 + + override fun update(container: GameContainer, game: StateBasedGame?, delta: Int) { + Terrarum.appgc.setTitle("VT — F: ${container.fps}" + + " — M: ${Terrarum.memInUse}M / ${Terrarum.memTotal}M / ${Terrarum.memXmx}M") + monitor.update(container, delta) + computer.update(container, delta) + + val sprite = (computer.getPeripheral("ppu") as PeripheralVideoCard).vram.sprites[0] + + angle += delta / 500.0 + + sprite.posX = (Math.cos(angle) * 80 + 100).roundInt() + sprite.posY = (Math.sin(angle) * 80 + 100).roundInt() + + sprite.pal0 = (sprite.pal0 + 1) % 65 + sprite.pal1 = (sprite.pal1 + 1) % 65 + sprite.pal2 = (sprite.pal2 + 1) % 65 + sprite.pal3 = (sprite.pal3 + 1) % 65 + + sprite.rotation = (angle * 2 / Math.PI).roundInt() % 4 + + } + + override fun getID() = Terrarum.STATE_ID_TEST_TTY + + override fun render(container: GameContainer, game: StateBasedGame?, g: Graphics) { + monitor.render(container, g) + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index 6f121b7ea..5cb39cf60 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -131,10 +131,11 @@ constructor(gamename: String) : StateBasedGame(gamename) { gc.graphics.clear() // clean up any 'dust' in the buffer //addState(StateVTTest()) + addState(StateGraphicComputerTest()) //addState(StateTestingLightning()) //addState(StateSplash()) //addState(StateMonitorCheck()) - addState(StateFontTester()) + //addState(StateFontTester()) //addState(StateNoiseTexGen()) //addState(StateBlurTest()) //addState(StateShaderTest()) @@ -467,7 +468,14 @@ constructor(gamename: String) : StateBasedGame(gamename) { } val currentSaveDir: File - get() = File(defaultSaveDir + "/test") // TODO TEST CODE + get() { + val file = File(defaultSaveDir + "/test") + + // failsafe? + if (!file.exists()) file.mkdir() + + return file // TODO TEST CODE + } } } diff --git a/src/net/torvald/terrarum/virtualcomputer/computer/BaseTerrarumComputer.kt b/src/net/torvald/terrarum/virtualcomputer/computer/BaseTerrarumComputer.kt index a538ddec3..867bab8e9 100644 --- a/src/net/torvald/terrarum/virtualcomputer/computer/BaseTerrarumComputer.kt +++ b/src/net/torvald/terrarum/virtualcomputer/computer/BaseTerrarumComputer.kt @@ -107,10 +107,18 @@ class BaseTerrarumComputer(peripheralSlots: Int) { computerValue["boot"] = computerValue.getAsString("hda")!! } + fun getPeripheral(tableName: String): Peripheral? { + peripheralTable.forEach { + if (it.tableName == tableName) + return it + } + return null + } + fun attachPeripheral(peri: Peripheral) { if (peripheralTable.size < maxPeripherals) { peripheralTable.add(peri) - peri.loadLib() + peri.loadLib(luaJ_globals) println("[BaseTerrarumComputer] loading peripheral $peri") } else { @@ -121,7 +129,6 @@ class BaseTerrarumComputer(peripheralSlots: Int) { fun detachPeripheral(peri: Peripheral) { if (peripheralTable.contains(peri)) { peripheralTable.remove(peri) - peri.unloadLib() println("[BaseTerrarumComputer] unloading peripheral $peri") } else { @@ -153,7 +160,6 @@ class BaseTerrarumComputer(peripheralSlots: Int) { Filesystem(luaJ_globals, this) HostAccessProvider(luaJ_globals, this) Input(luaJ_globals, this) - PeripheralInternet(luaJ_globals, this) PcSpeakerDriver(luaJ_globals, this) WorldInformationProvider(luaJ_globals) @@ -179,8 +185,8 @@ class BaseTerrarumComputer(peripheralSlots: Int) { // load every peripheral if we're in DEBUG if (DEBUG) { maxPeripherals = 32 - attachPeripheral(PeripheralInternet(luaJ_globals, this)) - attachPeripheral(PeripheralPSG(luaJ_globals, this)) + attachPeripheral(PeripheralInternet(this)) + attachPeripheral(PeripheralPSG(this)) // ... } } @@ -281,8 +287,8 @@ class BaseTerrarumComputer(peripheralSlots: Int) { chunk.call() } catch (e: LuaError) { - lua.STDERR.println("${SimpleTextTerminal.ASCII_DLE}${e.message}${SimpleTextTerminal.ASCII_DC4}") e.printStackTrace(System.err) + lua.STDERR.println("${SimpleTextTerminal.ASCII_DLE}${e.message}${SimpleTextTerminal.ASCII_DC4}") } } } diff --git a/src/net/torvald/terrarum/virtualcomputer/luaapi/Filesystem.kt b/src/net/torvald/terrarum/virtualcomputer/luaapi/Filesystem.kt index 692574c9e..e11aa0bad 100644 --- a/src/net/torvald/terrarum/virtualcomputer/luaapi/Filesystem.kt +++ b/src/net/torvald/terrarum/virtualcomputer/luaapi/Filesystem.kt @@ -74,9 +74,12 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) { lowerCase.delete() isCaseInsensitive = insensitive + + println("[Filesystem] Case insensitivity: $isCaseInsensitive") } catch (e: IOException) { - println("[Filesystem] Couldn't determine if file system is case sensitive, falling back to insensitive.") + System.err.println("[Filesystem] Couldn't determine if the file system is case sensitive, falling back to insensitive.") + e.printStackTrace(System.out) isCaseInsensitive = true } } diff --git a/src/net/torvald/terrarum/virtualcomputer/peripheral/Peripheral.kt b/src/net/torvald/terrarum/virtualcomputer/peripheral/Peripheral.kt index 220e06e50..13820ed79 100644 --- a/src/net/torvald/terrarum/virtualcomputer/peripheral/Peripheral.kt +++ b/src/net/torvald/terrarum/virtualcomputer/peripheral/Peripheral.kt @@ -7,14 +7,9 @@ import org.luaj.vm2.LuaValue /** * Created by minjaesong on 16-09-29. */ -open class Peripheral(val luaG: Globals, val tableName: String) { +abstract class Peripheral(val tableName: String) { - open fun loadLib() { - luaG[tableName] = LuaTable() - } - open fun unloadLib() { - luaG[tableName] = LuaValue.NIL - } + abstract fun loadLib(globals: Globals) - override fun toString(): String = tableName + override fun toString(): String = "Peripheral:$tableName" } \ No newline at end of file diff --git a/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralInternet.kt b/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralInternet.kt index 551a5d094..263c0a7e7 100644 --- a/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralInternet.kt +++ b/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralInternet.kt @@ -2,6 +2,7 @@ package net.torvald.terrarum.virtualcomputer.peripheral import org.luaj.vm2.Globals import net.torvald.terrarum.virtualcomputer.computer.BaseTerrarumComputer +import org.luaj.vm2.LuaTable import org.luaj.vm2.LuaValue import org.luaj.vm2.lib.OneArgFunction import java.io.BufferedReader @@ -13,11 +14,11 @@ import java.net.URL * * Created by minjaesong on 16-09-24. */ -internal class PeripheralInternet(val globals: Globals, val host: BaseTerrarumComputer) -: Peripheral(globals, "internet"){ +internal class PeripheralInternet(val host: BaseTerrarumComputer) +: Peripheral("internet"){ - override fun loadLib() { - super.loadLib() + override fun loadLib(globals: Globals) { + globals["internet"] = LuaTable() globals["internet"]["fetch"] = FetchWebPage() } diff --git a/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralPSG.kt b/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralPSG.kt index 3dd9c6355..3613bbb5d 100644 --- a/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralPSG.kt +++ b/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralPSG.kt @@ -11,11 +11,11 @@ import org.luaj.vm2.LuaValue * * Created by minjaesong on 16-09-27. */ -internal class PeripheralPSG(val globals: Globals, val host: BaseTerrarumComputer) -: Peripheral(globals, "psg") { +internal class PeripheralPSG(val host: BaseTerrarumComputer) +: Peripheral("psg") { - override fun loadLib() { - super.loadLib() + override fun loadLib(globals: Globals) { + globals["psg"] = LuaTable() } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralVideoCard.kt b/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralVideoCard.kt index 8f67099ac..5c5fd43bf 100644 --- a/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralVideoCard.kt +++ b/src/net/torvald/terrarum/virtualcomputer/peripheral/PeripheralVideoCard.kt @@ -10,13 +10,15 @@ import org.luaj.vm2.lib.OneArgFunction import org.luaj.vm2.lib.ThreeArgFunction import org.luaj.vm2.lib.TwoArgFunction import org.luaj.vm2.lib.ZeroArgFunction +import org.lwjgl.opengl.GL11 import org.newdawn.slick.* import java.util.* /** * Created by SKYHi14 on 2017-02-08. */ -class PeripheralVideoCard(val globals: Globals, val termW: Int = 40, val termH: Int = 25) : Peripheral(globals, "ppu") { +class PeripheralVideoCard(val termW: Int = 40, val termH: Int = 25) : + Peripheral("ppu") { companion object { val blockW = 8 val blockH = 8 @@ -43,53 +45,121 @@ class PeripheralVideoCard(val globals: Globals, val termW: Int = 40, val termH: val height = termH * blockH val vram = VRAM(width, height, 64) + val frameBuffer = Image(width, height) + val frameBufferG = frameBuffer.graphics - var fontRom = SpriteSheet("./assets/graphics/fonts/milky.tga", blockW, blockH) + // hard-coded 8x8 + var fontRom = Array(256, { Array(blockH, { 0 }).toIntArray() }) - val CLUT = vram.CLUT + init { + // build it for first time + resetTextRom() + } + + val CLUT = VRAM.CLUT val coloursCount = CLUT.size - override fun loadLib() { - super.loadLib() - globals["ppu"]["setColor"] = SetColor(this) - globals["ppu"]["getColor"] = GetColor(this) - globals["ppu"]["emitChar"] = EmitChar(this) + fun buildFontRom(ref: String) { + // load font rom out of TGA + val imageRef = Image(ref) + val image = imageRef.texture.textureData + val imageWidth = imageRef.width + + for (i in 0..255) { + for (y in 0..blockH - 1) { + // letter mirrored horizontally! + var scanline = 0 + for (x in 0..blockW - 1) { + val subX = i % 16 + val subY = i / 16 + val bit = image[4 * ((subY * blockH + y) * imageWidth + blockW * subX + x) + 3] != 0.toByte() + if (bit) scanline = scanline or (1 shl x) + } + + fontRom[i][y] = scanline + } + } } + override fun loadLib(globals: Globals) { + globals["ppu"] = LuaTable() + globals["ppu"]["setForeColor"] = SetForeColor(this) + globals["ppu"]["getForeColor"] = GetForeColor(this) + globals["ppu"]["setBackColor"] = SetBackColor(this) + globals["ppu"]["getBackColor"] = GetBackColor(this) + globals["ppu"]["emitChar"] = EmitChar(this) + globals["ppu"]["clearAll"] = ClearAll(this) + globals["ppu"]["clearBack"] = ClearBackground(this) + globals["ppu"]["clearFore"] = ClearForeground(this) + } + + private val spriteBuffer = ImageBuffer(VSprite.width, VSprite.height) + fun render(g: Graphics) { - g.drawImage(vram.background.image, 0f, 0f) + fun VSprite.render() { + val h = VSprite.height + val w = VSprite.width + if (rotation and 1 == 0) { // deg 0, 180 + (if (rotation == 0 && !vFlip || rotation == 2 && vFlip) 0..h-1 else h-1 downTo 0).forEachIndexed { ordY, y -> + (if (rotation == 0 && !hFlip || rotation == 2 && hFlip) 0..w-1 else w-1 downTo 0).forEachIndexed { ordX, x -> + val pixelData = data[y].ushr(2 * x).and(0b11) + val col = getColourFromPalette(pixelData) + spriteBuffer.setRGBA(ordX, ordY, col.red, col.green, col.blue, col.alpha) + } + } + } + else { // deg 90, 270 + (if (rotation == 3 && !hFlip || rotation == 1 && hFlip) 0..w-1 else w-1 downTo 0).forEachIndexed { ordY, y -> + (if (rotation == 3 && !vFlip || rotation == 1 && vFlip) h-1 downTo 0 else 0..h-1).forEachIndexed { ordX, x -> + val pixelData = data[y].ushr(2 * x).and(0b11) + val col = getColourFromPalette(pixelData) + spriteBuffer.setRGBA(ordY, ordX, col.red, col.green, col.blue, col.alpha) + } + } + } + } + + frameBuffer.filter = Image.FILTER_NEAREST + frameBufferG.clear() + + frameBufferG.drawImage(vram.background.image, 0f, 0f) vram.sprites.forEach { if (it.isBackground) { - val spriteImage = it.data.image.getFlippedCopy(it.hFlip, it.vFlip) - spriteImage.rotate(90f * it.rotation) - g.drawImage(spriteImage, it.xpos.toFloat(), it.ypos.toFloat()) + it.render() + frameBufferG.drawImage(spriteBuffer.image, it.posX.toFloat(), it.posY.toFloat()) } } - g.drawImage(vram.foreground.image, 0f, 0f) + frameBufferG.drawImage(vram.foreground.image, 0f, 0f) vram.sprites.forEach { if (!it.isBackground) { - val spriteImage = it.data.image.getFlippedCopy(it.hFlip, it.vFlip) - spriteImage.rotate(90f * it.rotation) - g.drawImage(spriteImage, it.xpos.toFloat(), it.ypos.toFloat()) + it.render() + frameBufferG.drawImage(spriteBuffer.image, it.posX.toFloat(), it.posY.toFloat()) } } + + frameBufferG.flush() + + g.drawImage(frameBuffer.getScaledCopy(2f), 0f, 0f) } - private var currentColour = 49 // white - fun getColor() = currentColour - fun setColor(value: Int) { currentColour = value } + private var foreColor = 49 // white + private var backColor = 64 // transparent - fun drawChar(c: Char, x: Int, y: Int, col: Int = currentColour) { - val glyph = fontRom.getSubImage(c.toInt() % 16, c.toInt() / 16) - val color = CLUT[col] + fun drawChar(c: Char, x: Int, y: Int, colFore: Int = foreColor, colBack: Int = backColor) { + val glyph = fontRom[c.toInt()] + val fore = CLUT[colFore] + val back = CLUT[colBack] // software render - for (gy in 0..blockH) { - for (gx in 0..blockW) { - val glyAlpha = glyph.getPixel(gx, gy)[3] + for (gy in 0..blockH - 1) { + for (gx in 0..blockW - 1) { + val glyAlpha = glyph[gy].ushr(gx).and(1) - if (glyAlpha > 0) { - vram.foreground.setRGBA(x * blockW + gx, y * blockH + gy, color.red, color.green, color.blue, 255) + if (glyAlpha != 0) { + vram.foreground.setRGBA(x * blockW + gx, y * blockH + gy, fore.red, fore.green, fore.blue, fore.alpha) + } + else { + vram.foreground.setRGBA(x * blockW + gx, y * blockH + gy, back.red, back.green, back.blue, back.alpha) } } } @@ -104,39 +174,75 @@ class PeripheralVideoCard(val globals: Globals, val termW: Int = 40, val termH: fun clearForeground() { for (i in 0..width * height - 1) { - vram.foreground.rgba[i] = if (i % 4 == 3) 0xFF.toByte() else 0x00.toByte() + vram.foreground.rgba[i] = 0x00.toByte() } } fun clearAll() { for (i in 0..width * height - 1) { vram.background.rgba[i] = if (i % 4 == 3) 0xFF.toByte() else 0x00.toByte() - vram.foreground.rgba[i] = if (i % 4 == 3) 0xFF.toByte() else 0x00.toByte() + vram.foreground.rgba[i] = 0x00.toByte() } } fun getSprite(index: Int) = vram.sprites[index] - - fun setTextRom(data: Array) { - TODO("Not implemented") + /** + * Array be like, in binary; notice that glyphs are flipped horizontally: + * ... + * 00011000 + * 00011100 + * 00011000 + * 00011000 + * 00011000 + * 00011000 + * 01111111 + * 00000000 + * 00111110 + * 01100011 + * 01100000 + * 00111111 + * 00000011 + * 00000011 + * 01111111 + * 00000000 + * ... + */ + fun setTextRom(data: Array) { + for (i in 0..255) { + for (y in 0..blockH - 1) { + // letter mirrored horizontally! + fontRom[i][y] = data[blockH * i + y] + } + } } fun resetTextRom() { - fontRom = SpriteSheet("./assets/graphics/fonts/milky.tga", blockW, blockH) + buildFontRom("./assets/graphics/fonts/milky.tga") } - class SetColor(val videoCard: PeripheralVideoCard) : OneArgFunction() { + class SetForeColor(val videoCard: PeripheralVideoCard) : OneArgFunction() { override fun call(arg: LuaValue): LuaValue { - videoCard.setColor(arg.checkint()) + videoCard.foreColor = arg.checkint() return LuaValue.NONE } } - class GetColor(val videoCard: PeripheralVideoCard) : ZeroArgFunction() { + class GetForeColor(val videoCard: PeripheralVideoCard) : ZeroArgFunction() { override fun call(): LuaValue { - return videoCard.getColor().toLua() + return videoCard.foreColor.toLua() + } + } + class SetBackColor(val videoCard: PeripheralVideoCard) : OneArgFunction() { + override fun call(arg: LuaValue): LuaValue { + videoCard.backColor = arg.checkint() + return LuaValue.NONE + } + } + class GetBackColor(val videoCard: PeripheralVideoCard) : ZeroArgFunction() { + override fun call(): LuaValue { + return videoCard.backColor.toLua() } } class EmitChar(val videoCard: PeripheralVideoCard) : ThreeArgFunction() { @@ -146,6 +252,24 @@ class PeripheralVideoCard(val globals: Globals, val termW: Int = 40, val termH: return LuaValue.NONE } } + class ClearAll(val videoCard: PeripheralVideoCard) : ZeroArgFunction() { + override fun call(): LuaValue { + videoCard.clearAll() + return LuaValue.NONE + } + } + class ClearBackground(val videoCard: PeripheralVideoCard) : ZeroArgFunction() { + override fun call(): LuaValue { + videoCard.clearBackground() + return LuaValue.NONE + } + } + class ClearForeground(val videoCard: PeripheralVideoCard) : ZeroArgFunction() { + override fun call(): LuaValue { + videoCard.clearForeground() + return LuaValue.NONE + } + } ///////////// // Sprites // @@ -211,9 +335,9 @@ class VRAM(pxlWidth: Int, pxlHeight: Int, nSprites: Int) { val background = ImageBuffer(pxlWidth, pxlHeight) val foreground = ImageBuffer(pxlWidth, pxlHeight) // text mode glyphs rendered here - var transparentKey: Int = 15 // black - - val CLUT = DecodeTapestry.colourIndices64 + companion object { + val CLUT = DecodeTapestry.colourIndices64 + Color(0, 0, 0, 0) + } fun setBackgroundPixel(x: Int, y: Int, color: Int) { @@ -223,26 +347,26 @@ class VRAM(pxlWidth: Int, pxlHeight: Int, nSprites: Int) { fun setForegroundPixel(x: Int, y: Int, color: Int) { val col = CLUT[color] - background.setRGBA(x, y, col.red, col.green, col.blue, if (color == transparentKey) 0 else 255) + background.setRGBA(x, y, col.red, col.green, col.blue, col.alpha) } } class VSprite { - private val width = 8 - private val height = 8 + companion object { + val width = 8 + val height = 8 + } - val CLUT = DecodeTapestry.colourIndices64 - val data = ImageBuffer(width, height) + internal val CLUT = VRAM.CLUT + internal val data = IntArray(height) - var pal0 = 15 // black + var pal0 = 64 // transparent var pal1 = 56 // light cyan var pal2 = 19 // magenta var pal3 = 49 // white - var transparentKey = 15 // black - - var xpos = 0 - var ypos = 0 + var posX = 0 + var posY = 0 var hFlip = false var vFlip = false @@ -270,18 +394,18 @@ class VSprite { } fun setPixel(x: Int, y: Int, color: Int) { - val col = getColourFromPalette(color) - data.setRGBA(x, y, col.red, col.green, col.blue, if (color == transparentKey) 0 else 255) + data[y] = data[y] xor data[y].and(3 shl (2 * x)) // mask off desired area to 0b00 + data[y] = data[y] or (color shl (2 * x)) } fun setLine(y: Int, rowData: IntArray) { - for (i in 0..width) { + for (i in 0..width - 1) { setPixel(i, y, rowData[i]) } } fun setAll(data: IntArray) { - for (i in 0..width * height) { + for (i in 0..width * height - 1) { setPixel(i % width, i / width, data[i]) } } diff --git a/src/net/torvald/terrarum/virtualcomputer/terminal/GraphicsTerminal.kt b/src/net/torvald/terrarum/virtualcomputer/terminal/GraphicsTerminal.kt index 8031362aa..36222c199 100644 --- a/src/net/torvald/terrarum/virtualcomputer/terminal/GraphicsTerminal.kt +++ b/src/net/torvald/terrarum/virtualcomputer/terminal/GraphicsTerminal.kt @@ -1,6 +1,7 @@ package net.torvald.terrarum.virtualcomputer.terminal import net.torvald.terrarum.blendMul +import net.torvald.terrarum.gameactors.DecodeTapestry import net.torvald.terrarum.virtualcomputer.computer.BaseTerrarumComputer import net.torvald.terrarum.virtualcomputer.peripheral.PeripheralVideoCard import org.newdawn.slick.Color @@ -9,32 +10,45 @@ import org.newdawn.slick.Graphics import org.newdawn.slick.Image /** + * Printing text using Term API triggers 'compatibility' mode, where you are limited to 16 colours. + * Use PPU API for full 64 colours! + * * Created by SKYHi14 on 2017-02-08. */ -class GraphicsTerminal( - private val host: BaseTerrarumComputer, val videoCard: PeripheralVideoCard -) : Terminal { - override val width = videoCard.termW - override val height = videoCard.termH - override val coloursCount = videoCard.coloursCount +class GraphicsTerminal(private val host: BaseTerrarumComputer) : Terminal { + lateinit var videoCard: PeripheralVideoCard + + override val width: Int; get() = videoCard.termW + override val height: Int; get() = videoCard.termH + override val coloursCount: Int; get() = videoCard.coloursCount override var cursorX = 0 override var cursorY = 0 override var cursorBlink = true - override var backColour = 15 // black - override var foreColour = 48 // bright grey + val backDefault = 0 // black + val foreDefault = 1 // white + + override var backColour = backDefault + override var foreColour = foreDefault + + private val colourKey: Int + get() = backColour.shl(4) or (foreColour).and(0xFF) override var lastInputByte = -1 override fun getColor(index: Int) = videoCard.CLUT[index] - override val displayW = videoCard.width //+ 2 * borderSize - override val displayH = videoCard.height //+ 2 * borderSize + override val displayW: Int; get() = videoCard.width //+ 2 * borderSize + override val displayH: Int; get() = videoCard.height //+ 2 * borderSize - private val videoScreen = Image(videoCard.width, videoCard.height) + private lateinit var videoScreen: Image + + var TABSIZE = 4 + + val errorColour = 6 override fun printChars(s: String) { - TODO("not implemented") + printString(s, cursorX, cursorY) } override fun update(gc: GameContainer, delta: Int) { @@ -60,16 +74,15 @@ class GraphicsTerminal( } override fun render(gc: GameContainer, g: Graphics) { - videoCard.render(videoScreen.graphics) - g.drawImage(videoScreen.getScaledCopy(2f), 0f, 0f) + videoCard.render(g) } override fun keyPressed(key: Int, c: Char) { - TODO("not implemented") + //TODO("not implemented") } override fun writeChars(s: String) { - TODO("not implemented") + writeString(s, cursorX, cursorY) } /** Unlike lua function, this one in Zero-based. */ @@ -79,42 +92,78 @@ class GraphicsTerminal( } override fun openInput(echo: Boolean) { - TODO("not implemented") + //TODO("not implemented") } override fun emitChar(bufferChar: Int, x: Int, y: Int) { - TODO("not implemented") + videoCard.drawChar( + bufferChar.and(0xFF).toChar(), x, y, + CLUT16_TO_64[bufferChar.ushr(8).and(0xF)], + CLUT16_TO_64[bufferChar.ushr(12).and(0xF)] + ) } override fun closeInputKey(keyFromUI: Int): Int { - TODO("not implemented") + //TODO("not implemented") + return 0 } override fun closeInputString(): String { - TODO("not implemented") + //TODO("not implemented") + return " " } override var lastStreamInput: String? = null override var lastKeyPress: Int? = null override fun emitChar(c: Char, x: Int, y: Int) { - TODO("not implemented") + videoCard.drawChar(c, x, y, CLUT16_TO_64[foreColour]) } override fun printChar(c: Char) { - TODO("not implemented") + wrap() + if (c >= ' ' && c.toInt() != 127) { + emitChar(c) + cursorX += 1 + } + else { + when (c) { + ASCII_BEL -> bell(".") + ASCII_BS -> { cursorX -= 1; wrap() } + ASCII_TAB -> { cursorX = (cursorX).div(TABSIZE).times(TABSIZE) + TABSIZE } + ASCII_LF -> newLine() + ASCII_FF -> clear() + ASCII_CR -> { cursorX = 0 } + ASCII_DEL -> { cursorX -= 1; wrap(); emitChar(colourKey.shl(8)) } + ASCII_DC1, ASCII_DC2, ASCII_DC3, ASCII_DC4 -> { foreColour = c - ASCII_DC1 } + ASCII_DLE -> { foreColour = errorColour } + } + } } override fun emitString(s: String, x: Int, y: Int) { - TODO("not implemented") + setCursor(x, y) + + for (i in 0..s.length - 1) { + printChar(s[i]) + wrap() + } + + setCursor(x, y) } override fun printString(s: String, x: Int, y: Int) { - TODO("not implemented") + writeString(s, x, y) + newLine() } override fun writeString(s: String, x: Int, y: Int) { - TODO("not implemented") + setCursor(x, y) + + for (i in 0..s.length - 1) { + printChar(s[i]) + wrap() + } } override fun clear() { @@ -122,23 +171,31 @@ class GraphicsTerminal( } override fun clearLine() { - TODO("not implemented") + //TODO("not implemented") } override fun newLine() { - TODO("not implemented") + //TODO("not implemented") } override fun scroll(amount: Int) { - TODO("not implemented") + //TODO("not implemented") } + /** + * does not changes color setting in PPU + */ override fun setColour(back: Int, fore: Int) { - TODO("not implemented") + foreColour = fore + backColour = back } + /** + * does not changes color setting in PPU + */ override fun resetColour() { - TODO("not implemented") + foreColour = foreDefault + backColour = backDefault } /** // copied from SimpleTextTerminal @@ -174,6 +231,53 @@ class GraphicsTerminal( } override fun getKeyPress(): Int? { - TODO("not implemented") + //TODO("not implemented") + return null + } + + companion object { + private val WHITE7500 = Color(0xe4eaff) + + val ASCII_NUL = 0.toChar() + val ASCII_BEL = 7.toChar() // *BEEP!* + val ASCII_BS = 8.toChar() // x = x - 1 + val ASCII_TAB = 9.toChar() // move cursor to next (TABSIZE * yy) pos (5 -> 8, 3- > 4, 4 -> 8) + val ASCII_LF = 10.toChar() // new line + val ASCII_FF = 12.toChar() // new page + val ASCII_CR = 13.toChar() // x <- 0 + val ASCII_DEL = 127.toChar() // backspace and delete char + val ASCII_DC1 = 17.toChar() // foreground colour 0 + val ASCII_DC2 = 18.toChar() // foreground colour 1 + val ASCII_DC3 = 19.toChar() // foreground colour 2 + val ASCII_DC4 = 20.toChar() // foreground colour 3 + val ASCII_DLE = 16.toChar() // error message colour + + val asciiControlInUse = charArrayOf( + ASCII_NUL, + ASCII_BEL, + ASCII_BS, + ASCII_TAB, + ASCII_LF, + ASCII_FF, + ASCII_CR, + ASCII_DEL, + ASCII_DC1, + ASCII_DC2, + ASCII_DC3, + ASCII_DC4, + ASCII_DLE + ) + + val CLUT = DecodeTapestry.colourIndices64 + val CLUT16_TO_64 = intArrayOf( + 15, 49, 16, 48, 44, 29, 33, 18, + 5, 22, 39, 26, 25, 10, 31, 13 + ) + } + + fun attachVideoCard(videocard: PeripheralVideoCard) { + this.videoCard = videocard + + videoScreen = Image(videoCard.width, videoCard.height) } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/virtualcomputer/terminal/SimpleTextTerminal.kt b/src/net/torvald/terrarum/virtualcomputer/terminal/SimpleTextTerminal.kt index bc5bd089a..e5dfa66e5 100644 --- a/src/net/torvald/terrarum/virtualcomputer/terminal/SimpleTextTerminal.kt +++ b/src/net/torvald/terrarum/virtualcomputer/terminal/SimpleTextTerminal.kt @@ -47,7 +47,7 @@ open class SimpleTextTerminal( override var backColour = backDefault override var foreColour = foreDefault private val colourKey: Int - get() = backColour.shl(4).plus(foreColour).and(0xFF) + get() = backColour.shl(4) or (foreColour).and(0xFF) override var cursorX = 0 override var cursorY = 0