more work on the Terminal, ComputerCraft compatibility layer (wip), quarried stone texture

Former-commit-id: 1fd1b5ce05663dd41d6077077b64e08ac0f1b5a0
Former-commit-id: bd52729417fc4dfcd8ad11f00d34507943156a83
This commit is contained in:
Song Minjae
2016-09-16 20:49:46 +09:00
parent abf167d6b8
commit a0afc8ab7a
37 changed files with 897 additions and 128 deletions

View File

@@ -9,31 +9,33 @@ import org.newdawn.slick.Image
/**
* Created by minjaesong on 16-09-12.
*/
class ColouredTextTerminal(override val width: Int, override val height: Int
class ColouredTextTerminal(
override val width: Int, override val height: Int
) : SimpleTextTerminal(Color.white, width, height) {
override val colours = arrayOf(
Color(0x00, 0x00, 0x00), // black
Color(0xff, 0xff, 0xff), // white
Color(0x55, 0x55, 0x55), // dim grey
Color(0xaa, 0xaa, 0xaa), // light grey
Color(0x00, 0x00, 0x00), // 0 black
Color(0xff, 0xff, 0xff), // 1 white
Color(0x55, 0x55, 0x55), // 2 dim grey
Color(0xaa, 0xaa, 0xaa), // 3 light grey
Color(0xff, 0xff, 0x00), // yellow
Color(0xff, 0x66, 0x00), // orange
Color(0xdd, 0x00, 0x00), // red
Color(0xff, 0x00, 0x99), // magenta
Color(0xff, 0xff, 0x00), // 4 yellow
Color(0xff, 0x66, 0x00), // 5 orange
Color(0xdd, 0x00, 0x00), // 6 red
Color(0xff, 0x00, 0x99), // 7 magenta
Color(0x33, 0x00, 0x99), // purple
Color(0x00, 0x00, 0xcc), // blue
Color(0x00, 0x99, 0xff), // cyan
Color(0x66, 0xff, 0x33), // lime
Color(0x33, 0x00, 0x99), // 8 purple
Color(0x00, 0x00, 0xcc), // 9 blue
Color(0x00, 0x99, 0xff), //10 cyan
Color(0x66, 0xff, 0x33), //11 lime
Color(0x00, 0xaa, 0x00), // green
Color(0x00, 0x66, 0x00), // dark green
Color(0x66, 0x33, 0x00), // brown
Color(0x99, 0x66, 0x33) // tan
Color(0x00, 0xaa, 0x00), //12 green
Color(0x00, 0x66, 0x00), //13 dark green
Color(0x66, 0x33, 0x00), //14 brown
Color(0x99, 0x66, 0x33) //15 tan
) // THESE ARE THE STANDARD
override val coloursCount = colours.size
override val coloursCount: Int
get() = colours.size
override val backDefault = 0
override val foreDefault = 3
@@ -41,11 +43,11 @@ class ColouredTextTerminal(override val width: Int, override val height: Int
override var backColour = backDefault
override var foreColour = foreDefault
override val fontRef = "./assets/graphics/fonts/CGA.png"
override val fontRef = "./assets/graphics/fonts/cp949.png"
override val fontImg = Image(fontRef)
override val fontW = fontImg.width / 16
override val fontH = fontImg.height / 16
override val font = ColouredFastFont(this, fontRef, fontW, fontH)
override val colourScreen = Color.black
override val colourScreen: Color = Color.black
}

View File

@@ -31,7 +31,8 @@ open class SimpleTextTerminal(
Color(0xaa, 0xaa, 0xaa) // light grey
) // THESE ARE THE STANDARD
override val coloursCount = colours.size
override val coloursCount: Int
get() = colours.size
open protected val backDefault = 0 // STANDARD
open protected val foreDefault = 3 // STANDARD
@@ -59,14 +60,11 @@ open class SimpleTextTerminal(
private val TABSIZE = 4
private val ASCII_NUL = 0.toChar()
private var cursorBlinkTimer = 0
private val cursorBlinkLen = 250
private var cursorBlinkOn = true
override fun getColor(index: Int): Color = colours[index]
override fun update(gc: GameContainer, delta: Int) {
@@ -177,21 +175,6 @@ open class SimpleTextTerminal(
screenBuffer.drawBuffer(cursorX, cursorY, c.toInt().and(0xFF).toChar(), colourKey)
}
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
)
/** Prints a char and move cursor accordingly. */
override fun printChar(c: Char) {
wrap()
@@ -204,7 +187,7 @@ open class SimpleTextTerminal(
ASCII_BEL -> beep()
ASCII_BS -> { cursorX -= 1; wrap() }
ASCII_TAB -> { cursorX = (cursorX).div(TABSIZE).times(TABSIZE) + TABSIZE }
ASCII_LF -> { cursorX = 0; cursorY += 1; wrap() }
ASCII_LF -> newLine()
ASCII_FF -> clear()
ASCII_CR -> { cursorX = 0 }
ASCII_DEL -> { cursorX -= 1; wrap(); emitChar(colourKey.shl(8)) }
@@ -213,14 +196,30 @@ open class SimpleTextTerminal(
}
}
/** Emits a string and move cursor accordingly. */
/** (TTY): Prints a series of chars and move cursor accordingly, then LF
* (term): printString() on current cursor pos */
override fun printChars(s: String) {
printString(s, cursorX, cursorY)
}
/** (TTY): Prints a series of chars and move cursor accordingly
* (term): writeString() on current cursor pos */
override fun writeChars(s: String) {
writeString(s, cursorX, cursorY)
}
/** Emits a string and move cursor accordingly, then do LF */
override fun printString(s: String, x: Int, y: Int) {
writeString(s, x, y)
newLine()
}
/** Emits a string and move cursor accordingly. */
override fun writeString(s: String, x: Int, y: Int) {
setCursor(x, y)
emitString(s)
val absCursorPos = cursorX + cursorY * width + s.length
setCursor(absCursorPos % width, absCursorPos / width)
printChar(ASCII_LF)
}
/** Emits a string. Does not move cursor */
@@ -245,7 +244,13 @@ open class SimpleTextTerminal(
screenBuffer.drawBuffer(i, cursorY, 0.toChar(), colourKey)
}
override fun newLine() {
cursorX = 0; cursorY += 1; wrap()
}
override fun scroll(amount: Int) {
if (amount < 0) throw IllegalArgumentException("cannot scroll up")
val offset = amount * width
for (i in offset..screenBuffer.sizeof.ushr(1) - 1) {
screenBuffer.frameBuffer[i - offset] = screenBuffer.frameBuffer[i]
@@ -341,7 +346,7 @@ open class SimpleTextTerminal(
}
/** for "beep code" on modern BIOS. Pattern: - . */
override fun beep(pattern: String) {
override fun bell(pattern: String) {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -390,6 +395,7 @@ open class SimpleTextTerminal(
val ELECTRIC_BLUE = Color(0, 239, 255) // imaginary, 486 nm
val RED = Color(250, 0, 0) // <= 645 nm
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)
@@ -401,6 +407,21 @@ open class SimpleTextTerminal(
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 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
)
}
private val DEBUG = true

View File

@@ -0,0 +1,38 @@
package net.torvald.terrarum.virtualcomputer.terminal
import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics
/**
* Created by minjaesong on 16-09-14.
*/
interface Teletype {
val width: Int
val displayW: Int
var cursorX: Int
/**
* 0: Teletype
* 4: Non-colour terminal (Note that '2' is invalid!)
* >4: Colour terminal
*/
val coloursCount: Int
fun update(gc: GameContainer, delta: Int)
fun render(gc: GameContainer, g: Graphics)
fun keyPressed(key: Int, c: Char)
/** Prints a char and move cursor accordingly */
fun printChar(c: Char)
/** (TTY): Prints a series of chars and move cursor accordingly, then LF
* (term): printString() on current cursor pos */
fun printChars(s: String)
/** (TTY): Prints a series of chars and move cursor accordingly
* (term): writeString() on current cursor pos */
fun writeChars(s: String)
fun newLine()
fun scroll(amount: Int = 1)
fun bell(pattern: String = ".")
}

View File

@@ -0,0 +1,223 @@
package net.torvald.terrarum.virtualcomputer.terminal
import net.torvald.imagefont.GameFontBase
import net.torvald.terrarum.blendMul
import net.torvald.terrarum.blendNormal
import org.newdawn.slick.*
import java.util.*
/**
* Created by minjaesong on 16-09-15.
*/
class TeletypeTerminal : Teletype {
override val width = 40
override val displayW: Int
get() = width * font.W
/**
* 0: Teletype
* 4: Non-colour terminal (Note that '2' is invalid!)
* >4: Colour terminal
*/
override val coloursCount = 0
override var cursorX = 0
private val font = TTYFont()
private var lineBuffer = StringBuilder()
private var currentJob = 0
private var currentJobStep = 0
private var currentJobLen = 0
private var currentJobQueue: Any? = null
// make sure certain jobs deliberately take long time by doing them one-by-one, for each frame.
private val JOB_IDLE = 0
private val JOB_MOVEHEAD = 1
private val JOB_PRINTCHAR = 2
private val JOB_LINEFEED = 3
override fun update(gc: GameContainer, delta: Int) {
wrap()
/*when (currentJob) {
JOB_PRINTCHAR -> {
printChar((currentJobQueue!! as String)[currentJobStep])
currentJobStep += 1
}
JOB_LINEFEED -> {
newLine()
currentJobStep += 1
}
}*/
if (currentJobStep > currentJobLen) {
currentJob = JOB_IDLE
currentJobLen = 0
currentJobStep = 0
currentJobQueue = null
}
}
override fun render(gc: GameContainer, g: Graphics) {
g.font = font
g.drawString(lineBuffer.toString(), 0f, 0f)
}
val TABSIZE = 4
/** Prints a char and move cursor accordingly */
override fun printChar(c: Char) {
wrap()
if (c >= ' ' && c.toInt() != 127) {
lineBuffer.append(c)
cursorX += 1
}
else {
when (c) {
SimpleTextTerminal.ASCII_BEL -> bell()
SimpleTextTerminal.ASCII_BS -> { cursorX -= 1; wrap() }
SimpleTextTerminal.ASCII_TAB -> { cursorX = (cursorX).div(TABSIZE).times(TABSIZE) + TABSIZE }
SimpleTextTerminal.ASCII_LF -> newLine()
SimpleTextTerminal.ASCII_FF -> newLine()
SimpleTextTerminal.ASCII_CR -> { cursorX = 0 }
SimpleTextTerminal.ASCII_DEL -> { } // NOT supported, do nothing
SimpleTextTerminal.ASCII_DC1, SimpleTextTerminal.ASCII_DC2, SimpleTextTerminal.ASCII_DC3, SimpleTextTerminal.ASCII_DC4
-> { } // NOT supported, do nothing
}
}
}
/** (TTY): Prints a series of chars and move cursor accordingly
* (term): writeString() on current cursor pos */
override fun writeChars(s: String) {
/*currentJob = JOB_PRINTCHAR
currentJobLen = s.length
currentJobQueue = s*/
for (i in 0..s.length - 1)
printChar(s[i])
}
/** (TTY): Prints a series of chars and move cursor accordingly, then LF
* (term): writeString() on current cursor pos */
override fun printChars(s: String) {
/*currentJob = JOB_PRINTCHAR
currentJobLen = s.length + 1
currentJobQueue = "$s\n"*/
writeChars("$s\n")
}
override fun newLine() {
lineBuffer = StringBuilder()
}
override fun scroll(amount: Int) {
if (amount < 0) throw IllegalArgumentException("cannot scroll up")
if (amount == 1) { newLine(); return }
currentJob = JOB_LINEFEED
currentJobLen = amount
}
override fun bell(pattern: String) {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
private fun wrap() {
if (cursorX < 0) cursorX = 0
else if (cursorX >= width) newLine()
}
var sb: StringBuilder = StringBuilder()
private var inputOpen = false
val DEBUG = true
/**
* Technically, this is different from Java's InputStream
*/
fun openInput() {
inputOpen = true
if (DEBUG) println("[SimpleTextTerminal] openInput()")
}
fun closeInput(): String {
inputOpen = false
val ret = sb.toString()
sb = StringBuilder()
if (DEBUG) println("[SimpleTextTerminal] closeInput(), $ret")
return ret
}
override fun keyPressed(key: Int, c: Char) {
if (inputOpen) {
if (c == SimpleTextTerminal.ASCII_CR)
printChar(SimpleTextTerminal.ASCII_LF)
else
printChar(c)
if (!SimpleTextTerminal.asciiControlInUse.contains(c)) sb.append(c)
else if (c == SimpleTextTerminal.ASCII_DEL && sb.length > 0) sb.deleteCharAt(sb.length - 1)
}
}
class TTYFont : Font {
internal val fontSheet: SpriteSheet
internal val W = 9
internal val H = 12
private val chars = arrayOf(
'0','1','2','3','4','5','6','7',
'8','9','[','#','@',':','>','?',
' ','A','B','C','D','E','F','G',
'H','I','&','.',']','(','<','\\',
'^','J','K','L','M','N','O','P', // ^: escape for capital letter
'Q','R','-','¤','*',')',';','\'',
'+','/','S','T','U','V','W','X',
'Y','Z','_',',','%','=','"','!'
)
private val mappingTable = HashMap<Int, Int>()
init {
fontSheet = SpriteSheet("./assets/graphics/fonts/teletype_9x12.png", W, H)
chars.forEachIndexed { i, c -> mappingTable[c.toInt()] = i }
}
override fun getHeight(str: String): Int = H
override fun getWidth(str: String): Int {
var ret = 0
for (i in 0..str.length - 1)
ret += W
return ret
}
override fun getLineHeight(): Int = H
override fun drawString(x: Float, y: Float, text: String) = drawString(x, y, text, Color.white)
override fun drawString(x: Float, y: Float, text: String, col: Color) {
var thisCol = col
var textPosOffset = 0
for (i in 0..text.length - 1) {
val index = charToSpriteNum(text.toUpperCase().codePointAt(i))
val ch = text[i]
if (index != null) {
// main
fontSheet.getSubImage(index % 8, index / 8).draw(
x + textPosOffset, y, thisCol
)
}
textPosOffset += W
}
}
override fun drawString(x: Float, y: Float, text: String, col: Color, startIndex: Int, endIndex: Int) {
throw UnsupportedOperationException()
}
private fun charToSpriteNum(ch: Int): Int? = mappingTable[ch]
}
}

View File

@@ -6,19 +6,19 @@ import org.newdawn.slick.Graphics
import org.newdawn.slick.Input
/**
* A tty (terminal)
* A terminal
*
* Framebuffer : use net.torvald.aa.AAFrame
* Framebuffer: USE net.torvald.aa.AAFrame
*
* Background color is fixed; text color is variable
*
* Created by minjaesong on 16-09-07.
*/
interface Terminal {
val width: Int
interface Terminal : Teletype {
override val width: Int
val height: Int
val coloursCount: Int
var cursorX: Int
override val coloursCount: Int
override var cursorX: Int
var cursorY: Int
var cursorBlink: Boolean
var backColour: Int
@@ -27,13 +27,13 @@ interface Terminal {
var lastInputByte: Int
// to be used in UI
val displayW: Int
override val displayW: Int
val displayH: Int
fun getColor(index: Int): Color
fun update(gc: GameContainer, delta: Int)
fun render(gc: GameContainer, g: Graphics)
fun keyPressed(key: Int, c: Char)
override fun update(gc: GameContainer, delta: Int)
override fun render(gc: GameContainer, g: Graphics)
override fun keyPressed(key: Int, c: Char)
// API calls
fun setCursor(x: Int, y: Int)
@@ -44,14 +44,17 @@ interface Terminal {
* It is also not affected by the control sequences; just print them out as symbol */
fun emitChar(c: Char)
/** Prints a char and move cursor accordingly. */
fun printChar(c: Char)
override fun printChar(c: Char)
/** Emits a string. Does not move cursor */
fun emitString(s: String)
/** Emits a string and move cursor accordingly. */
/** Emits a string and move cursor accordingly, then do LF */
fun printString(s: String, x: Int = cursorX, y: Int = cursorY)
/** Emits a string and move cursor accordingly. */
fun writeString(s: String, x: Int = cursorX, y: Int = cursorY)
fun clear()
fun clearLine()
fun scroll(amount: Int = 1)
override fun newLine()
override fun scroll(amount: Int)
fun setColour(back: Int, fore: Int)
fun resetColour()
/**
@@ -60,7 +63,7 @@ interface Terminal {
*/
fun beep(freq: Float = 1000f, duration: Int = 200)
/** for "beep code" on modern BIOS. Pattern: - . */
fun beep(pattern: String)
override fun bell(pattern: String)
/** Requires keyPressed() event to be processed.
*
* null indicates the input stream is waiting for an input

View File

@@ -6,10 +6,8 @@ import java.io.InputStream
/**
* Created by minjaesong on 16-09-10.
*/
class TerminalInputStream(val term: Terminal) : InputStream() {
class TerminalInputStream(val term: Teletype) : InputStream() {
override fun read(): Int {
val ret = term.lastInputByte
term.lastInputByte = -1
return ret
return -1
}
}

View File

@@ -6,10 +6,10 @@ import java.io.PrintStream
/**
* Created by minjaesong on 16-09-10.
*/
class TerminalPrintStream(val term: Terminal) : PrintStream(TerminalOutputStream(term)) {
class TerminalPrintStream(val term: Teletype) : PrintStream(TerminalOutputStream(term)) {
}
class TerminalOutputStream(val term: Terminal) : OutputStream() {
class TerminalOutputStream(val term: Teletype) : OutputStream() {
override fun write(b: Int) = term.printChar(b.and(0xFF).toChar())
}