diff --git a/.idea/runConfigurations/MTMC_debug.xml b/.idea/runConfigurations/MTMC_debug.xml
new file mode 100644
index 0000000..bc803aa
--- /dev/null
+++ b/.idea/runConfigurations/MTMC_debug.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/MainKt.xml b/.idea/runConfigurations/MainKt.xml
new file mode 100644
index 0000000..16b522e
--- /dev/null
+++ b/.idea/runConfigurations/MainKt.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/commonMain/kotlin/mtmc/emulator/BufferedImage.kt b/src/commonMain/kotlin/mtmc/emulator/BufferedImage.kt
index d17a833..05d2496 100644
--- a/src/commonMain/kotlin/mtmc/emulator/BufferedImage.kt
+++ b/src/commonMain/kotlin/mtmc/emulator/BufferedImage.kt
@@ -8,15 +8,22 @@ class BufferedImage(
val display = ByteArray(width * height * 4)
fun getRGB(x: Int, y: Int): Int {
- return display[x * 4 + y * width * 4 + 0].toInt() +
- display[x * 4 + y * width * 4 + 1].toInt() shl 8 +
- display[x * 4 + y * width * 4 + 2].toInt() shl 16
+ check(x in 0 until width && y in 0 until height)
+
+ val offset = (x + y * width) * 4
+ return display[offset + 0].toInt() +
+ display[offset + 1].toInt() shl 8 +
+ display[offset + 2].toInt() shl 16
}
fun setRGB(x: Int, y: Int, intVal: Int) {
- display[x * 4 + y * width * 4 + 0] = intVal.toByte()
- display[x * 4 + y * width * 4 + 1] = (intVal shr 8).toByte()
- display[x * 4 + y * width * 4 + 2] = (intVal shr 16).toByte()
+ check(x in 0 until width && y in 0 until height)
+
+ val offset = (x + y * width) * 4
+ display[offset + 0] = intVal.toByte()
+ display[offset + 1] = (intVal shr 8).toByte()
+ display[offset + 2] = (intVal shr 16).toByte()
+ display[offset + 3] = 255.toByte()
}
}
diff --git a/src/jsMain/kotlin/mtmc/Main.kt b/src/jsMain/kotlin/mtmc/Main.kt
index e9250ed..ef9fb82 100644
--- a/src/jsMain/kotlin/mtmc/Main.kt
+++ b/src/jsMain/kotlin/mtmc/Main.kt
@@ -4,6 +4,7 @@ import kotlinx.browser.document
import kotlinx.html.div
import kotlinx.html.style
import mtmc.emulator.MonTanaMiniComputer
+import mtmc.view.DisplayView
import mtmc.view.MTMCView
import nl.astraeus.komp.HtmlBuilder
import nl.astraeus.komp.Komponent
@@ -20,6 +21,7 @@ class HelloKomponent : Komponent() {
val computer = MonTanaMiniComputer()
val mainView = MTMCView(computer)
+val display = DisplayView(computer)
fun main() {
computer.speed = 1 // default to 1hz
diff --git a/src/jsMain/kotlin/mtmc/view/ConsoleView.kt b/src/jsMain/kotlin/mtmc/view/ConsoleView.kt
index e2964ae..f1d83a8 100644
--- a/src/jsMain/kotlin/mtmc/view/ConsoleView.kt
+++ b/src/jsMain/kotlin/mtmc/view/ConsoleView.kt
@@ -3,6 +3,7 @@ package mtmc.view
import kotlinx.browser.window
import kotlinx.html.div
import kotlinx.html.input
+import kotlinx.html.js.onClickFunction
import kotlinx.html.js.onKeyUpFunction
import kotlinx.html.span
import mtmc.emulator.MonTanaMiniComputer
@@ -19,11 +20,15 @@ class ConsoleView(
) : Komponent() {
val history: MutableList = mutableListOf()
var input: String = ""
+ private var inputElement: HTMLInputElement? = null
override fun HtmlBuilder.render() {
div("console") {
+"Console view"
+ onClickFunction = {
+ inputElement?.focus()
+ }
div("console-history") {
for (line in history) {
div {
@@ -38,7 +43,7 @@ class ConsoleView(
input(classes = "console-input") {
value = input
autoFocus = true
- val inputElement = currentElement() as? HTMLInputElement
+ inputElement = currentElement() as? HTMLInputElement
window.setTimeout({
inputElement?.focus()
}, 0)
diff --git a/src/jsMain/kotlin/mtmc/view/DisplayView.kt b/src/jsMain/kotlin/mtmc/view/DisplayView.kt
index df7a513..a9e7076 100644
--- a/src/jsMain/kotlin/mtmc/view/DisplayView.kt
+++ b/src/jsMain/kotlin/mtmc/view/DisplayView.kt
@@ -1,18 +1,52 @@
package mtmc.view
+import kotlinx.html.canvas
import kotlinx.html.div
+import mtmc.display
import mtmc.emulator.MonTanaMiniComputer
import nl.astraeus.komp.HtmlBuilder
import nl.astraeus.komp.Komponent
+import nl.astraeus.komp.currentElement
+import org.w3c.dom.CanvasRenderingContext2D
+import org.w3c.dom.HTMLCanvasElement
+import org.w3c.dom.ImageData
-class DisplayView(
+class DiplayControlView(
val computer: MonTanaMiniComputer
) : Komponent() {
override fun HtmlBuilder.render() {
div("display") {
- +"Display"
+ include(display)
+ }
+ }
+}
+
+class DisplayView(
+ val computer: MonTanaMiniComputer
+) : Komponent() {
+ var ctx: CanvasRenderingContext2D? = null
+ var imageData: ImageData? = null
+
+ override fun HtmlBuilder.render() {
+ canvas("display-canvas") {
+ width = "160px"
+ height = "144px"
+
+ val cv = currentElement() as? HTMLCanvasElement
+
+ ctx = cv?.getContext("2d")?.unsafeCast()
+
+ ctx?.fillStyle = "#404040"
+ ctx?.fillRect(0.0, 0.0, 160.0, 144.0)
+ imageData = ctx?.getImageData(0.0, 0.0, 160.0, 144.0)
}
}
+ override fun renderUpdate() {
+ // move data to canvas
+ imageData?.let { id ->
+ ctx?.putImageData(id, 0.0, 0.0)
+ }
+ }
}
diff --git a/src/jsMain/kotlin/mtmc/view/MTMCView.kt b/src/jsMain/kotlin/mtmc/view/MTMCView.kt
index bc154fe..f0eef51 100644
--- a/src/jsMain/kotlin/mtmc/view/MTMCView.kt
+++ b/src/jsMain/kotlin/mtmc/view/MTMCView.kt
@@ -11,7 +11,7 @@ class MTMCView(
val controlView = ControlView(computer)
val registerView = RegisterView(computer)
val memoryView = MemoryView(computer)
- val displayView = DisplayView(computer)
+ val displayView = DiplayControlView(computer)
val consoleView = ConsoleView(computer)
override fun HtmlBuilder.render() {
diff --git a/src/jsMain/resources/mtmc.css b/src/jsMain/resources/mtmc.css
index 43605ea..feb6039 100644
--- a/src/jsMain/resources/mtmc.css
+++ b/src/jsMain/resources/mtmc.css
@@ -116,6 +116,13 @@ table.register-table tr td.register-lights {
min-height: 480px;
}
+.display-canvas {
+ width: 320px;
+ height: 288px;
+ image-rendering: pixelated; /* Keeps sharp pixels, no smoothing */
+ image-rendering: -moz-crisp-edges; /* Firefox */
+ image-rendering: crisp-edges; /* Standard */
+}
/* console */
.console {