diff --git a/FontROM7x14.kra b/FontROM7x14.kra index e9ca39e..a67f593 100644 --- a/FontROM7x14.kra +++ b/FontROM7x14.kra @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b927d6be493319d3c8d21e69e3e3ca76420f016d3a849fcb199499dcbdcfefb2 -size 99990 +oid sha256:5ea59c01ad818dc10d6b1be4617c95c7b0c420288ff06d62126a4522d6ed066c +size 100464 diff --git a/FontROM7x14.png b/FontROM7x14.png index dd5e702..624f632 100644 Binary files a/FontROM7x14.png and b/FontROM7x14.png differ diff --git a/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt b/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt index f3eb4f5..d96749d 100644 --- a/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt +++ b/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt @@ -41,8 +41,8 @@ class GraphicsJSR223Delegate(val vm: VM) { fun plotPixel(x: Int, y: Int, color: Byte) { getFirstGPU()?.let { - if (x in 0 until GraphicsAdapter.WIDTH && y in 0 until GraphicsAdapter.HEIGHT) { - it.poke(y.toLong() * GraphicsAdapter.WIDTH + x, color) + if (x in 0 until it.config.width && y in 0 until it.config.height) { + it.poke(y.toLong() * it.config.width + x, color) } } } diff --git a/src/net/torvald/tsvm/VMGUI.kt b/src/net/torvald/tsvm/VMGUI.kt index 979092c..597a790 100644 --- a/src/net/torvald/tsvm/VMGUI.kt +++ b/src/net/torvald/tsvm/VMGUI.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.* import net.torvald.tsvm.CompressorDelegate.GZIP_HEADER import net.torvald.tsvm.peripheral.GenericBios import net.torvald.tsvm.peripheral.GraphicsAdapter +import net.torvald.tsvm.peripheral.TexticsAdapter import java.io.File fun ByteArray.startsWith(other: ByteArray) = this.sliceArray(other.indices).contentEquals(other) @@ -31,7 +32,8 @@ class VMGUI(val vm: VM, val appConfig: LwjglApplicationConfiguration) : Applicat override fun create() { super.create() - gpu = GraphicsAdapter(vm, theme = GraphicsAdapter.THEME_COLORCRT) + //gpu = TexticsAdapter(vm, theme = GraphicsAdapter.THEME_COLORCRT) + gpu = GraphicsAdapter(vm, GraphicsAdapter.DEFAULT_CONFIG_COLOR_CRT) vm.peripheralTable[1] = PeripheralEntry( VM.PERITYPE_GPU_AND_TERM, diff --git a/src/net/torvald/tsvm/peripheral/GraphicsAdapter.kt b/src/net/torvald/tsvm/peripheral/GraphicsAdapter.kt index 5be14a3..b973d35 100644 --- a/src/net/torvald/tsvm/peripheral/GraphicsAdapter.kt +++ b/src/net/torvald/tsvm/peripheral/GraphicsAdapter.kt @@ -15,12 +15,33 @@ import java.io.InputStream import java.io.OutputStream import kotlin.experimental.and -open class GraphicsAdapter(val vm: VM, val theme: String = "") : GlassTty(Companion.TEXT_ROWS, Companion.TEXT_COLS), PeriBase { +data class AdapterConfig( + val theme: String, + val width: Int, + val height: Int, + val textCols: Int, + val textRows: Int, + val ttyDefaultFore: Int, + val ttyDefaultBack: Int, + val vramSize: Long, + val chrRomPath: String, + val decay: Float +) + +open class GraphicsAdapter(val vm: VM, val config: AdapterConfig) : + GlassTty(config.textRows, config.textCols), PeriBase { override fun getVM(): VM { return vm } + private val WIDTH = config.width + private val HEIGHT = config.height + private val VRAM_SIZE = config.vramSize + private val TTY_FORE_DEFAULT = config.ttyDefaultFore + private val TTY_BACK_DEFAULT = config.ttyDefaultBack + private val theme = config.theme + internal val framebuffer = Pixmap(WIDTH, HEIGHT, Pixmap.Format.Alpha) protected var rendertex = Texture(1, 1, Pixmap.Format.RGBA8888) internal val paletteOfFloats = FloatArray(1024) { @@ -28,7 +49,7 @@ open class GraphicsAdapter(val vm: VM, val theme: String = "") : GlassTty(Compan val channel = it % 4 rgba.shr((3 - channel) * 8).and(255) / 255f } - private val chrrom0 = Texture("./FontROM7x14.png") + protected val chrrom0 = Texture(config.chrRomPath) private val faketex: Texture internal val spriteAndTextArea = UnsafeHelper.allocate(10660L) @@ -43,7 +64,9 @@ open class GraphicsAdapter(val vm: VM, val theme: String = "") : GlassTty(Compan DRAW_SHADER_FRAG ) protected val textShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, - if (theme.startsWith("pmlcd") && !theme.endsWith("_inverted")) + if (theme.startsWith("crt_") && !theme.endsWith("color")) + TEXT_TILING_SHADER_MONOCHROME + else if (theme.startsWith("pmlcd") && !theme.endsWith("_inverted")) TEXT_TILING_SHADER_LCD_NOINV else if (theme.startsWith("pmlcd")) TEXT_TILING_SHADER_LCD @@ -125,6 +148,10 @@ open class GraphicsAdapter(val vm: VM, val theme: String = "") : GlassTty(Compan // when in text mode, and that's undesired behaviour // -1 is preferred because it points to the colour CLEAR, and it's constant. spriteAndTextArea.fillWith(-1) + // fill text area with 0 + for (k in 0 until TEXT_ROWS * TEXT_COLS) { + spriteAndTextArea[k + memTextOffset] = 0 + } unusedArea[0] = 2 unusedArea[1] = 3 @@ -539,7 +566,7 @@ open class GraphicsAdapter(val vm: VM, val theme: String = "") : GlassTty(Compan private var textCursorBlinkTimer = 0f private val textCursorBlinkInterval = 0.5f private var textCursorIsOn = true - private var glowDecay = if (theme.startsWith("pmlcd")) 0.63f else 0.32f + private var glowDecay = config.decay private var decayColor = Color(1f, 1f, 1f, 1f - glowDecay) fun render(delta: Float, batch: SpriteBatch, x: Float, y: Float) { @@ -597,7 +624,7 @@ open class GraphicsAdapter(val vm: VM, val theme: String = "") : GlassTty(Compan val drawCursor = blinkCursor && textCursorIsOn && cx == x && cy == y val addr = y.toLong() * TEXT_COLS + x val char = - if (drawCursor) 0xDB else spriteAndTextArea[memTextOffset + addr].toInt().and(255) + if (drawCursor) 0xFF else spriteAndTextArea[memTextOffset + addr].toInt().and(255) val back = if (drawCursor) ttyBack else spriteAndTextArea[memTextBackOffset + addr].toInt() .and(255) @@ -732,20 +759,22 @@ open class GraphicsAdapter(val vm: VM, val theme: String = "") : GlassTty(Compan private fun Boolean.toInt() = if (this) 1 else 0 companion object { + val VRAM_SIZE = 256.kB() + + val DEFAULT_CONFIG_COLOR_CRT = AdapterConfig( + "crt_color", + 560, 448, 80, 32, 254, 255, 256.kB(), "./FontROM7x14.png", 0.32f + ) + val DEFAULT_CONFIG_PMLCD = AdapterConfig( + "pmlcd_inverted", + 560, 448, 80, 32, 254, 255, 256.kB(), "./FontROM7x14.png", 0.64f + ) + const val THEME_COLORCRT = "crt_color" const val THEME_GREYCRT = "crt" const val THEME_LCD = "pmlcd" const val THEME_LCD_INVERTED = "pmlcd_inverted" - const val WIDTH = 560 - const val HEIGHT = 448 - const val TEXT_COLS = 80 - const val TEXT_ROWS = 32 - val VRAM_SIZE = 256.kB() - - const val TTY_FORE_DEFAULT = 254 - const val TTY_BACK_DEFAULT = 255 - private val LCD_BASE_COL = Color(0xa1a99cff.toInt()) val DRAW_SHADER_FRAG = """ @@ -911,6 +940,87 @@ void main() { gl_FragColor = backColFromMap; } } +""".trimIndent() + + val TEXT_TILING_SHADER_MONOCHROME = """ +#version 130 +#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; +} + +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 + + 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); + + // apply colour + gl_FragColor = tileCol; + +} """.trimIndent() val TEXT_TILING_SHADER_LCD = """ diff --git a/src/net/torvald/tsvm/peripheral/TexticsAdapter.kt b/src/net/torvald/tsvm/peripheral/TexticsAdapter.kt index f8dea5c..e7a0cc6 100644 --- a/src/net/torvald/tsvm/peripheral/TexticsAdapter.kt +++ b/src/net/torvald/tsvm/peripheral/TexticsAdapter.kt @@ -1,8 +1,22 @@ package net.torvald.tsvm.peripheral +import com.badlogic.gdx.graphics.Pixmap +import com.badlogic.gdx.graphics.Texture import net.torvald.tsvm.VM +import net.torvald.tsvm.kB -class TexticsAdapter(vm: VM, theme: String) : GraphicsAdapter(vm, theme) { +class TexticsAdapter(vm: VM, theme: String) : GraphicsAdapter(vm, AdapterConfig( + "crt_green", + 720, + 400, + 80, + 25, + 239, + 0, + 256.kB(), + "./tty.png", + 0.7f +)) { override fun peek(addr: Long): Byte? { return when (addr) { @@ -18,4 +32,6 @@ class TexticsAdapter(vm: VM, theme: String) : GraphicsAdapter(vm, theme) { } } + + } \ No newline at end of file diff --git a/src/net/torvald/tsvm/vdc/V2kRunTest.kt b/src/net/torvald/tsvm/vdc/V2kRunTest.kt index 1ec2c4e..80b6222 100644 --- a/src/net/torvald/tsvm/vdc/V2kRunTest.kt +++ b/src/net/torvald/tsvm/vdc/V2kRunTest.kt @@ -29,7 +29,7 @@ class V2kRunTest(val appConfig: LwjglApplicationConfiguration) : ApplicationAdap override fun create() { super.create() - gpu = GraphicsAdapter(vm, theme = GraphicsAdapter.THEME_COLORCRT) + gpu = GraphicsAdapter(vm, GraphicsAdapter.DEFAULT_CONFIG_COLOR_CRT) vm.peripheralTable[1] = PeripheralEntry( VM.PERITYPE_GPU_AND_TERM, diff --git a/tty.png b/tty.png index e0e42b1..7e4140c 100644 Binary files a/tty.png and b/tty.png differ