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

30
assets/tvdos/command.js Normal file
View File

@@ -0,0 +1,30 @@
var DOS_VERSION = "1.0";
var PROMPT_TEXT = ">";
var CURRENT_DRIVE = "A";
var shell_pwd = [""];
var welcome_text = "TSVM Disk Operating System, version " + DOS_VERSION;
function get_prompt_text() {
return CURRENT_DRIVE + ":\\\\" + shell_pwd.join("\\\\") + PROMPT_TEXT;
}
function greet() {
println(welcome_text);
println();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
println("Starting TVDOS...");
greet();
while (true) {
print(get_prompt_text());
var s = read();
println();
println("String read: " + s + "@");
}

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
}
}

View File

@@ -21,14 +21,14 @@ User area: 8 MB, hardware area: 8 MB
1024 kB
Peripheral #7
...
1024 kB
1024 kB (where Peripheral #0 would be)
MMIO and Interrupt Vectors
128 kB
MMIO for Peri #8
128 kB
MMIO for Peri #7
...
128 kB
128 kB (where Peripheral #0 would be)
MMIO for the computer
130816 bytes
MMIO for Ports, etc.
@@ -40,6 +40,7 @@ User area: 8 MB, hardware area: 8 MB
IO Device
Endianness: little
Note: Always takes up the peripheral slot of zero
MMIO
@@ -54,6 +55,8 @@ MMIO
close it. Keyboard buffer will be cleared whenever request is received, so
MAKE SURE YOU REQUEST THE KEY INPUT ONLY ONCE!
64..67 RO: User area memory size in bytes
--------------------------------------------------------------------------------
@@ -102,25 +105,25 @@ FI
MMIO
2 bytes RO
0..1 RO
Framebuffer width in pixels
2 bytes RO
2..3 RO
Framebuffer height in pixels
1 bytes RO
4 RO
Text mode columns
1 bytes RO
5 RO
Text mode rows
1 bytes RW
6 RW
Text-mode attributes
0b kkkk 00rc (k: currently using character rom, r: TTY Raw mode, c: Cursor blink)
1 bytes RW
7 RW
Graphics-mode attributes
0b 0000 000g (g: Use sprites(wipes out text buffer))
1 bytes RO
8 RO
Last used colour (set by poking at the framebuffer)
1 bytes RW
9 RW
current TTY foreground colour (useful for print() function)
1 bytes RW
10 RW
current TTY background colour (useful for print() function)
Text-mode-font-ROM is immutable and does not belong to VRAM