mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-07 19:51:51 +09:00
painting screen on lua's side
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
}
|
||||
|
||||
|
||||
30
src/net/torvald/tsvm/VMRunnerFactory.kt
Normal file
30
src/net/torvald/tsvm/VMRunnerFactory.kt
Normal 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")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user