Unverified Commit ef876646 authored by Roman Sedaikin's avatar Roman Sedaikin Committed by GitHub

Update SkiaJvmSample. (#288)

parent 4420bbdb
package SkiaJvmSample
import kotlinx.coroutines.*
import org.jetbrains.skia.*
import org.jetbrains.skia.paragraph.FontCollection
import org.jetbrains.skia.paragraph.ParagraphBuilder
import org.jetbrains.skia.paragraph.ParagraphStyle
import org.jetbrains.skia.paragraph.TextStyle
import org.jetbrains.skiko.*
import java.awt.Color
import java.awt.Dimension
import java.awt.Toolkit
import java.awt.event.*
import javax.swing.*
import kotlin.math.cos
import kotlin.math.sin
import java.io.File
import java.nio.file.Files
import javax.imageio.ImageIO
......@@ -25,15 +19,16 @@ fun main() {
}
fun createWindow(title: String, exitOnClose: Boolean) = SwingUtilities.invokeLater {
var mouseX = 0
var mouseY = 0
val window = SkiaWindow()
val skiaLayer = SkiaLayer()
val clocks = ClocksJvm(skiaLayer)
val window = JFrame(title)
window.defaultCloseOperation =
if (exitOnClose) WindowConstants.EXIT_ON_CLOSE else WindowConstants.DISPOSE_ON_CLOSE
window.title = title
skiaLayer.attachTo(window.contentPane)
// Create menu.
val menuBar = JMenuBar()
val fileMenu = JMenu("File")
......@@ -44,7 +39,7 @@ fun createWindow(title: String, exitOnClose: Boolean) = SwingUtilities.invokeLat
miFullscreenState.setAccelerator(ctrlI)
miFullscreenState.addActionListener(object : ActionListener {
override fun actionPerformed(actionEvent: ActionEvent?) {
println("${window.title} is in fullscreen mode: ${window.layer.fullscreen}")
println("${window.title} is in fullscreen mode: ${skiaLayer.fullscreen}")
}
})
......@@ -53,7 +48,7 @@ fun createWindow(title: String, exitOnClose: Boolean) = SwingUtilities.invokeLat
miToggleFullscreen.setAccelerator(ctrlF)
miToggleFullscreen.addActionListener(object : ActionListener {
override fun actionPerformed(actionEvent: ActionEvent?) {
window.layer.fullscreen = !window.layer.fullscreen
skiaLayer.fullscreen = !skiaLayer.fullscreen
}
})
......@@ -64,7 +59,7 @@ fun createWindow(title: String, exitOnClose: Boolean) = SwingUtilities.invokeLat
miTakeScreenshot.setAccelerator(ctrlS)
miTakeScreenshot.addActionListener(object : ActionListener {
override fun actionPerformed(actionEvent: ActionEvent?) {
val screenshot = window.layer.screenshot()!!
val screenshot = skiaLayer.screenshot()!!
GlobalScope.launch(Dispatchers.IO) {
val image = screenshot.toBufferedImage()
ImageIO.write(image, "png", File(defaultScreenshotPath))
......@@ -92,21 +87,16 @@ fun createWindow(title: String, exitOnClose: Boolean) = SwingUtilities.invokeLat
window.setJMenuBar(menuBar)
val state = State()
state.text = title
window.layer.onStateChanged(SkiaLayer.PropertyKind.Renderer) { layer ->
skiaLayer.onStateChanged(SkiaLayer.PropertyKind.Renderer) { layer ->
println("Changed renderer for $layer: new value is ${layer.renderApi}")
}
window.layer.renderer = Renderer(window.layer) {
renderer, w, h, nanoTime -> displayScene(renderer, w, h, nanoTime, mouseX, mouseY, state)
}
skiaLayer.skikoView = GenericSkikoView(skiaLayer, clocks)
window.layer.addMouseMotionListener(object : MouseMotionAdapter() {
skiaLayer.addMouseMotionListener(object : MouseMotionAdapter() {
override fun mouseMoved(event: MouseEvent) {
mouseX = event.x
mouseY = event.y
clocks.xpos = event.x
clocks.ypos = event.y
}
})
......@@ -115,124 +105,16 @@ fun createWindow(title: String, exitOnClose: Boolean) = SwingUtilities.invokeLat
window.setUndecorated(true)
// On Windows we don't set transparent background to avoid event input issues (JDK specific)
if (hostOs != OS.Windows) {
window.background = java.awt.Color(0, 0, 0, 0)
window.background = Color(0, 0, 0, 0)
}
window.layer.transparency = true
skiaLayer.transparency = true
} else {
window.layer.background = java.awt.Color.WHITE
skiaLayer.background = Color.WHITE
}
// MANDATORY: set window preferred size before calling pack()
window.preferredSize = Dimension(800, 600)
window.pack()
window.layer.paint(window.graphics)
skiaLayer.paint(window.graphics)
window.isVisible = true
}
class Renderer(
val layer: SkiaLayer,
val displayScene: (Renderer, Int, Int, Long) -> Unit
): SkiaRenderer {
val typeface = Typeface.makeFromFile("fonts/JetBrainsMono-Regular.ttf")
val font = Font(typeface, 40f)
val paint = Paint().apply {
color = 0xff9BC730L.toInt()
mode = PaintMode.FILL
strokeWidth = 1f
}
var canvas: Canvas? = null
override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
this.canvas = canvas
val contentScale = layer.contentScale
canvas.scale(contentScale, contentScale)
displayScene(this, (width / contentScale).toInt(), (height / contentScale).toInt(), nanoTime)
// Alpha layers test
val rectW = 100f
val rectH = 100f
val left = (width / layer.contentScale - rectW) / 2f
val top = (height / layer.contentScale - rectH) / 2f
val pictureRecorder = PictureRecorder()
val pictureCanvas = pictureRecorder.beginRecording(
Rect.makeLTRB(left, top, left + rectW, top + rectH)
)
pictureCanvas.drawLine(left, top, left + rectW, top + rectH, Paint())
val picture = pictureRecorder.finishRecordingAsPicture()
canvas.drawPicture(picture, null, Paint())
canvas.drawLine(left, top + rectH, left + rectW, top, Paint())
layer.needRedraw()
}
}
class State {
var frame: Int = 0
var text: String = "Hello Skija"
}
private val fontCollection = FontCollection()
.setDefaultFontManager(FontMgr.default)
fun displayScene(renderer: Renderer, width: Int, height: Int, nanoTime: Long, xpos: Int, ypos: Int, state: State) {
val canvas = renderer.canvas!!
val watchFill = Paint().apply { color = 0xFFFFFFFF.toInt() }
val watchStroke = Paint().apply {
color = 0xFF000000.toInt()
mode = PaintMode.STROKE
strokeWidth = 1f
}
val watchStrokeAA = Paint().apply {
color = 0xFF000000.toInt()
mode = PaintMode.STROKE
strokeWidth = 1f
}
val watchFillHover = Paint().apply { color = 0xFFE4FF01.toInt() }
for (x in 0 .. (width - 50) step 50) {
for (y in 20 .. (height - 50) step 50) {
val hover = xpos > x + 0 && xpos < x + 50 && ypos > y + 0 && ypos < y + 50
val fill = if (hover) watchFillHover else watchFill
val stroke = if (x > width / 2) watchStrokeAA else watchStroke
canvas.drawOval(Rect.makeXYWH(x + 5f, y + 5f, 40f, 40f), fill)
canvas.drawOval(Rect.makeXYWH(x + 5f, y + 5f, 40f, 40f), stroke)
var angle = 0f
while (angle < 2f * Math.PI) {
canvas.drawLine(
(x + 25 - 17 * sin(angle)),
(y + 25 + 17 * cos(angle)),
(x + 25 - 20 * sin(angle)),
(y + 25 + 20 * cos(angle)),
stroke
)
angle += (2.0 * Math.PI / 12.0).toFloat()
}
val time = (nanoTime / 1E6) % 60000 +
(x.toFloat() / width * 5000).toLong() +
(y.toFloat() / width * 5000).toLong()
val angle1 = (time.toFloat() / 5000 * 2f * Math.PI).toFloat()
canvas.drawLine(x + 25f, y + 25f,
x + 25f - 15f * sin(angle1),
y + 25f + 15 * cos(angle1),
stroke)
val angle2 = (time / 60000 * 2f * Math.PI).toFloat()
canvas.drawLine(x + 25f, y + 25f,
x + 25f - 10f * sin(angle2),
y + 25f + 10f * cos(angle2),
stroke)
}
}
val text = "${state.text} ${state.frame++}!"
canvas.drawString(text, xpos.toFloat(), ypos.toFloat(), renderer.font, renderer.paint)
val style = ParagraphStyle()
val paragraph = ParagraphBuilder(style, fontCollection)
.pushStyle(TextStyle().setColor(0xFF000000.toInt()))
.addText("Graphics API: ${renderer.layer.renderApi} ✿゚ ${currentSystemTheme}")
.popStyle()
.build()
paragraph.layout(Float.POSITIVE_INFINITY)
paragraph.paint(canvas, 5f, 5f)
}
package SkiaJvmSample
import org.jetbrains.skiko.*
import org.jetbrains.skia.*
import org.jetbrains.skia.paragraph.FontCollection
import org.jetbrains.skia.paragraph.ParagraphBuilder
import org.jetbrains.skia.paragraph.ParagraphStyle
import org.jetbrains.skia.paragraph.TextStyle
import kotlin.math.cos
import kotlin.math.sin
import kotlin.math.PI
class ClocksJvm(private val layer: SkiaLayer): SkikoView {
val typeface = Typeface.makeFromFile("fonts/JetBrainsMono-Regular.ttf")
val font = Font(typeface, 40f)
val paint = Paint().apply {
color = 0xff9BC730L.toInt()
mode = PaintMode.FILL
strokeWidth = 1f
}
private var frame = 0
var xpos = 0
var ypos = 0
private val fontCollection = FontCollection()
.setDefaultFontManager(FontMgr.default)
override fun onRender(canvas: Canvas, width: Int, height: Int, currentTimestamp: Long) {
val watchFill = Paint().apply { color = 0xFFFFFFFF.toInt() }
val watchStroke = Paint().apply {
color = 0xFF000000.toInt()
mode = PaintMode.STROKE
strokeWidth = 1f
}
val watchStrokeAA = Paint().apply {
color = 0xFF000000.toInt()
mode = PaintMode.STROKE
strokeWidth = 1f
}
val watchFillHover = Paint().apply { color = 0xFFE4FF01.toInt() }
for (x in 0 .. (width - 50) step 50) {
for (y in 20 .. (height - 50) step 50) {
val hover = xpos > x + 0 && xpos < x + 50 && ypos > y + 0 && ypos < y + 50
val fill = if (hover) watchFillHover else watchFill
val stroke = if (x > width / 2) watchStrokeAA else watchStroke
canvas.drawOval(Rect.makeXYWH(x + 5f, y + 5f, 40f, 40f), fill)
canvas.drawOval(Rect.makeXYWH(x + 5f, y + 5f, 40f, 40f), stroke)
var angle = 0f
while (angle < 2f * PI) {
canvas.drawLine(
(x + 25 - 17 * sin(angle)),
(y + 25 + 17 * cos(angle)),
(x + 25 - 20 * sin(angle)),
(y + 25 + 20 * cos(angle)),
stroke
)
angle += (2.0 * PI / 12.0).toFloat()
}
val time = (currentTimestamp / 1E6) % 60000 +
(x.toFloat() / width * 5000).toLong() +
(y.toFloat() / width * 5000).toLong()
val angle1 = (time.toFloat() / 5000 * 2f * PI).toFloat()
canvas.drawLine(x + 25f, y + 25f,
x + 25f - 15f * sin(angle1),
y + 25f + 15 * cos(angle1),
stroke)
val angle2 = (time / 60000 * 2f * PI).toFloat()
canvas.drawLine(x + 25f, y + 25f,
x + 25f - 10f * sin(angle2),
y + 25f + 10f * cos(angle2),
stroke)
}
}
val text = "Frames: ${frame++}!"
canvas.drawString(text, xpos.toFloat(), ypos.toFloat(), font, paint)
val style = ParagraphStyle()
val renderInfo = ParagraphBuilder(style, fontCollection)
.pushStyle(TextStyle().setColor(0xFF000000.toInt()))
.addText("Graphics API: ${layer.renderApi} ✿゚ ${currentSystemTheme}")
.popStyle()
.build()
renderInfo.layout(Float.POSITIVE_INFINITY)
renderInfo.paint(canvas, 5f, 5f)
// Alpha layers test
val rectW = 100f
val rectH = 100f
val left = (width / layer.contentScale - rectW) / 2f
val top = (height / layer.contentScale - rectH) / 2f
val pictureRecorder = PictureRecorder()
val pictureCanvas = pictureRecorder.beginRecording(
Rect.makeLTRB(left, top, left + rectW, top + rectH)
)
pictureCanvas.drawLine(left, top, left + rectW, top + rectH, Paint())
val picture = pictureRecorder.finishRecordingAsPicture()
canvas.drawPicture(picture, null, Paint())
canvas.drawLine(left, top + rectH, left + rectW, top, Paint())
}
}
\ No newline at end of file
......@@ -10,10 +10,7 @@ import java.awt.event.ComponentEvent
import java.awt.event.MouseEvent
import java.awt.event.MouseMotionAdapter
import javax.swing.*
private val state = State()
private var mouseX = 0
private var mouseY = 0
import org.jetbrains.skiko.GenericSkikoView
fun Button(
text: String,
......@@ -36,8 +33,6 @@ fun SwingSkia() = SwingUtilities.invokeLater {
window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
window.title = "SwingSkiaWindow"
state.text = window.title
var panel = getSkiaPanel()
window.contentPane.add(
......@@ -87,6 +82,8 @@ fun SwingSkia() = SwingUtilities.invokeLater {
private fun getSkiaPanel(): SkiaPanel {
val panel = SkiaPanel()
val clocks = ClocksJvm(panel.layer)
panel.layer.skikoView = GenericSkikoView(panel.layer, clocks)
val btnPanelOK = JPanel()
btnPanelOK.setLayout(BorderLayout(0, 0))
btnPanelOK.setBackground(Color.white)
......@@ -103,11 +100,10 @@ private fun getSkiaPanel(): SkiaPanel {
panel.repaint()
}
})
panel.layer.renderer = Renderer(panel.layer) { renderer, w, h, nanoTime -> displayScene(renderer, w, h, nanoTime, mouseX, mouseY, state) }
panel.layer.addMouseMotionListener(object : MouseMotionAdapter() {
override fun mouseMoved(event: MouseEvent) {
mouseX = event.x
mouseY = event.y
clocks.xpos = event.x
clocks.ypos = event.y
}
})
return panel
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment