graphics: scanline scroll and the splash screen demonstrating the feature

This commit is contained in:
minjaesong
2021-09-26 13:23:26 +09:00
parent 79a0ffb4c3
commit 6fdfd3f794
3 changed files with 115 additions and 56 deletions

View File

@@ -4,12 +4,29 @@ graphics.resetPalette();graphics.setBackground(0,0,0);
let logo = gzip.decomp(base64.atob("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")); let logo = gzip.decomp(base64.atob("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"));
// display logo in kickin' ass-style of panasonic // display logo in kickin' ass-style of panasonic
//let m=56;let r=()=>{let i=Math.random()*2-1;return(i<0)?i-1:i+1}; // hide entire framebuffer with black text to hide the slow image drawing
//let o=[];for(let y=0;y<164;y++)o[y]=Math.round(r()*560/m)|0;
//for(let p=0;p<=1120/m;p++){for(let y=0;y<164;y++){for(let x=0;x<560;x++)
//{let f=y*560+x;let d=x+m*o[y];if(d>=0&&d<560)graphics.plotPixel(d,95+y,logo[f]);}
//if(o[y]!=0)o[y]-=Math.sign(o[y]);}}
con.color_pair(0,0);
for(let i=0;i<2560;i++)graphics.putSymbolAt(1+(i/80)|0,1+(i%80),239);
// draw logo
for(let i=0;i<logo.length;i++){graphics.plotPixel(i%560,95+(i/560)|0,logo[i])}
// scramble lines
let m=4;let r=()=>{let i=Math.random()*2-1;return(i<0)?i-1:i+1};
let o=[];for(let y=0;y<164;y++){
let k=Math.round(r()*560/m)|0;
o.push(k);graphics.setLineOffset(95+y,k*m);}
// unhide screen
graphics.setBackground(0,0,15);con.color_pair(239,255);
for(let i=0;i<2560;i++)graphics.putSymbolAt(1+(i/80)|0,1+(i%80),0);
// unscramble
let tmr=0;let n=560*2;while(n>0){
for(let y=0;y<164;y++){o[y]-=Math.sign(o[y]);graphics.setLineOffset(95+y,o[y]*m);}
// wait for timer
tmr=sys.nanoTime();while(sys.nanoTime()-tmr<250000*m)Math.sqrt(tmr) // waste some cpu time
n-=m;}
/*
// display logo in mundane, true-to-msx way // display logo in mundane, true-to-msx way
graphics.setFramebufferScroll(0,-164); graphics.setFramebufferScroll(0,-164);
// hide entire framebuffer with black text to hide the slow image drawing // hide entire framebuffer with black text to hide the slow image drawing
@@ -27,6 +44,7 @@ let tmr=sys.nanoTime();
let tlen=1073741824; let tlen=1073741824;
while(1){let tdiff=sys.nanoTime()-tmr;if(tdiff>=tlen)break; while(1){let tdiff=sys.nanoTime()-tmr;if(tdiff>=tlen)break;
graphics.setFramebufferScroll(0,-((1.0-tdiff/tlen)*164)|0);} graphics.setFramebufferScroll(0,-((1.0-tdiff/tlen)*164)|0);}
*/
// show how much ram is there // show how much ram is there
con.color_pair(239,4); con.color_pair(239,4);
@@ -57,7 +75,7 @@ Object.freeze(_BIOS);
tmr = sys.nanoTime(); tmr = sys.nanoTime();
while (sys.nanoTime() - tmr < 2147483648) sys.spin(); while (sys.nanoTime() - tmr < 2147483648) sys.spin();
// clear screen // clear screen
graphics.clearPixels(255); graphics.clearPixels(255);con.color_pair(254,255);
con.clear();con.move(1,1); con.clear();con.move(1,1);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@@ -1,6 +1,7 @@
package net.torvald.tsvm package net.torvald.tsvm
import net.torvald.UnsafeHelper import net.torvald.UnsafeHelper
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.toUint
import net.torvald.tsvm.peripheral.GraphicsAdapter import net.torvald.tsvm.peripheral.GraphicsAdapter
import net.torvald.tsvm.peripheral.fmod import net.torvald.tsvm.peripheral.fmod
@@ -60,6 +61,22 @@ class GraphicsJSR223Delegate(val vm: VM) {
} }
} }
fun setLineOffset(line: Int, offset: Int) {
getFirstGPU()?.let {
it.poke(250900L + 2*line, offset.shr(8).toByte()) // absolutely not USHR
it.poke(250901L + 2*line, offset.toByte())
}
}
fun getLineOffset(line: Int): Int {
getFirstGPU()?.let {
var xoff = it.peek(250900L + 2*line)!!.toUint().shl(8) or it.peek(250901L + 2*line)!!.toUint()
if (xoff.and(0x8000) != 0) xoff = xoff or 0xFFFF0000.toInt()
return xoff
}
return 0
}
fun getPixelDimension(): IntArray { fun getPixelDimension(): IntArray {
getFirstGPU()?.let { return intArrayOf(it.framebuffer.width, it.framebuffer.height) } getFirstGPU()?.let { return intArrayOf(it.framebuffer.width, it.framebuffer.height) }
return intArrayOf(-1, -1) return intArrayOf(-1, -1)
@@ -139,14 +156,14 @@ class GraphicsJSR223Delegate(val vm: VM) {
private fun GraphicsAdapter._loadSprite(spriteNum: Int, ptr: Int) { private fun GraphicsAdapter._loadSprite(spriteNum: Int, ptr: Int) {
UnsafeHelper.memcpy( UnsafeHelper.memcpy(
vm.usermem.ptr + ptr, vm.usermem.ptr + ptr,
(this.spriteAndTextArea).ptr + (260 * spriteNum) + 4, (this.textArea).ptr + (260 * spriteNum) + 4,
256 256
) )
} }
private fun GraphicsAdapter._storeSprite(spriteNum: Int, ptr: Int) { private fun GraphicsAdapter._storeSprite(spriteNum: Int, ptr: Int) {
UnsafeHelper.memcpy( UnsafeHelper.memcpy(
(this.spriteAndTextArea).ptr + (260 * spriteNum) + 4, (this.textArea).ptr + (260 * spriteNum) + 4,
vm.usermem.ptr + ptr, vm.usermem.ptr + ptr,
256 256
) )

View File

@@ -7,6 +7,7 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion
import com.badlogic.gdx.graphics.glutils.FrameBuffer import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.badlogic.gdx.math.Matrix4 import com.badlogic.gdx.math.Matrix4
import net.torvald.UnsafeHelper import net.torvald.UnsafeHelper
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.toUint
import net.torvald.tsvm.AppLoader import net.torvald.tsvm.AppLoader
import net.torvald.tsvm.VM import net.torvald.tsvm.VM
import net.torvald.tsvm.kB import net.torvald.tsvm.kB
@@ -14,7 +15,6 @@ import net.torvald.tsvm.peripheral.GraphicsAdapter.Companion.DRAW_SHADER_FRAG
import java.io.InputStream import java.io.InputStream
import java.io.OutputStream import java.io.OutputStream
import kotlin.experimental.and import kotlin.experimental.and
import kotlin.math.roundToInt
data class AdapterConfig( data class AdapterConfig(
val theme: String, val theme: String,
@@ -59,6 +59,7 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
protected val TAB_SIZE = 8 protected val TAB_SIZE = 8
internal val framebuffer = Pixmap(WIDTH, HEIGHT, Pixmap.Format.Alpha) internal val framebuffer = Pixmap(WIDTH, HEIGHT, Pixmap.Format.Alpha)
internal val framebuffer2 = Pixmap(WIDTH, HEIGHT, Pixmap.Format.Alpha)
protected var rendertex = Texture(1, 1, Pixmap.Format.RGBA8888) protected var rendertex = Texture(1, 1, Pixmap.Format.RGBA8888)
internal val paletteOfFloats = FloatArray(1024) { internal val paletteOfFloats = FloatArray(1024) {
val rgba = DEFAULT_PALETTE[it / 4] val rgba = DEFAULT_PALETTE[it / 4]
@@ -68,8 +69,8 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
protected val chrrom0 = Texture("./assets/"+config.chrRomPath) protected val chrrom0 = Texture("./assets/"+config.chrRomPath)
protected val faketex: Texture protected val faketex: Texture
internal val spriteAndTextArea = UnsafeHelper.allocate(10660L) internal val textArea = UnsafeHelper.allocate(7682)
protected val unusedArea = ByteArray(92) internal val unusedArea = UnsafeHelper.allocate(1024)
protected val paletteShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, config.paletteShader) protected val paletteShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, config.paletteShader)
protected val textShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, config.fragShader) protected val textShader = AppLoader.loadShaderInline(DRAW_SHADER_VERT, config.fragShader)
@@ -100,15 +101,15 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
private val outFBObatch = SpriteBatch() private val outFBObatch = SpriteBatch()
private val memTextCursorPosOffset = 2978L private val memTextCursorPosOffset = 0L
private val memTextForeOffset = 2980L private val memTextForeOffset = 2L
private val memTextBackOffset = 2980L + 2560 private val memTextBackOffset = 2L + 2560
private val memTextOffset = 2980L + 2560 + 2560 private val memTextOffset = 2L + 2560 + 2560
private val TEXT_AREA_SIZE = TEXT_COLS * TEXT_ROWS private val TEXT_AREA_SIZE = TEXT_COLS * TEXT_ROWS
override var rawCursorPos: Int override var rawCursorPos: Int
get() = spriteAndTextArea.getShort(memTextCursorPosOffset).toInt() get() = textArea.getShort(memTextCursorPosOffset).toInt()
set(value) { spriteAndTextArea.setShort(memTextCursorPosOffset, value.toShort()) } set(value) { textArea.setShort(memTextCursorPosOffset, value.toShort()) }
override fun getCursorPos() = rawCursorPos % TEXT_COLS to rawCursorPos / TEXT_COLS override fun getCursorPos() = rawCursorPos % TEXT_COLS to rawCursorPos / TEXT_COLS
@@ -144,13 +145,15 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
outFBObatch.projectionMatrix = m outFBObatch.projectionMatrix = m
framebuffer.blending = Pixmap.Blending.None framebuffer.blending = Pixmap.Blending.None
framebuffer2.blending = Pixmap.Blending.None
textForePixmap.blending = Pixmap.Blending.None textForePixmap.blending = Pixmap.Blending.None
textBackPixmap.blending = Pixmap.Blending.None textBackPixmap.blending = Pixmap.Blending.None
framebuffer.setColor(-1) framebuffer.setColor(-1)
framebuffer.fill() framebuffer.fill()
unusedArea.fillWith(0)
val pm = Pixmap(1, 1, Pixmap.Format.RGBA8888) val pm = Pixmap(1, 1, Pixmap.Format.RGBA8888)
pm.drawPixel(0, 0, -1) pm.drawPixel(0, 0, -1)
faketex = Texture(pm) faketex = Texture(pm)
@@ -159,10 +162,10 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
// initialise with NONZERO value; value zero corresponds to opaque black, and it will paint the whole screen black // initialise with NONZERO value; value zero corresponds to opaque black, and it will paint the whole screen black
// when in text mode, and that's undesired behaviour // when in text mode, and that's undesired behaviour
// -1 is preferred because it points to the colour CLEAR, and it's constant. // -1 is preferred because it points to the colour CLEAR, and it's constant.
spriteAndTextArea.fillWith(-1) textArea.fillWith(-1)
// fill text area with 0 // fill text area with 0
for (k in 0 until TEXT_ROWS * TEXT_COLS) { for (k in 0 until TEXT_ROWS * TEXT_COLS) {
spriteAndTextArea[k + memTextOffset] = 0 textArea[k + memTextOffset] = 0
} }
if (theme.contains("color")) { if (theme.contains("color")) {
@@ -173,7 +176,7 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
setCursorPos(0, 0) setCursorPos(0, 0)
println(framebuffer.pixels.limit()) println("Framebuffer pixels limit: ${framebuffer.pixels.limit()}")
} }
override fun peek(addr: Long): Byte? { override fun peek(addr: Long): Byte? {
@@ -184,8 +187,8 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
250897L -> framebufferScrollX.ushr(8).toByte() 250897L -> framebufferScrollX.ushr(8).toByte()
250898L -> framebufferScrollY.toByte() 250898L -> framebufferScrollY.toByte()
250899L -> framebufferScrollY.ushr(8).toByte() 250899L -> framebufferScrollY.ushr(8).toByte()
in 250880 until 250972 -> unusedArea[adi - 250880] in 250880 until 250880+1024 -> unusedArea[addr - 250880]
in 250972 until 261632 -> spriteAndTextArea[addr - 250972] in 253950 until 261632 -> textArea[addr - 253950]
in 261632 until 262144 -> peekPalette(adi - 261632) in 261632 until 262144 -> peekPalette(adi - 261632)
in 0 until VM.HW_RESERVE_SIZE -> { in 0 until VM.HW_RESERVE_SIZE -> {
println("[GraphicsAdapter] mirroring with input address $addr") println("[GraphicsAdapter] mirroring with input address $addr")
@@ -204,15 +207,15 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
framebuffer.pixels.put(adi, byte) framebuffer.pixels.put(adi, byte)
} }
250883L -> { 250883L -> {
unusedArea[adi - 250880] = byte unusedArea[addr - 250880] = byte
runCommand(byte) runCommand(byte)
} }
250896L -> framebufferScrollX = framebufferScrollX.and(0xFFFFFF00.toInt()).or(bi) 250896L -> framebufferScrollX = framebufferScrollX.and(0xFFFFFF00.toInt()).or(bi)
250897L -> framebufferScrollX = framebufferScrollX.and(0xFFFF00FF.toInt()).or(bi shl 8) 250897L -> framebufferScrollX = framebufferScrollX.and(0xFFFF00FF.toInt()).or(bi shl 8)
250898L -> framebufferScrollY = framebufferScrollY.and(0xFFFFFF00.toInt()).or(bi) 250898L -> framebufferScrollY = framebufferScrollY.and(0xFFFFFF00.toInt()).or(bi)
250899L -> framebufferScrollY = framebufferScrollY.and(0xFFFF00FF.toInt()).or(bi shl 8) 250899L -> framebufferScrollY = framebufferScrollY.and(0xFFFF00FF.toInt()).or(bi shl 8)
in 250880 until 250972 -> unusedArea[adi - 250880] = byte in 250880 until 250880+1024 -> unusedArea[addr - 250880] = byte
in 250972 until 261632 -> spriteAndTextArea[addr - 250972] = byte in 253950 until 261632 -> textArea[addr - 253950] = byte
in 261632 until 262144 -> pokePalette(adi - 261632, byte) in 261632 until 262144 -> pokePalette(adi - 261632, byte)
in 0 until VM.HW_RESERVE_SIZE -> { in 0 until VM.HW_RESERVE_SIZE -> {
println("[GraphicsAdapter] mirroring with input address $addr") println("[GraphicsAdapter] mirroring with input address $addr")
@@ -287,9 +290,9 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
override fun putChar(x: Int, y: Int, text: Byte, foreColour: Byte, backColour: Byte) { override fun putChar(x: Int, y: Int, text: Byte, foreColour: Byte, backColour: Byte) {
val textOff = toTtyTextOffset(x, y) val textOff = toTtyTextOffset(x, y)
spriteAndTextArea[memTextForeOffset + textOff] = foreColour textArea[memTextForeOffset + textOff] = foreColour
spriteAndTextArea[memTextBackOffset + textOff] = backColour textArea[memTextBackOffset + textOff] = backColour
spriteAndTextArea[memTextOffset + textOff] = text textArea[memTextOffset + textOff] = text
} }
override fun cursorUp(arg: Int) { override fun cursorUp(arg: Int) {
@@ -338,11 +341,11 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
val foreBits = ttyFore or ttyFore.shl(8) or ttyFore.shl(16) or ttyFore.shl(24) val foreBits = ttyFore or ttyFore.shl(8) or ttyFore.shl(16) or ttyFore.shl(24)
val backBits = ttyBack or ttyBack.shl(8) or ttyBack.shl(16) or ttyBack.shl(24) val backBits = ttyBack or ttyBack.shl(8) or ttyBack.shl(16) or ttyBack.shl(24)
for (i in 0 until TEXT_COLS * TEXT_ROWS step 4) { for (i in 0 until TEXT_COLS * TEXT_ROWS step 4) {
spriteAndTextArea.setInt(memTextForeOffset + i, foreBits) textArea.setInt(memTextForeOffset + i, foreBits)
spriteAndTextArea.setInt(memTextBackOffset + i, backBits) textArea.setInt(memTextBackOffset + i, backBits)
spriteAndTextArea.setInt(memTextOffset + i, 0) textArea.setInt(memTextOffset + i, 0)
} }
spriteAndTextArea.setShort(memTextCursorPosOffset, 0) textArea.setShort(memTextCursorPosOffset, 0)
} }
else -> TODO() else -> TODO()
} }
@@ -358,24 +361,24 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
override fun scrollUp(arg: Int) { override fun scrollUp(arg: Int) {
val displacement = arg.toLong() * TEXT_COLS val displacement = arg.toLong() * TEXT_COLS
UnsafeHelper.memcpy( UnsafeHelper.memcpy(
spriteAndTextArea.ptr + memTextOffset + displacement, textArea.ptr + memTextOffset + displacement,
spriteAndTextArea.ptr + memTextOffset, textArea.ptr + memTextOffset,
TEXT_AREA_SIZE - displacement TEXT_AREA_SIZE - displacement
) )
UnsafeHelper.memcpy( UnsafeHelper.memcpy(
spriteAndTextArea.ptr + memTextBackOffset + displacement, textArea.ptr + memTextBackOffset + displacement,
spriteAndTextArea.ptr + memTextBackOffset, textArea.ptr + memTextBackOffset,
TEXT_AREA_SIZE - displacement TEXT_AREA_SIZE - displacement
) )
UnsafeHelper.memcpy( UnsafeHelper.memcpy(
spriteAndTextArea.ptr + memTextForeOffset + displacement, textArea.ptr + memTextForeOffset + displacement,
spriteAndTextArea.ptr + memTextForeOffset, textArea.ptr + memTextForeOffset,
TEXT_AREA_SIZE - displacement TEXT_AREA_SIZE - displacement
) )
for (i in 0 until displacement) { for (i in 0 until displacement) {
spriteAndTextArea[memTextOffset + TEXT_AREA_SIZE - displacement + i] = 0 textArea[memTextOffset + TEXT_AREA_SIZE - displacement + i] = 0
spriteAndTextArea[memTextBackOffset + TEXT_AREA_SIZE - displacement + i] = ttyBack.toByte() textArea[memTextBackOffset + TEXT_AREA_SIZE - displacement + i] = ttyBack.toByte()
spriteAndTextArea[memTextForeOffset + TEXT_AREA_SIZE - displacement + i] = ttyFore.toByte() textArea[memTextForeOffset + TEXT_AREA_SIZE - displacement + i] = ttyFore.toByte()
} }
} }
@@ -383,24 +386,24 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
override fun scrollDown(arg: Int) { override fun scrollDown(arg: Int) {
val displacement = arg.toLong() * TEXT_COLS val displacement = arg.toLong() * TEXT_COLS
UnsafeHelper.memcpy( UnsafeHelper.memcpy(
spriteAndTextArea.ptr + memTextOffset, textArea.ptr + memTextOffset,
spriteAndTextArea.ptr + memTextOffset + displacement, textArea.ptr + memTextOffset + displacement,
TEXT_AREA_SIZE - displacement TEXT_AREA_SIZE - displacement
) )
UnsafeHelper.memcpy( UnsafeHelper.memcpy(
spriteAndTextArea.ptr + memTextBackOffset, textArea.ptr + memTextBackOffset,
spriteAndTextArea.ptr + memTextBackOffset + displacement, textArea.ptr + memTextBackOffset + displacement,
TEXT_AREA_SIZE - displacement TEXT_AREA_SIZE - displacement
) )
UnsafeHelper.memcpy( UnsafeHelper.memcpy(
spriteAndTextArea.ptr + memTextForeOffset, textArea.ptr + memTextForeOffset,
spriteAndTextArea.ptr + memTextForeOffset + displacement, textArea.ptr + memTextForeOffset + displacement,
TEXT_AREA_SIZE - displacement TEXT_AREA_SIZE - displacement
) )
for (i in 0 until displacement) { for (i in 0 until displacement) {
spriteAndTextArea[memTextOffset + TEXT_AREA_SIZE + i] = 0 textArea[memTextOffset + TEXT_AREA_SIZE + i] = 0
spriteAndTextArea[memTextBackOffset + TEXT_AREA_SIZE + i] = ttyBack.toByte() textArea[memTextBackOffset + TEXT_AREA_SIZE + i] = ttyBack.toByte()
spriteAndTextArea[memTextForeOffset + TEXT_AREA_SIZE + i] = ttyFore.toByte() textArea[memTextForeOffset + TEXT_AREA_SIZE + i] = ttyFore.toByte()
} }
} }
@@ -570,8 +573,9 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
override fun dispose() { override fun dispose() {
//testTex.dispose() //testTex.dispose()
framebuffer.dispose() framebuffer.dispose()
framebuffer2.dispose()
rendertex.dispose() rendertex.dispose()
spriteAndTextArea.destroy() textArea.destroy()
textForePixmap.dispose() textForePixmap.dispose()
textBackPixmap.dispose() textBackPixmap.dispose()
textPixmap.dispose() textPixmap.dispose()
@@ -585,6 +589,7 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
try { textBackTex.dispose() } catch (_: Throwable) {} try { textBackTex.dispose() } catch (_: Throwable) {}
chrrom0.dispose() chrrom0.dispose()
unusedArea.destroy()
} }
private var textCursorBlinkTimer = 0f private var textCursorBlinkTimer = 0f
@@ -594,8 +599,27 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
private var decayColor = Color(1f, 1f, 1f, 1f - glowDecay) private var decayColor = Color(1f, 1f, 1f, 1f - glowDecay)
open fun render(delta: Float, uiBatch: SpriteBatch, xoff: Float, yoff: Float) { open fun render(delta: Float, uiBatch: SpriteBatch, xoff: Float, yoff: Float) {
framebuffer2.setColor(-1);framebuffer2.fill()
for (y in 0 until 448) {
var xoff = unusedArea[20L + 2*y].toUint().shl(8) or unusedArea[20L + 2*y + 1].toUint()
if (xoff.and(0x8000) != 0) xoff = xoff or 0xFFFF0000.toInt()
val xs = (0+xoff).coerceIn(0,559) .. (559+xoff).coerceIn(0,559)
if (xoff in -559..559) {
for (x in xs) {
//framebuffer2.drawPixel(x, y, framebuffer.getPixel(x + xs.first - xoff, y))
// this only works because framebuffer is guaranteed to be 8bpp
framebuffer2.pixels.put(y*560+x,
framebuffer.pixels.get(y*560 + (x - xoff).coerceIn(0, 559))
)
}
}
}
rendertex.dispose() rendertex.dispose()
rendertex = Texture(framebuffer, Pixmap.Format.RGBA8888, false) rendertex = Texture(framebuffer2, Pixmap.Format.RGBA8888, false)
val texOffX = (framebufferScrollX fmod framebuffer.width) * -1f val texOffX = (framebufferScrollX fmod framebuffer.width) * -1f
val texOffY = (framebufferScrollY fmod framebuffer.height) * 1f val texOffY = (framebufferScrollY fmod framebuffer.height) * 1f
@@ -657,12 +681,12 @@ open class GraphicsAdapter(val vm: VM, val config: AdapterConfig, val sgr: Super
val drawCursor = blinkCursor && textCursorIsOn && cx == x && cy == y val drawCursor = blinkCursor && textCursorIsOn && cx == x && cy == y
val addr = y.toLong() * TEXT_COLS + x val addr = y.toLong() * TEXT_COLS + x
val char = val char =
if (drawCursor) 0xFF else spriteAndTextArea[memTextOffset + addr].toInt().and(255) if (drawCursor) 0xFF else textArea[memTextOffset + addr].toInt().and(255)
var back = var back =
if (drawCursor) ttyBack else spriteAndTextArea[memTextBackOffset + addr].toInt() if (drawCursor) ttyBack else textArea[memTextBackOffset + addr].toInt()
.and(255) .and(255)
var fore = var fore =
if (drawCursor) ttyFore else spriteAndTextArea[memTextForeOffset + addr].toInt() if (drawCursor) ttyFore else textArea[memTextForeOffset + addr].toInt()
.and(255) .and(255)
textPixmap.setColor(Color(0f, 0f, char / 255f, 1f)) textPixmap.setColor(Color(0f, 0f, char / 255f, 1f))