Unverified Commit 1ecd5c8a authored by Nikolay Igotti's avatar Nikolay Igotti Committed by GitHub

More commonized rendering (#258)

parent 41589829
...@@ -53,7 +53,10 @@ kotlin { ...@@ -53,7 +53,10 @@ kotlin {
binaries { binaries {
executable { executable {
entryPoint = "org.jetbrains.skiko.sample.main" entryPoint = "org.jetbrains.skiko.sample.main"
freeCompilerArgs += listOf("-linker-option", "-framework", "-linker-option", "Metal") freeCompilerArgs += listOf(
"-linker-option", "-framework", "-linker-option", "Metal",
"-linker-option", "-framework", "-linker-option", "CoreText",
)
} }
} }
} }
......
// Use `xcodegen` first, then `open ./SkikoSample.xcodeproj` and then Rub // Use `xcodegen` first, then `open ./SkikoSample.xcodeproj` and then Run button in XCode.
package org.jetbrains.skiko.sample package org.jetbrains.skiko.sample
import org.jetbrains.skia.* import org.jetbrains.skia.*
import org.jetbrains.skiko.* import org.jetbrains.skiko.*
import kotlinx.cinterop.*
import platform.UIKit.*
import platform.Foundation.*
fun main(args: Array<String>) { fun main() {
val paint = Paint().apply { color = Color.GREEN } val paint = Paint().apply { color = Color.GREEN }
println("Paint is $paint") println("Paint is $paint")
runSkikoMain() runSkikoMain()
} }
fun runSkikoMain(args: Array<String> = emptyArray()) {
memScoped {
val argc = args.size + 1
val argv = (arrayOf("skikoApp") + args).map { it.cstr.ptr }.toCValues()
autoreleasepool {
UIApplicationMain(argc, argv, null, NSStringFromClass(SkikoAppDelegate))
}
}
}
package org.jetbrains.skiko package org.jetbrains.skiko.sample
import kotlinx.cinterop.* import kotlinx.cinterop.*
import platform.Foundation.* import platform.Foundation.*
...@@ -22,15 +22,4 @@ class SkikoAppDelegate : UIResponder, UIApplicationDelegateProtocol { ...@@ -22,15 +22,4 @@ class SkikoAppDelegate : UIResponder, UIApplicationDelegateProtocol {
window!!.makeKeyAndVisible() window!!.makeKeyAndVisible()
return true return true
} }
}
fun runSkikoMain(args: Array<String> = emptyArray()) {
memScoped {
val argc = args.size + 1
val argv = (arrayOf("skikoApp") + args).map { it.cstr.ptr }.toCValues()
autoreleasepool {
UIApplicationMain(argc, argv, null, NSStringFromClass(SkikoAppDelegate))
}
}
} }
\ No newline at end of file
package org.jetbrains.skiko package org.jetbrains.skiko.sample
import kotlinx.cinterop.* import kotlinx.cinterop.*
import org.jetbrains.skiko.SkiaLayer
import platform.Foundation.* import platform.Foundation.*
import platform.UIKit.* import platform.UIKit.*
import platform.CoreGraphics.CGPointMake
import platform.CoreGraphics.CGRectMake
import platform.Foundation.NSCoder import platform.Foundation.NSCoder
import platform.Foundation.NSSelectorFromString
@ExportObjCClass @ExportObjCClass
class SkikoViewController : UIViewController { class SkikoViewController : UIViewController {
...@@ -17,19 +15,6 @@ class SkikoViewController : UIViewController { ...@@ -17,19 +15,6 @@ class SkikoViewController : UIViewController {
@OverrideInit @OverrideInit
constructor(coder: NSCoder) : super(coder) constructor(coder: NSCoder) : super(coder)
@ObjCOutlet
lateinit var label: UILabel
@ObjCOutlet
lateinit var button: UIButton
var pressed = 0
@ObjCAction
fun buttonPressed() {
label.text = "Hello #${pressed++} from Skiko!"
println("Button pressed")
}
override fun viewDidLoad() { override fun viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
...@@ -38,7 +23,11 @@ class SkikoViewController : UIViewController { ...@@ -38,7 +23,11 @@ class SkikoViewController : UIViewController {
this.size.width to this.size.height this.size.width to this.size.height
} }
val header = UIView().apply { val layer = SkiaLayer(width.toInt(), height.toInt())
layer.initLayer()
layer.view = UIView().apply {
backgroundColor = UIColor.lightGrayColor backgroundColor = UIColor.lightGrayColor
view.addSubview(this) view.addSubview(this)
translatesAutoresizingMaskIntoConstraints = false translatesAutoresizingMaskIntoConstraints = false
...@@ -47,27 +36,5 @@ class SkikoViewController : UIViewController { ...@@ -47,27 +36,5 @@ class SkikoViewController : UIViewController {
widthAnchor.constraintEqualToAnchor(view.widthAnchor).active = true widthAnchor.constraintEqualToAnchor(view.widthAnchor).active = true
heightAnchor.constraintEqualToAnchor(view.heightAnchor).active = true heightAnchor.constraintEqualToAnchor(view.heightAnchor).active = true
} }
label = UILabel().apply {
setFrame(CGRectMake(x = 10.0, y = 10.0, width = width - 100.0, height = 40.0))
center = CGPointMake(x = width / 2, y = 40.0 )
textAlignment = NSTextAlignmentCenter
text = "Press OK"
header.addSubview(this)
}
button = UIButton().apply {
setFrame(CGRectMake(x = 10.0, y = height - 100.0, width = width - 100.0, height = 40.0))
center = CGPointMake(x = width / 2, y = height / 2)
backgroundColor = UIColor.blueColor
setTitle("OK", forState = UIControlStateNormal)
font = UIFont.fontWithName(fontName = font.fontName, size = 28.0)!!
layer.borderWidth = 1.0
layer.borderColor = UIColor.colorWithRed(0x47 / 255.0, 0x43 / 255.0, 0x70 / 255.0, 1.0).CGColor
layer.masksToBounds = true
addTarget(target = this@SkikoViewController, action = NSSelectorFromString("buttonPressed"),
forControlEvents = UIControlEventTouchUpInside)
header.addSubview(this)
}
} }
} }
...@@ -5,42 +5,18 @@ import platform.AppKit.* ...@@ -5,42 +5,18 @@ import platform.AppKit.*
import org.jetbrains.skia.* import org.jetbrains.skia.*
import org.jetbrains.skiko.* import org.jetbrains.skiko.*
import kotlinx.cinterop.* import kotlinx.cinterop.*
import kotlin.math.cos
import kotlin.math.sin
fun main() { fun main() {
// TODO: Remove me! This is to run all cleaners before main() exits.
kotlin.native.internal.Debugging.forceCheckedShutdown = true
NSApplication.sharedApplication() NSApplication.sharedApplication()
createWindow("Skia/Native macos sample") createWindow()
NSApp?.run() NSApp?.run()
} }
fun createWindow(title: String) { fun createWindow() {
val window = SkiaWindow() val layer = SkiaLayer()
layer.renderer = GenericRenderer(layer) {
var angle = 0.0f canvas, w, h, nanoTime -> displayScene(canvas, nanoTime)
window.layer.renderer = Renderer(window.layer) {
renderer, w, h, nanoTime -> displayScene(renderer.canvas!!, nanoTime)
} }
val window = SkiaWindow(layer)
window.nsWindow.orderFrontRegardless() window.nsWindow.orderFrontRegardless()
} }
class Renderer(
val layer: SkiaLayer,
val displayScene: (Renderer, Int, Int, Long) -> Unit
): SkiaRenderer {
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)
layer.needRedraw()
}
}
...@@ -5,7 +5,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile ...@@ -5,7 +5,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.kotlin.utils.keysToMap
plugins { plugins {
kotlin("multiplatform") version "1.5.31" kotlin("multiplatform") version "1.5.31" // "1.6.0-M1"
`maven-publish` `maven-publish`
id("org.gradle.crypto.checksum") version "1.1.0" id("org.gradle.crypto.checksum") version "1.1.0"
id("de.undercouch.download") version "4.1.1" id("de.undercouch.download") version "4.1.1"
...@@ -1113,4 +1113,4 @@ if (hostOs == OS.Linux && hostArch != Arch.X64) { ...@@ -1113,4 +1113,4 @@ if (hostOs == OS.Linux && hostArch != Arch.X64) {
fun Task.projectDirs(vararg relativePaths: String): List<Directory> { fun Task.projectDirs(vararg relativePaths: String): List<Directory> {
val projectDir = project.layout.projectDirectory val projectDir = project.layout.projectDirectory
return relativePaths.map { path -> projectDir.dir(path) } return relativePaths.map { path -> projectDir.dir(path) }
} }
\ No newline at end of file
...@@ -3,15 +3,29 @@ package org.jetbrains.skiko ...@@ -3,15 +3,29 @@ package org.jetbrains.skiko
import org.jetbrains.skia.Canvas import org.jetbrains.skia.Canvas
import org.jetbrains.skia.Picture import org.jetbrains.skia.Picture
interface SkiaRenderer { expect open class SkiaLayer(properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties()) {
fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long)
}
expect open class SkiaLayer {
var renderApi: GraphicsApi var renderApi: GraphicsApi
val contentScale: Float val contentScale: Float
var fullscreen: Boolean var fullscreen: Boolean
var transparency: Boolean var transparency: Boolean
fun needRedraw()
}
interface SkiaRenderer {
fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long)
}
open class GenericRenderer(
val layer: SkiaLayer,
val displayScene: (Canvas, Int, Int, Long) -> Unit
): SkiaRenderer {
override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
val contentScale = layer.contentScale
canvas.scale(contentScale, contentScale)
displayScene(canvas, (width / contentScale).toInt(), (height / contentScale).toInt(), nanoTime)
layer.needRedraw()
}
} }
internal class PictureHolder(val instance: Picture, val width: Int, val height: Int) internal class PictureHolder(val instance: Picture, val width: Int, val height: Int)
package org.jetbrains.skiko package org.jetbrains.skiko
import kotlinx.cinterop.* import kotlinx.cinterop.*
import org.jetbrains.skia.PictureRecorder
import org.jetbrains.skia.Rect
import org.jetbrains.skiko.redrawer.Redrawer
import platform.Foundation.* import platform.Foundation.*
import platform.UIKit.* import platform.UIKit.*
actual open class SkiaLayer { actual open class SkiaLayer actual constructor(
actual var renderApi: GraphicsApi = GraphicsApi.OPENGL properties: SkiaLayerProperties
) {
var width: Int = 0
var height: Int = 0
constructor(width: Int, height: Int) : this(
makeDefaultSkiaLayerProperties()) {
this.width = width
this.height = height
}
actual var renderApi: GraphicsApi
get() = GraphicsApi.METAL
set(value) { throw UnsupportedOperationException() }
actual val contentScale: Float actual val contentScale: Float
get() = 1.0f get() = 1.0f
actual var fullscreen: Boolean actual var fullscreen: Boolean
get() = TODO("Not yet implemented") get() = true
set(value) {} set(value) { throw UnsupportedOperationException() }
actual var transparency: Boolean actual var transparency: Boolean
get() = TODO("Not yet implemented") get() = false
set(value) {} set(value) { throw UnsupportedOperationException() }
}
\ No newline at end of file actual fun needRedraw() {
redrawer?.needRedraw()
}
lateinit var view: UIView
fun initLayer() {
println("SkiaLayer.initLayer")
//redrawer = createNativeRedrawer(this, renderApi, properties)
redrawer?.redrawImmediately()
}
var renderer: SkiaRenderer? = null
private var redrawer: Redrawer? = null
private var picture: PictureHolder? = null
private val pictureRecorder = PictureRecorder()
fun update(nanoTime: Long) {
println("SkiaLayer.update")
val width = 800f
val height = 600f
val pictureWidth = (width * contentScale).coerceAtLeast(0.0F)
val pictureHeight = (height * contentScale).coerceAtLeast(0.0F)
val bounds = Rect.makeWH(pictureWidth, pictureHeight)
val canvas = pictureRecorder.beginRecording(bounds)
renderer?.onRender(canvas, pictureWidth.toInt(), pictureHeight.toInt(), nanoTime)
val picture = pictureRecorder.finishRecordingAsPicture()
this.picture = PictureHolder(picture, pictureWidth.toInt(), pictureHeight.toInt())
}
}
package org.jetbrains.skiko.redrawer
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.SkiaLayerProperties
internal class MetalRedrawer(
private val layer: SkiaLayer,
private val properties: SkiaLayerProperties
) : Redrawer {
override fun dispose() {
TODO()
}
override fun syncSize() {
TODO()
}
override fun needRedraw() {
TODO()
}
override fun redrawImmediately() {
TODO()
}
}
...@@ -2,24 +2,25 @@ package org.jetbrains.skiko.redrawer ...@@ -2,24 +2,25 @@ package org.jetbrains.skiko.redrawer
import org.jetbrains.skiko.SkiaLayer import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.SkiaLayerProperties import org.jetbrains.skiko.SkiaLayerProperties
import kotlin.system.getTimeNanos
internal class OpenGLRedrawer( internal class OpenGLRedrawer(
private val layer: SkiaLayer, private val layer: SkiaLayer,
private val properties: SkiaLayerProperties private val properties: SkiaLayerProperties
) : Redrawer { ) : Redrawer {
override fun dispose() { override fun dispose() {
TODO() println("dispose")
} }
override fun syncSize() { override fun syncSize() {
TODO() println("syncSize")
} }
override fun needRedraw() { override fun needRedraw() {
TODO() println("needRedraw")
} }
override fun redrawImmediately() { override fun redrawImmediately() {
TODO() layer.update(getTimeNanos())
} }
} }
package org.jetbrains.skiko package org.jetbrains.skiko
actual open class SkiaLayer { actual open class SkiaLayer actual constructor(
properties: SkiaLayerProperties
) {
actual var renderApi: GraphicsApi = GraphicsApi.WEBGL actual var renderApi: GraphicsApi = GraphicsApi.WEBGL
actual val contentScale: Float actual val contentScale: Float
get() = 1.0f get() = 1.0f
...@@ -10,4 +12,7 @@ actual open class SkiaLayer { ...@@ -10,4 +12,7 @@ actual open class SkiaLayer {
actual var transparency: Boolean actual var transparency: Boolean
get() = false get() = false
set(value) = throw Exception("Transparency is not supported!") set(value) = throw Exception("Transparency is not supported!")
actual fun needRedraw() {
TODO("unimplemented")
}
} }
...@@ -28,6 +28,7 @@ actual open class SkiaLayer internal constructor( ...@@ -28,6 +28,7 @@ actual open class SkiaLayer internal constructor(
private val properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties(), private val properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties(),
private val renderFactory: RenderFactory private val renderFactory: RenderFactory
) : JPanel() { ) : JPanel() {
companion object { companion object {
init { init {
Library.load() Library.load()
...@@ -43,6 +44,11 @@ actual open class SkiaLayer internal constructor( ...@@ -43,6 +44,11 @@ actual open class SkiaLayer internal constructor(
internal val backedLayer: HardwareLayer internal val backedLayer: HardwareLayer
actual constructor(
properties: SkiaLayerProperties
) : this(null, properties, RenderFactory.Default)
constructor( constructor(
properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties(), properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties(),
externalAccessibleFactory: ((Component) -> Accessible)? = null externalAccessibleFactory: ((Component) -> Accessible)? = null
...@@ -311,7 +317,7 @@ actual open class SkiaLayer internal constructor( ...@@ -311,7 +317,7 @@ actual open class SkiaLayer internal constructor(
/** /**
* Redraw on the next animation Frame (on vsync signal if vsync is enabled). * Redraw on the next animation Frame (on vsync signal if vsync is enabled).
*/ */
fun needRedraw() { actual fun needRedraw() {
check(isEventDispatchThread()) { "Method should be called from AWT event dispatch thread" } check(isEventDispatchThread()) { "Method should be called from AWT event dispatch thread" }
check(!isDisposed) { "SkiaLayer is disposed" } check(!isDisposed) { "SkiaLayer is disposed" }
redrawer?.needRedraw() redrawer?.needRedraw()
......
package org.jetbrains.skiko package org.jetbrains.skiko
actual open class SkiaLayer { actual open class SkiaLayer actual constructor(
properties: SkiaLayerProperties
) {
actual var renderApi: GraphicsApi actual var renderApi: GraphicsApi
get() = TODO("Not yet implemented") get() = TODO("Not yet implemented")
set(value) {} set(value) {}
...@@ -12,4 +14,7 @@ actual open class SkiaLayer { ...@@ -12,4 +14,7 @@ actual open class SkiaLayer {
actual var transparency: Boolean actual var transparency: Boolean
get() = TODO("Not yet implemented") get() = TODO("Not yet implemented")
set(value) {} set(value) {}
actual fun needRedraw() {
TODO("unimplemented")
}
} }
\ No newline at end of file
...@@ -7,8 +7,8 @@ import org.jetbrains.skiko.redrawer.Redrawer ...@@ -7,8 +7,8 @@ import org.jetbrains.skiko.redrawer.Redrawer
import platform.AppKit.NSView import platform.AppKit.NSView
import platform.Foundation.NSMakeRect import platform.Foundation.NSMakeRect
actual open class SkiaLayer( actual open class SkiaLayer actual constructor(
private val properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties() private val properties: SkiaLayerProperties
) { ) {
actual var renderApi: GraphicsApi = GraphicsApi.OPENGL actual var renderApi: GraphicsApi = GraphicsApi.OPENGL
actual val contentScale: Float actual val contentScale: Float
...@@ -50,7 +50,7 @@ actual open class SkiaLayer( ...@@ -50,7 +50,7 @@ actual open class SkiaLayer(
initedCanvas = false initedCanvas = false
} }
fun needRedraw() { actual fun needRedraw() {
redrawer?.needRedraw() redrawer?.needRedraw()
} }
......
...@@ -3,9 +3,7 @@ package org.jetbrains.skiko ...@@ -3,9 +3,7 @@ package org.jetbrains.skiko
import platform.AppKit.* import platform.AppKit.*
import platform.Foundation.* import platform.Foundation.*
open class SkiaWindow( class SkiaWindow(layer: SkiaLayer) {
properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties()
) {
private val windowStyle = private val windowStyle =
NSWindowStyleMaskTitled or NSWindowStyleMaskTitled or
NSWindowStyleMaskMiniaturizable or NSWindowStyleMaskMiniaturizable or
...@@ -17,13 +15,11 @@ open class SkiaWindow( ...@@ -17,13 +15,11 @@ open class SkiaWindow(
// Provide multiple constructors for SkiaWindow? // Provide multiple constructors for SkiaWindow?
// Behave similar to Skiko/JVM? // Behave similar to Skiko/JVM?
val nsWindow = NSWindow( val nsWindow = NSWindow(
contentRect = NSMakeRect(0.0, 0.0, 640.0, 480.0), contentRect = NSMakeRect(0.0, 0.0, 640.0, 480.0),
styleMask = windowStyle, styleMask = windowStyle,
backing = NSBackingStoreBuffered, backing = NSBackingStoreBuffered,
defer = true) defer = true)
val layer = SkiaLayer(properties)
init { init {
nsWindow.contentView!!.addSubview(layer.nsView) nsWindow.contentView!!.addSubview(layer.nsView)
layer.initLayer() layer.initLayer()
......
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