mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 20:31:51 +09:00
graphics computer -- working sprite system
Former-commit-id: eedad5c99d0d8fa1d74a7a5b4e6250017d55163b Former-commit-id: 0dc08e778cca3300ffc6f696ba395eb8ca2b154b
This commit is contained in:
@@ -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 ```<item>.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.
|
||||
73
src/net/torvald/terrarum/StateGraphicComputerTest.kt
Normal file
73
src/net/torvald/terrarum/StateGraphicComputerTest.kt
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<IntArray>(256, { Array<Int>(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<BitSet>) {
|
||||
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<Int>) {
|
||||
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])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user