Running a Program at a specific frame rate

This can be done by leveraging Presentation Mode with Coroutines. Here’s a working example:

import kotlinx.coroutines.delay
import org.openrndr.PresentationMode
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.olive.oliveProgram
import org.openrndr.launch
import org.openrndr.shape.Circle


fun main() = application {
    configure {
        width = 800
        height = 800
        windowAlwaysOnTop = true
    }

    oliveProgram {
        val w = width * 1.0
        val h = height * 1.0

        window.presentationMode = PresentationMode.MANUAL

        val frameRate = 24L

        var prevTime = seconds
        var deltaTime: Double
        var lastUpdate = seconds

        extend {
            launch {
                delay(1000L / frameRate)
                window.requestDraw()
            }

            drawer.clear(ColorRGBa.BLACK)

            drawer.stroke = ColorRGBa.PINK
            drawer.strokeWeight = 14.0

            for (i in 1..10) {
                val sub = Circle(385.0, h / 2.0, 100.0).contour
                val time = seconds * 0.1
                val phase = (1.0 / 10.0) * i
                drawer.contour(sub.sub(time + phase, phase + time + 0.05))
            }

            // LOGGING FRAME RATE
            deltaTime = seconds - prevTime
            prevTime = seconds

            if (prevTime - lastUpdate > 1.0) {
                println("FPS: ${(1.0 / deltaTime)}")
                lastUpdate = prevTime
            }
        }
    }
}

PS: I haven’t done extensive testing, so if there are any issues please share them.

1 Like

Here’s an improved version which can be also tucked away. Now the delay only takes account of the time it would need to reach the nth frame at N frames per second. In other words, it takes into account the performance of the render loop.

fun Program.frameRate(frameRate: Long) {
    window.presentationMode = PresentationMode.MANUAL

    launch {
        val t = 1000.0 / frameRate // in millis
        val t0 = mod(seconds, t / 1000.0) // in seconds
        val d = (t - t0 * 1000).toLong() // in millis

        if (d > 0L) delay(d)

        window.requestDraw()
    }
}
1 Like

thanks, however this didn’t work for me, I mean it blocks main thread, but in the end it is never precisely frame rate I want. What I ended up doing is PresentationMode.MANUAL with scheduled thread in background requesting redraw.

Could you share your solution? I’m curious to try it out. Did you try the 2nd solution I posted? That one gives me a consistent frame rate.

Sure, this is in essence something I do. define var exe in global scope, then in program

exe?.shudownNow()
val rate = 24
application.presentationMode = PresentationMode.MANUAL
exe = Executors.newSingleThreadScheduledExecutor().apply {
                    scheduleAtFixedRate({
                       application.requestDraw()
                    }, 0, (1_000_000_000 / rate).roundToLong(), TimeUnit.NANOSECONDS)
                }

also I added

ended.listen {
               exe?.shudownNow()
            }

to force all background thread to end.