mirror of
https://github.com/irmen/prog8.git
synced 2024-06-17 04:29:44 +00:00
97 lines
3.1 KiB
Kotlin
97 lines
3.1 KiB
Kotlin
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()
|
||
}
|
||
}
|