prog8/virtualmachine/src/prog8/vm/GraphicsWindow.kt

97 lines
3.1 KiB
Kotlin
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package prog8.vm
import java.awt.*
import java.awt.image.BufferedImage
import javax.swing.JFrame
import javax.swing.JPanel
import javax.swing.Timer
import kotlin.math.max
import kotlin.math.min
class GraphicsWindow(val pixelWidth: Int, val pixelHeight: Int, val pixelScaling: Int): JFrame("Prog8 VM Graphics Screen $pixelWidth × $pixelHeight"), AutoCloseable {
private lateinit var repaintTimer: Timer
fun start() {
val refreshRate = optimalRefreshRate(this)
repaintTimer = Timer(1000/refreshRate) {
repaint()
}
repaintTimer.initialDelay = 0
repaintTimer.start()
}
override fun close() {
repaintTimer.stop()
dispose()
}
val image: BufferedImage
init {
contentPane.layout = BorderLayout()
background = Color.BLACK
contentPane.background = Color.BLACK
isResizable = false
isLocationByPlatform = true
defaultCloseOperation = EXIT_ON_CLOSE
image = graphicsConfiguration.createCompatibleImage(pixelWidth, pixelHeight, Transparency.OPAQUE)
contentPane.add(BitmapScreenPanel(image, pixelScaling), BorderLayout.CENTER)
pack()
requestFocusInWindow()
isVisible = true
}
private fun optimalRefreshRate(frame: JFrame): Int {
var rate = frame.graphicsConfiguration.device.displayMode.refreshRate
if(rate==0)
rate = GraphicsEnvironment.getLocalGraphicsEnvironment().screenDevices
.map { it.displayMode.refreshRate }
.firstOrNull { it>0 } ?: 60
return max(30, min(250, rate))
}
fun clear(color: Int) {
val g2d = image.graphics as Graphics2D
g2d.background = Color(color, color, color)
g2d.clearRect(0,0, pixelWidth*pixelScaling, pixelHeight*pixelScaling)
g2d.dispose()
}
fun plot(x: Int, y: Int, color: Int) {
if(x<0 || x>=pixelWidth)
throw IllegalArgumentException("plot x outside of screen: $x")
if(y<0 || y>=pixelHeight)
throw IllegalArgumentException("plot y outside of screen: $y")
image.setRGB(x, y, Color(color, color, color, 255).rgb)
}
fun getpixel(x: Int, y: Int): Int {
if(x<0 || x>=pixelWidth)
throw IllegalArgumentException("getpixel x outside of screen: $x")
if(y<0 || y>=pixelHeight)
throw IllegalArgumentException("getpixel y outside of screen: $y")
return image.getRGB(x, y)
}
}
internal class BitmapScreenPanel(private val drawImage: BufferedImage, pixelScaling: Int) : JPanel() {
init {
val size = Dimension(drawImage.width * pixelScaling, drawImage.height * pixelScaling)
minimumSize = size
maximumSize = size
preferredSize = size
isFocusable = true
isDoubleBuffered = false
requestFocusInWindow()
}
override fun paint(graphics: Graphics) {
val g2d = graphics as Graphics2D
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)
g2d.drawImage(drawImage, 0, 0, size.width, size.height, null)
Toolkit.getDefaultToolkit().sync()
}
}