impl of screen ghosting

This commit is contained in:
minjaesong
2020-05-16 09:06:17 +09:00
parent 772354d2d1
commit 57c16bcb44
8 changed files with 217 additions and 113 deletions

View File

@@ -78,6 +78,8 @@ class VM(
var getErrorStream: () -> OutputStream = { TODO() }
var getInputStream: () -> InputStream = { TODO() }
val startTime: Long
init {
peripheralTable[0] = PeripheralEntry(
"io",
@@ -88,6 +90,8 @@ class VM(
)
println("[VM] Creating new VM with ID of $id, memesize $memsize")
startTime = System.nanoTime()
}
@@ -107,6 +111,8 @@ class VM(
peripheralTable.forEach { it.peripheral?.dispose() }
}
open fun getUptime() = System.nanoTime() - startTime
/*
NOTE: re-fill peripheralTable whenever the VM cold-boots!
you are absolutely not supposed to hot-swap peripheral cards when the computer is on

View File

@@ -9,8 +9,10 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
import kotlinx.coroutines.*
import net.torvald.tsvm.peripheral.GraphicsAdapter
import net.torvald.tsvm.peripheral.IOSpace
import java.io.FileReader
import java.io.InputStream
import java.io.OutputStream
import java.io.StringReader
class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter() {
@@ -27,7 +29,7 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
override fun create() {
super.create()
gpu = GraphicsAdapter(vm, lcdMode = false)
gpu = GraphicsAdapter(vm, lcdMode = true)
vm.peripheralTable[1] = PeripheralEntry(
VM.PERITYPE_TERM,
@@ -49,9 +51,14 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
vm.getInputStream = { gpu.getInputStream() }
// TEST PRG
val fr = FileReader("./assets/tvdos/command.js")
val prg = fr.readText()
fr.close()
vmRunner = VMRunnerFactory(vm, "js")
coroutineJob = GlobalScope.launch {
vmRunner.executeCommand(sanitiseJS(shitcode))
//vmRunner.executeCommand(sanitiseJS(gpuTestPaletteJs))
vmRunner.executeCommand(sanitiseJS(prg))
}

View File

@@ -52,5 +52,5 @@ class VMJSR223Delegate(val vm: VM) {
}
class VMSerialDebugger(val vm: VM) {
fun print(s: String) = System.out.println(s)
fun println(s: String) = System.out.println(s)
}

View File

@@ -72,13 +72,16 @@ object VMRunnerFactory {
private val JS_INIT = """
function print(s) {
return vm.print(s)
vm.print(s);
}
function println(s) {
return vm.println(s)
if (typeof s == "undefined")
vm.print("\n");
else
vm.println(s);
}
function read() {
return vm.read()
return vm.read();
}
"""
}

View File

@@ -1,18 +1,18 @@
package net.torvald.tsvm.peripheral
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import net.torvald.UnsafeHelper
import net.torvald.tsvm.AppLoader
import net.torvald.tsvm.VM
import net.torvald.tsvm.kB
import net.torvald.util.CircularArray
import sun.nio.ch.DirectBuffer
import java.io.InputStream
import java.io.OutputStream
import java.io.PrintStream
import kotlin.experimental.and
class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Companion.TEXT_ROWS, Companion.TEXT_COLS), PeriBase {
@@ -56,6 +56,8 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
private var textBackTex = Texture(textBackPixmap)
private var textTex = Texture(textPixmap)
private val outFBOs = Array(2) { FrameBuffer(Pixmap.Format.RGBA8888, WIDTH, HEIGHT, false) }
private val memTextCursorPosOffset = 2978L
private val memTextForeOffset = 2980L
private val memTextBackOffset = 2980L + 2560
@@ -273,7 +275,8 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
override fun eraseInLine(arg: Int) {
when (arg) {
else -> TODO()
} }
}
}
/** New lines are added at the bottom */
override fun scrollUp(arg: Int) {
@@ -451,6 +454,7 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
paletteShader.dispose()
textShader.dispose()
faketex.dispose()
outFBOs.forEach { it.dispose() }
try { textForeTex.dispose() } catch (_: Throwable) {}
try { textBackTex.dispose() } catch (_: Throwable) {}
@@ -461,121 +465,159 @@ class GraphicsAdapter(val vm: VM, val lcdMode: Boolean = false) : GlassTty(Compa
private var textCursorBlinkTimer = 0f
private val textCursorBlinkInterval = 0.5f
private var textCursorIsOn = true
private var glowDecay = if (lcdMode) 0.69f else 0.25f
private var decayColor = Color(1f, 1f, 1f, 1f - glowDecay)
fun render(delta: Float, batch: SpriteBatch, x: Float, y: Float) {
rendertex.dispose()
rendertex = Texture(framebuffer, Pixmap.Format.RGBA8888, false)
batch.shader = null
batch.begin()
// clear screen
batch.color = if (lcdMode) LCD_BASE_COL else Color.BLACK
batch.draw(faketex, 0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat())
// initiialise draw
batch.color = Color.WHITE
batch.shader = paletteShader
// feed palette data
// must be done every time the shader is "actually loaded"
// try this: if above line precedes 'batch.shader = paletteShader', it won't work
batch.shader.setUniform4fv("pal", paletteOfFloats, 0, paletteOfFloats.size)
if (lcdMode) batch.shader.setUniformf("lcdBaseCol", LCD_BASE_COL)
// draw framebuffer
batch.draw(rendertex, x, y)
// draw texts or sprites
batch.color = Color.WHITE
if (!graphicsUseSprites) {
// draw texts
val (cx, cy) = getCursorPos()
// prepare char buffer texture
for (y in 0 until TEXT_ROWS) {
for (x in 0 until TEXT_COLS) {
val drawCursor = textCursorIsOn && cx == x && cy == y
val addr = y.toLong() * TEXT_COLS + x
val char = if (drawCursor) 0xDB else spriteAndTextArea[memTextOffset + addr].toInt().and(255)
val back = if (drawCursor) ttyBack else spriteAndTextArea[memTextBackOffset + addr].toInt().and(255)
val fore = if (drawCursor) ttyFore else spriteAndTextArea[memTextForeOffset + addr].toInt().and(255)
textPixmap.setColor(Color(0f, 0f, char / 255f, 1f))
textPixmap.drawPixel(x, y)
textBackPixmap.setColor(Color(paletteOfFloats[4 * back], paletteOfFloats[4 * back + 1], paletteOfFloats[4 * back + 2], paletteOfFloats[4 * back + 3]))
textBackPixmap.drawPixel(x, y)
textForePixmap.setColor(Color(paletteOfFloats[4 * fore], paletteOfFloats[4 * fore + 1], paletteOfFloats[4 * fore + 2], paletteOfFloats[4 * fore + 3]))
textForePixmap.drawPixel(x, y)
}
outFBOs[1].inUse {
batch.shader = null
batch.inUse {
batch.color = decayColor
batch.draw(outFBOs[0].colorBufferTexture, 0f, HEIGHT.toFloat(), WIDTH.toFloat(), -HEIGHT.toFloat())
}
}
// bake char buffer texture
textForeTex.dispose()
textBackTex.dispose()
textTex.dispose()
textForeTex = Texture(textForePixmap)
textBackTex = Texture(textBackPixmap)
textTex = Texture(textPixmap)
textForeTex.bind(4)
textBackTex.bind(3)
textTex.bind(2)
chrrom0.bind(1)
faketex.bind(0)
outFBOs[0].inUse {
Gdx.gl.glClearColor(0f, 0f, 0f, 0f)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
batch.shader = textShader
textShader.setUniformi("foreColours", 4)
textShader.setUniformi("backColours", 3)
textShader.setUniformi("tilemap", 2)
textShader.setUniformi("tilesAtlas", 1)
textShader.setUniformi("u_texture", 0)
textShader.setUniformf("tilesInAxes", TEXT_COLS.toFloat(), TEXT_ROWS.toFloat())
textShader.setUniformf("screenDimension", WIDTH.toFloat(), HEIGHT.toFloat())
textShader.setUniformf("tilesInAtlas", 16f, 16f)
textShader.setUniformf("atlasTexSize", chrrom0.width.toFloat(), chrrom0.height.toFloat())
if (lcdMode) batch.shader.setUniformf("lcdBaseCol", LCD_BASE_COL)
batch.shader = null
batch.inUse {
batch.draw(faketex, 0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat())
// clear screen
batch.color = if (lcdMode) LCD_BASE_COL else Color.BLACK
batch.draw(faketex, 0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat())
// initiialise draw
batch.color = Color.WHITE
batch.shader = paletteShader
// feed palette data
// must be done every time the shader is "actually loaded"
// try this: if above line precedes 'batch.shader = paletteShader', it won't work
batch.shader.setUniform4fv("pal", paletteOfFloats, 0, paletteOfFloats.size)
if (lcdMode) batch.shader.setUniformf("lcdBaseCol", LCD_BASE_COL)
// draw framebuffer
batch.draw(rendertex, x, y)
// draw texts or sprites
batch.color = Color.WHITE
if (!graphicsUseSprites) {
// draw texts
val (cx, cy) = getCursorPos()
// prepare char buffer texture
for (y in 0 until TEXT_ROWS) {
for (x in 0 until TEXT_COLS) {
val drawCursor = textCursorIsOn && cx == x && cy == y
val addr = y.toLong() * TEXT_COLS + x
val char =
if (drawCursor) 0xDB else spriteAndTextArea[memTextOffset + addr].toInt().and(255)
val back =
if (drawCursor) ttyBack else spriteAndTextArea[memTextBackOffset + addr].toInt()
.and(255)
val fore =
if (drawCursor) ttyFore else spriteAndTextArea[memTextForeOffset + addr].toInt()
.and(255)
textPixmap.setColor(Color(0f, 0f, char / 255f, 1f))
textPixmap.drawPixel(x, y)
textBackPixmap.setColor(
Color(
paletteOfFloats[4 * back],
paletteOfFloats[4 * back + 1],
paletteOfFloats[4 * back + 2],
paletteOfFloats[4 * back + 3]
)
)
textBackPixmap.drawPixel(x, y)
textForePixmap.setColor(
Color(
paletteOfFloats[4 * fore],
paletteOfFloats[4 * fore + 1],
paletteOfFloats[4 * fore + 2],
paletteOfFloats[4 * fore + 3]
)
)
textForePixmap.drawPixel(x, y)
}
}
// bake char buffer texture
textForeTex.dispose()
textBackTex.dispose()
textTex.dispose()
textForeTex = Texture(textForePixmap)
textBackTex = Texture(textBackPixmap)
textTex = Texture(textPixmap)
textForeTex.bind(4)
textBackTex.bind(3)
textTex.bind(2)
chrrom0.bind(1)
faketex.bind(0)
batch.shader = textShader
textShader.setUniformi("foreColours", 4)
textShader.setUniformi("backColours", 3)
textShader.setUniformi("tilemap", 2)
textShader.setUniformi("tilesAtlas", 1)
textShader.setUniformi("u_texture", 0)
textShader.setUniformf("tilesInAxes", TEXT_COLS.toFloat(), TEXT_ROWS.toFloat())
textShader.setUniformf("screenDimension", WIDTH.toFloat(), HEIGHT.toFloat())
textShader.setUniformf("tilesInAtlas", 16f, 16f)
textShader.setUniformf("atlasTexSize", chrrom0.width.toFloat(), chrrom0.height.toFloat())
if (lcdMode) batch.shader.setUniformf("lcdBaseCol", LCD_BASE_COL)
batch.draw(faketex, 0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat())
batch.shader = null
} else {
// draw sprites
batch.shader = paletteShader
// feed palette data
// must be done every time the shader is "actually loaded"
// try this: if above line precedes 'batch.shader = paletteShader', it won't work
paletteShader.setUniform4fv("pal", paletteOfFloats, 0, paletteOfFloats.size)
TODO("sprite draw")
}
}
batch.shader = null
/*if (textCursorIsOn) {
batch.color = Color(
paletteOfFloats[4 * ttyFore],
paletteOfFloats[4 * ttyFore + 1],
paletteOfFloats[4 * ttyFore + 2],
paletteOfFloats[4 * ttyFore + 3]
)
val (cursorx, cursory) = getCursorPos()
batch.draw(faketex, cursorx * chrWidth, (TEXT_ROWS - cursory - 1) * chrHeight, chrWidth, chrHeight)
}*/
}
else {
// draw sprites
batch.shader = paletteShader
// feed palette data
// must be done every time the shader is "actually loaded"
// try this: if above line precedes 'batch.shader = paletteShader', it won't work
paletteShader.setUniform4fv("pal", paletteOfFloats, 0, paletteOfFloats.size)
TODO("sprite draw")
}
batch.end()
outFBOs[1].inUse {
batch.shader = null
batch.inUse {
batch.color = decayColor
batch.draw(outFBOs[0].colorBufferTexture, 0f, HEIGHT.toFloat(), WIDTH.toFloat(), -HEIGHT.toFloat())
}
}
batch.shader = null
batch.inUse {
batch.color = Color.WHITE
batch.draw(outFBOs[1].colorBufferTexture, 0f, HEIGHT.toFloat(), WIDTH.toFloat(), -HEIGHT.toFloat())
}
textCursorBlinkTimer += delta
if (textCursorBlinkTimer > textCursorBlinkInterval) {
textCursorBlinkTimer -= 0.5f
textCursorIsOn = !textCursorIsOn
}
}
private fun peekPalette(offset: Int): Byte {
@@ -1128,4 +1170,16 @@ void main() {
0
)
}
private fun FrameBuffer.inUse(action: () -> Unit) {
this.begin()
action()
this.end()
}
private fun SpriteBatch.inUse(action: () -> Unit) {
this.begin()
action()
this.end()
}
}

View File

@@ -41,6 +41,7 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor {
36L -> if (mouseDown) 1 else 0
37L -> keyboardBuffer.removeTail() ?: -1
38L -> if (keyboardInputRequested) 1 else 0
in 64..67 -> vm.memsize.shr((adi - 64) * 8).toByte()
else -> -1
}
}