# OPENRNDR 0.4.0 + ORX 0.4.0 released!

**URL:** <https://openrndr.discourse.group/t/openrndr-0-4-0-orx-0-4-0-released/394>\
**Category:** Announcements\
**Created:** [July 9, 2022, 6:40am UTC](https://openrndr.discourse.group/t/openrndr-0-4-0-orx-0-4-0-released/394 "2022-07-09T06:40:01Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![edwin](https://avatars.discourse-cdn.com/v4/letter/e/73ab20/32.png) [@edwin](https://openrndr.discourse.group/u/edwin)\
**Post date:** [July 9, 2022, 6:40am UTC](https://openrndr.discourse.group/t/openrndr-0-4-0-orx-0-4-0-released/394/1 "2022-07-09T06:40:01Z")

</div>

It took a while, it took a long while.

OPENRNDR 0.4.0 release notes:

> **[Release OPENRNDR 0.4.0 · openrndr/openrndr](https://github.com/openrndr/openrndr/releases/tag/v0.4.0)**
>
> Thanks to @Vechro, @hamoid, @morisil, @jbellis, @goudreinette, @Yvee1, @ricardomatias, @tortila and @sam-tsao for their kind contributions.
> Changes since 0.3.58
> 
> Introduction of multi platform supp...

ORX 0.4.0 release notes:

> **[Release ORX 0.4.0 · openrndr/orx](https://github.com/openrndr/orx/releases/tag/v0.4.0-1)**
>
> Thanks to @hamoid, @Yvee1, @Vechro, @jbellis, @goudreinette, @ylegall, @morisil, @ricardomatias, @i-n-g-o for their kind contributions.
> Changes since 0.3.58
> 
> Introduction of Kotlin multi platform a...

Both releases pack more than a year’s worth of features, improvements and bug fixes. There is quite a bit to unpack here.

I will start listing some of my personal favorites:

- Improved quality of the Bezier polygon (Shape) clipper
- The new `hobbyCurve` feature
- The new `Shape.scatter()` feature

I will update this post with images and code! I also invite anyone to showcase their favorite 0.4.0 features!

---

<div class="post-metadata">

**Author:** ![abe](https://yyz2.discourse-cdn.com/free1/user_avatar/openrndr.discourse.group/abe/32/700_2.png) [@abe](https://openrndr.discourse.group/u/abe)\
**Post date:** [July 9, 2022, 8:54am UTC](https://openrndr.discourse.group/t/openrndr-0-4-0-orx-0-4-0-released/394/2 "2022-07-09T08:54:46Z")

</div>

🎉

# 485 commits!

That’s the number of commits in this release if I counted them correctly.

Big thank you to Edwin for the huge effort and to the RNDR Studio for creating OPENRNDR and making it Free Software 🙂 And thanks to everyone who contributes and uses it. It makes me happy to be part of this growing family.

# ⚡ ApplicationPreload

This is one feature I enjoy in OPENRNDR 0.4.0. It allowed me to add screenshots, video exporting and pressing ESC to quit to hundreds of programs in a project at once, instead of repeating the code in every program.

# ⚡ Video export pause and resume

Adding video exporting by default required to actually not export video until I press a key (to avoid filling my drive with video files) and then be able to _start, pause and resume video exporting_. This is possible thanks to the `screenRecorder.outputToVideo` boolean.

Both features are described in [Enable Screenshots, ScreenRecorder and more in all programs by default](https://openrndr.discourse.group/t/enable-screenshots-screenrecorder-and-more-in-all-programs-by-default/384)

---

<div class="post-metadata">

**Author:** ![abe](https://yyz2.discourse-cdn.com/free1/user_avatar/openrndr.discourse.group/abe/32/700_2.png) [@abe](https://openrndr.discourse.group/u/abe)\
**Post date:** [July 9, 2022, 9:12am UTC](https://openrndr.discourse.group/t/openrndr-0-4-0-orx-0-4-0-released/394/3 "2022-07-09T09:12:38Z")

</div>

## ⚡ `Rectangle.grid()` now with cell dimensions

The `.grid()` method makes it easy to convert a `Rectangle` into a `List<List<Rectangle>>`. Previously one could specify the number of columns and rows by using `Int` arguments, but with ORX 0.4.0 one can also specify the dimensions of the cells by using `Double` values.

This makes it easy to define cell sizes with specific aspect ratios (for example, squares). The number of resulting columns and rows is calculated by the library according to the the requested cell dimensions, gutter values and window size.

```kotlin
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.shapes.grid

fun main() = application {
    configure {
        width = 750
        height = 250
    }

    program {
        extend {
            drawer.clear(ColorRGBa.PINK)
            drawer.fill = ColorRGBa.WHITE
            drawer.stroke = null
            drawer.bounds.grid(
                100.0, 100.0, 10.0, 10.0, 10.0, 10.0
            ).flatten().forEach {
                drawer.rectangle(it)
            }
        }
    }
}

```

 ![2022-07-14-162032_750x250_scrot](https://global.discourse-cdn.com/free1/uploads/openrndr/original/1X/ee6a7e5f2d2988bdab99927269123e4a014cc20d.png)

Another example using this feature ([source code](https://github.com/openrndr/orx/pull/223/files#diff-3b3b6d8071b7797ccd62c5b26269e0de856faee040e5b18d6e27eb3b7252c47c)).

 ![image](https://global.discourse-cdn.com/free1/uploads/openrndr/original/1X/ea155ed2c09df1b84a0ee1e9c8a8863fa00df203.png)

---

<div class="post-metadata">

**Author:** ![abe](https://yyz2.discourse-cdn.com/free1/user_avatar/openrndr.discourse.group/abe/32/700_2.png) [@abe](https://openrndr.discourse.group/u/abe)\
**Post date:** [August 21, 2022, 11:25am UTC](https://openrndr.discourse.group/t/openrndr-0-4-0-orx-0-4-0-released/394/4 "2022-08-21T11:25:51Z")

</div>

Here a quick demo showing how `myShapeContour.hobbyCurve()` converts polygonal contours into smooth contours. The bézier control points are made symmetric thanks to John Hobby’s algorithm.

 ![apps2022.HobbyDemo-2022-08-21-13.14.16](https://global.discourse-cdn.com/free1/uploads/openrndr/original/1X/028e55ad465a8e5c2e523f5a4cf5b1db47e69427.jpeg)

> **imports**
>
> ```kotlin
> import org.openrndr.Fullscreen
> import org.openrndr.application
> import org.openrndr.color.ColorRGBa
> import org.openrndr.extra.noise.Random
> import org.openrndr.extra.shapes.grid
> import org.openrndr.extra.shapes.hobbyCurve
> import org.openrndr.math.Polar
> import org.openrndr.shape.ShapeContour
> 
> ```

```kotlin
fun main() = application {
    configure {
        fullscreen = Fullscreen.CURRENT_DISPLAY_MODE
    }
    program {
        extend {
            Random.seed = "bkwd"
            drawer.clear(ColorRGBa.WHITE)
            drawer.bounds.grid(4, 4, 50.0, 50.0, 50.0, 50.0).flatten().forEachIndexed { i, rect ->
                val count = i + 2
                // points with even angular spacing and randomized radius
                val points = List(count) {
                    rect.center + Polar(it * 360.0 / count, rect.width * Random.double(0.1, 0.4)).cartesian
                }
                val pointyContour = ShapeContour.fromPoints(points, true)
                val smoothContour = pointyContour.hobbyCurve()

                drawer.fill = ColorRGBa.PINK
                drawer.contour(smoothContour)

                drawer.stroke = ColorRGBa.BLACK.opacify(0.4)
                drawer.fill = ColorRGBa.BLACK.opacify(0.2)
                drawer.contour(pointyContour)

                drawer.fill = ColorRGBa.RED
                drawer.circles(points, 5.0)
            }
        }
    }
}

```

---

<div class="post-metadata">

**Author:** ![abe](https://yyz2.discourse-cdn.com/free1/user_avatar/openrndr.discourse.group/abe/32/700_2.png) [@abe](https://openrndr.discourse.group/u/abe)\
**Post date:** [August 23, 2022, 5:47pm UTC](https://openrndr.discourse.group/t/openrndr-0-4-0-orx-0-4-0-released/394/5 "2022-08-23T17:47:58Z")

</div>

Another new feature mentioned by Edwin above is the `Shape.scatter()` function, which allows to fill shapes with 2D points while keeping the specified distance to other points and to the edge of the shape.

 ![image](https://global.discourse-cdn.com/free1/uploads/openrndr/original/1X/3500d99643c83abd838a0a9fd7655d179b176e9c.png)

> **imports**
>
> ```kotlin
> import org.openrndr.application
> import org.openrndr.color.ColorRGBa
> import org.openrndr.extra.noise.scatter
> import org.openrndr.extra.shapes.hobbyCurve
> import org.openrndr.math.Polar
> import org.openrndr.shape.ShapeContour
> 
> ```

```kotlin
fun main() = application {
    program {
        val star = ShapeContour.fromPoints(List(15) {
            Polar(it * 360.0 / 15.0, (it % 3) * 100.0 + 100.0).cartesian
        }, true).hobbyCurve().shape

        val points = star.scatter(placementRadius = 20.0, distanceToEdge = 30.0)

        extend {
            drawer.clear(ColorRGBa.WHITE)
            drawer.translate(drawer.bounds.center)
            drawer.stroke = null

            drawer.fill = ColorRGBa.PINK
            drawer.shape(star)

            drawer.fill = ColorRGBa.WHITE
            drawer.circles(points, 16.0)
        }
    }
}

```
