diff --git a/assets/disk0/tvdos/bin/taut.js b/assets/disk0/tvdos/bin/taut.js index 90e4333..7d46995 100644 --- a/assets/disk0/tvdos/bin/taut.js +++ b/assets/disk0/tvdos/bin/taut.js @@ -3356,7 +3356,7 @@ function sampleWaveformRect() { function clearSampleWaveformArea() { const r = sampleWaveformRect() - graphics.plotRect(r.x, r.y, r.w, r.h, 255) // 255 = transparent + graphics.plotRect(r.x-1, r.y-1, r.w+1, r.h+1, 255) // 255 = transparent } function drawSampleWaveform() { @@ -3364,7 +3364,7 @@ function drawSampleWaveform() { const wx0 = r.x, wy0 = r.y, wW = r.w, wH = r.h // Clear waveform area to transparent (255 = transparent against text bg) - graphics.plotRect(wx0, wy0, wW, wH, 255) + clearSampleWaveformArea() const s = (samplesCache && samplesCache[smpListCursor]) || null if (!s || s.len === 0) return @@ -3931,7 +3931,7 @@ function instEnvelopeRect() { // the instrument viewer (mirrors clearSampleWaveformArea for the same reason). function clearInstrumentsEnvelopeArea() { const r = instEnvelopeRect() - graphics.plotRect(r.x, r.y, r.w, r.h, 255) + graphics.plotRect(r.x-1, r.y-1, r.w+1, r.h+1, 255) // Also clear the row of text that the graph overlays would otherwise visually // smudge — the body redraw paints these rows blank anyway, but switchToPanel // bypasses the body redraw on exit. @@ -3962,7 +3962,7 @@ function envPlotLine(x0, y0, x1, y1, col) { // Value axis: 0 at bottom, env.valueMax at top. function drawEnvelopeGraph(env) { const r = instEnvelopeRect() - graphics.plotRect(r.x, r.y, r.w, r.h, 255) // clear + clearInstrumentsEnvelopeArea() // clear // Dashed reference hairlines at quarter points of the value range. Drawn // first so the solid axis line / loop bands / polyline can stack on top. @@ -4026,13 +4026,13 @@ function drawEnvelopeGraph(env) { const x0 = pxX(xs[env.loopStart]) const x1 = pxX(xs[env.loopEnd]) const bw = Math.max(1, x1 - x0) - graphics.plotRect(x0, r.y, bw, r.h, colInstEnvLoop) + graphics.plotRect(x0, r.y, bw, r.h, colInstEnvLoop, 2) } if (env.sustEnable && env.sustStart <= lastIdx && env.sustEnd <= lastIdx) { const x0 = pxX(xs[env.sustStart]) const x1 = pxX(xs[env.sustEnd]) const bw = Math.max(1, x1 - x0) - graphics.plotRect(x0, r.y, bw, r.h, colInstEnvSust) + graphics.plotRect(x0, r.y, bw, r.h, colInstEnvSust, 2) } // Polyline through the envelope. diff --git a/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt b/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt index d4f58b1..967ec94 100644 --- a/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt +++ b/tsvm_core/src/net/torvald/tsvm/GraphicsJSR223Delegate.kt @@ -149,17 +149,41 @@ class GraphicsJSR223Delegate(private val vm: VM) { } } - fun plotRect(x: Int, y: Int, w: Int, h: Int, colour: Int) { + fun plotRect(x: Int, y: Int, w: Int, h: Int, colour: Int) = plotRect(x, y, w, h, colour, 0) + + /** + * @param eff plot effect. 0 — solid, 1 — 50% checkerboard, 2 — 25% checkerboard + */ + fun plotRect(x: Int, y: Int, w: Int, h: Int, colour: Int, eff: Int) { val xs = min(x, x+w).toLong() val xe = max(x, x+w).toLong() val ys = min(y, y+h).toLong() val ye = max(y, y+h).toLong() getFirstGPU()?.let { - for (py in ys until ye) { - for (px in xs until xe) { - if (px in 0 until it.config.width && py in 0 until it.config.height) { - it.poke(py * it.config.width + px, colour.toByte()) + val forYcond = if (eff == 2) (ys until ye step 2) else (ys until ye) + + for (py in forYcond) { + when (eff) { + 0 -> for (px in xs until xe) { + if (px in 0 until it.config.width && py in 0 until it.config.height) { + it.poke(py * it.config.width + px, colour.toByte()) + } + } + 1 -> { + val parity = py % 2 + val forXcond = if (parity == 0L) (xs until xe step 2) else ((xs+1) until xe step 2) + + for (px in forXcond) { + if (px in 0 until it.config.width && py in 0 until it.config.height) { + it.poke(py * it.config.width + px, colour.toByte()) + } + } + } + 2 -> for (px in xs until xe step 2) { + if (px in 0 until it.config.width && py in 0 until it.config.height) { + it.poke(py * it.config.width + px, colour.toByte()) + } } } } @@ -167,17 +191,41 @@ class GraphicsJSR223Delegate(private val vm: VM) { } } - fun plotRect2(x: Int, y: Int, w: Int, h: Int, colour: Int) { + fun plotRect2(x: Int, y: Int, w: Int, h: Int, colour: Int) = plotRect2(x, y, w, h, colour, 0) + + /** + * @param eff plot effect. 0 — solid, 1 — 50% checkerboard, 2 — 25% checkerboard + */ + fun plotRect2(x: Int, y: Int, w: Int, h: Int, colour: Int, eff: Int) { val xs = min(x, x+w).toLong() val xe = max(x, x+w).toLong() val ys = min(y, y+h).toLong() val ye = max(y, y+h).toLong() getFirstGPU()?.let { - for (py in ys until ye) { - for (px in xs until xe) { - if (px in 0 until it.config.width && py in 0 until it.config.height) { - it.poke(262144 + py * it.config.width + px, colour.toByte()) + val forYcond = if (eff == 2) (ys until ye step 2) else (ys until ye) + + for (py in forYcond) { + when (eff) { + 0 -> for (px in xs until xe) { + if (px in 0 until it.config.width && py in 0 until it.config.height) { + it.poke(262144 + py * it.config.width + px, colour.toByte()) + } + } + 1 -> { + val parity = py % 2 + val forXcond = if (parity == 0L) (xs until xe step 2) else ((xs+1) until xe step 2) + + for (px in forXcond) { + if (px in 0 until it.config.width && py in 0 until it.config.height) { + it.poke(py * it.config.width + px, colour.toByte()) + } + } + } + 2 -> for (px in xs until xe step 2) { + if (px in 0 until it.config.width && py in 0 until it.config.height) { + it.poke(py * it.config.width + px, colour.toByte()) + } } } } @@ -195,7 +243,12 @@ class GraphicsJSR223Delegate(private val vm: VM) { } } - fun plotRectMode1(x: Int, y: Int, w: Int, h: Int, colour: Int, plane: Int) { + fun plotRectMode1(x: Int, y: Int, w: Int, h: Int, colour: Int, plane: Int) = plotRectMode1(x, y, w, h, colour, plane, 0) + + /** + * @param eff plot effect. 0 — solid, 1 — 50% checkerboard, 2 — 25% checkerboard + */ + fun plotRectMode1(x: Int, y: Int, w: Int, h: Int, colour: Int, plane: Int, eff: Int) { val xs = min(x, x+w).toLong() val xe = max(x, x+w).toLong() val ys = min(y, y+h).toLong() @@ -205,10 +258,29 @@ class GraphicsJSR223Delegate(private val vm: VM) { val halfW = it.config.width / 2 val halfH = it.config.height / 2 val planesize = it.config.width * it.config.height / 4 - for (py in ys until ye) { - for (px in xs until xe) { - if (px in 0 until halfW && py in 0 until halfH) { - it.poke(py * halfW + px + planesize * plane, colour.toByte()) + val forYcond = if (eff == 2) (ys until ye step 2) else (ys until ye) + + for (py in forYcond) { + when (eff) { + 0 -> for (px in xs until xe) { + if (px in 0 until halfW && py in 0 until halfH) { + it.poke(py * halfW + px + planesize * plane, colour.toByte()) + } + } + 1 -> { + val parity = py % 2 + val forXcond = if (parity == 0L) (xs until xe step 2) else ((xs+1) until xe step 2) + + for (px in forXcond) { + if (px in 0 until halfW && py in 0 until halfH) { + it.poke(py * halfW + px + planesize * plane, colour.toByte()) + } + } + } + 2 -> for (px in xs until xe step 2) { + if (px in 0 until halfW && py in 0 until halfH) { + it.poke(py * halfW + px + planesize * plane, colour.toByte()) + } } } }