OPENRNDR 0.3.40 + ORX 0.3.50 released!

Release notes can be found on Github

The OPENRNDR template has been updated to use the latest versions of OPENRNDR and ORX.

Note: we have merged the openrndr-panel project into ORX and it can now be found under orx-panel.

4 Likes

One major improvement in OPENRNDR 0.3.40 is how uncaught exceptions are now handled.

The following program will throw an exception whenever the slider is touched.

fun main() =
    application {
        program {
            val cm = controlManager {
                layout {
                    slider {
                        events.valueChanged.listen {
                            require(false) { "Pretty clear exception messages" }
                        }
                    }
                }
            }
            extend(cm)
        }
    }

Prior to version 0.3.40, whever we would touch the slider we would see a very lengthy wall of text (which turns out to be a dump of the stack trace), that would require a lot of work to decode. First of all the order of the dump is in a way that the root cause is found near the top of the dump, which means we would have to scroll through several pages of text just to find the root cause. So we reversed the order.

We also added coloring to the dump and attempt to highlight the parts of the call stack that are in user code. User code nearest to the root cause now has an extra clear highlight.

The stack trace shows Kotlin classes and functions as JVM classes, those names look like Program01Kt$main$1$1cm$1$2 and are not easily understandable to the untrained user. The stack trace printer in version 0.3.40 attempts to decode the JVM class names to present an easier to read dump.

Here is what the error report and stack looks like:

3 Likes

Here some examples of what you can do with ShapeContour.offset

The first one produces something closer to what you might expect:

TestCurveOffset1.kt (1.5 KB)

Notice how it is calling .offset() with SegmentJoin.BEVEL as an argument. Other options are SegmentJoin.ROUND and SegmentJoin.MITER

By having just one line of code:

extend(Screenshots())

you can press the [space] key to save a screenshot. When doing that the console informs you:

[main] INFO org.openrndr.extensions.Screenshots - [Screenshots] saved to: screenshots/TestCurveOffset1-2020-03-28-13.36.59.png

In this new version the image file name follows the name of the kotlin file that produced it: TestCurveOffset1 which helps a lot figure out which program produced a certain image.

A second, wilder example of using .offset() with ROUND, BEVEL and MITER:

TestCurveOffset2.kt (1.6 KB)

4 Likes

Panel, now known as orx-panel, gained a new control called XYPad, that allows you to control a Vector2 value:

fun main() = application {
    configure {
        width = 400
        height = 400
    }

    program {
        val cm = ControlManager()
        var pad: XYPad? = null

        cm.body = layout(cm) {
            pad = xyPad {
                minX = 0.0
                maxX = width.toDouble()
                minY = 0.0
                maxY = height.toDouble()
                invertY = false
            }
        }

        extend(cm)
        extend {
            drawer.background(ColorRGBa.BLACK)
            drawer.circle(pad!!.value, 50.0)
        }
    }
}

It can also be used in orx-gui using XYParameter:

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

    program {
        val gui = GUI()

        val settings = @Description("Vector parameter!") object {
            @XYParameter("Position", 0.0, 800.0, 0.0, 800.0, 
                                     precision = 2, 
                                     invertY = true, 
                                     showVector = true)
            var position: Vector2 = Vector2(0.0,0.0)
        }

        gui.add(settings)

        extend(gui)
        extend {
            drawer.circle(settings.position, 50.0)
        }
    }
}
1 Like

The Program's keyboard now has a pressedKeys property, a Set<String> which keeps track of the keys currently being held.

Here it is used to move a circle with the WASD or arrow keys:

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

    program {
        var position = drawer.bounds.center
        val speed = 10.0

        extend {
            keyboard.pressedKeys.let {
                if (it.contains("arrow-up") || it.contains("w")) {
                    position = Vector2(position.x, position.y - speed)
                }

                if (it.contains("arrow-down") || it.contains("s")) {
                    position = Vector2(position.x, position.y + speed)
                }

                if (it.contains("arrow-left") || it.contains("a")) {
                    position = Vector2(position.x - speed, position.y)
                }

                if (it.contains("arrow-right") || it.contains("d")) {
                    position = Vector2(position.x + speed, position.y)
                }
            }

            drawer.circle(position, 100.0)
        }
    }
}
1 Like

orx-shapes adds the roundedRectangle() method to Drawer, so you can easily draw rounded rectangles.

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

    program {
        extend {
            drawer.roundedRectangle(width/2.0 - 100.0, height/2.0 - 100.0, 200.0, 200.0, radius = sin(seconds) * 50 + 50)
        }
    }
}

3 Likes

ORX 0.3.50 adds new filters to orx-fx and orx-jumpflood.

To orx-fx the new filters additions are: StretchWaves, PerspectivePlane, DisplaceBlend and FishEye

To orx-jumpflood which is an extra that adds distance transform based functionality the additions are: OuterGlow and InnerGlow

2 Likes

OPENRNDR 0.3.40 adds short-hand functions rgb, rgba and hsv, hsva to make it a bit simpler to define colors.

Before one would write:

val color = ColorRGBa(0.2, 0.3, 0.6)

now one can write:

val color = rgb(0.2, 0.3, 0.6)
2 Likes

With ORX 0.3.50 the orx-compositor extension saw the introduction of 2 new features: mask and use.

  • mask allows defining a mask within a layer, f.ex:
val c = compose {
    layer {
        post(Checkers())
    }
    layer {
        // invertMask = false // <--
        draw {
            drawer.imageFit(image, 0.0, 0.0, w , h, fitMethod = FitMethod.Contain)
        }
        mask {
            drawer.circles(circles)
        }
    }.addTo(gui, "Image")
}

Or inverted via invertMask:

  • use lets you re-use easily the buffer from another layer, f.ex:
val c = compose {
    layer {
        post(Checkers())
    }
    layer {
        val imageLayer = layer {
            draw {
                drawer.imageFit(image, 0.0, 0.0, w , h, fitMethod = FitMethod.Contain)
            }
            mask {
                drawer.circles(circles)
            }
        }.addTo(gui, "Image")
        layer {
            use(imageLayer) // <--
            post(Sepia()) {
                amount = 1.0
            }
            post(BlockRepeat().addTo(gui))
        }.addTo(gui, "Image Copy")
    }
}

3 Likes