Is it possible to let compose render to something ...
# compose-desktop
j
Is it possible to let compose render to something else than the high level window abstraction? I was thinking of something more primitive, like a
BufferedImage
. As compose-jb can render to a
JFrame
, shouldn't this theoretically work?
1
i
Next week there will be ComposeScene for that. Until then, you can use TestComposeWindow, but it doesn't support animations/events at the moment.
j
Great! Looking forward for that.
but it doesn't support animations/events at the moment.
does that mean it crashes when using animations - or are animations just not displayed correctly?
i
It means it isn't tested with them 🙂 . Maybe it works with the latest changes, maybe not. If it doesn't work, only the first frame will be rendered.
👍 1
m
I double the request. My use case is to render everything into fixed-size image and then resize and print the image onto the window. It has to be done this way as it is a pixel-perfect game with fixed-size virtual screen. Therefore something like FrameBuffer in OpenGL would be very welcome.
i
Try to pass coroutineContext = Dispatchers.Swing to enable animations
m
Also if I could capture the input events at the top level, rescale the coordinates to match the virtual screen and pass them to the real compose tree I would be very pleased. 🙏
i
Therefore something like FrameBuffer in OpenGL
It can be done via
ComposeScene
. Just create appropriate Skia Surface, obtain Canvas from it, and call
ComposeScene.render(canvas, time)
Skia supports rendering into any graphics context (that it is how we implemented rendering in skiko (1 2))
Also if I could capture the input events at the top level
Yes, passing events in pixels also possible:
Copy code
scene.sendPointerEvent(PointerEventType.Press, Offset(0f, 10f))
After we complete the current rebase to the latest Compose, we will perform a new rebase this or next week which will contain
ComposeScene
🙌 1
fixed-size image and then resize and print the image onto the window
Note that the graphic context created inside Skiko for rendering into the default
ComposeWindow
(it is JFrame) isn't available for external usage, so if you need to draw into texture and use it inside the usual ComposeWindow, it doesn't work. You probably need to create your own graphic context and rasterize the graphic buffer into Bitmap.
m
@Igor Demin Well, because everything would be drawn inside the texture I guess I don't quite need the
ComposeWindow
, once I have the texture it would probably be quite easy to display it natively. Therefore maybe I can avoid creating second skia context, assuming the default one would work.
As long as there aren't any issues with say screen pixel density or alike
i
once I have the texture it would probably be quite easy to display it natively
Yes, if you entirely use your own context for Compose rendering then there is no issue 🙂 . But ComposeScene currently doesn't support some features which is/will be supported by ComposeWindow (Input methods, Accessibility, Pointer icon change). Maybe they aren't so important for a game.
j
Next week there will be ComposeScene for that.
so
ComposeScene
is available now :), and I was asking myself how I can read out the RGB values using it currently I have:
Copy code
val bitmap = Bitmap()
val canvas = Canvas(bitmap)

val scene = ComposeScene()
scene.setContent { TestComposable() }
scene.render(canvas, System.nanoTime())
and to read the RGB values I tried
bitmap.getColor(x, y)
but that always gives me
0
.
i
Skia requires allocating pixels for Bitmap:
Copy code
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.ui.ComposeScene
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import org.jetbrains.skia.Bitmap
import org.jetbrains.skia.Canvas
import org.jetbrains.skia.ColorAlphaType
import org.jetbrains.skia.Image
import org.jetbrains.skia.ImageInfo
import java.io.File

fun main() {
    val bitmap = Bitmap()
    bitmap.allocPixels(ImageInfo.makeN32(500, 500, ColorAlphaType.PREMUL))

    val canvas = Canvas(bitmap)
    val scene = ComposeScene()
    scene.setContent {
        Box(Modifier.size(200.dp, 200.dp).background(Color.Red))
    }
    scene.render(canvas, System.nanoTime())
    File("D:/1.png").writeBytes(Image.makeFromBitmap(bitmap).encodeToData()!!.bytes)
    println(Color(bitmap.getColor(0, 0)).red)
}
j
thank you very much ♥️
I love that with ComposeScene in compose-jb compose can now be used in so many special cases very easily
🚀 2
Is it possible to set the filter quality to
FilterQuality.None
in that context?
i
Yes, just pass
FilterMipmap(FilterMode.NEAREST, MipmapMode.NONE)
when you draw image via
drawImageRect
Alternative is to convert Skia Canvas to Compose Canvas:
skiaCanvas.asComposeCanvas()
, and just use
FilterQuality.None
j
The first screenshot below shows what I am doing, and I want to disable the anti aliasing there, because Minecraft has anti aliasing by itself. The second image shows the effect I want to remove. The code there is basically the following:
Copy code
val bitmap = Bitmap()
if (bitmap.allocN32Pixels(blockWidth * 128, blockHeight * 128, false)) {
    val canvas = Canvas(bitmap)

    val scene = ComposeScene()
    scene.setContent { contenthere }
    scene.render(canvas, System.nanoTime())

    scene.close()
}
Is it possible to disable the effect displayed in the second image in the above code?
i
Unfortunately, the only way to remove antialiasing is to draw an image with a higher resolution. Antialiasing isn't the property of Canvas, it is the property of Paint or Font, which are constructed individually inside each component. Probably this should work:
Copy code
val canvasWithoutAntialias = object : PaintFilterCanvas(canvas, true) {
    override fun onFilter(paint: Paint): Boolean {
        paint.isAntiAlias = false
        return true
    }
}
but it is broken in 1.0.0-beta1 (it worked in 1.0.0-alpha3, you can file a bug in skiko). and probably doesn't affect text (not sure)
Minecraft has anti aliasing by itself
It applies antialiasing to 3D content, Compose content itself is 2D content, Minecraft doesn't know how to apply antialiasing to it. Not sure, but the only possible way to draw a high quality image in any camera angle is to draw Compose content in a higher resolution with enabled Compose antialiasing.
j
but it is broken in 1.0.0-beta1 (it worked in 1.0.0-alpha3, you can file a bug in skiko).
do I have to file a bug to get this fixed or will it probably be fixed sometime in the future?
i
A filed bug helps not to forget about the issue
j
Created one https://github.com/JetBrains/skiko/issues/304 Thank you once again for your help! Even with the anti aliasing issue I can already work quite well with the current result :)
👍 1