mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-11 23:34:04 +09:00
using coroutines/graphics: lcd mode just for the heck of it
This commit is contained in:
@@ -5,7 +5,10 @@ import com.badlogic.gdx.Gdx
|
|||||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
||||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
|
import kotlinx.coroutines.*
|
||||||
import net.torvald.tsvm.peripheral.GraphicsAdapter
|
import net.torvald.tsvm.peripheral.GraphicsAdapter
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter() {
|
class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter() {
|
||||||
|
|
||||||
@@ -17,10 +20,12 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
|
|||||||
|
|
||||||
lateinit var vmRunner: VMRunner
|
lateinit var vmRunner: VMRunner
|
||||||
|
|
||||||
|
lateinit var coroutineJob: Job
|
||||||
|
|
||||||
override fun create() {
|
override fun create() {
|
||||||
super.create()
|
super.create()
|
||||||
|
|
||||||
gpu = GraphicsAdapter()
|
gpu = GraphicsAdapter(lcdMode = true)
|
||||||
|
|
||||||
vm.peripheralTable[1] = PeripheralEntry(
|
vm.peripheralTable[1] = PeripheralEntry(
|
||||||
VM.PERITYPE_GRAPHICS,
|
VM.PERITYPE_GRAPHICS,
|
||||||
@@ -43,7 +48,11 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
|
|||||||
//vmRunner.executeCommand(gpuTestPalette)
|
//vmRunner.executeCommand(gpuTestPalette)
|
||||||
// TEST KTS PRG
|
// TEST KTS PRG
|
||||||
vmRunner = VMRunnerFactory(vm, "kts")
|
vmRunner = VMRunnerFactory(vm, "kts")
|
||||||
vmRunner.executeCommand(gpuTestPaletteKt)
|
//vmRunner.executeCommand(gpuTestPaletteKt)
|
||||||
|
//launch { vmRunner.executeCommand(gpuTestPaletteKt) } }
|
||||||
|
coroutineJob = GlobalScope.launch {
|
||||||
|
vmRunner.executeCommand(gpuTestPaletteKt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var updateAkku = 0.0
|
private var updateAkku = 0.0
|
||||||
@@ -70,6 +79,8 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
|
|||||||
private var latch = true
|
private var latch = true
|
||||||
|
|
||||||
private fun updateGame(delta: Float) {
|
private fun updateGame(delta: Float) {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun poke(addr: Long, value: Byte) = vm.poke(addr, value)
|
fun poke(addr: Long, value: Byte) = vm.poke(addr, value)
|
||||||
@@ -357,6 +368,8 @@ while True:
|
|||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
super.dispose()
|
super.dispose()
|
||||||
|
batch.dispose()
|
||||||
|
coroutineJob.cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ import kotlin.test.assertNotNull
|
|||||||
|
|
||||||
abstract class VMRunner(val extension: String) {
|
abstract class VMRunner(val extension: String) {
|
||||||
|
|
||||||
var thread = Thread()
|
abstract suspend fun executeCommand(command: String)
|
||||||
abstract fun executeCommand(command: String)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,11 +31,8 @@ object VMRunnerFactory {
|
|||||||
|
|
||||||
private val vmLua = VMLuaAdapter(vm)
|
private val vmLua = VMLuaAdapter(vm)
|
||||||
|
|
||||||
override fun executeCommand(command: String) {
|
override suspend fun executeCommand(command: String) {
|
||||||
thread = Thread {
|
vmLua.lua.load(command).call()
|
||||||
vmLua.lua.load(command).call()
|
|
||||||
}
|
|
||||||
thread.start()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,12 +54,9 @@ object VMRunnerFactory {
|
|||||||
//bind.put("nanotime", { System.nanoTime() })
|
//bind.put("nanotime", { System.nanoTime() })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun executeCommand(command: String) {
|
override suspend fun executeCommand(command: String) {
|
||||||
thread = Thread {
|
//(engine as Compilable).compile(command).eval(context) // compiling does not work with bindings in kts
|
||||||
//(engine as Compilable).compile(command).eval(context) // compiling does not work with bindings in kts
|
engine.eval(command, context)
|
||||||
engine.eval(command, context)
|
|
||||||
}
|
|
||||||
thread.start()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import net.torvald.tsvm.kB
|
|||||||
import sun.nio.ch.DirectBuffer
|
import sun.nio.ch.DirectBuffer
|
||||||
import kotlin.experimental.and
|
import kotlin.experimental.and
|
||||||
|
|
||||||
class GraphicsAdapter : PeriBase {
|
class GraphicsAdapter(val lcdMode: Boolean = false) : PeriBase {
|
||||||
|
|
||||||
internal val framebuffer = Pixmap(WIDTH, HEIGHT, Pixmap.Format.RGBA8888)
|
internal val framebuffer = Pixmap(WIDTH, HEIGHT, Pixmap.Format.RGBA8888)
|
||||||
private var rendertex = Texture(1, 1, Pixmap.Format.RGBA8888)
|
private var rendertex = Texture(1, 1, Pixmap.Format.RGBA8888)
|
||||||
@@ -26,8 +26,8 @@ class GraphicsAdapter : PeriBase {
|
|||||||
private val spriteAndTextArea = UnsafeHelper.allocate(10660L)
|
private val spriteAndTextArea = UnsafeHelper.allocate(10660L)
|
||||||
private val unusedArea = ByteArray(92)
|
private val unusedArea = ByteArray(92)
|
||||||
|
|
||||||
private val paletteShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, DRAW_SHADER_FRAG)
|
private val paletteShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, if (lcdMode) DRAW_SHADER_FRAG_LCD else DRAW_SHADER_FRAG)
|
||||||
private val textShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, TEXT_TILING_SHADER)
|
private val textShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, if (lcdMode) TEXT_TILING_SHADER_LCD else TEXT_TILING_SHADER)
|
||||||
|
|
||||||
private var textmodeBlinkCursor = true
|
private var textmodeBlinkCursor = true
|
||||||
private var graphicsUseSprites = false
|
private var graphicsUseSprites = false
|
||||||
@@ -232,7 +232,7 @@ class GraphicsAdapter : PeriBase {
|
|||||||
batch.begin()
|
batch.begin()
|
||||||
|
|
||||||
// clear screen
|
// clear screen
|
||||||
batch.color = Color.BLACK
|
batch.color = if (lcdMode) LCD_BASE_COL else Color.BLACK
|
||||||
batch.draw(faketex, 0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat())
|
batch.draw(faketex, 0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat())
|
||||||
|
|
||||||
|
|
||||||
@@ -244,6 +244,7 @@ class GraphicsAdapter : PeriBase {
|
|||||||
// must be done every time the shader is "actually loaded"
|
// must be done every time the shader is "actually loaded"
|
||||||
// try this: if above line precedes 'batch.shader = paletteShader', it won't work
|
// try this: if above line precedes 'batch.shader = paletteShader', it won't work
|
||||||
batch.shader.setUniform4fv("pal", paletteOfFloats, 0, paletteOfFloats.size)
|
batch.shader.setUniform4fv("pal", paletteOfFloats, 0, paletteOfFloats.size)
|
||||||
|
if (lcdMode) batch.shader.setUniformf("lcdBaseCol", LCD_BASE_COL)
|
||||||
|
|
||||||
// draw framebuffer
|
// draw framebuffer
|
||||||
batch.draw(rendertex, x, y)
|
batch.draw(rendertex, x, y)
|
||||||
@@ -296,6 +297,7 @@ class GraphicsAdapter : PeriBase {
|
|||||||
textShader.setUniformf("screenDimension", WIDTH.toFloat(), HEIGHT.toFloat())
|
textShader.setUniformf("screenDimension", WIDTH.toFloat(), HEIGHT.toFloat())
|
||||||
textShader.setUniformf("tilesInAtlas", 16f, 16f)
|
textShader.setUniformf("tilesInAtlas", 16f, 16f)
|
||||||
textShader.setUniformf("atlasTexSize", chrrom0.width.toFloat(), chrrom0.height.toFloat())
|
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.draw(faketex, 0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat())
|
||||||
|
|
||||||
@@ -366,6 +368,8 @@ class GraphicsAdapter : PeriBase {
|
|||||||
const val TEXT_ROWS = 32
|
const val TEXT_ROWS = 32
|
||||||
val VRAM_SIZE = 256.kB()
|
val VRAM_SIZE = 256.kB()
|
||||||
|
|
||||||
|
private val LCD_BASE_COL = Color(0xa1a99cff.toInt())
|
||||||
|
|
||||||
val DRAW_SHADER_FRAG = """
|
val DRAW_SHADER_FRAG = """
|
||||||
#version 120
|
#version 120
|
||||||
|
|
||||||
@@ -380,7 +384,31 @@ float rand(vec2 co){
|
|||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
gl_FragColor = pal[int(texture2D(u_texture, v_texCoords).r * 255.0)];
|
gl_FragColor = pal[int(texture2D(u_texture, v_texCoords).r * 255.0)];
|
||||||
//gl_FragColor = vec4(texture2D(u_texture, v_texCoords).rrr, 1.0);
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
val DRAW_SHADER_FRAG_LCD = """
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
varying vec4 v_color;
|
||||||
|
varying vec2 v_texCoords;
|
||||||
|
uniform sampler2D u_texture;
|
||||||
|
uniform vec4 pal[256];
|
||||||
|
|
||||||
|
float intensitySteps = 4.0;
|
||||||
|
uniform vec4 lcdBaseCol;
|
||||||
|
|
||||||
|
float rand(vec2 co){
|
||||||
|
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
vec4 palCol = pal[int(texture2D(u_texture, v_texCoords).r * 255.0)];
|
||||||
|
float lum = floor((3.0 * palCol.r + 4.0 * palCol.g + palCol.b) / 8.0 * intensitySteps) / intensitySteps;
|
||||||
|
vec4 outIntensity = vec4(vec3(1.0 - lum), palCol.a);
|
||||||
|
|
||||||
|
// LCD output will invert the luminosity. That is, normally white colour will be black on PM-LCD.
|
||||||
|
gl_FragColor = lcdBaseCol * outIntensity;
|
||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
@@ -488,8 +516,103 @@ void main() {
|
|||||||
gl_FragColor = backColFromMap;
|
gl_FragColor = backColFromMap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
val TEXT_TILING_SHADER_LCD = """
|
||||||
|
#version 120
|
||||||
|
#ifdef GL_ES
|
||||||
|
precision mediump float;
|
||||||
|
#endif
|
||||||
|
#extension GL_EXT_gpu_shader4 : enable
|
||||||
|
|
||||||
|
//layout(origin_upper_left) in vec4 gl_FragCoord; // commented; requires #version 150 or later
|
||||||
|
// gl_FragCoord is origin to bottom-left
|
||||||
|
|
||||||
|
varying vec4 v_color;
|
||||||
|
varying vec2 v_texCoords;
|
||||||
|
uniform sampler2D u_texture;
|
||||||
|
|
||||||
|
|
||||||
|
uniform vec2 screenDimension;
|
||||||
|
uniform vec2 tilesInAxes; // size of the tilemap texture; vec2(tiles_in_horizontal, tiles_in_vertical)
|
||||||
|
|
||||||
|
uniform sampler2D tilesAtlas;
|
||||||
|
uniform sampler2D foreColours;
|
||||||
|
uniform sampler2D backColours;
|
||||||
|
uniform sampler2D tilemap;
|
||||||
|
|
||||||
|
uniform vec2 tilesInAtlas = ivec2(16.0, 16.0);
|
||||||
|
uniform vec2 atlasTexSize = ivec2(128.0, 224.0);
|
||||||
|
vec2 tileSizeInPx = atlasTexSize / tilesInAtlas; // should be like ivec2(16, 16)
|
||||||
|
|
||||||
|
ivec2 getTileXY(int tileNumber) {
|
||||||
|
return ivec2(tileNumber % int(tilesInAtlas.x), tileNumber / int(tilesInAtlas.x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// return: int=0xaarrggbb
|
||||||
|
int _colToInt(vec4 color) {
|
||||||
|
return int(color.b * 255) | (int(color.g * 255) << 8) | (int(color.r * 255) << 16) | (int(color.a * 255) << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x0rggbb where int=0xaarrggbb
|
||||||
|
// return: [0..1048575]
|
||||||
|
int getTileFromColor(vec4 color) {
|
||||||
|
return _colToInt(color) & 0xFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
float intensitySteps = 4.0;
|
||||||
|
uniform vec4 lcdBaseCol;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
|
||||||
|
// READ THE FUCKING MANUAL, YOU DONKEY !! //
|
||||||
|
// This code purposedly uses flipped fragcoord. //
|
||||||
|
// Make sure you don't use gl_FragCoord unknowingly! //
|
||||||
|
// Remember, if there's a compile error, shader SILENTLY won't do anything //
|
||||||
|
|
||||||
|
|
||||||
|
// 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 flippedFragCoord = vec2(gl_FragCoord.x, screenDimension.y - gl_FragCoord.y); // NO IVEC2!!; this flips Y
|
||||||
|
|
||||||
|
// get required tile numbers //
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// calculate the UV coord value for texture sampling //
|
||||||
|
|
||||||
|
// don't really need highp here; read the GLES spec
|
||||||
|
vec2 uvCoordForTile = (mod(flippedFragCoord, tileSizeInPx) / tileSizeInPx) / tilesInAtlas; // 0..0.00390625 regardless of tile position in atlas
|
||||||
|
vec2 uvCoordOffsetTile = tileXY / tilesInAtlas; // where the tile starts in the atlas, using uv coord (0..1)
|
||||||
|
|
||||||
|
// get final UV coord for the actual sampling //
|
||||||
|
|
||||||
|
vec2 finalUVCoordForTile = uvCoordForTile + uvCoordOffsetTile;// where we should be actually looking for in atlas, using UV coord (0..1)
|
||||||
|
|
||||||
|
// blending a breakage tex with main tex //
|
||||||
|
|
||||||
|
vec4 tileCol = texture2D(tilesAtlas, finalUVCoordForTile);
|
||||||
|
|
||||||
|
vec4 palCol = vec4(1.0);
|
||||||
|
// apply colour
|
||||||
|
if (tileCol.r > 0) {
|
||||||
|
palCol = foreColFromMap;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
palCol = backColFromMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
float lum = floor((3.0 * palCol.r + 4.0 * palCol.g + palCol.b) / 8.0 * intensitySteps) / intensitySteps;
|
||||||
|
vec4 outIntensity = vec4(vec3(1.0 - lum), palCol.a);
|
||||||
|
|
||||||
|
// LCD output will invert the luminosity. That is, normally white colour will be black on PM-LCD.
|
||||||
|
gl_FragColor = lcdBaseCol * outIntensity;
|
||||||
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
val DEFAULT_PALETTE = intArrayOf( // 0b rrrrrrrr gggggggg bbbbbbbb aaaaaaaa
|
val DEFAULT_PALETTE = intArrayOf( // 0b rrrrrrrr gggggggg bbbbbbbb aaaaaaaa
|
||||||
|
|||||||
Reference in New Issue
Block a user