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)
|
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) {
|
fun setFloat(index: Long, value: Float) {
|
||||||
checkNullPtr(index)
|
checkNullPtr(index)
|
||||||
UnsafeHelper.unsafe.putFloat(ptr + index, value)
|
UnsafeHelper.unsafe.putFloat(ptr + index, value)
|
||||||
@@ -124,6 +129,11 @@ internal class UnsafePtr(pointer: Long, allocSize: Long) {
|
|||||||
UnsafeHelper.unsafe.putInt(ptr + index, value)
|
UnsafeHelper.unsafe.putInt(ptr + index, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setShort(index: Long, value: Short) {
|
||||||
|
checkNullPtr(index)
|
||||||
|
UnsafeHelper.unsafe.putShort(ptr + index, value)
|
||||||
|
}
|
||||||
|
|
||||||
fun fillWith(byte: Byte) {
|
fun fillWith(byte: Byte) {
|
||||||
UnsafeHelper.unsafe.setMemory(ptr, size, 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.IOSpace
|
||||||
import net.torvald.tsvm.peripheral.PeriBase
|
import net.torvald.tsvm.peripheral.PeriBase
|
||||||
import org.luaj.vm2.LuaValue
|
import org.luaj.vm2.LuaValue
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1 byte = 2 pixels
|
* 1 byte = 2 pixels
|
||||||
@@ -51,6 +52,8 @@ class VM(
|
|||||||
_memsize: Int
|
_memsize: Int
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
val id = java.util.Random().nextInt()
|
||||||
|
|
||||||
val memsize = minOf(USER_SPACE_SIZE, _memsize.toLong())
|
val memsize = minOf(USER_SPACE_SIZE, _memsize.toLong())
|
||||||
|
|
||||||
internal val usermem = UnsafeHelper.allocate(memsize)
|
internal val usermem = UnsafeHelper.allocate(memsize)
|
||||||
@@ -65,6 +68,8 @@ class VM(
|
|||||||
MMIO_SIZE.toInt() - 256,
|
MMIO_SIZE.toInt() - 256,
|
||||||
64
|
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() {
|
class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter() {
|
||||||
|
|
||||||
val vm = VM(8192)
|
val vm = VM(8192)
|
||||||
val vmLua = VMLuaAdapter(vm)
|
|
||||||
lateinit var gpu: GraphicsAdapter
|
lateinit var gpu: GraphicsAdapter
|
||||||
|
|
||||||
lateinit var batch: SpriteBatch
|
lateinit var batch: SpriteBatch
|
||||||
lateinit var camera: OrthographicCamera
|
lateinit var camera: OrthographicCamera
|
||||||
|
|
||||||
|
lateinit var vmRunner: VMRunner
|
||||||
|
|
||||||
override fun create() {
|
override fun create() {
|
||||||
super.create()
|
super.create()
|
||||||
|
|
||||||
@@ -37,9 +38,11 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
|
|||||||
batch.projectionMatrix = camera.combined
|
batch.projectionMatrix = camera.combined
|
||||||
Gdx.gl20.glViewport(0, 0, appConfig.width, appConfig.height)
|
Gdx.gl20.glViewport(0, 0, appConfig.width, appConfig.height)
|
||||||
|
|
||||||
|
vmRunner = VMRunnerFactory(vm, "lua")
|
||||||
|
|
||||||
// TEST LUA PRG
|
// TEST LUA PRG
|
||||||
//vmLua.lua.load(gpuTestPalette).call()
|
//vmLua.lua.load(gpuTestPalette).call()
|
||||||
|
vmRunner.executeCommand(gpuTestPalette)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var updateAkku = 0.0
|
private var updateAkku = 0.0
|
||||||
@@ -60,18 +63,19 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
|
|||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
renderGame()
|
renderGame(dt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun updateGame(delta: Float) {
|
private fun updateGame(delta: Float) {
|
||||||
paintTestPalette()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun paintTestPalette() {
|
private fun paintTestPalette() {
|
||||||
val peripheralSlot = vm.findPeribyType(VM.PERITYPE_GRAPHICS)!!
|
val peripheralSlot = vm.findPeribyType(VM.PERITYPE_GRAPHICS)!!
|
||||||
val hwoff = VM.HW_RESERVE_SIZE * peripheralSlot
|
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) {
|
for (x in 0 until GraphicsAdapter.WIDTH) {
|
||||||
val palnum = 20 * (y / 30) + (x / (GraphicsAdapter.WIDTH / 20))
|
val palnum = 20 * (y / 30) + (x / (GraphicsAdapter.WIDTH / 20))
|
||||||
vm.poke(-(y.toLong() * GraphicsAdapter.WIDTH + x + 1) - hwoff, palnum.toByte())
|
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)
|
val palnum = 240 + (x / 35)
|
||||||
vm.poke(-(y.toLong() * GraphicsAdapter.WIDTH + x + 1) - hwoff, palnum.toByte())
|
vm.poke(-(y.toLong() * GraphicsAdapter.WIDTH + x + 1) - hwoff, palnum.toByte())
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
//vm.poke(-262143L - hwoff, Math.random().times(255.0).toByte())
|
//vm.poke(-262143L - hwoff, Math.random().times(255.0).toByte())
|
||||||
//vm.poke(-262144L - hwoff, Math.random().times(255.0).toByte())
|
//vm.poke(-262144L - hwoff, Math.random().times(255.0).toByte())
|
||||||
|
|
||||||
for (k in 0 until 2240) {
|
for (k in 0 until 2240) {
|
||||||
// text foreground
|
// 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
|
// 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
|
// 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 = """
|
private val gpuTestPalette = """
|
||||||
local vm = require("rawmem")
|
local vm = require("rawmem")
|
||||||
local w = 560
|
local w = 560
|
||||||
local h = 448
|
local h = 448
|
||||||
local hwoff = 1048576
|
local hwoff = 1048576
|
||||||
|
|
||||||
for y = 0, 359 do
|
while true do
|
||||||
for x = 0, w - 1 do
|
local tstart = os.clock()
|
||||||
palnum = 20 * int(y / 30) + int(x / 28)
|
|
||||||
vm.poke(-(y * w + x + 1) - hwoff, palnum)
|
for y = 0, 359 do
|
||||||
end
|
for x = 0, w - 1 do
|
||||||
|
palnum = 20 * int(y / 30) + int(x / 28)
|
||||||
|
vm.poke(-(y * w + x + 1) - hwoff, palnum)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
for y = 360, h - 1 do
|
for y = 360, h - 1 do
|
||||||
for x = 0, w - 1 do
|
for x = 0, w - 1 do
|
||||||
palnum = 240 + int(x / 35)
|
palnum = 240 + int(x / 35)
|
||||||
vm.poke(-(y * w + x + 1) - hwoff, palnum)
|
vm.poke(-(y * w + x + 1) - hwoff, palnum)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
vm.poke(-262143 - hwoff, math.floor(math.random() * 255.0))
|
for k = 0, 2239 do
|
||||||
vm.poke(-262144 - hwoff, math.floor(math.random() * 255.0))
|
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()
|
""".trimIndent()
|
||||||
|
|
||||||
private fun renderGame() {
|
private fun renderGame(delta: Float) {
|
||||||
gpu.render(batch, 0f, 0f)
|
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)
|
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)
|
||||||
private val paletteOfFloats = FloatArray(1024) {
|
internal val paletteOfFloats = FloatArray(1024) {
|
||||||
val rgba = DEFAULT_PALETTE[it / 4]
|
val rgba = DEFAULT_PALETTE[it / 4]
|
||||||
val channel = it % 4
|
val channel = it % 4
|
||||||
rgba.shr((3 - channel) * 8).and(255) / 255f
|
rgba.shr((3 - channel) * 8).and(255) / 255f
|
||||||
@@ -34,7 +34,11 @@ class GraphicsAdapter : PeriBase {
|
|||||||
private var graphicsUseSprites = false
|
private var graphicsUseSprites = false
|
||||||
private var lastUsedColour = (-1).toByte()
|
private var lastUsedColour = (-1).toByte()
|
||||||
private var currentChrRom = 0
|
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 textForePixmap = Pixmap(TEXT_COLS, TEXT_ROWS, Pixmap.Format.RGBA8888)
|
||||||
private val textBackPixmap = 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 textBackTex = Texture(textBackPixmap)
|
||||||
private var textTex = Texture(textPixmap)
|
private var textTex = Texture(textPixmap)
|
||||||
|
|
||||||
|
private fun getTtyCursorPos() = spriteAndTextArea.getShort(3938L) % TEXT_COLS to spriteAndTextArea.getShort(3938L) / TEXT_COLS
|
||||||
|
|
||||||
init {
|
init {
|
||||||
framebuffer.blending = Pixmap.Blending.None
|
framebuffer.blending = Pixmap.Blending.None
|
||||||
@@ -57,6 +61,8 @@ class GraphicsAdapter : PeriBase {
|
|||||||
pm.drawPixel(0, 0, -1)
|
pm.drawPixel(0, 0, -1)
|
||||||
faketex = Texture(pm)
|
faketex = Texture(pm)
|
||||||
pm.dispose()
|
pm.dispose()
|
||||||
|
|
||||||
|
spriteAndTextArea.fillWith(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun peek(addr: Long): Byte? {
|
override fun peek(addr: Long): Byte? {
|
||||||
@@ -143,7 +149,11 @@ class GraphicsAdapter : PeriBase {
|
|||||||
chrrom0.dispose()
|
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.dispose()
|
||||||
rendertex = Texture(framebuffer)
|
rendertex = Texture(framebuffer)
|
||||||
|
|
||||||
@@ -163,16 +173,13 @@ class GraphicsAdapter : PeriBase {
|
|||||||
// feed palette data
|
// feed palette data
|
||||||
// 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
|
||||||
paletteShader.setUniform4fv("pal", paletteOfFloats, 0, paletteOfFloats.size)
|
batch.shader.setUniform4fv("pal", paletteOfFloats, 0, paletteOfFloats.size)
|
||||||
|
|
||||||
// draw framebuffer
|
// draw framebuffer
|
||||||
batch.draw(rendertex, x, y)
|
batch.draw(rendertex, x, y)
|
||||||
|
|
||||||
batch.end()
|
|
||||||
|
|
||||||
|
|
||||||
// draw texts or sprites
|
// draw texts or sprites
|
||||||
batch.begin()
|
|
||||||
|
|
||||||
batch.color = Color.WHITE
|
batch.color = Color.WHITE
|
||||||
|
|
||||||
@@ -222,6 +229,19 @@ class GraphicsAdapter : PeriBase {
|
|||||||
textShader.setUniformf("atlasTexSize", chrrom0.width.toFloat(), chrrom0.height.toFloat())
|
textShader.setUniformf("atlasTexSize", chrrom0.width.toFloat(), chrrom0.height.toFloat())
|
||||||
|
|
||||||
batch.draw(faketex, 0f, 0f, WIDTH.toFloat(), 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 {
|
else {
|
||||||
// draw sprites
|
// draw sprites
|
||||||
@@ -238,11 +258,19 @@ class GraphicsAdapter : PeriBase {
|
|||||||
batch.end()
|
batch.end()
|
||||||
|
|
||||||
batch.shader = null
|
batch.shader = null
|
||||||
|
|
||||||
|
textCursorBlinkTimer += delta
|
||||||
|
if (textCursorBlinkTimer > textCursorBlinkInterval) {
|
||||||
|
textCursorBlinkTimer -= 0.5f
|
||||||
|
textCursorIsOn = !textCursorIsOn
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun peekPalette(offset: Int): Byte {
|
private fun peekPalette(offset: Int): Byte {
|
||||||
if (offset == 255) return 0 // palette 255 is always transparent
|
if (offset == 255) return 0 // palette 255 is always transparent
|
||||||
|
|
||||||
|
// FIXME always return zero?
|
||||||
|
|
||||||
val highvalue = paletteOfFloats[offset * 2] // R, B
|
val highvalue = paletteOfFloats[offset * 2] // R, B
|
||||||
val lowvalue = paletteOfFloats[offset * 2 + 1] // G, A
|
val lowvalue = paletteOfFloats[offset * 2 + 1] // G, A
|
||||||
return (highvalue.div(15f).toInt().shl(4) or lowvalue.div(15f).toInt()).toByte()
|
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 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 tilesAtlas;
|
||||||
uniform sampler2D foreColours;
|
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?
|
// 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. //
|
// 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
|
vec2 flippedFragCoord = vec2(gl_FragCoord.x, screenDimension.y - gl_FragCoord.y); // NO IVEC2!!; this flips Y
|
||||||
|
|
||||||
// get required tile numbers //
|
// get required tile numbers //
|
||||||
|
|
||||||
vec4 tileFromMap = texture2D(tilemap, flippedFragCoord / overscannedScreenDimension); // raw tile number
|
vec4 tileFromMap = texture2D(tilemap, flippedFragCoord / screenDimension); // raw tile number
|
||||||
vec4 foreColFromMap = texture2D(foreColours, flippedFragCoord / overscannedScreenDimension);
|
vec4 foreColFromMap = texture2D(foreColours, flippedFragCoord / screenDimension);
|
||||||
vec4 backColFromMap = texture2D(backColours, flippedFragCoord / overscannedScreenDimension);
|
vec4 backColFromMap = texture2D(backColours, flippedFragCoord / screenDimension);
|
||||||
|
|
||||||
int tile = getTileFromColor(tileFromMap);
|
int tile = getTileFromColor(tileFromMap);
|
||||||
ivec2 tileXY = getTileXY(tile);
|
ivec2 tileXY = getTileXY(tile);
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ User area: 8 MB, hardware area: 8 MB
|
|||||||
|
|
||||||
VRAM Bank 0 (256 kB)
|
VRAM Bank 0 (256 kB)
|
||||||
|
|
||||||
|
Endianness: little
|
||||||
|
|
||||||
From the start of the memory space:
|
From the start of the memory space:
|
||||||
250880 bytes
|
250880 bytes
|
||||||
Framebuffer
|
Framebuffer
|
||||||
@@ -87,6 +89,10 @@ MMIO
|
|||||||
0b 0000 000g (g: Use sprites(wipes out text buffer))
|
0b 0000 000g (g: Use sprites(wipes out text buffer))
|
||||||
1 bytes RO
|
1 bytes RO
|
||||||
Last used colour (set by poking at the framebuffer)
|
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
|
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
|
Even in the text mode framebuffer is still being drawn onto the screen, and the texts are drawn on top of it
|
||||||
Reference in New Issue
Block a user