painting screen on lua's side

This commit is contained in:
minjaesong
2020-04-16 10:18:45 +09:00
parent e35dad635f
commit 373bfdb11e
6 changed files with 131 additions and 39 deletions

View File

@@ -114,6 +114,11 @@ internal class UnsafePtr(pointer: Long, allocSize: Long) {
return UnsafeHelper.unsafe.getInt(ptr + index)
}
fun getShort(index: Long): Short {
checkNullPtr(index)
return UnsafeHelper.unsafe.getShort(ptr + index)
}
fun setFloat(index: Long, value: Float) {
checkNullPtr(index)
UnsafeHelper.unsafe.putFloat(ptr + index, value)
@@ -124,6 +129,11 @@ internal class UnsafePtr(pointer: Long, allocSize: Long) {
UnsafeHelper.unsafe.putInt(ptr + index, value)
}
fun setShort(index: Long, value: Short) {
checkNullPtr(index)
UnsafeHelper.unsafe.putShort(ptr + index, value)
}
fun fillWith(byte: Byte) {
UnsafeHelper.unsafe.setMemory(ptr, size, byte)
}

View File

@@ -7,6 +7,7 @@ import net.torvald.tsvm.firmware.Firmware.Companion.toLuaValue
import net.torvald.tsvm.peripheral.IOSpace
import net.torvald.tsvm.peripheral.PeriBase
import org.luaj.vm2.LuaValue
import kotlin.random.Random
/**
* 1 byte = 2 pixels
@@ -51,6 +52,8 @@ class VM(
_memsize: Int
) {
val id = java.util.Random().nextInt()
val memsize = minOf(USER_SPACE_SIZE, _memsize.toLong())
internal val usermem = UnsafeHelper.allocate(memsize)
@@ -65,6 +68,8 @@ class VM(
MMIO_SIZE.toInt() - 256,
64
)
println("[VM] Creating new VM with ID of $id, memesize $memsize")
}

View File

@@ -11,12 +11,13 @@ import kotlin.math.roundToInt
class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter() {
val vm = VM(8192)
val vmLua = VMLuaAdapter(vm)
lateinit var gpu: GraphicsAdapter
lateinit var batch: SpriteBatch
lateinit var camera: OrthographicCamera
lateinit var vmRunner: VMRunner
override fun create() {
super.create()
@@ -37,9 +38,11 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
batch.projectionMatrix = camera.combined
Gdx.gl20.glViewport(0, 0, appConfig.width, appConfig.height)
vmRunner = VMRunnerFactory(vm, "lua")
// TEST LUA PRG
//vmLua.lua.load(gpuTestPalette).call()
vmRunner.executeCommand(gpuTestPalette)
}
private var updateAkku = 0.0
@@ -60,18 +63,19 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
i += 1
}
renderGame()
renderGame(dt)
}
private fun updateGame(delta: Float) {
paintTestPalette()
}
private fun paintTestPalette() {
val peripheralSlot = vm.findPeribyType(VM.PERITYPE_GRAPHICS)!!
val hwoff = VM.HW_RESERVE_SIZE * peripheralSlot
for (y in 0 until 360) {
/*for (y in 0 until 360) {
for (x in 0 until GraphicsAdapter.WIDTH) {
val palnum = 20 * (y / 30) + (x / (GraphicsAdapter.WIDTH / 20))
vm.poke(-(y.toLong() * GraphicsAdapter.WIDTH + x + 1) - hwoff, palnum.toByte())
@@ -83,47 +87,57 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
val palnum = 240 + (x / 35)
vm.poke(-(y.toLong() * GraphicsAdapter.WIDTH + x + 1) - hwoff, palnum.toByte())
}
}
}*/
//vm.poke(-262143L - hwoff, Math.random().times(255.0).toByte())
//vm.poke(-262144L - hwoff, Math.random().times(255.0).toByte())
for (k in 0 until 2240) {
// text foreground
vm.poke(-(254912 + k + 1) - hwoff, (Math.random().times(255f).roundToInt()).toByte()) // white
vm.poke(-(254912 + k + 1) - hwoff, -2) // white
// text background
vm.poke(-(254912 + 2240 + k + 1) - hwoff, (Math.random().times(255f).roundToInt()).toByte()) // transparent
vm.poke(-(254912 + 2240 + k + 1) - hwoff, -1) // transparent
// texts
vm.poke(-(254912 + 2240*2 + k + 1) - hwoff, (Math.random().times(255f).roundToInt()).toByte())
vm.poke(-(254912 + 2240*2 + k + 1) - hwoff, if (k == 0) 0x30 else 0x40)
}
}
private val gpuTestPalette = """
local vm = require("rawmem")
local w = 560
local h = 448
local hwoff = 1048576
local vm = require("rawmem")
local w = 560
local h = 448
local hwoff = 1048576
for y = 0, 359 do
for x = 0, w - 1 do
palnum = 20 * int(y / 30) + int(x / 28)
vm.poke(-(y * w + x + 1) - hwoff, palnum)
end
while true do
local tstart = os.clock()
for y = 0, 359 do
for x = 0, w - 1 do
palnum = 20 * int(y / 30) + int(x / 28)
vm.poke(-(y * w + x + 1) - hwoff, palnum)
end
end
for y = 360, h - 1 do
for x = 0, w - 1 do
palnum = 240 + int(x / 35)
vm.poke(-(y * w + x + 1) - hwoff, palnum)
end
for y = 360, h - 1 do
for x = 0, w - 1 do
palnum = 240 + int(x / 35)
vm.poke(-(y * w + x + 1) - hwoff, palnum)
end
end
vm.poke(-262143 - hwoff, math.floor(math.random() * 255.0))
vm.poke(-262144 - hwoff, math.floor(math.random() * 255.0))
for k = 0, 2239 do
vm.poke(-(254912 + k + 1) - hwoff, 254)
vm.poke(-(254912 + 2240 + k + 1) - hwoff, 255)
vm.poke(-(254912 + 2240*2 + k + 1) - hwoff, math.floor(math.random() * 255.0))
end
local tend = os.clock()
print("Apparent FPS: "..tostring(1.0 / (tend - tstart)))
end
""".trimIndent()
private fun renderGame() {
gpu.render(batch, 0f, 0f)
private fun renderGame(delta: Float) {
gpu.render(delta, batch, 0f, 0f)
}

View File

@@ -0,0 +1,30 @@
package net.torvald.tsvm
abstract class VMRunner(val extension: String) {
var thread = Thread()
abstract fun executeCommand(command: String)
}
object VMRunnerFactory {
operator fun invoke(vm: VM, extension: String): VMRunner {
return when (extension) {
"lua" -> {
object : VMRunner(extension) {
private val vmLua = VMLuaAdapter(vm)
override fun executeCommand(command: String) {
thread = Thread {
vmLua.lua.load(command).call()
}
thread.start()
}
}
}
else -> throw UnsupportedOperationException("Unsupported script extension: $extension")
}
}
}

View File

@@ -16,7 +16,7 @@ class GraphicsAdapter : PeriBase {
internal val framebuffer = Pixmap(WIDTH, HEIGHT, Pixmap.Format.RGBA8888)
private var rendertex = Texture(1, 1, Pixmap.Format.RGBA8888)
private val paletteOfFloats = FloatArray(1024) {
internal val paletteOfFloats = FloatArray(1024) {
val rgba = DEFAULT_PALETTE[it / 4]
val channel = it % 4
rgba.shr((3 - channel) * 8).and(255) / 255f
@@ -34,7 +34,11 @@ class GraphicsAdapter : PeriBase {
private var graphicsUseSprites = false
private var lastUsedColour = (-1).toByte()
private var currentChrRom = 0
private var chrWidth = 8f
private var chrHeight = 14f
private var ttyFore = 254
private var ttyBack = 255
private val textForePixmap = Pixmap(TEXT_COLS, TEXT_ROWS, Pixmap.Format.RGBA8888)
private val textBackPixmap = Pixmap(TEXT_COLS, TEXT_ROWS, Pixmap.Format.RGBA8888)
@@ -44,7 +48,7 @@ class GraphicsAdapter : PeriBase {
private var textBackTex = Texture(textBackPixmap)
private var textTex = Texture(textPixmap)
private fun getTtyCursorPos() = spriteAndTextArea.getShort(3938L) % TEXT_COLS to spriteAndTextArea.getShort(3938L) / TEXT_COLS
init {
framebuffer.blending = Pixmap.Blending.None
@@ -57,6 +61,8 @@ class GraphicsAdapter : PeriBase {
pm.drawPixel(0, 0, -1)
faketex = Texture(pm)
pm.dispose()
spriteAndTextArea.fillWith(0)
}
override fun peek(addr: Long): Byte? {
@@ -143,7 +149,11 @@ class GraphicsAdapter : PeriBase {
chrrom0.dispose()
}
fun render(batch: SpriteBatch, x: Float, y: Float) {
private var textCursorBlinkTimer = 0f
private val textCursorBlinkInterval = 0.5f
private var textCursorIsOn = true
fun render(delta: Float, batch: SpriteBatch, x: Float, y: Float) {
rendertex.dispose()
rendertex = Texture(framebuffer)
@@ -163,16 +173,13 @@ class GraphicsAdapter : PeriBase {
// 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)
batch.shader.setUniform4fv("pal", paletteOfFloats, 0, paletteOfFloats.size)
// draw framebuffer
batch.draw(rendertex, x, y)
batch.end()
// draw texts or sprites
batch.begin()
batch.color = Color.WHITE
@@ -222,6 +229,19 @@ class GraphicsAdapter : PeriBase {
textShader.setUniformf("atlasTexSize", chrrom0.width.toFloat(), chrrom0.height.toFloat())
batch.draw(faketex, 0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat())
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) = getTtyCursorPos()
batch.draw(faketex, cursorx * chrWidth, (TEXT_ROWS - cursory - 1) * chrHeight, chrWidth, chrHeight)
}
}
else {
// draw sprites
@@ -238,11 +258,19 @@ class GraphicsAdapter : PeriBase {
batch.end()
batch.shader = null
textCursorBlinkTimer += delta
if (textCursorBlinkTimer > textCursorBlinkInterval) {
textCursorBlinkTimer -= 0.5f
textCursorIsOn = !textCursorIsOn
}
}
private fun peekPalette(offset: Int): Byte {
if (offset == 255) return 0 // palette 255 is always transparent
// FIXME always return zero?
val highvalue = paletteOfFloats[offset * 2] // R, B
val lowvalue = paletteOfFloats[offset * 2 + 1] // G, A
return (highvalue.div(15f).toInt().shl(4) or lowvalue.div(15f).toInt()).toByte()
@@ -322,7 +350,7 @@ uniform sampler2D u_texture;
uniform vec2 screenDimension;
uniform vec2 tilesInAxes; // basically a screen dimension; vec2(tiles_in_horizontal, tiles_in_vertical)
uniform vec2 tilesInAxes; // size of the tilemap texture; vec2(tiles_in_horizontal, tiles_in_vertical)
uniform sampler2D tilesAtlas;
uniform sampler2D foreColours;
@@ -358,14 +386,13 @@ void main() {
// default gl_FragCoord takes half-integer (represeting centre of the pixel) -- could be useful for phys solver?
// This one, however, takes exact integer by rounding down. //
vec2 overscannedScreenDimension = tilesInAxes * tileSizeInPx; // how many tiles will fit into a screen; one used by the tileFromMap
vec2 flippedFragCoord = vec2(gl_FragCoord.x, screenDimension.y - gl_FragCoord.y); // NO IVEC2!!; this flips Y
// get required tile numbers //
vec4 tileFromMap = texture2D(tilemap, flippedFragCoord / overscannedScreenDimension); // raw tile number
vec4 foreColFromMap = texture2D(foreColours, flippedFragCoord / overscannedScreenDimension);
vec4 backColFromMap = texture2D(backColours, flippedFragCoord / overscannedScreenDimension);
vec4 tileFromMap = texture2D(tilemap, flippedFragCoord / screenDimension); // raw tile number
vec4 foreColFromMap = texture2D(foreColours, flippedFragCoord / screenDimension);
vec4 backColFromMap = texture2D(backColours, flippedFragCoord / screenDimension);
int tile = getTileFromColor(tileFromMap);
ivec2 tileXY = getTileXY(tile);

View File

@@ -39,6 +39,8 @@ User area: 8 MB, hardware area: 8 MB
VRAM Bank 0 (256 kB)
Endianness: little
From the start of the memory space:
250880 bytes
Framebuffer
@@ -87,6 +89,10 @@ MMIO
0b 0000 000g (g: Use sprites(wipes out text buffer))
1 bytes RO
Last used colour (set by poking at the framebuffer)
1 bytes RW
current TTY foreground colour (useful for print() function)
1 bytes RW
current TTY background colour (useful for print() function)
Text-mode-font-ROM is immutable and does not belong to VRAM
Even in the text mode framebuffer is still being drawn onto the screen, and the texts are drawn on top of it