working io.read from STDIN

Former-commit-id: b1168a53fd5fbd09c6a5a76506402560fc4e0fd7
Former-commit-id: a0d455da14a6eb7bf0127e136949273ec5a28628
This commit is contained in:
Song Minjae
2017-03-02 22:35:13 +09:00
parent 74250150de
commit 55f7a4ed46
12 changed files with 457 additions and 401 deletions

View File

@@ -1,6 +1,7 @@
package net.torvald.terrarum package net.torvald.terrarum
import net.torvald.random.HQRNG import net.torvald.random.HQRNG
import net.torvald.terrarum.Terrarum.UPDATE_DELTA
import net.torvald.terrarum.gameactors.roundInt import net.torvald.terrarum.gameactors.roundInt
import net.torvald.terrarum.virtualcomputer.computer.TerrarumComputer import net.torvald.terrarum.virtualcomputer.computer.TerrarumComputer
import net.torvald.terrarum.virtualcomputer.peripheral.PeripheralVideoCard import net.torvald.terrarum.virtualcomputer.peripheral.PeripheralVideoCard
@@ -20,7 +21,7 @@ class StateGraphicComputerTest : BasicGameState() {
val monitor = GraphicsTerminal(computer) val monitor = GraphicsTerminal(computer)
init { init {
val videocard = PeripheralVideoCard() val videocard = PeripheralVideoCard(computer)
monitor.attachVideoCard(videocard) monitor.attachVideoCard(videocard)
computer.attachTerminal(monitor) computer.attachTerminal(monitor)
@@ -31,7 +32,11 @@ class StateGraphicComputerTest : BasicGameState() {
val vcard = (computer.getPeripheral("ppu") as PeripheralVideoCard).vram val vcard = (computer.getPeripheral("ppu") as PeripheralVideoCard).vram
// it's a-me, Mario! // it's a-me, Mario!
/*(0..3).forEach { vcard.sprites[it].setPaletteSet(64,33,12,62) } /*(0..3).forEach {
vcard.sprites[it].setPaletteSet(64,33,12,62)
vcard.sprites[it].isVisible = true
vcard.sprites[it].drawWide = true
}
vcard.sprites[0].setAll(intArrayOf( vcard.sprites[0].setAll(intArrayOf(
0,0,0,0,0,1,1,1, 0,0,0,0,0,1,1,1,
@@ -76,6 +81,8 @@ class StateGraphicComputerTest : BasicGameState() {
} }
override fun update(container: GameContainer, game: StateBasedGame?, delta: Int) { override fun update(container: GameContainer, game: StateBasedGame?, delta: Int) {
UPDATE_DELTA = delta
Terrarum.appgc.setTitle("VT — F: ${container.fps}" + Terrarum.appgc.setTitle("VT — F: ${container.fps}" +
" — M: ${Terrarum.memInUse}M / ${Terrarum.memTotal}M / ${Terrarum.memXmx}M" + " — M: ${Terrarum.memInUse}M / ${Terrarum.memTotal}M / ${Terrarum.memXmx}M" +
" ${Random().nextInt(100)}") " ${Random().nextInt(100)}")
@@ -83,7 +90,11 @@ class StateGraphicComputerTest : BasicGameState() {
computer.update(container, delta) computer.update(container, delta)
/*val vcard = (computer.getPeripheral("ppu") as PeripheralVideoCard).vram
vcard.sprites[0].setPos(20, 20)
vcard.sprites[1].setPos(36, 20)
vcard.sprites[2].setPos(20, 28)
vcard.sprites[3].setPos(36, 28)*/
} }
override fun getID() = Terrarum.STATE_ID_TEST_TTY override fun getID() = Terrarum.STATE_ID_TEST_TTY

View File

@@ -2,6 +2,7 @@ package net.torvald.terrarum
import net.torvald.imagefont.GameFontBase import net.torvald.imagefont.GameFontBase
import net.torvald.random.HQRNG import net.torvald.random.HQRNG
import net.torvald.terrarum.Terrarum.UPDATE_DELTA
import net.torvald.terrarum.audio.AudioResourceLibrary import net.torvald.terrarum.audio.AudioResourceLibrary
import net.torvald.terrarum.concurrent.ThreadParallel import net.torvald.terrarum.concurrent.ThreadParallel
import net.torvald.terrarum.console.* import net.torvald.terrarum.console.*
@@ -91,8 +92,6 @@ class StateInGame : BasicGameState() {
val KEY_LIGHTMAP_RENDER = Key.F7 val KEY_LIGHTMAP_RENDER = Key.F7
val KEY_LIGHTMAP_SMOOTH = Key.F8 val KEY_LIGHTMAP_SMOOTH = Key.F8
var UPDATE_DELTA: Int = 0
// UI aliases // UI aliases
val uiAliases = HashMap<String, UIHandler>() val uiAliases = HashMap<String, UIHandler>()
private val UI_PIE_MENU = "uiPieMenu" private val UI_PIE_MENU = "uiPieMenu"

View File

@@ -2,7 +2,7 @@ package net.torvald.terrarum
import com.sudoplay.joise.Joise import com.sudoplay.joise.Joise
import com.sudoplay.joise.module.* import com.sudoplay.joise.module.*
import net.torvald.terrarum.Terrarum.Companion.STATE_ID_TOOL_NOISEGEN import net.torvald.terrarum.Terrarum.STATE_ID_TOOL_NOISEGEN
import net.torvald.terrarum.concurrent.ThreadParallel import net.torvald.terrarum.concurrent.ThreadParallel
import net.torvald.terrarum.gameactors.roundInt import net.torvald.terrarum.gameactors.roundInt
import org.newdawn.slick.* import org.newdawn.slick.*

View File

@@ -1,6 +1,5 @@
package net.torvald.terrarum package net.torvald.terrarum
import net.torvald.terrarum.Terrarum.Companion.STATE_ID_TEST_SHADER
import org.lwjgl.opengl.* import org.lwjgl.opengl.*
import org.newdawn.slick.GameContainer import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics import org.newdawn.slick.Graphics
@@ -13,6 +12,7 @@ import org.lwjgl.opengl.GL11
import org.lwjgl.opengl.ARBShaderObjects import org.lwjgl.opengl.ARBShaderObjects
import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil.close import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil.close
import jdk.nashorn.internal.runtime.ScriptingFunctions.readLine import jdk.nashorn.internal.runtime.ScriptingFunctions.readLine
import net.torvald.terrarum.Terrarum.STATE_ID_TEST_SHADER
import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarum.gameworld.fmod
import org.newdawn.slick.Color import org.newdawn.slick.Color
import org.newdawn.slick.opengl.TextureImpl import org.newdawn.slick.opengl.TextureImpl

View File

@@ -24,138 +24,13 @@ import java.util.logging.Level
import java.util.logging.Logger import java.util.logging.Logger
import java.util.logging.SimpleFormatter import java.util.logging.SimpleFormatter
const val GAME_NAME = "Terrarum"
/** /**
* Created by minjaesong on 15-12-30. * Created by minjaesong on 15-12-30.
*/ */
class Terrarum @Throws(SlickException::class) object Terrarum : StateBasedGame(GAME_NAME) {
constructor(gamename: String) : StateBasedGame(gamename) {
// these properties goes into the GameContainer
var previousState: Int? = null // to be used with temporary states like StateMonitorCheck
val systemArch = System.getProperty("os.arch")
private val thirtyTwoBitArchs = arrayOf("i386", "i686", "ppc", "x86", "x86_32") // I know I should Write Once, Run Everywhere; but just in case :)
val is32Bit = thirtyTwoBitArchs.contains(systemArch)
init {
// just in case
println("[Terrarum] os.arch = $systemArch")
if (is32Bit) {
println("Java is running in 32 Bit")
}
gameConfig = GameConfig()
joypadLabelStart = when (getConfigString("joypadlabelstyle")) {
"nwii" -> 0xE04B.toChar() // + mark
"logitech" -> 0xE05A.toChar() // number 10
else -> 0xE042.toChar() // |> mark (sonyps, msxb360, generic)
}
joypadLableSelect = when (getConfigString("joypadlabelstyle")) {
"nwii" -> 0xE04D.toChar() // - mark
"logitech" -> 0xE059.toChar() // number 9
"sonyps" -> 0xE043.toChar() // solid rectangle
"msxb360" -> 0xE041.toChar() // <| mark
else -> 0xE043.toChar() // solid rectangle
}
getDefaultDirectory()
createDirs()
val readFromDisk = readConfigJson()
if (!readFromDisk) readConfigJson()
try {
Controllers.getController(0)
environment = if (getConfigString("pcgamepadenv") == "console")
RunningEnvironment.CONSOLE
else
RunningEnvironment.PC
}
catch (e: IndexOutOfBoundsException) {
environment = RunningEnvironment.PC
}
}
@Throws(SlickException::class)
override fun initStatesList(gc: GameContainer) {
gc.input.enableKeyRepeat()
// get locale from config
val gameLocaleFromConfig = gameConfig.getAsString("language") ?: sysLang
// if bad game locale were set, use system locale
if (gameLocaleFromConfig.length < 2)
gameLocale = sysLang
else
gameLocale = gameLocaleFromConfig
println("[Terrarum] Locale: " + gameLocale)
fontGame = GameFontImpl()
fontSmallNumbers = TinyAlphNum()
// search for real controller
// exclude controllers with name "Mouse", "keyboard"
val notControllerRegex = Regex("mouse|keyboard")
try {
// gc.input.controllerCount is unreliable
for (i in 0..255) {
val controllerInQuo = Controllers.getController(i)
println("Controller $i: ${controllerInQuo.name}")
// check the name
if (!controllerInQuo.name.toLowerCase().contains(notControllerRegex)) {
controller = controllerInQuo
println("Controller $i selected: ${controller!!.name}")
break
}
}
}
catch (e: IndexOutOfBoundsException) {
}
if (controller != null) {
for (c in 0..controller!!.axisCount - 1) {
controller!!.setDeadZone(c, CONTROLLER_DEADZONE)
}
}
gc.graphics.clear() // clean up any 'dust' in the buffer
//addState(StateVTTest())
addState(StateGraphicComputerTest())
//addState(StateTestingLightning())
//addState(StateSplash())
//addState(StateMonitorCheck())
//addState(StateFontTester())
//addState(StateNoiseTexGen())
//addState(StateBlurTest())
//addState(StateShaderTest())
//addState(StateNoiseTester())
ingame = StateInGame()
addState(ingame)
// foolproof
if (stateCount < 1) {
throw Error("Please add or un-comment addState statements")
}
}
companion object {
val sysLang: String val sysLang: String
get() { get() {
@@ -231,7 +106,7 @@ constructor(gamename: String) : StateBasedGame(gamename) {
private set private set
var joypadLabelStart: Char = 0xE000.toChar() // lateinit var joypadLabelStart: Char = 0xE000.toChar() // lateinit
var joypadLableSelect:Char = 0xE000.toChar() // lateinit var joypadLableSelect: Char = 0xE000.toChar() // lateinit
var joypadLabelNinA: Char = 0xE000.toChar() // lateinit TODO var joypadLabelNinA: Char = 0xE000.toChar() // lateinit TODO
var joypadLabelNinB: Char = 0xE000.toChar() // lateinit TODO var joypadLabelNinB: Char = 0xE000.toChar() // lateinit TODO
var joypadLabelNinX: Char = 0xE000.toChar() // lateinit TODO var joypadLabelNinX: Char = 0xE000.toChar() // lateinit TODO
@@ -292,47 +167,59 @@ constructor(gamename: String) : StateBasedGame(gamename) {
"${VERSION_RAW.ushr(24)}.${VERSION_RAW.and(0xFF0000).ushr(16)}.${VERSION_RAW.and(0xFFFF)}" "${VERSION_RAW.ushr(24)}.${VERSION_RAW.and(0xFF0000).ushr(16)}.${VERSION_RAW.and(0xFFFF)}"
const val NAME = "Terrarum" const val NAME = "Terrarum"
fun main(args: Array<String>) { var UPDATE_DELTA: Int = 0
System.setProperty("java.library.path", "lib")
System.setProperty("org.lwjgl.librarypath", File("lib").absolutePath) // these properties goes into the GameContainer
var previousState: Int? = null // to be used with temporary states like StateMonitorCheck
val systemArch = System.getProperty("os.arch")
private val thirtyTwoBitArchs = arrayOf("i386", "i686", "ppc", "x86", "x86_32") // I know I should Write Once, Run Everywhere; but just in case :)
val is32Bit = thirtyTwoBitArchs.contains(systemArch)
init {
// just in case
println("[Terrarum] os.arch = $systemArch")
if (is32Bit) {
println("Java is running in 32 Bit")
}
gameConfig = GameConfig()
joypadLabelStart = when (getConfigString("joypadlabelstyle")) {
"nwii" -> 0xE04B.toChar() // + mark
"logitech" -> 0xE05A.toChar() // number 10
else -> 0xE042.toChar() // |> mark (sonyps, msxb360, generic)
}
joypadLableSelect = when (getConfigString("joypadlabelstyle")) {
"nwii" -> 0xE04D.toChar() // - mark
"logitech" -> 0xE059.toChar() // number 9
"sonyps" -> 0xE043.toChar() // solid rectangle
"msxb360" -> 0xE041.toChar() // <| mark
else -> 0xE043.toChar() // solid rectangle
}
getDefaultDirectory()
createDirs()
val readFromDisk = readConfigJson()
if (!readFromDisk) readConfigJson()
try { try {
appgc = AppGameContainer(Terrarum(NAME)) Controllers.getController(0)
appgc.setDisplayMode(WIDTH, HEIGHT, false) environment = if (getConfigString("pcgamepadenv") == "console")
RunningEnvironment.CONSOLE
appgc.setTargetFrameRate(TARGET_INTERNAL_FPS) else
appgc.setVSync(VSYNC) RunningEnvironment.PC
appgc.setMaximumLogicUpdateInterval(1000 / TARGET_INTERNAL_FPS) // 10 ms
appgc.setMinimumLogicUpdateInterval(1000 / TARGET_INTERNAL_FPS - 1) // 9 ms
appgc.setMultiSample(0)
appgc.setShowFPS(false)
// game will run normally even if it is not focused
appgc.setUpdateOnlyWhenVisible(false)
appgc.alwaysRender = true
appgc.start()
} }
catch (ex: Exception) { catch (e: IndexOutOfBoundsException) {
val logger = Logger.getLogger(Terrarum::class.java.name) environment = RunningEnvironment.PC
val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss")
val calendar = Calendar.getInstance()
val filepath = "$defaultDir/crashlog-${dateFormat.format(calendar.time)}.txt"
val fileHandler = FileHandler(filepath)
logger.addHandler(fileHandler)
val formatter = SimpleFormatter()
fileHandler.formatter = formatter
//logger.info()
println("The game has crashed!")
println("Crash log were saved to $filepath.")
println("================================================================================")
logger.log(Level.SEVERE, null, ex)
} }
} }
private fun getDefaultDirectory() { private fun getDefaultDirectory() {
@@ -463,10 +350,16 @@ constructor(gamename: String) : StateBasedGame(gamename) {
private fun getConfigMaster(key: String): Any { private fun getConfigMaster(key: String): Any {
var cfg: Any? = null var cfg: Any? = null
try { cfg = gameConfig[key.toLowerCase()]!! } try {
cfg = gameConfig[key.toLowerCase()]!!
}
catch (e: NullPointerException) { catch (e: NullPointerException) {
try { cfg = DefaultConfig.fetch()[key.toLowerCase()] } try {
catch (e1: NullPointerException) { e.printStackTrace() } cfg = DefaultConfig.fetch()[key.toLowerCase()]
}
catch (e1: NullPointerException) {
e.printStackTrace()
}
} }
return cfg!! return cfg!!
} }
@@ -480,11 +373,119 @@ constructor(gamename: String) : StateBasedGame(gamename) {
return file // TODO TEST CODE return file // TODO TEST CODE
} }
@Throws(SlickException::class)
override fun initStatesList(gc: GameContainer) {
gc.input.enableKeyRepeat()
// get locale from config
val gameLocaleFromConfig = gameConfig.getAsString("language") ?: sysLang
// if bad game locale were set, use system locale
if (gameLocaleFromConfig.length < 2)
gameLocale = sysLang
else
gameLocale = gameLocaleFromConfig
println("[Terrarum] Locale: " + gameLocale)
fontGame = GameFontImpl()
fontSmallNumbers = TinyAlphNum()
// search for real controller
// exclude controllers with name "Mouse", "keyboard"
val notControllerRegex = Regex("mouse|keyboard")
try {
// gc.input.controllerCount is unreliable
for (i in 0..255) {
val controllerInQuo = Controllers.getController(i)
println("Controller $i: ${controllerInQuo.name}")
// check the name
if (!controllerInQuo.name.toLowerCase().contains(notControllerRegex)) {
controller = controllerInQuo
println("Controller $i selected: ${controller!!.name}")
break
}
}
}
catch (e: IndexOutOfBoundsException) {
}
if (controller != null) {
for (c in 0..controller!!.axisCount - 1) {
controller!!.setDeadZone(c, CONTROLLER_DEADZONE)
}
}
gc.graphics.clear() // clean up any 'dust' in the buffer
//addState(StateVTTest())
addState(StateGraphicComputerTest())
//addState(StateTestingLightning())
//addState(StateSplash())
//addState(StateMonitorCheck())
//addState(StateFontTester())
//addState(StateNoiseTexGen())
//addState(StateBlurTest())
//addState(StateShaderTest())
//addState(StateNoiseTester())
ingame = StateInGame()
addState(ingame)
// foolproof
if (stateCount < 1) {
throw Error("Please add or un-comment addState statements")
}
} }
} }
fun main(args: Array<String>) { fun main(args: Array<String>) {
Terrarum.main(args) System.setProperty("java.library.path", "lib")
System.setProperty("org.lwjgl.librarypath", File("lib").absolutePath)
try {
Terrarum.appgc = AppGameContainer(Terrarum)
Terrarum.appgc.setDisplayMode(Terrarum.WIDTH, Terrarum.HEIGHT, false)
Terrarum.appgc.setTargetFrameRate(Terrarum.TARGET_INTERNAL_FPS)
Terrarum.appgc.setVSync(Terrarum.VSYNC)
Terrarum.appgc.setMaximumLogicUpdateInterval(1000 / Terrarum.TARGET_INTERNAL_FPS) // 10 ms
Terrarum.appgc.setMinimumLogicUpdateInterval(1000 / Terrarum.TARGET_INTERNAL_FPS - 1) // 9 ms
Terrarum.appgc.setMultiSample(0)
Terrarum.appgc.setShowFPS(false)
// game will run normally even if it is not focused
Terrarum.appgc.setUpdateOnlyWhenVisible(false)
Terrarum.appgc.alwaysRender = true
Terrarum.appgc.start()
}
catch (ex: Exception) {
val logger = Logger.getLogger(Terrarum::class.java.name)
val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss")
val calendar = Calendar.getInstance()
val filepath = "${Terrarum.defaultDir}/crashlog-${dateFormat.format(calendar.time)}.txt"
val fileHandler = FileHandler(filepath)
logger.addHandler(fileHandler)
val formatter = SimpleFormatter()
fileHandler.formatter = formatter
//logger.info()
println("The game has crashed!")
println("Crash log were saved to $filepath.")
println("================================================================================")
logger.log(Level.SEVERE, null, ex)
}
} }
/////////////////////////////////// ///////////////////////////////////
@@ -566,6 +567,7 @@ fun Texture.getPixel(x: Int, y: Int): IntArray {
) )
} }
} }
/** @return Intarray(R, G, B, A) */ /** @return Intarray(R, G, B, A) */
fun Image.getPixel(x: Int, y: Int) = this.texture.getPixel(x, y) fun Image.getPixel(x: Int, y: Int) = this.texture.getPixel(x, y)

View File

@@ -235,7 +235,7 @@ open class ActorWithSprite(renderOrder: ActorOrder, val immobileBody: Boolean =
protected val gameContainer: GameContainer protected val gameContainer: GameContainer
get() = Terrarum.appgc get() = Terrarum.appgc
protected val updateDelta: Int protected val updateDelta: Int
get() = Terrarum.ingame.UPDATE_DELTA get() = Terrarum.UPDATE_DELTA
/** /**
* true: This actor had just made collision * true: This actor had just made collision

View File

@@ -20,7 +20,7 @@ open class ParticleBase(renderOrder: ActorOrder, maxLifeTime: Int? = null) : Run
/** Will NOT actually delete from the CircularArray */ /** Will NOT actually delete from the CircularArray */
@Volatile var flagDespawn = false @Volatile var flagDespawn = false
override fun run() = update(Terrarum.appgc, Terrarum.ingame.UPDATE_DELTA) override fun run() = update(Terrarum.appgc, Terrarum.UPDATE_DELTA)
var isNoSubjectToGrav = false var isNoSubjectToGrav = false
var dragCoefficient = 3.0 var dragCoefficient = 3.0

View File

@@ -75,40 +75,48 @@ end]] -- DELETED: use _G.input.isKeyDown(keycode)
--- --- --- ---
--input.readLine = _G.__scanforline__ io.__openfile__ = "stdin"
--[[io.__openfile__ = "stdin"
io.stdin = "stdin" io.stdin = "stdin"
io.stdout = "stdout" io.stdout = "stdout"
io.stderr = "stderr" io.stderr = "stderr"
io.open = fs.open]] io.open = fs.open
--[[io.input = function(luafile) io.input = function(luafile)
io.__openfile__ = luafile io.__openfile__ = luafile
end end
io.read = function(option) io.read = function(option)
if io.__openfile__ == "stdin" then if io.__openfile__ == "stdin" then
return _G.__scanforline__() local input = ""
local inkey = null -- local variable init REQUIRED!
-- RETURN not hit
while inkey ~= 13 do
inkey = machine.__readFromStdin()
if inkey >= 32 then
io.write(string.char(inkey))
input = input..string.char(inkey)
end
end
-- RETURN finally hit
io.write("\n")
return input
end end
function _readAll() function _readAll()
return io.__openfile__.readAll() return io.open(io.__openfile__).readAll()
end end
function _readLine() function _readLine()
return io.__openfile__.readLine() return io.open(io.__openfile__).readLine()
end end
options = {} options = {}
options["*n"] = function() error("Read number is not supported, yet!") end--_readNumber options["*n"] = function() error("Read number is not supported, yet!") end--_readNumber
options["*a"] = _readAll options["*a"] = _readAll
options["*l"] = _readLine options["*l"] = _readLine
end]]
io.read = function()
return string.char(machine.__readFromStdin())
end end
----------------- -----------------

View File

@@ -213,23 +213,15 @@ class TerrarumComputer(peripheralSlots: Int) {
fun keyPressed(key: Int, c: Char) { fun keyPressed(key: Int, c: Char) {
stdinInput = c.toInt() stdinInput = c.toInt()
System.err.println("TerrarumComputer.keyPressed got input: $stdinInput")
// wake thread // wake thread
runnableRunCommand.resume() runnableRunCommand.resume()
synchronized(stdin!!) { synchronized(stdin!!) {
(stdin as java.lang.Object).notifyAll() (stdin as java.lang.Object).notifyAll()
} }
} }
fun openStdin() { fun openStdin() {
System.err.println("TerrarumComputer.openStdin")
stdinInput = -1 stdinInput = -1
// sleep the thread // sleep the thread
runnableRunCommand.pause() runnableRunCommand.pause()
@@ -344,8 +336,6 @@ class TerrarumComputer(peripheralSlots: Int) {
synchronized(pauseLock) { synchronized(pauseLock) {
paused = false paused = false
pauseLock.notifyAll() // Unblocks thread pauseLock.notifyAll() // Unblocks thread
System.err.println("ThreadRunCommand resume()")
} }
} }
} }

View File

@@ -1,16 +1,22 @@
package net.torvald.terrarum.virtualcomputer.peripheral package net.torvald.terrarum.virtualcomputer.peripheral
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gameactors.DecodeTapestry import net.torvald.terrarum.gameactors.DecodeTapestry
import net.torvald.terrarum.gameactors.ai.toLua import net.torvald.terrarum.gameactors.ai.toLua
import net.torvald.terrarum.virtualcomputer.computer.TerrarumComputer
import net.torvald.terrarum.virtualcomputer.terminal.Terminal
import org.luaj.vm2.* import org.luaj.vm2.*
import org.luaj.vm2.lib.* import org.luaj.vm2.lib.*
import org.luaj.vm2.lib.ThreeArgFunction import org.luaj.vm2.lib.ThreeArgFunction
import org.newdawn.slick.* import org.newdawn.slick.*
import java.util.*
/** /**
* Resolution: 640 x 200, non-square pixels
*
* Created by SKYHi14 on 2017-02-08. * Created by SKYHi14 on 2017-02-08.
*/ */
class PeripheralVideoCard(val termW: Int = 40, val termH: Int = 25) : class PeripheralVideoCard(val host: TerrarumComputer, val termW: Int = 80, val termH: Int = 25) :
Peripheral("ppu") { Peripheral("ppu") {
companion object { companion object {
val blockW = 8 // MUST BE 8 val blockW = 8 // MUST BE 8
@@ -46,6 +52,12 @@ class PeripheralVideoCard(val termW: Int = 40, val termH: Int = 25) :
// hard-coded 8x8 // hard-coded 8x8
var fontRom = Array<IntArray>(256, { IntArray(blockH) }) var fontRom = Array<IntArray>(256, { IntArray(blockH) })
var showCursor = true
private var cursorBlinkOn = true
private var cursorBlinkTimer = 0
private val cursorBlinkTime = 250
init { init {
// build it for first time // build it for first time
resetTextRom() resetTextRom()
@@ -68,7 +80,13 @@ class PeripheralVideoCard(val termW: Int = 40, val termH: Int = 25) :
} }
} }
val cursorSprite = ImageBuffer(blockW, blockH * 2)
val cursorImage: Image
init { init {
Arrays.fill(cursorSprite.rgba, 0xFF.toByte())
cursorImage = cursorSprite.image
fun composeSpriteObject(spriteIndex: Int) : LuaValue { fun composeSpriteObject(spriteIndex: Int) : LuaValue {
val sprite = vram.sprites[spriteIndex] val sprite = vram.sprites[spriteIndex]
val t = LuaTable() val t = LuaTable()
@@ -124,8 +142,8 @@ class PeripheralVideoCard(val termW: Int = 40, val termH: Int = 25) :
globals["ppu"]["clearFore"] = ClearForeground(this) globals["ppu"]["clearFore"] = ClearForeground(this)
globals["ppu"]["getSpritesCount"] = GetSpritesCount(this) globals["ppu"]["getSpritesCount"] = GetSpritesCount(this)
globals["ppu"]["getWidth"] = GetWidth(this) globals["ppu"]["width"] = GetWidth(this)
globals["ppu"]["getHeight"] = GetHeight(this) globals["ppu"]["height"] = GetHeight(this)
globals["ppu"]["getSprite"] = GetSprite(this) globals["ppu"]["getSprite"] = GetSprite(this)
@@ -137,31 +155,53 @@ class PeripheralVideoCard(val termW: Int = 40, val termH: Int = 25) :
globals["ppu"]["drawString"] = DrawString(this) globals["ppu"]["drawString"] = DrawString(this)
} }
private val spriteBuffer = ImageBuffer(VSprite.width, VSprite.height) private val spriteBuffer = ImageBuffer(VSprite.width * 2, VSprite.height)
fun render(g: Graphics) { fun render(g: Graphics) {
cursorBlinkTimer += Terrarum.UPDATE_DELTA
if (cursorBlinkTimer > cursorBlinkTime) {
cursorBlinkTimer -= cursorBlinkTime
cursorBlinkOn = !cursorBlinkOn
}
fun VSprite.render() { fun VSprite.render() {
if (this.isVisible) {
val h = VSprite.height val h = VSprite.height
val w = VSprite.width val w = VSprite.width
if (rotation and 1 == 0) { // deg 0, 180 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 && !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 -> (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 pixelData = data[y].ushr(2 * x).and(0b11)
val col = getColourFromPalette(pixelData) val col = getColourFromPalette(pixelData)
if (this.drawWide) {
spriteBuffer.setRGBA(ordX * 2, ordY, col.red, col.green, col.blue, col.alpha)
spriteBuffer.setRGBA(ordX * 2 + 1, ordY, col.red, col.green, col.blue, col.alpha)
}
else {
spriteBuffer.setRGBA(ordX, ordY, col.red, col.green, col.blue, col.alpha) spriteBuffer.setRGBA(ordX, ordY, col.red, col.green, col.blue, col.alpha)
} }
} }
} }
}
else { // deg 90, 270 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 && !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 -> (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 pixelData = data[y].ushr(2 * x).and(0b11)
val col = getColourFromPalette(pixelData) val col = getColourFromPalette(pixelData)
if (this.drawWide) {
spriteBuffer.setRGBA(ordY * 2, ordX, col.red, col.green, col.blue, col.alpha)
spriteBuffer.setRGBA(ordY * 2 + 1, ordX, col.red, col.green, col.blue, col.alpha)
}
else {
spriteBuffer.setRGBA(ordY, ordX, col.red, col.green, col.blue, col.alpha) spriteBuffer.setRGBA(ordY, ordX, col.red, col.green, col.blue, col.alpha)
} }
} }
} }
} }
}
}
System.arraycopy(vram.background.rgba, 0, frameBuffer.rgba, 0, vram.background.rgba.size) System.arraycopy(vram.background.rgba, 0, frameBuffer.rgba, 0, vram.background.rgba.size)
@@ -182,7 +222,24 @@ class PeripheralVideoCard(val termW: Int = 40, val termH: Int = 25) :
val img = frameBuffer.image val img = frameBuffer.image
img.filter = Image.FILTER_NEAREST img.filter = Image.FILTER_NEAREST
g.drawImage(img.getScaledCopy(2f), 0f, 0f) g.drawImage(img.getScaledCopy(blockW * termW, blockH * termH * 2), 0f, 0f)
if (cursorBlinkOn && showCursor) {
g.drawImage(
cursorImage,
host.term.cursorX * blockW.toFloat(),
(host.term as Terminal).cursorY * blockH * 2f
)
}
// scanlines
g.color = Color(0, 0, 0, 40)
g.lineWidth = 1f
for (i in 1..blockH * termH * 2 step 2) {
g.drawLine(0f, i.toFloat(), blockW * termW - 1f, i.toFloat())
}
img.destroy() img.destroy()
} }
@@ -538,6 +595,7 @@ class VSprite {
var isBackground = false var isBackground = false
var isVisible = false var isVisible = false
var drawWide = false
fun setPaletteSet(col0: Int, col1: Int, col2: Int, col3: Int) { fun setPaletteSet(col0: Int, col1: Int, col2: Int, col3: Int) {
pal0 = col0 pal0 = col0
@@ -557,6 +615,11 @@ class VSprite {
return CLUT[clutIndex] return CLUT[clutIndex]
} }
fun setPos(x: Int, y: Int) {
posX = x
posY = y
}
fun setPixel(x: Int, y: Int, color: Int) { fun setPixel(x: Int, y: Int, color: Int) {
data[y] = data[y] xor data[y].and(3 shl (2 * x)) // mask off desired area to 0b00 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)) data[y] = data[y] or (color shl (2 * x))

View File

@@ -206,6 +206,8 @@ class GraphicsTerminal(private val host: TerrarumComputer) : Terminal {
) )
(0..displacement - 1).forEach { rgba[it] = 0.toByte() } (0..displacement - 1).forEach { rgba[it] = 0.toByte() }
} }
cursorY += -amount
} }
/** /**

View File

@@ -8,35 +8,16 @@ import java.io.InputStream
*/ */
class TerminalInputStream(val host: TerrarumComputer) : InputStream() { class TerminalInputStream(val host: TerrarumComputer) : InputStream() {
private val pauseLock = java.lang.Object()
override fun read(): Int { override fun read(): Int {
System.err.println("TerminalInputStream.read called")
//System.err.println(Thread.currentThread().name) //System.err.println(Thread.currentThread().name)
// would display "LuaJ Separated", which means this InputStream will not block main thread // would display "LuaJ Separated", which means this InputStream will not block main thread
host.openStdin() host.openStdin()
synchronized(this) { synchronized(this) {
(this as java.lang.Object).wait() (this as java.lang.Object).wait()
} }
System.err.println("TerminalInputStream.read exit")
return host.stdinInput return host.stdinInput
} }
override fun read(b: ByteArray?): Int {
TODO()
}
override fun read(b: ByteArray?, off: Int, len: Int): Int {
TODO()
}
} }