diff --git a/assets/bios/pipcode.bas b/assets/bios/pipcode.bas index 409e385..6212a49 100644 --- a/assets/bios/pipcode.bas +++ b/assets/bios/pipcode.bas @@ -1,4 +1,12 @@ -10 FOR K = 0 TO (160*140) -20 POKE(-1048576-K, INT(RND(1)*16)) -30 NEXT -40 GOTO 10 \ No newline at end of file +10 print("polling radar...") +20 s=cput(1,"POLL") +30 if s><0 then goto 900 +40 l=cget(1,0) +41 print("length: "+l+", pixels: "+l/3) +50 for i=0 to l step 3 +60 m=peek(i)*160+peek(i+1) +62 p=peek(i+2) +63 poke(-1048576-m,p) +70 next +899 end +900 print("Polling failed: "+s) diff --git a/src/net/torvald/terrarum/modulecomputers/tsvmperipheral/WorldRadar.kt b/src/net/torvald/terrarum/modulecomputers/tsvmperipheral/WorldRadar.kt new file mode 100644 index 0000000..37cd8ca --- /dev/null +++ b/src/net/torvald/terrarum/modulecomputers/tsvmperipheral/WorldRadar.kt @@ -0,0 +1,130 @@ +package net.torvald.terrarum.modulecomputers.tsvmperipheral + +import com.badlogic.gdx.files.FileHandle +import com.badlogic.gdx.graphics.Pixmap +import net.torvald.tsvm.VM +import net.torvald.tsvm.peripheral.BlockTransferInterface +import net.torvald.tsvm.peripheral.TestDiskDrive +import net.torvald.tsvm.peripheral.trimNull +import java.io.ByteArrayOutputStream + +/** + * Created by minjaesong on 2021-12-02. + */ +class WorldRadar(pngfile: FileHandle) : BlockTransferInterface(false, true) { + + private val W = 160 + private val H = 140 + + private val world = ByteArray(W*H) + + private val AIR = 0.toByte() + private val DIRT = 1.toByte() + private val GRASS = 2.toByte() + private val STONE = 16.toByte() + + private val AIR_OUT = 0.toByte() + private val GRASS_OUT = 2.toByte() + private val DIRT_OUT = 4.toByte() + private val STONE_OUT = 7.toByte() + + init { + statusCode = TestDiskDrive.STATE_CODE_STANDBY + + val worldTex = Pixmap(pngfile) + for (y in 0 until 140) { for (x in 0 until 160) { + val c = worldTex.getPixel(x, y) + world[y * W + x] = when (c) { + 0x46712dff -> GRASS + 0x9b9a9bff.toInt() -> STONE + 0x6a5130ff -> DIRT + else -> AIR + } + }} + + worldTex.dispose() + } + + private val messageComposeBuffer = ByteArrayOutputStream(BLOCK_SIZE) // always use this and don't alter blockSendBuffer please + private var blockSendBuffer = ByteArray(1) + private var blockSendCount = 0 + + private fun resetBuf() { + blockSendCount = 0 + messageComposeBuffer.reset() + } + + + override fun hasNext(): Boolean { + return (blockSendCount * BLOCK_SIZE < blockSendBuffer.size) + } + + override fun startSendImpl(recipient: BlockTransferInterface): Int { + if (blockSendCount == 0) { + blockSendBuffer = messageComposeBuffer.toByteArray() + } + + val sendSize = if (blockSendBuffer.size - (blockSendCount * BLOCK_SIZE) < BLOCK_SIZE) + blockSendBuffer.size % BLOCK_SIZE + else BLOCK_SIZE + + recipient.writeout(ByteArray(sendSize) { + blockSendBuffer[blockSendCount * BLOCK_SIZE + it] + }) + + blockSendCount += 1 + + return sendSize + } + + override fun writeoutImpl(inputData: ByteArray) { + val inputString = inputData.trimNull().toString(VM.CHARSET) + + // prepare draw commands + /* + * draw command format: + * + * + * + * marking rules: + * + * : exposed = has at least 1 nonsolid on 4 sides + * + * 1. exposed grass -> 2 + * 2. exposed dirt -> 4 + * 3. exposed stone -> 7 + * 4. stone exposed to dirt/grass -> 7 + */ + if (inputString.startsWith("POLL")) { + resetBuf() + val cmdbuf = HashMap(1024) + + for (y in 1 until H-1) { for (x in 1 until W-1) { + val yx = y.shl(8) or x + val i = y * W + x + val nearby = listOf(i-W,i-1,i+1,i+W).map { world[it] } // up, left, right, down + val block = world[i] + + if (block == GRASS && nearby.contains(AIR)) { + cmdbuf[yx] = GRASS_OUT + } + else if (block == DIRT && nearby.contains(AIR)) { + cmdbuf[yx] = DIRT_OUT + } + else if (block == STONE && (nearby.contains(AIR) || nearby.contains(GRASS) || nearby.contains(DIRT))) { + cmdbuf[yx] = STONE_OUT + } + }} + + cmdbuf.keys.sorted().forEach { key -> + val value = cmdbuf[key]!!.toInt() + val x = key % 256 + val y = key / 256 + messageComposeBuffer.write(y) + messageComposeBuffer.write(x) + messageComposeBuffer.write(value) + } + + } + } +} \ No newline at end of file diff --git a/src/net/torvald/tsvm/VMGUI.kt b/src/net/torvald/tsvm/VMGUI.kt index 5eab0b8..ea680fd 100644 --- a/src/net/torvald/tsvm/VMGUI.kt +++ b/src/net/torvald/tsvm/VMGUI.kt @@ -5,6 +5,7 @@ import com.badlogic.gdx.Gdx import com.badlogic.gdx.graphics.* import com.badlogic.gdx.graphics.g2d.SpriteBatch import kotlinx.coroutines.* +import net.torvald.terrarum.modulecomputers.tsvmperipheral.WorldRadar import net.torvald.tsvm.CompressorDelegate.GZIP_HEADER import net.torvald.tsvm.peripheral.* import java.io.File @@ -96,6 +97,8 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe vm.getInputStream = { System.`in` } } + vm.getIO().blockTransferPorts[1].attachDevice(WorldRadar(Gdx.files.internal("test_assets/test_terrain.png"))) + loaderInfo.extraPeripherals.forEach { (port, peri) -> val typeargs = peri.args.map { it.javaClass }.toTypedArray() diff --git a/src/net/torvald/tsvm/peripheral/ExtDisp.kt b/src/net/torvald/tsvm/peripheral/ExtDisp.kt index 78b03b6..c2893f5 100644 --- a/src/net/torvald/tsvm/peripheral/ExtDisp.kt +++ b/src/net/torvald/tsvm/peripheral/ExtDisp.kt @@ -97,6 +97,10 @@ class ExtDisp(val vm: VM, val width: Int, val height: Int) : PeriBase { in 0 until width * height -> { framebuffer.pixels.put(adi, byte) } + (width * height).toLong() -> { + framebuffer.setColor(bi.shl(24) or bi.shr(16) or bi.shl(8) or bi) + framebuffer.fill() + } in 0 until nextPowerOfTwo(width * height) -> { /* do nothing */ } else -> poke(addr % nextPowerOfTwo(width * height), byte) } diff --git a/test_assets/test_terrain.png b/test_assets/test_terrain.png new file mode 100644 index 0000000..45e5cf4 Binary files /dev/null and b/test_assets/test_terrain.png differ diff --git a/test_assets/test_terrain_out.png b/test_assets/test_terrain_out.png new file mode 100644 index 0000000..bd6cdea Binary files /dev/null and b/test_assets/test_terrain_out.png differ