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

97 lines
3.1 KiB
Kotlin
Raw Normal View History

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
2022-03-23 00:52:01 +00:00
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
2022-04-03 15:33:50 +00:00
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)
2022-03-19 00:08:10 +00:00
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)
}
2022-07-02 22:41:04 +00:00
fun getpixel(x: Int, y: Int): Int {
if(x<0 || x>=pixelWidth)
throw IllegalArgumentException("getpixel x outside of screen: $x")
2022-07-02 22:41:04 +00:00
if(y<0 || y>=pixelHeight)
throw IllegalArgumentException("getpixel y outside of screen: $y")
2022-07-02 22:41:04 +00:00
return image.getRGB(x, y)
}
}
2023-07-30 16:42:45 +00:00
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
2023-04-11 20:28:19 +00:00
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)
g2d.drawImage(drawImage, 0, 0, size.width, size.height, null)
Toolkit.getDefaultToolkit().sync()
}
}