Demos: ensure all use fun main() = application {

- Adjust some demo window sizes.
- Replace Random.double by Double.uniform
- Tweak some demos so screenshots look more interesting
This commit is contained in:
Abe Pazos
2025-01-26 20:57:04 +01:00
parent 1975a820fc
commit c8f7dd52c6
116 changed files with 2889 additions and 2942 deletions

View File

@@ -4,41 +4,39 @@ import org.openrndr.draw.isolated
import org.openrndr.shape.Circle import org.openrndr.shape.Circle
import org.openrndr.shape.Rectangle import org.openrndr.shape.Rectangle
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
}
program { program {
val cs = Rectangle(0.0, 0.0, 200.0, 200.0).contour val cs = Rectangle(0.0, 0.0, 200.0, 200.0).contour
val cc = Circle(100.0, 0.0, 100.0).contour val cc = Circle(100.0, 0.0, 100.0).contour
extend { extend {
drawer.fill = ColorRGBa.GRAY drawer.fill = ColorRGBa.GRAY
drawer.stroke = ColorRGBa.PINK drawer.stroke = ColorRGBa.PINK
drawer.isolated { drawer.isolated {
drawer.contour(cs) drawer.contour(cs)
drawer.translate(300.0, 0.0) drawer.translate(300.0, 0.0)
// this should create a contour similar to the input contour // this should create a contour similar to the input contour
drawer.contour(cs.sampleEquidistant(4)) drawer.contour(cs.sampleEquidistant(4))
drawer.contour(cs.sampleEquidistant(3)) drawer.contour(cs.sampleEquidistant(3))
} }
drawer.isolated { drawer.isolated {
drawer.translate(.0, 400.0) drawer.translate(.0, 400.0)
drawer.contour(cc) drawer.contour(cc)
drawer.translate(300.0, 0.0) drawer.translate(300.0, 0.0)
drawer.contour(cc) drawer.contour(cc)
// this should draw a hexagon // this should draw a hexagon
drawer.contour(cc.sampleEquidistant(6)) drawer.contour(cc.sampleEquidistant(6))
// this should draw a triangle // this should draw a triangle
drawer.contour(cc.sampleEquidistant(3)) drawer.contour(cc.sampleEquidistant(3))
}
} }
} }
} }
} }

View File

@@ -13,42 +13,40 @@ import org.openrndr.shape.Triangle
* a 3x3 grid of triangles and lines. * a 3x3 grid of triangles and lines.
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
}
program { program {
val font = loadFont("demo-data/fonts/IBMPlexMono-Regular.ttf", 20.0) val font = loadFont("demo-data/fonts/IBMPlexMono-Regular.ttf", 20.0)
val pointA = Vector2(0.0, 50.0) val pointA = Vector2(0.0, 50.0)
val pointB = Vector2(50.0, -20.0) val pointB = Vector2(50.0, -20.0)
val pointC = Vector2(-50.0, 0.0) val pointC = Vector2(-50.0, 0.0)
val triangle = Triangle(pointA, pointB, pointC).contour val triangle = Triangle(pointA, pointB, pointC).contour
extend { extend {
drawer.apply { drawer.apply {
fill = ColorRGBa.GRAY fill = ColorRGBa.GRAY
stroke = ColorRGBa.PINK stroke = ColorRGBa.PINK
strokeWeight = 8.0 strokeWeight = 8.0
fontMap = font fontMap = font
LineCap.entries.forEachIndexed { x, cap -> LineCap.entries.forEachIndexed { x, cap ->
lineCap = cap lineCap = cap
LineJoin.entries.forEachIndexed { y, join -> LineJoin.entries.forEachIndexed { y, join ->
lineJoin = join lineJoin = join
val pos = IntVector2(x - 1, y - 1).vector2 * 180.0 val pos = IntVector2(x - 1, y - 1).vector2 * 180.0
isolated { isolated {
translate(bounds.position(0.46, 0.46) + pos) translate(bounds.position(0.46, 0.46) + pos)
text("cap: ${cap.name}", -30.5, 80.5) text("cap: ${cap.name}", -30.5, 80.5)
text("join: ${join.name}", -30.5, 100.5) text("join: ${join.name}", -30.5, 100.5)
contour(triangle) contour(triangle)
lineSegment(pointA - pointC, pointB - pointC) lineSegment(pointA - pointC, pointB - pointC)
}
} }
} }
} }
} }
} }
} }
} }

View File

@@ -2,41 +2,37 @@ import org.openrndr.application
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.extra.composition.composition import org.openrndr.extra.composition.composition
import org.openrndr.extra.composition.drawComposition import org.openrndr.extra.composition.drawComposition
import org.openrndr.extra.svg.saveToFile
import org.openrndr.extra.svg.toSVG import org.openrndr.extra.svg.toSVG
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import java.io.File
fun main() { fun main() = application {
application { program {
program { val composition = drawComposition {
val composition = drawComposition { val layer = group {
val layer = group { fill = ColorRGBa.PINK
fill = ColorRGBa.PINK stroke = ColorRGBa.BLACK
stroke = ColorRGBa.BLACK strokeWeight = 10.0
strokeWeight = 10.0 circle(Vector2(width / 2.0, height / 2.0), 100.0)
circle(Vector2(width / 2.0, height / 2.0), 100.0) circle(Vector2(200.0, 200.0), 50.0)
circle(Vector2(200.0, 200.0), 50.0)
}
// demonstrating how to set custom attributes on the CompositionNode
// these are stored in SVG
//layer.id = "Layer_2"
//layer.attributes["inkscape:label"] = "Layer 1"
//layer.attributes["inkscape:groupmode"] = "layer"
} }
// demonstrating how to set custom attributes on the CompositionNode
// these are stored in SVG
//layer.id = "Layer_2"
//layer.attributes["inkscape:label"] = "Layer 1"
//layer.attributes["inkscape:groupmode"] = "layer"
}
// print the svg to the console // print the svg to the console
println(composition.toSVG()) println(composition.toSVG())
// save svg to a File // save svg to a File
//composition.saveToFile(File("/path/to/design.svg")) //composition.saveToFile(File("/path/to/design.svg"))
extend { extend {
drawer.clear(ColorRGBa.WHITE) drawer.clear(ColorRGBa.WHITE)
// draw the composition to the screen // draw the composition to the screen
drawer.composition(composition) drawer.composition(composition)
}
} }
} }
} }

View File

@@ -4,23 +4,21 @@ import org.openrndr.extra.composition.ClipMode
import org.openrndr.extra.composition.composition import org.openrndr.extra.composition.composition
import org.openrndr.extra.composition.drawComposition import org.openrndr.extra.composition.drawComposition
fun main() { fun main() = application {
application { program {
program { val cd = drawComposition {
val cd = drawComposition { fill = null
fill = null circle(width / 2.0, height / 2.0, 100.0)
circle(width / 2.0, height / 2.0, 100.0)
fill = ColorRGBa.BLACK fill = ColorRGBa.BLACK
clipMode = ClipMode.REVERSE_DIFFERENCE clipMode = ClipMode.REVERSE_DIFFERENCE
circle(width / 2.0 + 50.0, height / 2.0, 100.0) circle(width / 2.0 + 50.0, height / 2.0, 100.0)
} }
extend { extend {
drawer.clear(ColorRGBa.PINK) drawer.clear(ColorRGBa.PINK)
drawer.composition(cd) drawer.composition(cd)
}
} }
} }
} }

View File

@@ -4,25 +4,22 @@ import org.openrndr.extra.composition.ClipMode
import org.openrndr.extra.composition.composition import org.openrndr.extra.composition.composition
import org.openrndr.extra.composition.drawComposition import org.openrndr.extra.composition.drawComposition
fun main() { fun main() = application {
application { program {
program { val cd = drawComposition {
val cd = drawComposition { fill = null
fill = null clipMode = ClipMode.REVERSE_DIFFERENCE
clipMode = ClipMode.REVERSE_DIFFERENCE
circle(width / 2.0-50.0, height / 2.0, 100.0) circle(width / 2.0 - 50.0, height / 2.0, 100.0)
circle(width / 2.0+50.0, height / 2.0, 100.0) circle(width / 2.0 + 50.0, height / 2.0, 100.0)
fill = ColorRGBa.BLACK fill = ColorRGBa.BLACK
circle(width / 2.0, height / 2.0, 100.0) circle(width / 2.0, height / 2.0, 100.0)
} }
extend {
extend { drawer.clear(ColorRGBa.PINK)
drawer.clear(ColorRGBa.PINK) drawer.composition(cd)
drawer.composition(cd)
}
} }
} }
} }

View File

@@ -201,38 +201,36 @@ import org.openrndr.extra.fx.edges.EdgesWork
import org.openrndr.extra.gui.GUI import org.openrndr.extra.gui.GUI
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
fun main() { fun main() = application {
application { configure {
configure { width = 768
width = 768 height = 768
height = 768 }
} program {
program { val w2 = width / 2.0
val w2 = width / 2.0 val h2 = height / 2.0
val h2 = height / 2.0
val c = compose {
draw {
drawer.fill = ColorRGBa.PINK
drawer.circle(width / 2.0, height / 2.0, 10.0)
}
layer {
blend(Add())
val c = compose {
draw { draw {
drawer.fill = ColorRGBa.PINK drawer.circle(width / 2.0, height / 2.0, 100.0)
drawer.circle(width / 2.0, height / 2.0, 10.0)
} }
post(ApproximateGaussianBlur()) {
layer { window = 10
blend(Add()) sigma = Math.cos(seconds * 10.0) * 10.0 + 10.0
draw {
drawer.circle(width / 2.0, height / 2.0, 100.0)
}
post(ApproximateGaussianBlur()) {
window = 10
sigma = Math.cos(seconds * 10.0) * 10.0 + 10.0
}
} }
} }
extend(gui) }
extend { extend(gui)
c.draw(drawer) extend {
} c.draw(drawer)
} }
} }
} }

View File

@@ -6,29 +6,31 @@ import org.openrndr.extra.fx.blur.HashBlurDynamic
import org.openrndr.extra.fx.patterns.Checkers import org.openrndr.extra.fx.patterns.Checkers
import kotlin.math.cos import kotlin.math.cos
fun main() { fun main() = application {
application { configure {
program { width = 720
val c = compose { height = 720
layer { }
val a = aside(colorType = ColorType.FLOAT32) { program {
post(Checkers()) { val c = compose {
this.size = cos(seconds)*0.5 + 0.5 layer {
} val a = aside(colorType = ColorType.FLOAT32) {
} post(Checkers()) {
draw { this.size = cos(seconds + 2.0) * 0.5 + 0.5
drawer.clear(ColorRGBa.GRAY.shade(0.5))
drawer.circle(width/2.0, height/2.0, 100.0)
}
post(HashBlurDynamic(), a) {
time = seconds
radius = 25.0
} }
} }
} draw {
extend { drawer.clear(ColorRGBa.GRAY.shade(0.5))
c.draw(drawer) drawer.circle(width / 2.0, height / 2.0, 100.0)
}
post(HashBlurDynamic(), a) {
time = seconds
radius = 25.0
}
} }
} }
extend {
c.draw(drawer)
}
} }
} }

View File

@@ -17,8 +17,8 @@ import kotlin.random.Random
*/ */
fun main() = application { fun main() = application {
configure { configure {
width = 900 width = 720
height = 900 height = 720
} }
program { program {

View File

@@ -14,10 +14,9 @@ import org.openrndr.shape.Rectangle
* Try changing which layer has multisampling applied and observe the results. * Try changing which layer has multisampling applied and observe the results.
*/ */
fun main() = application { fun main() = application {
System.setProperty("org.openrndr.gl3.debug", "true")
configure { configure {
width = 800 width = 720
height = 800 height = 720
} }
program { program {
@@ -25,17 +24,17 @@ fun main() = application {
layer(multisample = BufferMultisample.SampleCount(4)) { layer(multisample = BufferMultisample.SampleCount(4)) {
draw { draw {
drawer.translate(drawer.bounds.center) drawer.translate(drawer.bounds.center)
drawer.rotate(seconds) drawer.rotate(seconds + 5)
drawer.fill = ColorRGBa.PINK drawer.fill = ColorRGBa.PINK
drawer.rectangle(Rectangle.fromCenter(Vector2.ZERO, 200.0)) drawer.rectangle(Rectangle.fromCenter(Vector2.ZERO, 200.0))
} }
layer { layer() {
blend(Normal()) { blend(Normal()) {
clip = true clip = true
} }
draw { draw {
drawer.rotate(seconds * -2) drawer.rotate((seconds + 5) * -2)
drawer.fill = ColorRGBa.WHITE drawer.fill = ColorRGBa.WHITE
drawer.rectangle(Rectangle.fromCenter(Vector2.ZERO, 200.0)) drawer.rectangle(Rectangle.fromCenter(Vector2.ZERO, 200.0))
} }

View File

@@ -8,33 +8,31 @@ import org.openrndr.extra.gui.GUI
import org.openrndr.extra.parameters.DoubleParameter import org.openrndr.extra.parameters.DoubleParameter
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
fun main() { fun main() = application {
application { program {
program { val gui = GUI()
val gui = GUI()
val state = object { val state = object {
@DoubleParameter("radius", 0.0, 200.0) @DoubleParameter("radius", 0.0, 200.0)
var radius = 100.0 var radius = 100.0
val difference by differencing(::radius) val difference by differencing(::radius)
val differenceHistory by tracking(::difference) val differenceHistory by tracking(::difference)
val differenceMax by aggregating(::differenceHistory) { val differenceMax by aggregating(::differenceHistory) {
it.maxMag() it.maxMag()
}
}
gui.add(state, "state")
extend(gui)
extend {
drawer.circle(drawer.bounds.center, state.radius)
drawer.stroke = ColorRGBa.GREEN
drawer.lineSegment(drawer.bounds.center, drawer.bounds.center + Vector2(state.difference, 0.0))
drawer.translate(0.0, 4.0)
drawer.stroke = ColorRGBa.BLUE
drawer.lineSegment(drawer.bounds.center, drawer.bounds.center + Vector2(state.differenceMax, 0.0))
} }
} }
gui.add(state, "state")
extend(gui)
extend {
drawer.circle(drawer.bounds.center, state.radius)
drawer.stroke = ColorRGBa.GREEN
drawer.lineSegment(drawer.bounds.center, drawer.bounds.center + Vector2(state.difference, 0.0))
drawer.translate(0.0, 4.0)
drawer.stroke = ColorRGBa.BLUE
drawer.lineSegment(drawer.bounds.center, drawer.bounds.center + Vector2(state.differenceMax, 0.0))
}
} }
} }

View File

@@ -12,69 +12,67 @@ import org.openrndr.math.map
* [grid] is used to layout graphs on rows and columns. * [grid] is used to layout graphs on rows and columns.
* *
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 1280
width = 1280 height = 1080
height = 1080 }
} program {
program { val font = loadFont("demo-data/fonts/IBMPlexMono-Regular.ttf", 20.0)
val font = loadFont("demo-data/fonts/IBMPlexMono-Regular.ttf", 20.0)
// grid `columns * rows` must be >= Easing.values().size // grid `columns * rows` must be >= Easing.values().size
val grid = drawer.bounds.grid( val grid = drawer.bounds.grid(
3, 11, 10.0, 10.0, 10.0, 10.0 3, 11, 10.0, 10.0, 10.0, 10.0
).flatten() ).flatten()
// make pairs of (easing function, grid rectangle) // make pairs of (easing function, grid rectangle)
val pairs = Easing.values() zip grid val pairs = Easing.entries.toTypedArray() zip grid
extend { extend {
// ~4 seconds animation loop // ~4 seconds animation loop
val animT = (frameCount % 240) / 60.0 val animT = (frameCount % 240) / 60.0
pairs.forEach { (easing, gridRect) -> pairs.forEach { (easing, gridRect) ->
// background rectangle // background rectangle
drawer.stroke = null drawer.stroke = null
drawer.fill = ColorRGBa.WHITE.opacify(0.3) drawer.fill = ColorRGBa.WHITE.opacify(0.3)
drawer.rectangle(gridRect) drawer.rectangle(gridRect)
// graph // graph
drawer.stroke = ColorRGBa.PINK drawer.stroke = ColorRGBa.PINK
val points = List(40) { val points = List(40) {
val curveT = it / 39.0 val curveT = it / 39.0
gridRect.position( gridRect.position(
curveT, easing.function(curveT, 1.0, -1.0, 1.0) curveT, easing.function(curveT, 1.0, -1.0, 1.0)
)
}
drawer.lineStrip(points)
// label
drawer.fill = ColorRGBa.WHITE
drawer.stroke = null
drawer.fontMap = font
drawer.text(
easing.name,
// text position rounded for crisp font rendering
gridRect.position(0.02, 0.25).toInt().vector2
) )
// animation
drawer.fill = ColorRGBa.WHITE.opacify(
when { // 4-stage opacity
animT > 3.0 -> 0.0 // invisible
animT > 2.0 -> 3.0 - animT // fade-out
animT < 1.0 -> animT // fade-in
else -> 1.0 // visible
}
)
// move only while visible (when loop time in 1.0..2.0)
val t = animT.map(1.0, 2.0, 0.0, 1.0, true)
val xy = Vector2(1.0, easing.function(t, 1.0, -1.0, 1.0))
drawer.circle(gridRect.position(xy), 5.0)
} }
drawer.lineStrip(points)
// label
drawer.fill = ColorRGBa.WHITE
drawer.stroke = null
drawer.fontMap = font
drawer.text(
easing.name,
// text position rounded for crisp font rendering
gridRect.position(0.02, 0.25).toInt().vector2
)
// animation
drawer.fill = ColorRGBa.WHITE.opacify(
when { // 4-stage opacity
animT > 3.0 -> 0.0 // invisible
animT > 2.0 -> 3.0 - animT // fade-out
animT < 1.0 -> animT // fade-in
else -> 1.0 // visible
}
)
// move only while visible (when loop time in 1.0..2.0)
val t = animT.map(1.0, 2.0, 0.0, 1.0, true)
val xy = Vector2(1.0, easing.function(t, 1.0, -1.0, 1.0))
drawer.circle(gridRect.position(xy), 5.0)
} }
} }
} }
} }

View File

@@ -2,34 +2,32 @@ import org.openrndr.application
import org.openrndr.draw.loadFont import org.openrndr.draw.loadFont
import org.openrndr.extra.envelopes.ADSRTracker import org.openrndr.extra.envelopes.ADSRTracker
fun main() { fun main() = application {
application { program {
program { val tracker = ADSRTracker(this)
val tracker = ADSRTracker(this) tracker.attack = 1.0
tracker.attack = 1.0 tracker.decay = 0.2
tracker.decay = 0.2 tracker.sustain = 0.8
tracker.sustain = 0.8 tracker.release = 2.0
tracker.release = 2.0
keyboard.keyDown.listen { keyboard.keyDown.listen {
if (it.name == "t") if (it.name == "t")
tracker.triggerOn() tracker.triggerOn()
}
keyboard.keyUp.listen {
if (it.name == "t")
tracker.triggerOff()
}
extend {
tracker.values().forEach {
drawer.circle(40.0, 40.0, 20.0 * it.value)
drawer.translate(40.0, 0.0)
} }
keyboard.keyUp.listen { drawer.defaults()
if (it.name == "t") drawer.circle(drawer.bounds.center, 100.0 * tracker.value())
tracker.triggerOff()
}
extend {
tracker.values().forEach {
drawer.circle(40.0, 40.0, 20.0 * it.value)
drawer.translate(40.0, 0.0)
}
drawer.defaults()
drawer.circle(drawer.bounds.center, 100.0 * tracker.value())
drawer.fontMap = loadFont("demo-data/fonts/IBMPlexMono-Regular.ttf", 16.0) drawer.fontMap = loadFont("demo-data/fonts/IBMPlexMono-Regular.ttf", 16.0)
drawer.text("press and hold 't'", 20.0, height - 20.0) drawer.text("press and hold 't'", 20.0, height - 20.0)
}
} }
} }
} }

View File

@@ -4,43 +4,41 @@ import org.openrndr.extra.envelopes.ADSRTracker
import org.openrndr.extra.noise.shapes.uniform import org.openrndr.extra.noise.shapes.uniform
import org.openrndr.shape.Rectangle import org.openrndr.shape.Rectangle
fun main() { fun main() = application {
application { program {
program { val tracker = ADSRTracker(this)
val tracker = ADSRTracker(this) tracker.attack = 1.0
tracker.attack = 1.0 tracker.decay = 0.2
tracker.decay = 0.2 tracker.sustain = 0.8
tracker.sustain = 0.8 tracker.release = 2.0
tracker.release = 2.0
keyboard.keyDown.listen { keyboard.keyDown.listen {
if (it.name == "t") { if (it.name == "t") {
val center = drawer.bounds.offsetEdges(-30.0).uniform() val center = drawer.bounds.offsetEdges(-30.0).uniform()
tracker.triggerOn(0) { time, value, position -> tracker.triggerOn(0) { time, value, position ->
drawer.circle(center, value * 100.0) drawer.circle(center, value * 100.0)
}
}
if (it.name == "r") {
val center = drawer.bounds.offsetEdges(-30.0).uniform()
tracker.triggerOn(1) { time, value, position ->
val r = Rectangle.fromCenter(center, width = value * 100.0, height = value * 100.0)
drawer.rectangle(r)
}
} }
} }
keyboard.keyUp.listen { if (it.name == "r") {
if (it.name == "t") val center = drawer.bounds.offsetEdges(-30.0).uniform()
tracker.triggerOff(0) tracker.triggerOn(1) { time, value, position ->
if (it.name == "r") val r = Rectangle.fromCenter(center, width = value * 100.0, height = value * 100.0)
tracker.triggerOff(1) drawer.rectangle(r)
}
extend {
tracker.values().forEach {
it()
} }
drawer.fontMap = loadFont("demo-data/fonts/IBMPlexMono-Regular.ttf", 16.0)
drawer.text("press and hold 't' and/or 'r'", 20.0, height - 20.0)
} }
} }
keyboard.keyUp.listen {
if (it.name == "t")
tracker.triggerOff(0)
if (it.name == "r")
tracker.triggerOff(1)
}
extend {
tracker.values().forEach {
it()
}
drawer.fontMap = loadFont("demo-data/fonts/IBMPlexMono-Regular.ttf", 16.0)
drawer.text("press and hold 't' and/or 'r'", 20.0, height - 20.0)
}
} }
} }

View File

@@ -4,43 +4,41 @@ import org.openrndr.extra.gui.GUI
import org.openrndr.extra.gui.addTo import org.openrndr.extra.gui.addTo
import org.openrndr.extra.parameters.TextParameter import org.openrndr.extra.parameters.TextParameter
fun main() { fun main() = application {
application { program {
program { val gui = GUI()
val gui = GUI() gui.compartmentsCollapsedByDefault = false
gui.compartmentsCollapsedByDefault = false
val settings = object { val settings = object {
@TextParameter("x expression", order = 10) @TextParameter("x expression", order = 10)
var xExpression = "cos(t) * 50.0 + width / 2.0" var xExpression = "cos(t) * 50.0 + width / 2.0"
@TextParameter("y expression", order = 20) @TextParameter("y expression", order = 20)
var yExpression = "sin(t) * 50.0 + height / 2.0" var yExpression = "sin(t) * 50.0 + height / 2.0"
@TextParameter("radius expression", order = 30) @TextParameter("radius expression", order = 30)
var radiusExpression = "cos(t) * 50.0 + 50.0" var radiusExpression = "cos(t) * 50.0 + 50.0"
}.addTo(gui) }.addTo(gui)
extend(gui) extend(gui)
extend { extend {
//gui.visible = mouse.position.x < 200.0 //gui.visible = mouse.position.x < 200.0
val expressionContext = val expressionContext =
mapOf("t" to seconds, "width" to drawer.bounds.width, "height" to drawer.bounds.height) mapOf("t" to seconds, "width" to drawer.bounds.width, "height" to drawer.bounds.height)
fun eval(expression: String): Double = fun eval(expression: String): Double =
try { try {
evaluateExpression(expression, expressionContext) ?: 0.0 evaluateExpression(expression, expressionContext) ?: 0.0
} catch (e: Throwable) { } catch (e: Throwable) {
0.0 0.0
} }
val x = eval(settings.xExpression) val x = eval(settings.xExpression)
val y = eval(settings.yExpression) val y = eval(settings.yExpression)
val radius = eval(settings.radiusExpression) val radius = eval(settings.radiusExpression)
drawer.circle(x, y, radius) drawer.circle(x, y, radius)
}
} }
} }
} }

View File

@@ -8,37 +8,35 @@ import org.openrndr.extra.parameters.TextParameter
* Improved version of DemoExpressionEvaluator01, it uses [watchingExpression1] to automatically convert an expression * Improved version of DemoExpressionEvaluator01, it uses [watchingExpression1] to automatically convert an expression
* string into a function with a parameter "t". * string into a function with a parameter "t".
*/ */
fun main() { fun main() = application {
application { program {
program { val gui = GUI()
val gui = GUI() gui.compartmentsCollapsedByDefault = false
gui.compartmentsCollapsedByDefault = false
// the constants used in our expressions // the constants used in our expressions
val constants = mutableMapOf("width" to drawer.width.toDouble(), "height" to drawer.height.toDouble()) val constants = mutableMapOf("width" to drawer.width.toDouble(), "height" to drawer.height.toDouble())
val settings = object { val settings = object {
@TextParameter("x expression", order = 10) @TextParameter("x expression", order = 10)
var xExpression = "cos(t) * 50.0 + width / 2.0" var xExpression = "cos(t) * 50.0 + width / 2.0"
@TextParameter("y expression", order = 20) @TextParameter("y expression", order = 20)
var yExpression = "sin(t) * 50.0 + height / 2.0" var yExpression = "sin(t) * 50.0 + height / 2.0"
@TextParameter("radius expression", order = 30) @TextParameter("radius expression", order = 30)
var radiusExpression = "cos(t) * 50.0 + 50.0" var radiusExpression = "cos(t) * 50.0 + 50.0"
}.addTo(gui) }.addTo(gui)
val xFunction by watchingExpression1(settings::xExpression, "t", constants) val xFunction by watchingExpression1(settings::xExpression, "t", constants)
val yFunction by watchingExpression1(settings::yExpression, "t", constants) val yFunction by watchingExpression1(settings::yExpression, "t", constants)
val radiusFunction by watchingExpression1(settings::radiusExpression, "t", constants) val radiusFunction by watchingExpression1(settings::radiusExpression, "t", constants)
extend(gui) extend(gui)
extend { extend {
val x = xFunction(seconds) val x = xFunction(seconds)
val y = yFunction(seconds) val y = yFunction(seconds)
val radius = radiusFunction(seconds) val radius = radiusFunction(seconds)
drawer.circle(x, y, radius) drawer.circle(x, y, radius)
}
} }
} }
} }

View File

@@ -118,26 +118,25 @@ Drawing FCurves is useful for debugging, but their typical use is for animation.
The FCurve sampler allows us to query values for the given time value like this: The FCurve sampler allows us to query values for the given time value like this:
```kotlin ```kotlin
fun main() { fun main() = application {
application { program {
program { val xCurve = fcurve(
val xCurve = fcurve( """
""" M320 H0.4
M320 H0.4 S2,0, 2,320
S2,0, 2,320 S2,0, 2,320
S2,0, 2,320 S2,0, 2,320
S2,0, 2,320 S2,0, 2,320
S2,0, 2,320 T0.6,320
T0.6,320 """
""".trimIndent() )
).sampler() // <-- val xCurveSampler = xCurve.sampler()
extend { extend {
drawer.circle( drawer.circle(
xCurve(seconds % 9.0), xCurveSampler(seconds % 9.0),
height * 0.5, 240.0,
20.0 20.0
) )
}
} }
} }
} }
@@ -194,6 +193,7 @@ For example `(M0 (h1 m1)[3])[2]` expands to `M0 h1 m1 h1 m1 h1 m1 M0 h1 m1 h1 m1
# References # References
* https://x.com/ruby0x1/status/1258252352672247814 * https://x.com/ruby0x1/status/1258252352672247814
* https://blender.stackexchange.com/questions/52403/what-is-the-mathematical-basis-for-f-curves/52468#52468 * https://blender.stackexchange.com/questions/52403/what-is-the-mathematical-basis-for-f-curves/52468#52468
* https://pomax.github.io/bezierinfo/#yforx * https://pomax.github.io/bezierinfo/#yforx
@@ -210,6 +210,11 @@ For example `(M0 (h1 m1)[3])[2]` expands to `M0 h1 m1 h1 m1 h1 m1 M0 h1 m1 h1 m1
![DemoFCurve02Kt](https://raw.githubusercontent.com/openrndr/orx/media/orx-fcurve/images/DemoFCurve02Kt.png) ![DemoFCurve02Kt](https://raw.githubusercontent.com/openrndr/orx/media/orx-fcurve/images/DemoFCurve02Kt.png)
### DemoFCurve03
[source code](src/jvmDemo/kotlin/DemoFCurve03.kt)
![DemoFCurve03Kt](https://raw.githubusercontent.com/openrndr/orx/media/orx-fcurve/images/DemoFCurve03Kt.png)
### DemoFCurveSheet01 ### DemoFCurveSheet01
[source code](src/jvmDemo/kotlin/DemoFCurveSheet01.kt) [source code](src/jvmDemo/kotlin/DemoFCurveSheet01.kt)

View File

@@ -1,19 +1,17 @@
import org.openrndr.application import org.openrndr.application
import org.openrndr.extra.fcurve.fcurve import org.openrndr.extra.fcurve.fcurve
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { val xpos = fcurve("M0 Q4,360,5,720").sampler()
val xpos = fcurve("M0 Q4,360,5,720").sampler() val ypos = fcurve("M360 h5").sampler()
val ypos = fcurve("M360 h5").sampler()
extend { extend {
drawer.circle(xpos(seconds.mod(5.0)), ypos(seconds.mod(5.0)), 100.0) drawer.circle(xpos(seconds.mod(5.0)), ypos(seconds.mod(5.0)), 100.0)
}
} }
} }
} }

View File

@@ -3,26 +3,24 @@ import org.openrndr.color.ColorRGBa
import org.openrndr.extra.fcurve.fcurve import org.openrndr.extra.fcurve.fcurve
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { val xposCurve = fcurve("M0 Q4,360,5,720")
val xposCurve = fcurve("M0 Q4,360,5,720") val xpos = xposCurve.sampler()
val xpos = xposCurve.sampler() val yposCurve = fcurve("M360 h5")
val yposCurve = fcurve("M360 h5") val ypos = yposCurve.sampler()
val ypos = yposCurve.sampler()
extend { extend {
drawer.circle(xpos(seconds.mod(5.0)), ypos(seconds.mod(5.0)), 100.0) drawer.circle(xpos(seconds.mod(5.0)), ypos(seconds.mod(5.0)), 100.0)
drawer.stroke = ColorRGBa.PINK drawer.stroke = ColorRGBa.PINK
drawer.contours(xposCurve.contours(Vector2(720.0 / 5.0, -1.0), Vector2(0.0, height * 1.0))) drawer.contours(xposCurve.contours(Vector2(720.0 / 5.0, -1.0), Vector2(0.0, height * 1.0)))
drawer.contours(yposCurve.contours(Vector2(720.0 / 5.0, -1.0), Vector2(0.0, height * 1.0))) drawer.contours(yposCurve.contours(Vector2(720.0 / 5.0, -1.0), Vector2(0.0, height * 1.0)))
drawer.translate(seconds.mod(5.0)*(720.0/5.0), 0.0) drawer.translate(seconds.mod(5.0) * (720.0 / 5.0), 0.0)
drawer.lineSegment(0.0, 0.0, 0.0, 720.0) drawer.lineSegment(0.0, 0.0, 0.0, 720.0)
}
} }
} }
} }

View File

@@ -3,26 +3,26 @@ import org.openrndr.extra.fcurve.MultiFCurve
import org.openrndr.extra.fcurve.fcurve import org.openrndr.extra.fcurve.fcurve
import org.openrndr.extra.fcurve.vector2 import org.openrndr.extra.fcurve.vector2
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { class XYAnimation : MultiFCurve(
class XYAnimation : MultiFCurve(mapOf( mapOf(
"x" to fcurve("M0 Q4,360,5,720"), "x" to fcurve("M0 Q4,360,5,720"),
"y" to fcurve("M360 h5") "y" to fcurve("M360 h5")
)) { )
val position = vector2("x", "y") ) {
} val position = vector2("x", "y")
}
val xyAnimation = XYAnimation() val xyAnimation = XYAnimation()
val position = xyAnimation.position.sampler() val position = xyAnimation.position.sampler()
extend { extend {
drawer.circle(position(seconds.mod(5.0)), 100.0) drawer.circle(position(seconds.mod(5.0)), 100.0)
}
} }
} }
} }

View File

@@ -9,148 +9,148 @@ import org.openrndr.math.Vector2
import org.openrndr.math.smoothstep import org.openrndr.math.smoothstep
import org.openrndr.math.transforms.buildTransform import org.openrndr.math.transforms.buildTransform
import org.openrndr.shape.LineSegment import org.openrndr.shape.LineSegment
import kotlin.math.* import kotlin.math.max
import kotlin.random.Random import kotlin.random.Random
/** /**
* Demonstration of using FFT to filter a two-dimensional shape. Mouse xy-position is mapped * Demonstration of using FFT to filter a two-dimensional shape. Mouse xy-position is mapped
* to lowpass and highpass settings of the filter. * to lowpass and highpass settings of the filter.
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
program {
val fftSize = 512
val fft = FFT(fftSize)
fun List<Vector2>.toFloatArrays(x: FloatArray, y: FloatArray) {
for ((index, segment) in this.withIndex()) {
x[index] = segment.x.toFloat()
y[index] = segment.y.toFloat()
}
} }
program {
val fftSize = 512 fun vectorsFromFloatArrays(x: FloatArray, y: FloatArray): List<Vector2> {
val fft = FFT(fftSize) val n = x.size
fun List<Vector2>.toFloatArrays(x: FloatArray, y: FloatArray) { val result = mutableListOf<Vector2>()
for ((index, segment) in this.withIndex()) { for (i in 0 until n) {
x[index] = segment.x.toFloat() result.add(Vector2(x[i].toDouble(), y[i].toDouble()))
y[index] = segment.y.toFloat() }
} return result
}
fun lp(t: Double, c: Double): Double {
return smoothstep(c, c - 0.1, t)
}
fun hp(t: Double, c: Double): Double {
return smoothstep(c, c + 0.1, t)
}
val c = hobbyCurve(
drawer.bounds.scatter(30.0, distanceToEdge = 100.0, random = Random(3)).filter {
Random.nextBoolean()
},
true
).transform(buildTransform { translate(-drawer.bounds.center) })
val x = FloatArray(fftSize)
val y = FloatArray(fftSize)
val xFiltered = FloatArray(fftSize)
val yFiltered = FloatArray(fftSize)
extend {
c.equidistantPositions(fftSize).toFloatArrays(x, y)
// process x-component
fft.forward(x)
drawer.stroke = ColorRGBa.GRAY.shade(0.5)
drawer.lineSegments((0 until fft.size / 2).map {
LineSegment(
it.toDouble() * 2.0 + 0.5,
height * 0.5,
it.toDouble() * 2.0 + 0.5,
height * 0.5 - fft.magnitude(it) / 200.0,
)
})
val xpower = fft.magnitudeSum()
val hpc = mouse.position.x / width
val lpc = mouse.position.y / height
for (i in 1..fftSize / 2) {
val t = i.toDouble() / (fftSize / 2 - 1)
val f = if (hpc <= lpc) lp(t, lpc) * hp(t, hpc) else max(lp(t, lpc), hp(t, hpc))
fft.scaleBand(i, f.toFloat())
}
val xfpower = fft.magnitudeSum().coerceAtLeast(1.0)
fft.scaleAll((xpower / xfpower).toFloat())
drawer.stroke = ColorRGBa.PINK.opacify(0.8)
drawer.lineSegments((0 until fft.size / 2).map {
LineSegment(
it.toDouble() * 2.0 + 0.5,
height * 0.5,
it.toDouble() * 2.0 + 0.5,
height * 0.5 - fft.magnitude(it) / 200.0
)
})
fft.inverse(xFiltered)
// process y-component
fft.forward(y)
val ypower = fft.magnitudeSum()
drawer.stroke = ColorRGBa.GRAY.shade(0.5)
drawer.lineSegments((0 until fft.size / 2).map {
LineSegment(
it * 2.0 + 0.5,
height * 0.5,
it * 2.0 + 0.5,
height * 0.5 + fft.magnitude(it) / 200.0,
)
})
for (i in 1..fftSize / 2) {
val t = i.toDouble() / (fftSize / 2 - 1)
val f = if (hpc <= lpc) lp(t, lpc) * hp(t, hpc) else max(lp(t, lpc), hp(t, hpc))
fft.scaleBand(i, f.toFloat())
} }
fun vectorsFromFloatArrays(x: FloatArray, y: FloatArray): List<Vector2> { val yfpower = fft.magnitudeSum().coerceAtLeast(1.0)
val n = x.size
val result = mutableListOf<Vector2>()
for (i in 0 until n) {
result.add(Vector2(x[i].toDouble(), y[i].toDouble()))
}
return result
}
fun lp(t: Double, c: Double): Double { fft.scaleAll((ypower / yfpower).toFloat())
return smoothstep(c, c - 0.1, t) drawer.stroke = ColorRGBa.PINK.opacify(0.7)
} drawer.lineSegments((0 until fft.size / 2).map {
LineSegment(
it * 2.0 + 0.5,
height * 0.5,
it * 2.0 + 0.5,
height * 0.5 + fft.magnitude(it) / 200.0,
)
})
fft.inverse(yFiltered)
fun hp(t: Double, c: Double): Double { val cr = vectorsFromFloatArrays(xFiltered, yFiltered).catmullRom(closed = true).toContour()
return smoothstep(c, c + 0.1, t) //val cr = ShapeContour.fromPoints(vectorsFromFloatArrays(xr, yr), closed=true)
}
val c = hobbyCurve( val recenteredShape = cr.transform(buildTransform {
drawer.bounds.scatter(40.0, distanceToEdge = 100.0, random = Random(0)), translate(drawer.bounds.center)
true })
).transform(buildTransform { translate(-drawer.bounds.center) }) drawer.fill = null
drawer.stroke = ColorRGBa.WHITE
val x = FloatArray(fftSize) drawer.lineSegment(mouse.position.x / width * 512, 0.0, mouse.position.x / width * 512, height * 1.0)
val y = FloatArray(fftSize) drawer.lineSegment(mouse.position.y / height * 512, 0.0, mouse.position.y / height * 512, height * 1.0)
val xFiltered = FloatArray(fftSize) drawer.contour(recenteredShape)
val yFiltered = FloatArray(fftSize)
extend {
c.equidistantPositions(fftSize).toFloatArrays(x, y)
// process x-component
fft.forward(x)
drawer.stroke = ColorRGBa.GRAY.shade(0.5)
drawer.lineSegments((0 until fft.size / 2).map {
LineSegment(
it.toDouble() * 2.0 + 0.5,
height * 0.5,
it.toDouble() * 2.0 + 0.5,
height * 0.5 - fft.magnitude(it) / 200.0,
)
})
val xpower = fft.magnitudeSum()
val lpc = mouse.position.x / width
val hpc = mouse.position.y / height
for (i in 1..fftSize / 2) {
val t = i.toDouble() / (fftSize / 2 - 1)
val f = if (hpc <= lpc) lp(t, lpc) * hp(t, hpc) else max(lp(t, lpc), hp(t, hpc))
fft.scaleBand(i, f.toFloat())
}
val xfpower = fft.magnitudeSum().coerceAtLeast(1.0)
fft.scaleAll((xpower / xfpower).toFloat())
drawer.stroke = ColorRGBa.PINK.opacify(0.8)
drawer.lineSegments((0 until fft.size / 2).map {
LineSegment(
it.toDouble() * 2.0 + 0.5,
height * 0.5,
it.toDouble() * 2.0 + 0.5,
height * 0.5 - fft.magnitude(it) / 200.0
)
})
fft.inverse(xFiltered)
// process y-component
fft.forward(y)
val ypower = fft.magnitudeSum()
drawer.stroke = ColorRGBa.GRAY.shade(0.5)
drawer.lineSegments((0 until fft.size / 2).map {
LineSegment(
it.toDouble() * 2.0 + 0.5,
height * 0.5,
it.toDouble() * 2.0 + 0.5,
height * 0.5 + fft.magnitude(it) / 200.0,
)
})
for (i in 1..fftSize / 2) {
val t = i.toDouble() / (fftSize / 2 - 1)
val f = if (hpc <= lpc) lp(t, lpc) * hp(t, hpc) else max(lp(t, lpc), hp(t, hpc))
fft.scaleBand(i, f.toFloat())
}
val yfpower = fft.magnitudeSum().coerceAtLeast(1.0)
fft.scaleAll((ypower / yfpower).toFloat())
drawer.stroke = ColorRGBa.PINK.opacify(0.7)
drawer.lineSegments((0 until fft.size / 2).map {
LineSegment(
it.toDouble() * 2.0 + 0.5,
height * 0.5,
it.toDouble() * 2.0 + 0.5,
height * 0.5 + fft.magnitude(it) / 200.0,
)
})
fft.inverse(yFiltered)
val cr = vectorsFromFloatArrays(xFiltered, yFiltered).catmullRom(closed = true).toContour()
//val cr = ShapeContour.fromPoints(vectorsFromFloatArrays(xr, yr), closed=true)
val recenteredShape = cr.transform(buildTransform {
translate(drawer.bounds.center)
})
drawer.fill = null
drawer.stroke = ColorRGBa.WHITE
drawer.lineSegment(mouse.position.x / width * 512, 0.0, mouse.position.x / width * 512, height * 1.0)
drawer.lineSegment(mouse.position.y / height * 512, 0.0, mouse.position.y / height * 512, height * 1.0)
drawer.contour(recenteredShape)
}
} }
} }
} }

View File

@@ -1,29 +1,28 @@
import org.openrndr.application import org.openrndr.application
import org.openrndr.extra.fx.blend.* import org.openrndr.extra.fx.blend.*
fun main() {
application { fun main() = application {
program { program {
val add = Add() val add = Add()
val colorBurn = ColorBurn() val colorBurn = ColorBurn()
val colorDodge = ColorDodge() val colorDodge = ColorDodge()
val darken = Darken() val darken = Darken()
val destIn = DestinationIn() val destIn = DestinationIn()
val destOut = DestinationOut() val destOut = DestinationOut()
val destAtop = DestinationAtop() val destAtop = DestinationAtop()
val hardLight = HardLight() val hardLight = HardLight()
val lighten = Lighten() val lighten = Lighten()
val multiply = Multiply() val multiply = Multiply()
val multiplyContrast = MultiplyContrast() val multiplyContrast = MultiplyContrast()
val normal = Normal() val normal = Normal()
val overlay = Overlay() val overlay = Overlay()
val passthrough = Passthrough() val passthrough = Passthrough()
val screen = Screen() val screen = Screen()
val sourceIn = SourceIn() val sourceIn = SourceIn()
val sourceAtop = SourceAtop() val sourceAtop = SourceAtop()
val sourceOut = SourceOut() val sourceOut = SourceOut()
val subtract = Subtract() val subtract = Subtract()
val xor = Xor() val xor = Xor()
application.exit() application.exit()
}
} }
} }

View File

@@ -5,106 +5,117 @@ import org.openrndr.extra.fx.blur.*
import org.openrndr.math.Polar import org.openrndr.math.Polar
import kotlin.math.sin import kotlin.math.sin
fun main() { fun main() = application {
application { program {
program { // In this buffer we will draw some simple shapes
// In this buffer we will draw some simple shapes val dry = renderTarget(width / 3, height / 3) {
val dry = renderTarget(width / 3, height / 3) { colorBuffer()
colorBuffer() }
// The list of effects to demo
val effects = listOf(
BoxBlur(),
ApproximateGaussianBlur(),
HashBlur(),
GaussianBlur(),
GaussianBloom(),
FrameBlur(),
ZoomBlur(),
LaserBlur()
)
// On this buffer we will draw the dry buffer with an effect applied
val wet = colorBuffer(dry.width, dry.height)
val font = loadFont("demo-data/fonts/IBMPlexMono-Regular.ttf", 16.0)
extend {
// Draw two moving circles
drawer.isolatedWithTarget(dry) {
clear(ColorRGBa.BLACK)
fill = null
stroke = ColorRGBa.PINK
strokeWeight = 25.0
circle(
bounds.center +
Polar(seconds * 50.0, 100.0).cartesian,
200.0 + 50.0 * sin(seconds * 2.0)
)
fill = ColorRGBa.PINK
stroke = null
circle(
bounds.center +
Polar(seconds * 50.0 + 60, 100.0).cartesian,
100.0 + 20.0 * sin(seconds * 2.0 + 1)
)
} }
// The list of effects to demo effects.forEachIndexed { i, blur ->
val effects = listOf( // Adjust the effect settings.
BoxBlur(), // All the values could be animated.
ApproximateGaussianBlur(), when (blur) {
HashBlur(), is BoxBlur -> {
GaussianBlur(), blur.window = 30
GaussianBloom(), }
FrameBlur(),
ZoomBlur(),
LaserBlur()
)
// On this buffer we will draw the dry buffer with an effect applied is ApproximateGaussianBlur -> {
val wet = colorBuffer(dry.width, dry.height) blur.window = 25
blur.sigma = 15.0
}
val font = loadFont("demo-data/fonts/IBMPlexMono-Regular.ttf", 16.0) is HashBlur -> {
blur.samples = 50
blur.radius = 5.0
blur.time = seconds
}
extend { is GaussianBlur -> {
// Draw two moving circles blur.window = 25
drawer.isolatedWithTarget(dry) { blur.sigma = 15.0
clear(ColorRGBa.BLACK) }
fill = null is GaussianBloom -> {
stroke = ColorRGBa.PINK blur.window = 5
strokeWeight = 25.0 blur.sigma = 3.0
circle(bounds.center + blur.gain = 3.0
Polar(seconds * 50.0, 100.0).cartesian, blur.noiseSeed = seconds
200.0 + 50.0 * sin(seconds * 2.0)) }
fill = ColorRGBa.PINK is FrameBlur -> {
stroke = null blur.blend = 0.05
circle(bounds.center + }
Polar(seconds * 50.0 + 60, 100.0).cartesian,
100.0 + 20.0 * sin(seconds * 2.0 + 1)) is ZoomBlur -> {
blur.center = Polar(seconds * 77.0, 0.5)
.cartesian
blur.strength = 0.8
}
is LaserBlur -> {
blur.center = Polar(seconds * 77.0, 0.5)
.cartesian
blur.aberration = 0.03
blur.radius = 0.5
}
} }
effects.forEachIndexed { i, blur -> // Apply the effect on `dry` writing the result to `wet`
// Adjust the effect settings. blur.apply(dry.colorBuffer(0), wet)
// All the values could be animated.
when (blur) {
is BoxBlur -> {
blur.window = 30
}
is ApproximateGaussianBlur -> {
blur.window = 25
blur.sigma = 15.0
}
is HashBlur -> {
blur.samples = 50
blur.radius = 5.0
blur.time = seconds
}
is GaussianBlur -> {
blur.window = 25
blur.sigma = 15.0
}
is GaussianBloom -> {
blur.window = 5
blur.sigma = 3.0
blur.gain = 3.0
blur.noiseSeed = seconds
}
is FrameBlur -> {
blur.blend = 0.05
}
is ZoomBlur -> {
blur.center = Polar(seconds * 77.0, 0.5)
.cartesian
blur.strength = 0.8
}
is LaserBlur -> {
blur.center = Polar(seconds * 77.0, 0.5)
.cartesian
blur.aberration = 0.03
blur.radius = 0.5
} // Draw `wet` and write the effect name on top
} drawer.isolated {
translate(
// Apply the effect on `dry` writing the result to `wet` (i % 3) * width / 3.0,
blur.apply(dry.colorBuffer(0), wet) (i / 3) * height / 3.0
)
// Draw `wet` and write the effect name on top image(wet)
drawer.isolated { fontMap = font
translate((i % 3) * width / 3.0, text(blur.javaClass.simpleName, 20.0, 30.0)
(i / 3) * height / 3.0)
image(wet)
fontMap = font
text(blur.javaClass.simpleName, 20.0, 30.0)
}
} }
} }
} }
} }
} }

View File

@@ -3,19 +3,17 @@ import org.openrndr.draw.createEquivalent
import org.openrndr.draw.loadImage import org.openrndr.draw.loadImage
import org.openrndr.extra.fx.color.Duotone import org.openrndr.extra.fx.color.Duotone
fun main() { fun main() = application {
application { program {
program {
val image = loadImage("demo-data/images/image-001.png") val image = loadImage("demo-data/images/image-001.png")
val filteredImage = image.createEquivalent() val filteredImage = image.createEquivalent()
val duotone = Duotone() val duotone = Duotone()
extend { extend {
duotone.labInterpolation = seconds.mod(2.0) < 1.0 duotone.labInterpolation = seconds.mod(2.0) < 1.0
duotone.apply(image, filteredImage) duotone.apply(image, filteredImage)
drawer.image(filteredImage) drawer.image(filteredImage)
}
} }
} }
} }

View File

@@ -3,18 +3,16 @@ import org.openrndr.draw.createEquivalent
import org.openrndr.draw.loadImage import org.openrndr.draw.loadImage
import org.openrndr.extra.fx.color.Posterize import org.openrndr.extra.fx.color.Posterize
fun main() { fun main() = application {
application { program {
program { val image = loadImage("demo-data/images/image-001.png")
val image = loadImage("demo-data/images/image-001.png") val filteredImage = image.createEquivalent()
val filteredImage = image.createEquivalent() val posterize = Posterize()
val posterize = Posterize()
extend { extend {
posterize.levels = 2 posterize.levels = 2
posterize.apply(image, filteredImage) posterize.apply(image, filteredImage)
drawer.image(filteredImage) drawer.image(filteredImage)
}
} }
} }
} }

View File

@@ -5,17 +5,15 @@ import org.openrndr.draw.loadImage
import org.openrndr.extra.fx.colormap.GrayscaleColormap import org.openrndr.extra.fx.colormap.GrayscaleColormap
import kotlin.math.sin import kotlin.math.sin
fun main() { fun main() = application {
application { program {
program { val colormap = GrayscaleColormap()
val colormap = GrayscaleColormap() val image = loadImage("demo-data/images/image-001.png")
val image = loadImage("demo-data/images/image-001.png") val colormapImage = image.createEquivalent(type = ColorType.FLOAT32)
val colormapImage = image.createEquivalent(type = ColorType.FLOAT32) extend {
extend { colormap.curve = 1.0 + sin(seconds) * .5
colormap.curve = 1.0 + sin(seconds) * .5 colormap.apply(image, colormapImage)
colormap.apply(image, colormapImage) drawer.image(colormapImage)
drawer.image(colormapImage)
}
} }
} }
} }

View File

@@ -5,17 +5,15 @@ import org.openrndr.draw.loadImage
import org.openrndr.extra.fx.colormap.SpectralZucconiColormap import org.openrndr.extra.fx.colormap.SpectralZucconiColormap
import kotlin.math.sin import kotlin.math.sin
fun main() { fun main() = application {
application { program {
program { val colormap = SpectralZucconiColormap()
val colormap = SpectralZucconiColormap() val image = loadImage("demo-data/images/image-001.png")
val image = loadImage("demo-data/images/image-001.png") val colormapImage = image.createEquivalent(type = ColorType.FLOAT32)
val colormapImage = image.createEquivalent(type = ColorType.FLOAT32) extend {
extend { colormap.curve = 1.0 + sin(seconds) * .5
colormap.curve = 1.0 + sin(seconds) * .5 colormap.apply(image, colormapImage)
colormap.apply(image, colormapImage) drawer.image(colormapImage)
drawer.image(colormapImage)
}
} }
} }
} }

View File

@@ -5,17 +5,15 @@ import org.openrndr.draw.loadImage
import org.openrndr.extra.fx.colormap.TurboColormap import org.openrndr.extra.fx.colormap.TurboColormap
import kotlin.math.sin import kotlin.math.sin
fun main() { fun main() = application {
application { program {
program { val colormap = TurboColormap()
val colormap = TurboColormap() val image = loadImage("demo-data/images/image-001.png")
val image = loadImage("demo-data/images/image-001.png") val colormapImage = image.createEquivalent(type = ColorType.FLOAT32)
val colormapImage = image.createEquivalent(type = ColorType.FLOAT32) extend {
extend { colormap.curve = 1.0 + sin(seconds) * .5
colormap.curve = 1.0 + sin(seconds) * .5 colormap.apply(image, colormapImage)
colormap.apply(image, colormapImage) drawer.image(colormapImage)
drawer.image(colormapImage)
}
} }
} }
} }

View File

@@ -11,53 +11,55 @@ import org.openrndr.extra.noise.*
import org.openrndr.math.smoothstep import org.openrndr.math.smoothstep
import kotlin.math.cos import kotlin.math.cos
fun main() { fun main() = application {
application { program {
program { extend(Post()) {
extend(Post()) { // -- create a color buffer and fill it with random direction vectors
// -- create a color buffer and fill it with random direction vectors val direction = colorBuffer(width, height, type = ColorType.FLOAT32)
val direction = colorBuffer(width, height, type = ColorType.FLOAT32) val s = direction.shadow
val s = direction.shadow val n = simplex2D.bipolar().fbm().scaleShiftInput(0.01, 0.0, 0.01, 0.0).withVector2Output()
val n = simplex2D.bipolar().fbm().scaleShiftInput(0.01, 0.0, 0.01, 0.0).withVector2Output() val ng = simplex2D.unipolar().scaleShiftInput(0.005, 0.0, 0.005, 0.0)
val ng = simplex2D.unipolar().scaleShiftInput(0.005, 0.0, 0.005, 0.0) for (y in 0 until height) {
for (y in 0 until height) { for (x in 0 until width) {
for (x in 0 until width) { val a = smoothstep(0.4, 0.6, cos((x + y) * 0.01) * 0.5 + 0.5)
val a = smoothstep(0.4, 0.6, cos((x + y) * 0.01) * 0.5 + 0.5) val nv = n(2320, x.toDouble(), y.toDouble()) * smoothstep(
val nv = n(2320, x.toDouble(), y.toDouble()) * smoothstep(0.45, 0.55, ng(1032, x.toDouble(), y.toDouble())) 0.45,
s[x, y] = ColorRGBa(nv.x, nv.y, 0.0, 1.0) 0.55,
} ng(1032, x.toDouble(), y.toDouble())
)
s[x, y] = ColorRGBa(nv.x, nv.y, 0.0, 1.0)
} }
s.upload() }
s.upload()
val directional = DirectionalBlur() val directional = DirectionalBlur()
// -- create a bidirectional composite filter by using a directional filter twice // -- create a bidirectional composite filter by using a directional filter twice
val bidirectional = directional.then(directional) { val bidirectional = directional.then(directional) {
firstParameters { firstParameters {
window = 50 window = 50
perpendicular = false perpendicular = false
}
secondParameters {
window = 3
perpendicular = true
}
} }
secondParameters {
val grain = FilmGrain() window = 3
grain.grainStrength = 1.0 perpendicular = true
// -- create a grain-blur composite filter
val grainBlur = grain.then(bidirectional)
post { input, output ->
grainBlur.apply(arrayOf(input, direction), output)
} }
} }
val image = loadImage("demo-data/images/image-001.png") val grain = FilmGrain()
extend { grain.grainStrength = 1.0
drawer.image(image)
// -- create a grain-blur composite filter
val grainBlur = grain.then(bidirectional)
post { input, output ->
grainBlur.apply(arrayOf(input, direction), output)
} }
} }
val image = loadImage("demo-data/images/image-001.png")
extend {
drawer.image(image)
}
} }
} }

View File

@@ -3,23 +3,21 @@ import org.openrndr.draw.createEquivalent
import org.openrndr.draw.loadImage import org.openrndr.draw.loadImage
import org.openrndr.extra.fx.dither.LumaHalftone import org.openrndr.extra.fx.dither.LumaHalftone
fun main() { fun main() = application {
application { program {
program { val image = loadImage("demo-data/images/image-001.png")
val image = loadImage("demo-data/images/image-001.png") val filteredImage = image.createEquivalent()
val filteredImage = image.createEquivalent() val lumaHalftone = LumaHalftone()
val lumaHalftone = LumaHalftone() extend {
extend { lumaHalftone.rotation = -15.0
lumaHalftone.rotation = -15.0 lumaHalftone.freq0 = 100.0
lumaHalftone.freq0 = 100.0 lumaHalftone.gain1 = 1.0
lumaHalftone.gain1 = 1.0 lumaHalftone.threshold = 0.5
lumaHalftone.threshold = 0.5 lumaHalftone.phase0 = seconds * 0.1
lumaHalftone.phase0 = seconds*0.1 lumaHalftone.phase1 = -seconds * 0.1
lumaHalftone.phase1 = -seconds*0.1 lumaHalftone.apply(image, filteredImage)
lumaHalftone.apply(image, filteredImage) lumaHalftone.invert = seconds.mod(2.0) < 1.0
lumaHalftone.invert = seconds.mod(2.0) < 1.0 drawer.image(filteredImage)
drawer.image(filteredImage)
}
} }
} }
} }

View File

@@ -5,28 +5,26 @@ import org.openrndr.extensions.SingleScreenshot
import org.openrndr.extra.fx.distort.FluidDistort import org.openrndr.extra.fx.distort.FluidDistort
import org.openrndr.extra.fx.patterns.Checkers import org.openrndr.extra.fx.patterns.Checkers
fun main() { fun main() = application {
application { program {
program { val fd = FluidDistort()
val fd = FluidDistort() val checkers = Checkers()
val checkers = Checkers()
val image = colorBuffer(width, height) val image = colorBuffer(width, height)
val distorted = image.createEquivalent() val distorted = image.createEquivalent()
checkers.size = 64.0 checkers.size = 64.0
checkers.apply(emptyArray(), image) checkers.apply(emptyArray(), image)
if (System.getProperty("takeScreenshot") == "true") { if (System.getProperty("takeScreenshot") == "true") {
extensions.filterIsInstance<SingleScreenshot>().forEach { extensions.filterIsInstance<SingleScreenshot>().forEach {
it.delayFrames = 150 it.delayFrames = 150
}
}
extend {
// Ensure >0.01 for a better screenshot
fd.blend = (mouse.position.x / width).coerceAtLeast(0.01)
fd.apply(image, distorted)
drawer.image(distorted)
} }
} }
extend {
// Ensure >0.01 for a better screenshot
fd.blend = (mouse.position.x / width).coerceAtLeast(0.01)
fd.apply(image, distorted)
drawer.image(distorted)
}
} }
} }

View File

@@ -1,27 +1,25 @@
import org.openrndr.extra.fx.color.RgbToOkLab
import org.openrndr.extra.fx.color.OkLabToRgb
import org.openrndr.application import org.openrndr.application
import org.openrndr.draw.ColorType import org.openrndr.draw.ColorType
import org.openrndr.draw.createEquivalent import org.openrndr.draw.createEquivalent
import org.openrndr.draw.loadImage import org.openrndr.draw.loadImage
import org.openrndr.extra.fx.color.OkLabToRgb
import org.openrndr.extra.fx.color.RgbToOkLab
/** /**
* This demonstrates converting a [ColorBuffer] from and to (OK)LAB color space using the [RgbToOkLab] and [OkLabToRgb] * This demonstrates converting a [ColorBuffer] from and to (OK)LAB color space using the [RgbToOkLab] and [OkLabToRgb]
* filters. The (OK)Lab representation is signed and requires a floating point representation. * filters. The (OK)Lab representation is signed and requires a floating point representation.
*/ */
fun main() { fun main() = application {
application { program {
program { val rgbToOkLab = RgbToOkLab()
val rgbToOkLab = RgbToOkLab() val okLabToRgb = OkLabToRgb()
val okLabToRgb = OkLabToRgb() val image = loadImage("demo-data/images/image-001.png")
val image = loadImage("demo-data/images/image-001.png") val labImage = image.createEquivalent(type = ColorType.FLOAT32)
val labImage = image.createEquivalent(type = ColorType.FLOAT32) rgbToOkLab.apply(image, labImage)
rgbToOkLab.apply(image, labImage) okLabToRgb.apply(labImage, image)
okLabToRgb.apply(labImage, image) extend {
extend { drawer.image(image)
drawer.image(image)
}
} }
} }
} }

View File

@@ -8,38 +8,36 @@ import org.openrndr.extra.fx.patterns.Checkers
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import kotlin.math.sin import kotlin.math.sin
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
program {
val a = drawImage(width, height) {
drawer.stroke = null
drawer.fill = ColorRGBa.BLUE
drawer.circle(drawer.bounds.center - Vector2(100.0, 0.0), drawer.width * 0.25)
} }
program { val b = drawImage(width, height) {
val a = drawImage(width, height) { drawer.clear(ColorRGBa.TRANSPARENT)
drawer.stroke = null drawer.stroke = ColorRGBa.RED
drawer.fill = ColorRGBa.BLUE drawer.strokeWeight = 10.0
drawer.circle(drawer.bounds.center - Vector2(100.0, 0.0), drawer.width * 0.25) drawer.fill = ColorRGBa.YELLOW.opacify(1.0)
} drawer.circle(drawer.bounds.center + Vector2(100.0, 0.0), drawer.width * 0.25)
val b = drawImage(width, height) { }
drawer.clear(ColorRGBa.TRANSPARENT) BoxBlur().apply { window = 10 }.apply(b, b)
drawer.stroke = ColorRGBa.RED val checked = a.createEquivalent()
drawer.strokeWeight = 10.0 Checkers().apply(emptyArray(), checked)
drawer.fill = ColorRGBa.YELLOW.opacify(1.0)
drawer.circle(drawer.bounds.center + Vector2(100.0, 0.0), drawer.width * 0.25)
}
BoxBlur().apply { window = 10 }.apply(b, b)
val checked = a.createEquivalent()
Checkers().apply(emptyArray(), checked)
val mixed = a.createEquivalent() val mixed = a.createEquivalent()
val blendSpectral = BlendSpectral() val blendSpectral = BlendSpectral()
extend { extend {
drawer.image(checked) drawer.image(checked)
blendSpectral.fill = sin(seconds) * 0.5 + 0.5 blendSpectral.fill = sin(seconds) * 0.5 + 0.5
blendSpectral.clip = seconds.mod(4.0) > 2.0 blendSpectral.clip = seconds.mod(4.0) > 2.0
blendSpectral.apply(a, b, mixed) blendSpectral.apply(a, b, mixed)
drawer.image(mixed) drawer.image(mixed)
}
} }
} }
} }

View File

@@ -10,21 +10,19 @@ import kotlin.random.Random
* - Filters the generated points to enforce a minimum distance of 20.0 units between them. * - Filters the generated points to enforce a minimum distance of 20.0 units between them.
* - Visualizes the filtered points as circles with a radius of 10.0 units on the canvas. * - Visualizes the filtered points as circles with a radius of 10.0 units on the canvas.
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
program {
val r = Random(0)
val points = (0 until 10000).map {
drawer.bounds.uniform(random = r)
} }
program { val filteredPoints = points.filter(20.0)
val r = Random(0) extend {
val points = (0 until 10000).map { drawer.circles(filteredPoints, 10.0)
drawer.bounds.uniform(random = r)
}
val filteredPoints = points.filter(20.0)
extend {
drawer.circles(filteredPoints, 10.0)
}
} }
} }
} }

View File

@@ -13,32 +13,29 @@ import kotlin.random.Random
* - Rectangles representing the bounds of the cells in the grid. * - Rectangles representing the bounds of the cells in the grid.
* - Circles representing the generated points. * - Circles representing the generated points.
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { val r = Random(0)
val r = Random(0) val hashGrid = HashGrid(72.0)
val hashGrid = HashGrid(72.0)
extend { extend {
for (i in 0 until 100) { for (i in 0 until 100) {
val p = drawer.bounds.uniform(random = r) val p = drawer.bounds.uniform(random = r)
if (hashGrid.isFree(p)) { if (hashGrid.isFree(p)) {
hashGrid.insert(p) hashGrid.insert(p)
}
} }
drawer.fill = null
drawer.stroke = ColorRGBa.WHITE
drawer.rectangles(hashGrid.cells().map { it.bounds }.toList())
drawer.fill = null
drawer.stroke = ColorRGBa.PINK
drawer.circles(hashGrid.points().map { it.first }.toList(), 36.0)
} }
drawer.fill = null
drawer.stroke = ColorRGBa.WHITE
drawer.rectangles(hashGrid.cells().map { it.bounds }.toList())
drawer.fill = null
drawer.stroke = ColorRGBa.PINK
drawer.circles(hashGrid.points().map { it.first }.toList(), 36.0)
} }
} }
} }

View File

@@ -12,54 +12,56 @@ import org.openrndr.draw.loadImage
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
fun main() { fun main() = application {
application { program {
program { // Load an image, convert to BoofCV format using orx-boofcv
// Load an image, convert to BoofCV format using orx-boofcv val input = loadImage("demo-data/images/image-001.png").toGrayF32()
val input = loadImage("demo-data/images/image-001.png").toGrayF32()
// BoofCV: calculate a good threshold for the loaded image // BoofCV: calculate a good threshold for the loaded image
val threshold = GThresholdImageOps.computeOtsu(input, 0.0, 255.0) val threshold = GThresholdImageOps.computeOtsu(input, 0.0, 255.0)
// BoofCV: use the threshold to convert the image to black and white // BoofCV: use the threshold to convert the image to black and white
val binary = GrayU8(input.width, input.height) val binary = GrayU8(input.width, input.height)
ThresholdImageOps.threshold(input, binary, threshold.toFloat(), false) ThresholdImageOps.threshold(input, binary, threshold.toFloat(), false)
// BoofCV: Contract and expand the white areas to remove noise // BoofCV: Contract and expand the white areas to remove noise
var filtered = BinaryImageOps.erode8(binary, 1, null) var filtered = BinaryImageOps.erode8(binary, 1, null)
filtered = BinaryImageOps.dilate8(filtered, 1, null) filtered = BinaryImageOps.dilate8(filtered, 1, null)
// BoofCV: Calculate contours as vector data // BoofCV: Calculate contours as vector data
val contours = BinaryImageOps.contour(filtered, ConnectRule.EIGHT, null) val contours = BinaryImageOps.contour(filtered, ConnectRule.EIGHT, null)
// orx-boofcv: convert vector data to OPENRNDR ShapeContours // orx-boofcv: convert vector data to OPENRNDR ShapeContours
val externalShapes = contours.toShapeContours(true, val externalShapes = contours.toShapeContours(
internal = false, external = true) true,
val internalShapes = contours.toShapeContours(true, internal = false, external = true
internal = true, external = false) )
val internalShapes = contours.toShapeContours(
true,
internal = true, external = false
)
extend { extend {
drawer.run { drawer.run {
// Zoom in and out over time // Zoom in and out over time
translate(bounds.center) translate(bounds.center)
scale(1.5 + 0.5 * cos(seconds * 0.2)) scale(1.5 + 0.5 * cos(seconds * 0.2))
translate(-bounds.center) translate(-bounds.center)
stroke = null stroke = null
// Draw all external shapes // Draw all external shapes
fill = rgb(0.2) fill = rgb(0.2)
contours(externalShapes) contours(externalShapes)
// Draw internal shapes one by one to set unique colors // Draw internal shapes one by one to set unique colors
internalShapes.forEachIndexed { i, shp -> internalShapes.forEachIndexed { i, shp ->
val shade = 0.2 + (i % 7) * 0.1 + val shade = 0.2 + (i % 7) * 0.1 +
0.1 * sin(i + seconds) 0.1 * sin(i + seconds)
fill = ColorRGBa.PINK.shade(shade) fill = ColorRGBa.PINK.shade(shade)
contour(shp) contour(shp)
}
} }
} }
} }
} }
} }

View File

@@ -3,24 +3,21 @@ import org.openrndr.boofcv.binding.resizeBy
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.draw.loadImage import org.openrndr.draw.loadImage
fun main() = application {
program {
// Load an image, convert to BoofCV format using orx-boofcv
val input = loadImage("demo-data/images/image-001.png")
fun main() { val scaled = input.resizeBy(0.5)
application { val scaled2 = input.resizeBy(0.25, convertToGray = true)
program { val scaled3 = input.resizeBy(0.1)
// Load an image, convert to BoofCV format using orx-boofcv
val input = loadImage("demo-data/images/image-001.png")
val scaled = input.resizeBy(0.5) extend {
val scaled2 = input.resizeBy(0.25, convertToGray = true) drawer.clear(ColorRGBa.BLACK)
val scaled3 = input.resizeBy(0.1) drawer.translate(0.0, (height - scaled.bounds.height) / 2.0)
drawer.image(scaled)
extend { drawer.image(scaled2, scaled.bounds.width, scaled.bounds.height - scaled2.height)
drawer.clear(ColorRGBa.BLACK) drawer.image(scaled3, scaled.bounds.width + scaled2.bounds.width, scaled.bounds.height - scaled3.height)
drawer.translate(0.0, (height - scaled.bounds.height) / 2.0)
drawer.image(scaled)
drawer.image(scaled2, scaled.bounds.width, scaled.bounds.height - scaled2.height)
drawer.image(scaled3, scaled.bounds.width + scaled2.bounds.width, scaled.bounds.height - scaled3.height)
}
} }
} }
} }

View File

@@ -3,23 +3,20 @@ import org.openrndr.boofcv.binding.resizeTo
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.draw.loadImage import org.openrndr.draw.loadImage
fun main() = application {
program {
// Load an image, convert to BoofCV format using orx-boofcv
val input = loadImage("demo-data/images/image-001.png")
val scaled = input.resizeTo(input.width / 3)
val scaled2 = input.resizeTo(newHeight = input.height / 4, convertToGray = true)
val scaled3 = input.resizeTo(input.width / 5, input.height / 5)
fun main() { extend {
application { drawer.clear(ColorRGBa.BLACK)
program { drawer.translate(0.0, (height - scaled.bounds.height) / 2.0)
// Load an image, convert to BoofCV format using orx-boofcv drawer.image(scaled)
val input = loadImage("demo-data/images/image-001.png") drawer.image(scaled2, scaled.bounds.width, scaled.bounds.height - scaled2.height)
val scaled = input.resizeTo(input.width / 3) drawer.image(scaled3, scaled.bounds.width + scaled2.bounds.width, scaled.bounds.height - scaled3.height)
val scaled2 = input.resizeTo(newHeight = input.height / 4, convertToGray = true)
val scaled3 = input.resizeTo(input.width / 5, input.height / 5)
extend {
drawer.clear(ColorRGBa.BLACK)
drawer.translate(0.0, (height - scaled.bounds.height) / 2.0)
drawer.image(scaled)
drawer.image(scaled2, scaled.bounds.width, scaled.bounds.height - scaled2.height)
drawer.image(scaled3, scaled.bounds.width + scaled2.bounds.width, scaled.bounds.height - scaled3.height)
}
} }
} }
} }

View File

@@ -17,63 +17,65 @@ import org.openrndr.math.Vector2
import org.openrndr.shape.Rectangle import org.openrndr.shape.Rectangle
import org.openrndr.shape.ShapeContour import org.openrndr.shape.ShapeContour
fun main() { fun main() = application {
application { program {
program { // Create a buffer where to draw something for boofcv
// Create a buffer where to draw something for boofcv val rt = renderTarget(width, height) {
val rt = renderTarget(width, height) { colorBuffer()
colorBuffer() depthBuffer()
depthBuffer() }
} // Draw some shapes on that buffer
// Draw some shapes on that buffer drawer.isolatedWithTarget(rt) {
drawer.isolatedWithTarget(rt) { clear(ColorRGBa.BLACK)
clear(ColorRGBa.BLACK) fill = ColorRGBa.WHITE
fill = ColorRGBa.WHITE stroke = null
stroke = null rectangle(
rectangle(Rectangle.fromCenter(bounds.position(0.33, 0.5), Rectangle.fromCenter(
150.0, 150.0)) bounds.position(0.33, 0.5),
translate(bounds.position(0.62, 0.5)) 150.0, 150.0
rotate(30.0) )
rectangle(Rectangle.fromCenter(Vector2.ZERO, 200.0, 200.0)) )
rectangle(0.0, -200.0, 60.0, 60.0) translate(bounds.position(0.62, 0.5))
circle(0.0, 190.0, 60.0) rotate(30.0)
} rectangle(Rectangle.fromCenter(Vector2.ZERO, 200.0, 200.0))
// Convert the bitmap buffer into ShapeContours rectangle(0.0, -200.0, 60.0, 60.0)
val vectorized = imageToContours(rt.colorBuffer(0)) circle(0.0, 190.0, 60.0)
}
// Convert the bitmap buffer into ShapeContours
val vectorized = imageToContours(rt.colorBuffer(0))
// Show amount of segments in each shape (high number) // Show amount of segments in each shape (high number)
vectorized.forEachIndexed { i, it -> vectorized.forEachIndexed { i, it ->
println("boofcv shape $i: ${it.segments.size} segments") println("boofcv shape $i: ${it.segments.size} segments")
} }
// Make a simplified list of points // Make a simplified list of points
val simplePoints = vectorized.map { val simplePoints = vectorized.map {
simplify(it.adaptivePositions(), 4.0) simplify(it.adaptivePositions(), 4.0)
}.filter { it.size >= 3 } }.filter { it.size >= 3 }
// Use the simplified list to make a smooth contour // Use the simplified list to make a smooth contour
val smooth = simplePoints.map { val smooth = simplePoints.map {
CatmullRomChain2(it, 0.0, true).toContour() CatmullRomChain2(it, 0.0, true).toContour()
} }
// Use the simplified list to make a polygonal contour // Use the simplified list to make a polygonal contour
val polygonal = simplePoints.map { val polygonal = simplePoints.map {
ShapeContour.fromPoints(it, true) ShapeContour.fromPoints(it, true)
} }
// Show amount of segments in simplified shapes (low number). // Show amount of segments in simplified shapes (low number).
// Note: `smooth` and `polygonal` have the same number of segments // Note: `smooth` and `polygonal` have the same number of segments
smooth.forEachIndexed { i, it -> smooth.forEachIndexed { i, it ->
println("simplified shape $i: ${it.segments.size} segments") println("simplified shape $i: ${it.segments.size} segments")
} }
extend { extend {
drawer.run { drawer.run {
fill = null // ColorRGBa.PINK.opacify(0.15) fill = null // ColorRGBa.PINK.opacify(0.15)
stroke = ColorRGBa.PINK.opacify(0.7) stroke = ColorRGBa.PINK.opacify(0.7)
contours(polygonal) contours(polygonal)
contours(smooth) contours(smooth)
}
} }
} }
} }
@@ -97,4 +99,4 @@ fun imageToContours(input: ColorBuffer): List<ShapeContour> {
// orx-boofcv: convert vector data to OPENRNDR ShapeContours // orx-boofcv: convert vector data to OPENRNDR ShapeContours
return contours.toShapeContours(true, internal = true, external = true) return contours.toShapeContours(true, internal = true, external = true)
} }

View File

@@ -62,7 +62,7 @@ private fun SceneRenderer.processVoxelConeTracing(drawer: Drawer, scene: Scene,
val position = Vector3.ZERO val position = Vector3.ZERO
drawer.lookAt(position + side.forward*40.0, position , side.up) drawer.lookAt(position + side.forward*40.0, position , side.up)
drawPass(drawer, pass, materialContext, context) { drawPass(drawer, pass, materialContext, context) {
it.parameter("voxelMap", feature.voxelMap!!.imageBinding(0, ImageAccess.WRITE)) it.image("voxelMap", feature.voxelMap!!.imageBinding(0, ImageAccess.WRITE))
} }
} }
} }

View File

@@ -4,25 +4,23 @@ import org.openrndr.extra.parameters.Description
import org.openrndr.extra.parameters.PathParameter import org.openrndr.extra.parameters.PathParameter
import org.openrndr.extra.propertywatchers.watchingImagePath import org.openrndr.extra.propertywatchers.watchingImagePath
fun main() { fun main() = application {
application { program {
program { val gui = GUI()
val gui = GUI() gui.compartmentsCollapsedByDefault = false
gui.compartmentsCollapsedByDefault = false
val settings = @Description("Settings") object { val settings = @Description("Settings") object {
@PathParameter("image", extensions = ["jpg", "png"], order = 10) @PathParameter("image", extensions = ["jpg", "png"], order = 10)
var imagePath = "demo-data/images/image-001.png" var imagePath = "demo-data/images/image-001.png"
val image by watchingImagePath(::imagePath) { val image by watchingImagePath(::imagePath) {
it it
}
}
gui.add(settings)
extend(gui)
extend {
drawer.image(settings.image)
} }
} }
gui.add(settings)
extend(gui)
extend {
drawer.image(settings.image)
}
} }
} }

View File

@@ -8,7 +8,6 @@ import org.openrndr.*
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.dialogs.* import org.openrndr.dialogs.*
import org.openrndr.draw.Drawer import org.openrndr.draw.Drawer
import org.openrndr.extra.noise.random
import org.openrndr.extra.noise.uniform import org.openrndr.extra.noise.uniform
import org.openrndr.extra.parameters.* import org.openrndr.extra.parameters.*
import org.openrndr.internal.Driver import org.openrndr.internal.Driver
@@ -1077,7 +1076,7 @@ open class GUI(
val min = parameter.doubleRange!!.start val min = parameter.doubleRange!!.start
val max = parameter.doubleRange!!.endInclusive val max = parameter.doubleRange!!.endInclusive
val currentValue = (parameter.property as KMutableProperty1<Any, Double>).get(labeledObject.obj) val currentValue = (parameter.property as KMutableProperty1<Any, Double>).get(labeledObject.obj)
val randomValue = random(min, max) val randomValue = Double.uniform(min, max)
val newValue = mix(currentValue, randomValue, strength) val newValue = mix(currentValue, randomValue, strength)
(parameter.property as KMutableProperty1<Any, Double>).set(labeledObject.obj, newValue) (parameter.property as KMutableProperty1<Any, Double>).set(labeledObject.obj, newValue)
} }
@@ -1086,7 +1085,7 @@ open class GUI(
val min = parameter.intRange!!.first val min = parameter.intRange!!.first
val max = parameter.intRange!!.last val max = parameter.intRange!!.last
val currentValue = (parameter.property as KMutableProperty1<Any, Int>).get(labeledObject.obj) val currentValue = (parameter.property as KMutableProperty1<Any, Int>).get(labeledObject.obj)
val randomValue = random(min.toDouble(), max.toDouble()) val randomValue = Double.uniform(min.toDouble(), max.toDouble())
val newValue = mix(currentValue.toDouble(), randomValue, strength).roundToInt() val newValue = mix(currentValue.toDouble(), randomValue, strength).roundToInt()
(parameter.property as KMutableProperty1<Any, Int>).set(labeledObject.obj, newValue) (parameter.property as KMutableProperty1<Any, Int>).set(labeledObject.obj, newValue)
} }

View File

@@ -9,33 +9,31 @@ import org.openrndr.math.Vector2
/** /**
* Demonstration of two-way binding using [bindMidiControl] * Demonstration of two-way binding using [bindMidiControl]
*/ */
fun main() { fun main() = application {
application { program {
program { val midi = openMidiDevice("MIDI2x2 [hw:3,0,0]")
val midi = openMidiDevice("MIDI2x2 [hw:3,0,0]") val settings = object {
val settings = object { @DoubleParameter("radius", 0.0, 100.0)
@DoubleParameter("radius", 0.0, 100.0) var radius = 0.0
var radius = 0.0
@DoubleParameter("x", -100.0, 100.0) @DoubleParameter("x", -100.0, 100.0)
var x = 0.0 var x = 0.0
@DoubleParameter("y", -100.0, 100.0) @DoubleParameter("y", -100.0, 100.0)
var y = 0.0 var y = 0.0
@ColorParameter("fill") @ColorParameter("fill")
var color = ColorRGBa.WHITE var color = ColorRGBa.WHITE
} }
bindMidiControl(settings::radius, midi, 0, 1) bindMidiControl(settings::radius, midi, 0, 1)
bindMidiControl(settings::x, midi, 0, 2) bindMidiControl(settings::x, midi, 0, 2)
bindMidiControl(settings::y, midi, 0, 3) bindMidiControl(settings::y, midi, 0, 3)
bindMidiControl(settings::color, midi, 0, 4) bindMidiControl(settings::color, midi, 0, 4)
extend { extend {
drawer.fill = settings.color drawer.fill = settings.color
drawer.circle(drawer.bounds.center + Vector2(settings.x, settings.y), settings.radius) drawer.circle(drawer.bounds.center + Vector2(settings.x, settings.y), settings.radius)
}
} }
} }
} }

View File

@@ -6,14 +6,12 @@ import org.openrndr.extra.midi.openMidiDevice
/** /**
* Demonstration of [MidiConsole] * Demonstration of [MidiConsole]
*/ */
fun main() { fun main() = application {
application { program {
program { listMidiDevices().forEach { println(it.toString()) }
listMidiDevices().forEach { println(it.toString()) } val midi = openMidiDevice("Launchpad [hw:4,0,0]")
val midi = openMidiDevice("Launchpad [hw:4,0,0]") extend(MidiConsole()) {
extend(MidiConsole()) { register(midi)
register(midi)
}
} }
} }
} }

View File

@@ -13,98 +13,96 @@ import kotlin.random.Random
* Hold the mouse button to randomize the frequencies. * Hold the mouse button to randomize the frequencies.
* Press keys 'a' or 'b' for less random frequencies. * Press keys 'a' or 'b' for less random frequencies.
*/ */
fun main() { fun main() = application {
application { program {
program { val minim = minim()
val minim = minim() val out = minim.lineOut
val out = minim.lineOut
if (out == null) { if (out == null) {
application.exit() application.exit()
}
// generates a random frequency value biased down
fun randomFreq() = 20f + Random.nextFloat().pow(3) * 1000
// If one didn't want to visualize or control the synths we
// wouldn't need a data structure to store them. Here we store
// Pairs, so we have access both to the frequency of the wave
// and the current amplitude defined by the lfo (low frequency
// oscillator).
val synths = List(20) {
// By default, Oscil creates sine waves, but it can be changed.
val lfo = Oscil(
Random.nextFloat() * 0.1f + 0.005f,
0.05f
).apply {
// Here we set the center of the lfo to 0.05f.
// Since the amplitude is also 0.05f, it moves between
// 0.00f and 0.10f.
offset.lastValue = 0.05f
// Have the sine waves to not start in sync.
//phase.lastValue = Random.nextFloat() * 6.28f
} }
val wave = Oscil(randomFreq(), 0f)
// The `lfo` Oscil controls the `wave` Oscil's amplitude.
lfo.patch(wave.amplitude)
// Random pan to avoid a mono sound.
val pan = Pan(Random.nextFloat() * 2 - 1)
wave.patch(pan)
pan.patch(out)
// Store a [Pair] in `synths`.
Pair(wave, lfo)
}
val bgColor = rgb(0.094, 0.188, 0.349)
val lineColor = rgb(0.992, 0.918, 0.671)
val mouseTracker = MouseTracker(mouse)
// generates a random frequency value biased down extend {
fun randomFreq() = 20f + Random.nextFloat().pow(3) * 1000 drawer.clear(bgColor)
drawer.translate(drawer.bounds.center)
// If one didn't want to visualize or control the synths we drawer.rotate(seconds)
// wouldn't need a data structure to store them. Here we store // A CircleBatchBuilder for faster drawing of circles.
// Pairs, so we have access both to the frequency of the wave drawer.circles {
// and the current amplitude defined by the lfo (low frequency // For each synth draw a circle.
// oscillator). synths.forEachIndexed { i, (wave, lfo) ->
val synths = List(20) { stroke = lineColor.opacify(Random.nextDouble(0.4) + 0.6)
// By default, Oscil creates sine waves, but it can be changed. fill = lineColor.opacify(Random.nextDouble() * 0.04)
val lfo = Oscil( // A Polar arrangement centered on the screen.
Random.nextFloat() * 0.1f + 0.005f, // Higher pitch circles are farther away from the center.
0.05f val pos = Polar(
).apply { 360.0 * i / synths.size,
// Here we set the center of the lfo to 0.05f. 50.0 + wave.frequency.lastValue * 0.2
// Since the amplitude is also 0.05f, it moves between ).cartesian
// 0.00f and 0.10f. // The size of the circle depends on the current volume
offset.lastValue = 0.05f // set by the lfo.
circle(pos, 500 * lfo.lastValues.last().toDouble())
// Have the sine waves to not start in sync.
//phase.lastValue = Random.nextFloat() * 6.28f
} }
val wave = Oscil(randomFreq(), 0f)
// The `lfo` Oscil controls the `wave` Oscil's amplitude.
lfo.patch(wave.amplitude)
// Random pan to avoid a mono sound.
val pan = Pan(Random.nextFloat() * 2 - 1)
wave.patch(pan)
pan.patch(out)
// Store a [Pair] in `synths`.
Pair(wave, lfo)
} }
val bgColor = rgb(0.094, 0.188, 0.349) if (mouseTracker.pressedButtons.isNotEmpty()) {
val lineColor = rgb(0.992, 0.918, 0.671) synths.random().first.setFrequency(randomFreq())
val mouseTracker = MouseTracker(mouse) }
}
extend { keyboard.keyDown.listen { key ->
drawer.clear(bgColor) when (key.name) {
drawer.translate(drawer.bounds.center) "a" -> {
drawer.rotate(seconds) // make all frequencies close to a base frequency
// A CircleBatchBuilder for faster drawing of circles. // (circular arrangement)
drawer.circles { val baseFreq = 20 + Random.nextFloat() * 200
// For each synth draw a circle. synths.forEach {
synths.forEachIndexed { i, (wave, lfo) -> it.first.setFrequency(baseFreq + Random.nextFloat() * 20)
stroke = lineColor.opacify(Random.nextDouble(0.4) + 0.6)
fill = lineColor.opacify(Random.nextDouble() * 0.04)
// A Polar arrangement centered on the screen.
// Higher pitch circles are farther away from the center.
val pos = Polar(
360.0 * i / synths.size,
50.0 + wave.frequency.lastValue * 0.2
).cartesian
// The size of the circle depends on the current volume
// set by the lfo.
circle(pos, 500 * lfo.lastValues.last().toDouble())
} }
} }
if (mouseTracker.pressedButtons.isNotEmpty()) {
synths.random().first.setFrequency(randomFreq())
}
}
keyboard.keyDown.listen { key ->
when (key.name) {
"a" -> {
// make all frequencies close to a base frequency
// (circular arrangement)
val baseFreq = 20 + Random.nextFloat() * 200
synths.forEach {
it.first.setFrequency(baseFreq + Random.nextFloat() * 20)
}
}
"b" -> { "b" -> {
// make all frequencies follow an exponential series // make all frequencies follow an exponential series
// (spiral arrangement) // (spiral arrangement)
val inc = Random.nextFloat() * 0.1f val inc = Random.nextFloat() * 0.1f
synths.forEachIndexed { i, (wave, _) -> synths.forEachIndexed { i, (wave, _) ->
wave.setFrequency(25f.pow(1f + i * inc)) wave.setFrequency(25f.pow(1f + i * inc))
}
} }
} }
} }
} }
} }
} }

View File

@@ -1,38 +1,35 @@
import ddf.minim.Minim import ddf.minim.Minim
import ddf.minim.analysis.FFT import ddf.minim.analysis.FFT
import ddf.minim.analysis.LanczosWindow import ddf.minim.analysis.LanczosWindow
import org.openrndr.application import org.openrndr.application
import org.openrndr.extra.minim.minim import org.openrndr.extra.minim.minim
import org.openrndr.math.map import org.openrndr.math.map
import kotlin.math.ln import kotlin.math.ln
fun main() { fun main() = application {
application { configure {
configure { width = 1280
width = 1280 height = 720
height = 720 }
program {
val minim = minim()
if (minim.lineOut == null) {
application.exit()
} }
program { val lineIn = minim.getLineIn(Minim.MONO, 2048, 48000f)
val minim = minim() if (lineIn == null) {
if (minim.lineOut == null) { application.exit()
application.exit() }
} val fft = FFT(lineIn.bufferSize(), lineIn.sampleRate())
fft.window(LanczosWindow())
val lineIn = minim.getLineIn(Minim.MONO, 2048, 48000f) extend {
if (lineIn == null) { fft.forward(lineIn.mix)
application.exit() for (i in 0 until 200) {
} val bandDB = 20.0 * ln(2.0 * fft.getBand(i) / fft.timeSize())
val fft = FFT(lineIn.bufferSize(), lineIn.sampleRate()) drawer.rectangle(i * 5.0, height / 2.0, 5.0, bandDB.map(0.0, -150.0, 0.0, -height / 8.0))
fft.window(LanczosWindow())
extend {
fft.forward(lineIn.mix)
for (i in 0 until 200) {
val bandDB = 20.0 * ln(2.0 * fft.getBand(i) / fft.timeSize())
drawer.rectangle(i * 5.0, height / 2.0, 5.0, bandDB.map(0.0, -150.0, 0.0, -height / 8.0))
}
} }
} }
} }
} }

View File

@@ -1,28 +1,26 @@
import org.openrndr.application import org.openrndr.application
import org.openrndr.extra.minim.minim import org.openrndr.extra.minim.minim
fun main() { fun main() = application {
application { program {
program { val minim = minim()
val minim = minim() if (minim.lineOut == null) {
if (minim.lineOut == null) { application.exit()
application.exit() }
}
val player = minim.loadFile( val player = minim.loadFile(
"demo-data/sounds/26777__junggle__btn402.mp3" "demo-data/sounds/26777__junggle__btn402.mp3"
) )
// fade gain to -40dB in 15 seconds // fade gain to -40dB in 15 seconds
player.shiftGain(player.gain, -40f, 15000) player.shiftGain(player.gain, -40f, 15000)
extend { extend {
if(frameCount % 30 == 0) { if (frameCount % 30 == 0) {
player.rewind() player.rewind()
//player.gain = Random.nextDouble(-20.0, 0.0).toFloat() //player.gain = Random.nextDouble(-20.0, 0.0).toFloat()
player.play() player.play()
}
} }
} }
} }
} }

View File

@@ -8,39 +8,37 @@ import kotlin.math.cos
/** /**
* Live-coding with [oliveProgram] * Live-coding with [oliveProgram]
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 1280
width = 1280 height = 720
height = 720
}
oliveProgram {
extend {
drawer.clear(ColorRGBa.PINK)
drawer.fill = ColorRGBa.WHITE
for (i in 0 until 100) {
drawer.circle(
width / 2.0 + cos(seconds + i) * 320.0,
i * 7.2,
cos(i + seconds * 0.5) * 20.0 + 20.0
)
}
}
}
// -- this is only needed for the automated screenshots
.olive.scriptLoaded.listen {
if (System.getProperty("takeScreenshot") == "true") {
// -- this is a bit of hack, we need to push the screenshot extension in front of the olive one
fun <T : Extension> extendHead(extension: T, configure: T.() -> Unit): T {
program.extensions.add(0, extension)
extension.configure()
extension.setup(program)
return extension
}
extendHead(SingleScreenshot()) {
this.outputFile = System.getProperty("screenshotPath")
}
}
}
} }
} oliveProgram {
extend {
drawer.clear(ColorRGBa.PINK)
drawer.fill = ColorRGBa.WHITE
for (i in 0 until 100) {
drawer.circle(
width / 2.0 + cos(seconds + i) * 320.0,
i * 7.2,
cos(i + seconds * 0.5) * 20.0 + 20.0
)
}
}
}
// -- this is only needed for the automated screenshots
.olive.scriptLoaded.listen {
if (System.getProperty("takeScreenshot") == "true") {
// -- this is a bit of hack, we need to push the screenshot extension in front of the olive one
fun <T : Extension> extendHead(extension: T, configure: T.() -> Unit): T {
program.extensions.add(0, extension)
extension.configure()
extension.setup(program)
return extension
}
extendHead(SingleScreenshot()) {
this.outputFile = System.getProperty("screenshotPath")
}
}
}
}

View File

@@ -9,6 +9,7 @@ import org.openrndr.draw.colorBuffer
import org.openrndr.draw.isolatedWithTarget import org.openrndr.draw.isolatedWithTarget
import org.openrndr.draw.renderTarget import org.openrndr.draw.renderTarget
import org.openrndr.extra.noise.Random import org.openrndr.extra.noise.Random
import org.openrndr.extra.noise.uniform
import org.openrndr.math.Polar import org.openrndr.math.Polar
import org.openrndr.math.clamp import org.openrndr.math.clamp
import org.openrndr.poissonfill.PoissonFill import org.openrndr.poissonfill.PoissonFill
@@ -34,11 +35,11 @@ fun main() {
val things = List(10) { val things = List(10) {
Thing( Thing(
ColorHSVa(it * 182.0, ColorHSVa(it * 182.0,
Random.double(0.3, 0.6), Double.uniform(0.3, 0.6),
Random.double(0.1, 0.9)).toRGBa(), Double.uniform(0.1, 0.9)).toRGBa(),
Polar(Random.double0(360.0), Polar(Double.uniform(0.0, 360.0),
100.0 + it * 10.0), 100.0 + it * 10.0),
Polar(Random.double(-1.0, 1.0), 0.0)) Polar(Double.uniform(-1.0, 1.0), 0.0))
} }
val mouseTracker = MouseTracker(mouse) val mouseTracker = MouseTracker(mouse)

View File

@@ -6,29 +6,27 @@ import org.openrndr.draw.colorBuffer
import org.openrndr.draw.tint import org.openrndr.draw.tint
import org.openrndr.extra.realsense2.RS2Sensor import org.openrndr.extra.realsense2.RS2Sensor
fun main() { fun main() = application {
application { program {
program { val sensors = RS2Sensor.listSensors()
val sensors = RS2Sensor.listSensors() val depthFrame = colorBuffer(640, 480, format = ColorFormat.R, type = ColorType.UINT16)
val depthFrame = colorBuffer(640, 480, format = ColorFormat.R, type = ColorType.UINT16) for (sensor in sensors) {
for (sensor in sensors) {
println(sensor)
}
val sensor = RS2Sensor.openFirstOrDummy()
println(sensor) println(sensor)
for (stream in sensor.streams) { }
println(stream.intrinsics) val sensor = RS2Sensor.openFirstOrDummy()
} println(sensor)
for (stream in sensor.streams) {
println(stream.intrinsics)
}
sensor.depthFrameReceived.listen { sensor.depthFrameReceived.listen {
it.copyTo(depthFrame) it.copyTo(depthFrame)
} }
extend { extend {
sensor.waitForFrames() sensor.waitForFrames()
drawer.drawStyle.colorMatrix = tint(ColorRGBa.WHITE.shade(20.0)) drawer.drawStyle.colorMatrix = tint(ColorRGBa.WHITE.shade(20.0))
drawer.image(depthFrame) drawer.image(depthFrame)
}
} }
} }
} }

View File

@@ -11,35 +11,33 @@ import org.openrndr.extra.realsense2.RS2Sensor
* *
* Tested with two sensors, only uses depth stream now * Tested with two sensors, only uses depth stream now
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 1280
width = 1280 height = 720
height = 720 }
program {
val sensorDescriptions = RS2Sensor.listSensors()
val sensors = sensorDescriptions.map {
it.open()
} }
program {
val sensorDescriptions = RS2Sensor.listSensors()
val sensors = sensorDescriptions.map { val depthFrames = sensors.map {
it.open() colorBuffer(640, 480, format = ColorFormat.R, type = ColorType.UINT16)
}
sensors.forEachIndexed { index, it ->
it.depthFrameReceived.listen {
it.copyTo(depthFrames[index])
} }
}
val depthFrames = sensors.map { extend {
colorBuffer(640, 480, format = ColorFormat.R, type = ColorType.UINT16) drawer.drawStyle.colorMatrix = tint(ColorRGBa.WHITE.shade(20.0))
} for ((index, sensor) in sensors.withIndex()) {
sensors.forEachIndexed { index, it -> sensor.waitForFrames()
it.depthFrameReceived.listen { drawer.image(depthFrames[index])
it.copyTo(depthFrames[index]) drawer.translate(640.0, 0.0)
}
}
extend {
drawer.drawStyle.colorMatrix = tint(ColorRGBa.WHITE.shade(20.0))
for ((index, sensor) in sensors.withIndex()) {
sensor.waitForFrames()
drawer.image(depthFrames[index])
drawer.translate(640.0, 0.0)
}
} }
} }
} }
} }

View File

@@ -1,9 +1,7 @@
import org.openrndr.application import org.openrndr.application
fun main() { fun main() = application {
application { program {
program {
}
} }
} }

View File

@@ -6,20 +6,13 @@ import org.openrndr.draw.shadeStyle
import org.openrndr.extra.camera.Orbital import org.openrndr.extra.camera.Orbital
import org.openrndr.extra.mesh.IIndexedPolygon import org.openrndr.extra.mesh.IIndexedPolygon
import org.openrndr.extra.mesh.IVertexData import org.openrndr.extra.mesh.IVertexData
import org.openrndr.extra.mesh.noise.nonuniform
import org.openrndr.extra.mesh.noise.nonuniformHammersley
import org.openrndr.extra.mesh.noise.nonuniformRSeq import org.openrndr.extra.mesh.noise.nonuniformRSeq
import org.openrndr.extra.objloader.loadOBJMeshData
import org.openrndr.extra.mesh.noise.uniform
import org.openrndr.extra.meshgenerators.normals.estimateNormals import org.openrndr.extra.meshgenerators.normals.estimateNormals
import org.openrndr.extra.meshgenerators.sphereMesh import org.openrndr.extra.meshgenerators.sphereMesh
import org.openrndr.math.Spherical import org.openrndr.extra.objloader.loadOBJMeshData
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
import java.io.File import java.io.File
import kotlin.math.absoluteValue
import kotlin.math.cos
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.sin
import kotlin.random.Random import kotlin.random.Random

View File

@@ -6,28 +6,26 @@ import org.openrndr.drawImage
import org.openrndr.extra.propertywatchers.watchingImagePath import org.openrndr.extra.propertywatchers.watchingImagePath
import org.openrndr.extra.propertywatchers.watchingProperty import org.openrndr.extra.propertywatchers.watchingProperty
fun main() { fun main() = application {
application { program {
program { val state = object {
val state = object { var path = "demo-data/images/image-001.png"
var path = "demo-data/images/image-001.png" val image by watchingImagePath(::path) {
val image by watchingImagePath(::path) { drawImage(it.width, it.height) {
drawImage(it.width, it.height) { drawer.drawStyle.colorMatrix = grayscale()
drawer.drawStyle.colorMatrix = grayscale() drawer.image(it)
drawer.image(it)
}
}
val redImage by watchingProperty(::image, cleaner = { it.destroy() }) {
drawImage(it.width, it.height) {
drawer.drawStyle.colorMatrix = tint(ColorRGBa.RED)
drawer.image(it)
}
} }
} }
val redImage by watchingProperty(::image, cleaner = { it.destroy() }) {
extend { drawImage(it.width, it.height) {
drawer.image(state.redImage) drawer.drawStyle.colorMatrix = tint(ColorRGBa.RED)
drawer.image(it)
}
} }
} }
extend {
drawer.image(state.redImage)
}
} }
} }

View File

@@ -1,22 +1,20 @@
import org.openrndr.application import org.openrndr.application
import org.openrndr.extra.propertywatchers.watchingProperty import org.openrndr.extra.propertywatchers.watchingProperty
fun main() { fun main() = application {
application { program {
program { val state = object {
val state = object { val x by watchingProperty(mouse::position) {
val x by watchingProperty(mouse::position) { it.x
it.x
}
val xx by watchingProperty(::x) {
it * it
}
} }
extend { val xx by watchingProperty(::x) {
state.x it * it
} }
} }
extend {
state.x
}
} }
} }

View File

@@ -7,42 +7,40 @@ import org.openrndr.extra.quadtree.Quadtree
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.shape.Rectangle import org.openrndr.shape.Rectangle
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 title = "QuadTree"
title = "QuadTree" }
program {
val box = Rectangle.fromCenter(Vector2(400.0), 750.0)
val points = (0 until 1_000).map {
Vector2.gaussian(box.center, Vector2(95.0), Random.rnd)
} }
program {
val box = Rectangle.fromCenter(Vector2(400.0), 750.0)
val points = (0 until 1_000).map { val quadTree = Quadtree<Vector2>(box) { it }
Vector2.gaussian(box.center, Vector2(95.0), Random.rnd)
}
val quadTree = Quadtree<Vector2>(box) { it } for (point in points) {
quadTree.insert(point)
}
for (point in points) { val batch = drawer.rectangleBatch {
quadTree.insert(point) this.fill = null
} this.stroke = ColorRGBa.GRAY
this.strokeWeight = 0.5
quadTree.batch(this)
}
val batch = drawer.rectangleBatch { extend {
this.fill = null drawer.clear(ColorRGBa.BLACK)
this.stroke = ColorRGBa.GRAY
this.strokeWeight = 0.5
quadTree.batch(this)
}
extend { drawer.rectangles(batch)
drawer.clear(ColorRGBa.BLACK)
drawer.rectangles(batch) drawer.fill = ColorRGBa.PINK.opacify(0.7)
drawer.stroke = null
drawer.fill = ColorRGBa.PINK.opacify(0.7) drawer.circles(points, 5.0)
drawer.stroke = null
drawer.circles(points, 5.0)
}
} }
} }
} }

View File

@@ -7,69 +7,67 @@ import org.openrndr.extra.quadtree.Quadtree
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.shape.Rectangle import org.openrndr.shape.Rectangle
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 title = "QuadTree"
title = "QuadTree" }
program {
val box = Rectangle.fromCenter(Vector2(400.0), 750.0)
val points = (0 until 100).map {
Vector2.gaussian(box.center, Vector2(95.0), Random.rnd)
} }
program {
val box = Rectangle.fromCenter(Vector2(400.0), 750.0)
val points = (0 until 100).map { val quadTree = Quadtree<Vector2>(box) { it }
Vector2.gaussian(box.center, Vector2(95.0), Random.rnd)
}
val quadTree = Quadtree<Vector2>(box) { it } for (point in points) {
quadTree.insert(point)
}
for (point in points) { val selected = points[3]
quadTree.insert(point) val radius = 40.0
}
val selected = points[3] val nearestQuery = quadTree.nearest(selected, radius)
val radius = 40.0
val nearestQuery = quadTree.nearest(selected, radius) val batch = drawer.rectangleBatch {
this.fill = null
this.stroke = ColorRGBa.GRAY
this.strokeWeight = 0.5
quadTree.batch(this)
}
val batch = drawer.rectangleBatch { extend {
this.fill = null drawer.clear(ColorRGBa.BLACK)
this.stroke = ColorRGBa.GRAY
this.strokeWeight = 0.5
quadTree.batch(this)
}
extend { drawer.rectangles(batch)
drawer.clear(ColorRGBa.BLACK)
drawer.rectangles(batch) drawer.fill = ColorRGBa.PINK.opacify(0.7)
drawer.stroke = null
drawer.circles(points, 5.0)
drawer.fill = ColorRGBa.PINK.opacify(0.7) nearestQuery?.let { (nearest, neighbours, nodes) ->
drawer.stroke = null drawer.stroke = null
drawer.circles(points, 5.0) drawer.fill = ColorRGBa.YELLOW.opacify(0.2)
nearestQuery?.let { (nearest, neighbours, nodes) -> for (node in nodes) {
drawer.stroke = null node.draw(drawer)
drawer.fill = ColorRGBa.YELLOW.opacify(0.2)
for (node in nodes) {
node.draw(drawer)
}
drawer.fill = ColorRGBa.GREEN.opacify(0.7)
drawer.circles(neighbours, 5.0)
drawer.fill = ColorRGBa.RED.opacify(0.9)
drawer.circle(nearest, 5.0)
drawer.fill = ColorRGBa.PINK
drawer.circle(selected, 5.0)
drawer.stroke = ColorRGBa.PINK
drawer.fill = null
drawer.circle(selected, radius)
} }
drawer.fill = ColorRGBa.GREEN.opacify(0.7)
drawer.circles(neighbours, 5.0)
drawer.fill = ColorRGBa.RED.opacify(0.9)
drawer.circle(nearest, 5.0)
drawer.fill = ColorRGBa.PINK
drawer.circle(selected, 5.0)
drawer.stroke = ColorRGBa.PINK
drawer.fill = null
drawer.circle(selected, radius)
} }
} }
} }
} }

View File

@@ -9,77 +9,81 @@ import org.openrndr.shape.Rectangle
* Example of 5 gradient styles. * Example of 5 gradient styles.
* NPointLinear and NPoingGradient have separate demos. * NPointLinear and NPoingGradient have separate demos.
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 1000
width = 1000 height = 500
height = 500 }
} program {
program { // Create gradients with initial colors
// Create gradients with initial colors val gradients = listOf(
val gradients = listOf( RadialGradient(ColorRGBa.PINK, ColorRGBa.WHITE),
RadialGradient(ColorRGBa.PINK, ColorRGBa.WHITE), AngularGradient(ColorRGBa.PINK, ColorRGBa.WHITE),
AngularGradient(ColorRGBa.PINK, ColorRGBa.WHITE), NPointGradient(Array(4) {
NPointGradient(Array(4) { ColorRGBa.PINK.shade(it / 3.0)
ColorRGBa.PINK.shade(it / 3.0) }),
}), LinearGradient(ColorRGBa.PINK, ColorRGBa.WHITE),
LinearGradient(ColorRGBa.PINK, ColorRGBa.WHITE), HalfAngularGradient(ColorRGBa.PINK, ColorRGBa.WHITE)
HalfAngularGradient(ColorRGBa.PINK, ColorRGBa.WHITE) )
)
extend { extend {
gradients.forEachIndexed { gradientId, gradient -> gradients.forEachIndexed { gradientId, gradient ->
for (column in 0 until 10) { for (column in 0 until 10) {
val color1 = ColorRGBa.PINK.toHSVa().shiftHue(column * 12.0) val color1 = ColorRGBa.PINK.toHSVa().shiftHue(column * 12.0)
.shade(0.5).toRGBa() .shade(0.5).toRGBa()
val w = width.toDouble() / 10.0 val w = width.toDouble() / 10.0
val h = height.toDouble() / gradients.size val h = height.toDouble() / gradients.size
val rect = Rectangle(column * w, gradientId * h, w, h) val rect = Rectangle(column * w, gradientId * h, w, h)
val offset = Polar((seconds + column) * 15.0, 0.3).cartesian val offset = Polar((seconds + column) * 15.0, 0.3).cartesian
drawer.isolated { drawer.isolated {
when (gradient) { when (gradient) {
is RadialGradient -> { is RadialGradient -> {
gradient.color1 = color1 gradient.color1 = color1
gradient.exponent = column / 3.0 + 0.3 gradient.exponent = column / 3.0 + 0.3
gradient.length = 0.6 gradient.length = 0.6
gradient.offset = offset gradient.offset = offset
} }
is AngularGradient -> {
gradient.color1 = color1 is AngularGradient -> {
gradient.exponent = column / 3.0 + 0.3 gradient.color1 = color1
gradient.rotation = (seconds - column) * 10.0 gradient.exponent = column / 3.0 + 0.3
gradient.offset = offset gradient.rotation = (seconds - column) * 10.0
} gradient.offset = offset
is LinearGradient -> { }
gradient.color1 = color1
gradient.exponent = column / 3.0 + 0.3 is LinearGradient -> {
gradient.rotation = seconds * 10.0 gradient.color1 = color1
} gradient.exponent = column / 3.0 + 0.3
is HalfAngularGradient -> { gradient.rotation = seconds * 10.0
gradient.color1 = color1 }
gradient.exponent = column / 3.0 + 0.3
gradient.rotation = (column - seconds) * 10.0 is HalfAngularGradient -> {
gradient.offset = offset gradient.color1 = color1
} gradient.exponent = column / 3.0 + 0.3
is NPointGradient -> { gradient.rotation = (column - seconds) * 10.0
// Animate points. gradient.offset = offset
// We could also animate colors. }
gradient.points = Array(gradient.colors.size) {
rect.center + Polar(it * 90.0 + is NPointGradient -> {
// Animate points.
// We could also animate colors.
gradient.points = Array(gradient.colors.size) {
rect.center + Polar(
it * 90.0 +
column * 36 - seconds * 10, column * 36 - seconds * 10,
40.0).cartesian 40.0
} ).cartesian
} }
} }
shadeStyle = gradient
rectangle(rect)
} }
shadeStyle = gradient
rectangle(rect)
} }
} }
} }
} }
} }
} }

View File

@@ -3,23 +3,21 @@ import org.openrndr.color.ColorRGBa
import org.openrndr.extra.color.spaces.toOKLABa import org.openrndr.extra.color.spaces.toOKLABa
import org.openrndr.extra.shadestyles.linearGradient import org.openrndr.extra.shadestyles.linearGradient
fun main() { fun main() = application {
application { program {
program { extend {
extend { drawer.shadeStyle = linearGradient(
drawer.shadeStyle = linearGradient( ColorRGBa.RED.toOKLABa(),
ColorRGBa.RED.toOKLABa(), ColorRGBa.BLUE.toOKLABa(),
ColorRGBa.BLUE.toOKLABa(), )
) drawer.rectangle(120.0, 40.0, 200.0, 400.0)
drawer.rectangle(120.0, 40.0, 200.0, 400.0)
drawer.shadeStyle = linearGradient( drawer.shadeStyle = linearGradient(
ColorRGBa.RED, ColorRGBa.RED,
ColorRGBa.BLUE ColorRGBa.BLUE
) )
drawer.rectangle(120.0+200.0, 40.0, 200.0, 400.0) drawer.rectangle(120.0 + 200.0, 40.0, 200.0, 400.0)
}
} }
} }
} }

View File

@@ -16,31 +16,29 @@ import kotlin.math.cos
* on a static shape (a circle for example) or you can animate a shape * on a static shape (a circle for example) or you can animate a shape
* with a static gradient. * with a static gradient.
*/ */
fun main() { fun main() = application {
application { program {
program { val numPoints = 8
val numPoints = 8 val gradient = NPointGradient(Array(numPoints) {
val gradient = NPointGradient(Array(numPoints) { ColorXSVa(it * 360.0 / numPoints, 1.0, 1.0).toRGBa()
ColorXSVa(it * 360.0 / numPoints, 1.0, 1.0).toRGBa() })
})
extend { extend {
drawer.run { drawer.run {
clear(ColorRGBa.WHITE.shade(0.9)) clear(ColorRGBa.WHITE.shade(0.9))
val t = PI * 2 * (frameCount % 300) / 300.0 val t = PI * 2 * (frameCount % 300) / 300.0
val points = Array(numPoints) { val points = Array(numPoints) {
val lfo = cos(it * PI / 2 - t) val lfo = cos(it * PI / 2 - t)
val theta = it * 360.0 / numPoints - 22.5 * lfo val theta = it * 360.0 / numPoints - 22.5 * lfo
val radius = 200 + 170 * lfo val radius = 200 + 170 * lfo
bounds.center + Polar(theta, radius).cartesian bounds.center + Polar(theta, radius).cartesian
}
gradient.points = points
shadeStyle = gradient
stroke = ColorRGBa.WHITE
strokeWeight = 4.0
contour(ShapeContour.fromPoints(points.asList(), true))
} }
gradient.points = points
shadeStyle = gradient
stroke = ColorRGBa.WHITE
strokeWeight = 4.0
contour(ShapeContour.fromPoints(points.asList(), true))
} }
} }
} }
} }

View File

@@ -15,52 +15,50 @@ import kotlin.math.sin
* uniformly between 0.0 and 1.0 and then animated towards one of * uniformly between 0.0 and 1.0 and then animated towards one of
* the ends over time using pow() and sin(seconds). * the ends over time using pow() and sin(seconds).
*/ */
fun main() { fun main() = application {
application { program {
program { val numPoints = 8
val numPoints = 8 // Create gradients using two different color spaces
// Create gradients using two different color spaces val gradients = listOf(
val gradients = listOf( NPointLinearGradient(Array(numPoints) {
NPointLinearGradient(Array(numPoints) { ColorXSVa(it * 360.0 / numPoints, 1.0, 1.0).toRGBa()
ColorXSVa(it * 360.0 / numPoints, 1.0, 1.0).toRGBa() }),
}), // OKLab is better at maintaining luminosity across the gradient
// OKLab is better at maintaining luminosity across the gradient NPointLinearGradientOKLab(Array(numPoints) {
NPointLinearGradientOKLab(Array(numPoints) { ColorXSVa(it * 360.0 / numPoints, 1.0, 1.0).toRGBa()
ColorXSVa(it * 360.0 / numPoints, 1.0, 1.0).toRGBa() .toOKLABa()
.toOKLABa() })
}) )
)
extend { extend {
// The points should be sorted values between 0.0 and 1.0 // The points should be sorted values between 0.0 and 1.0
val distribution = Array(numPoints) { val distribution = Array(numPoints) {
// uniform distribution // uniform distribution
// (it / (numPoints - 1.0)) // (it / (numPoints - 1.0))
// skewed and animated distribution // skewed and animated distribution
(it / (numPoints - 1.0)).pow(1.0 + 0.5 * sin(seconds)) (it / (numPoints - 1.0)).pow(1.0 + 0.5 * sin(seconds))
} }
drawer.run { drawer.run {
clear(rgb(0.2)) clear(rgb(0.2))
stroke = rgb(0.35) stroke = rgb(0.35)
strokeWeight = 8.0 strokeWeight = 8.0
gradients.forEachIndexed { i, gradient -> gradients.forEachIndexed { i, gradient ->
shadeStyle = gradient shadeStyle = gradient
gradient.points = distribution gradient.points = distribution
gradient.rotation = seconds * 10 gradient.rotation = seconds * 10
circle(bounds.position(0.34, 0.29 + 0.44 * i), 110.0) circle(bounds.position(0.34, 0.29 + 0.44 * i), 110.0)
gradient.rotation += 90 gradient.rotation += 90
rectangle( rectangle(
Rectangle.fromCenter( Rectangle.fromCenter(
bounds.position(0.655, 0.29 + 0.44 * i), 200.0 bounds.position(0.655, 0.29 + 0.44 * i), 200.0
)
) )
} )
} }
} }
} }
} }
} }

View File

@@ -6,35 +6,37 @@ import org.openrndr.shape.Circle
import kotlin.random.Random import kotlin.random.Random
/** /**
* Demonstrate using a multi color radial gradient. * Demonstrate using a multicolor radial gradient.
* The gradient has 5 colors (first and last ones are transparent). * The gradient has 5 colors (first and last ones are transparent).
* Any of the properties can be animated, including colors and points. * Any of the properties can be animated, including colors and points.
* See DemoNPointLinearGradient01.kt for an example of animated properties. * See DemoNPointLinearGradient01.kt for an example of animated properties.
*/ */
fun main() { fun main() = application {
application { program {
program { val gradient = NPointRadialGradient(
val gradient = NPointRadialGradient(arrayOf( arrayOf(
ColorRGBa.PINK.opacify(0.0), ColorRGBa.PINK.opacify(0.0),
ColorRGBa.PINK, ColorRGBa.WHITE, ColorRGBa.PINK, ColorRGBa.PINK, ColorRGBa.WHITE, ColorRGBa.PINK,
ColorRGBa.PINK.opacify(0.0) ColorRGBa.PINK.opacify(0.0)
), arrayOf(0.0, 0.4, 0.5, 0.6, 1.0)) ), arrayOf(0.0, 0.4, 0.5, 0.6, 1.0)
)
val circles = List(25) { val circles = List(25) {
Circle(Random.nextDouble() * drawer.width, Circle(
Random.nextDouble() * drawer.height, Random.nextDouble() * drawer.width,
Random.nextDouble() * 150.0) Random.nextDouble() * drawer.height,
} Random.nextDouble() * 150.0
)
}
extend { extend {
drawer.run { drawer.run {
clear(rgb(0.2)) clear(rgb(0.2))
shadeStyle = gradient shadeStyle = gradient
fill = ColorRGBa.WHITE fill = ColorRGBa.WHITE
stroke = null stroke = null
circles(circles) circles(circles)
}
} }
} }
} }
} }

View File

@@ -3,17 +3,15 @@ import org.openrndr.color.ColorRGBa
import org.openrndr.extra.shadestyles.radialGradient import org.openrndr.extra.shadestyles.radialGradient
import kotlin.math.cos import kotlin.math.cos
fun main() { fun main() = application {
application { program {
program { extend {
extend { drawer.shadeStyle = radialGradient(
drawer.shadeStyle = radialGradient( ColorRGBa.PINK,
ColorRGBa.PINK, ColorRGBa.PINK.toHSVa().shiftHue(180.0).shade(0.5).toRGBa(),
ColorRGBa.PINK.toHSVa().shiftHue(180.0).shade(0.5).toRGBa(), exponent = cos(seconds) * 0.5 + 0.5
exponent = cos(seconds)*0.5+0.5 )
) drawer.rectangle(120.0, 40.0, 400.0, 400.0)
drawer.rectangle(120.0, 40.0, 400.0, 400.0)
}
} }
} }
} }

View File

@@ -8,28 +8,26 @@ import org.openrndr.shape.Circle
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program { extend {
extend { var contour = Circle(drawer.bounds.center, 300.0).contour
var contour = Circle(drawer.bounds.center, 300.0).contour contour = adjustContour(contour) {
contour = adjustContour(contour) { selectVertex(0)
selectVertex(0) vertex.moveBy(Vector2(cos(seconds) * 40.0, sin(seconds * 0.43) * 40.0))
vertex.moveBy(Vector2(cos(seconds) * 40.0, sin(seconds * 0.43) * 40.0))
selectVertex(2) selectVertex(2)
vertex.rotate(seconds * 45.0) vertex.rotate(seconds * 45.0)
selectVertex(1) selectVertex(1)
vertex.scale(cos(seconds*0.943)*2.0) vertex.scale(cos(seconds * 0.943) * 2.0)
}
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
} }
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
} }
} }
} }

View File

@@ -8,27 +8,25 @@ import org.openrndr.shape.Circle
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program { extend {
extend { var contour = Circle(drawer.bounds.center, 300.0).contour
var contour = Circle(drawer.bounds.center, 300.0).contour contour = adjustContour(contour) {
contour = adjustContour(contour) { selectVertex(0)
selectVertex(0) vertex.remove()
vertex.remove() selectVertex(0)
selectVertex(0) vertex.moveBy(Vector2(cos(seconds) * 40.0, sin(seconds * 0.43) * 40.0))
vertex.moveBy(Vector2(cos(seconds) * 40.0, sin(seconds * 0.43) * 40.0)) vertex.scale(cos(seconds * 2.0) * 2.0)
vertex.scale(cos(seconds*2.0)*2.0)
}
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
} }
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
} }
} }
} }

View File

@@ -7,37 +7,35 @@ import org.openrndr.math.Vector2
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program { extend {
extend { var contour = drawer.bounds.scaledBy(0.5, 0.5, 0.5).contour
var contour = drawer.bounds.scaledBy(0.5, 0.5, 0.5).contour contour = adjustContour(contour) {
contour = adjustContour(contour) { for (i in 0 until 4) {
for (i in 0 until 4) { selectEdge(i)
selectEdge(i)
edge.toCubic()
}
selectEdge(0)
edge.scale(0.5, 0.5)
edge.rotate(cos(seconds*0.5)*30.0)
selectEdge(1)
edge.toCubic() edge.toCubic()
edge.splitAt(0.5)
edge.moveBy(Vector2(cos(seconds*10.0) * 40.0, 0.0))
//edge.next?.select()
selectEdge(3)
edge.moveBy(Vector2(0.0, sin(seconds*10.0) * 40.0))
} }
drawer.stroke = ColorRGBa.RED selectEdge(0)
drawer.contour(contour) edge.scale(0.5, 0.5)
edge.rotate(cos(seconds * 0.5) * 30.0)
selectEdge(1)
edge.toCubic()
edge.splitAt(0.5)
edge.moveBy(Vector2(cos(seconds * 10.0) * 40.0, 0.0))
//edge.next?.select()
selectEdge(3)
edge.moveBy(Vector2(0.0, sin(seconds * 10.0) * 40.0))
} }
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
} }
} }
} }

View File

@@ -6,26 +6,24 @@ import org.openrndr.extra.shapes.adjust.adjustContour
import org.openrndr.shape.Circle import org.openrndr.shape.Circle
import kotlin.math.cos import kotlin.math.cos
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program { extend {
extend { var contour = if (seconds.mod(2.0) < 1.0) {
var contour = if (seconds.mod(2.0) < 1.0) { drawer.bounds.scaledBy(0.5, 0.5, 0.5).contour
drawer.bounds.scaledBy(0.5, 0.5, 0.5).contour } else {
} else { Circle(drawer.bounds.center, 300.0).contour
Circle(drawer.bounds.center, 300.0).contour
}
contour = adjustContour(contour) {
selectEdge(0)
edge.replaceWith(cos(seconds) * 0.5 + 0.5)
}
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
} }
contour = adjustContour(contour) {
selectEdge(0)
edge.replaceWith(cos(seconds) * 0.5 + 0.5)
}
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
} }
} }
} }

View File

@@ -6,31 +6,29 @@ import org.openrndr.extra.shapes.adjust.adjustContour
import org.openrndr.shape.Circle import org.openrndr.shape.Circle
import kotlin.math.cos import kotlin.math.cos
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program { extend {
extend { var contour =
var contour = Circle(drawer.bounds.center, 300.0).contour
Circle(drawer.bounds.center, 300.0).contour
contour = adjustContour(contour) { contour = adjustContour(contour) {
selectEdges(0, 1, 2, 3) selectEdges(0, 1, 2, 3)
edges.forEachIndexed { index, it -> edges.forEachIndexed { index, it ->
if (index == seconds.mod(4.0).toInt()) { if (index == seconds.mod(4.0).toInt()) {
it.replaceWith(0.5) it.replaceWith(0.5)
} else { } else {
val v = cos(seconds) * 0.15 + 0.25 val v = cos(seconds) * 0.15 + 0.25
it.sub(0.5 - v, 0.5 + v) it.sub(0.5 - v, 0.5 + v)
}
} }
} }
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
} }
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
} }
} }
} }

View File

@@ -6,38 +6,36 @@ import org.openrndr.extra.shapes.adjust.adjustContour
import org.openrndr.shape.Circle import org.openrndr.shape.Circle
import kotlin.math.cos import kotlin.math.cos
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program { extend {
extend { var contour =
var contour = Circle(drawer.bounds.center, 300.0).contour
Circle(drawer.bounds.center, 300.0).contour
contour = adjustContour(contour) { contour = adjustContour(contour) {
parameters.clearSelectedVertices = true parameters.clearSelectedVertices = true
parameters.selectInsertedVertices = true parameters.selectInsertedVertices = true
for (i in 0 until 4) { for (i in 0 until 4) {
val splitT = cos(seconds + i * Math.PI*0.5)*0.2+0.5 val splitT = cos(seconds + i * Math.PI * 0.5) * 0.2 + 0.5
selectEdges { it -> true } selectEdges { it -> true }
for (e in edges) { for (e in edges) {
e.splitAt(splitT) e.splitAt(splitT)
} }
// as a resut of the clearSelectedVertices and selectInsertedVertices settings // as a resut of the clearSelectedVertices and selectInsertedVertices settings
// the vertex selection is set to the newly inserted vertices // the vertex selection is set to the newly inserted vertices
for ((index, v) in vertices.withIndex()) { for ((index, v) in vertices.withIndex()) {
v.scale(cos(seconds + i + index) * 0.5 * (1.0 / (1.0 + i)) + 1.0, drawer.bounds.center) v.scale(cos(seconds + i + index) * 0.5 * (1.0 / (1.0 + i)) + 1.0, drawer.bounds.center)
}
} }
} }
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
} }
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
} }
} }
} }

View File

@@ -7,36 +7,34 @@ import org.openrndr.math.Vector2
import org.openrndr.shape.contour import org.openrndr.shape.contour
import kotlin.math.cos import kotlin.math.cos
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program { extend {
extend { var contour = contour {
var contour = contour { moveTo(drawer.bounds.center - Vector2(300.0, 0.0))
moveTo(drawer.bounds.center - Vector2(300.0, 0.0)) lineTo(drawer.bounds.center + Vector2(300.0, 0.0))
lineTo(drawer.bounds.center + Vector2(300.0, 0.0))
}
contour = adjustContour(contour) {
selectEdge(0)
edge.splitIn(128)
val tr = cos(seconds) * 0.5 + 0.5
selectVertices { i, v -> v.t >= tr }
val anchor = contour.position(tr)
for (v in vertices) {
v.rotate((v.t - tr) * 2000.0, anchor)
v.scale(0.05, anchor)
}
}
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
} }
contour = adjustContour(contour) {
selectEdge(0)
edge.splitIn(128)
val tr = cos(seconds) * 0.5 + 0.5
selectVertices { i, v -> v.t >= tr }
val anchor = contour.position(tr)
for (v in vertices) {
v.rotate((v.t - tr) * 2000.0, anchor)
v.scale(0.05, anchor)
}
}
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
} }
} }
} }

View File

@@ -1,4 +1,4 @@
//package adjust package adjust
import org.openrndr.application import org.openrndr.application
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
@@ -6,46 +6,44 @@ import org.openrndr.extra.shapes.adjust.adjustContour
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.shape.contour import org.openrndr.shape.contour
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program { extend {
extend { var contour = contour {
var contour = contour { moveTo(drawer.bounds.position(0.5, 0.1) - Vector2(300.0, 0.0))
moveTo(drawer.bounds.position(0.5, 0.1) - Vector2(300.0, 0.0)) lineTo(drawer.bounds.position(0.5, 0.1) + Vector2(300.0, 0.0))
lineTo(drawer.bounds.position(0.5, 0.1) + Vector2(300.0, 0.0)) }
}
contour = adjustContour(contour) { contour = adjustContour(contour) {
selectVertex(0) selectVertex(0)
vertex.moveControlOutBy(Vector2(0.0, 100.0)) vertex.moveControlOutBy(Vector2(0.0, 100.0))
selectVertex(1) selectVertex(1)
vertex.moveControlInBy(Vector2(0.0, -100.0)) vertex.moveControlInBy(Vector2(0.0, -100.0))
}
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
contour = contour {
moveTo(drawer.bounds.position(0.5, 0.2) - Vector2(300.0, 0.0))
lineTo(drawer.bounds.position(0.5, 0.2) + Vector2(300.0, 0.0))
}
contour = adjustContour(contour) {
selectEdge(0)
edge.moveControl0By(Vector2(0.0, 100.0))
edge.moveControl1By(Vector2(0.0, -100.0))
}
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
} }
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
contour = contour {
moveTo(drawer.bounds.position(0.5, 0.2) - Vector2(300.0, 0.0))
lineTo(drawer.bounds.position(0.5, 0.2) + Vector2(300.0, 0.0))
}
contour = adjustContour(contour) {
selectEdge(0)
edge.moveControl0By(Vector2(0.0, 100.0))
edge.moveControl1By(Vector2(0.0, -100.0))
}
drawer.stroke = ColorRGBa.RED
drawer.contour(contour)
} }
} }
} }

View File

@@ -9,52 +9,50 @@ import org.openrndr.extra.shapes.tunni.tunniLine
import org.openrndr.extra.shapes.tunni.tunniPoint import org.openrndr.extra.shapes.tunni.tunniPoint
import kotlin.math.sqrt import kotlin.math.sqrt
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program { extend {
extend { drawer.clear(ColorRGBa.WHITE)
drawer.clear(ColorRGBa.WHITE) var contour = drawer.bounds.offsetEdges(-200.0).contour
var contour = drawer.bounds.offsetEdges(-200.0).contour
drawer.fill = null drawer.fill = null
contour = adjustContour(contour) { contour = adjustContour(contour) {
selectVertices(0, 1) selectVertices(0, 1)
for (v in vertices) { for (v in vertices) {
v.averageTangents() v.averageTangents()
v.scale(sqrt(2.0)) v.scale(sqrt(2.0))
v.rotate(45.0) v.rotate(45.0)
}
selectVertices(2)
for (v in vertices) {
v.switchTangents()
}
} }
drawer.stroke = ColorRGBa.BLACK
drawer.contour(contour)
drawer.stroke = ColorRGBa.RED selectVertices(2)
for (v in vertices) {
for (s in contour.segments) { v.switchTangents()
drawer.lineSegment(s.start, s.cubic.control[0])
drawer.lineSegment(s.end, s.cubic.control[1])
} }
drawer.fill = ColorRGBa.BLACK }
drawer.stroke = null drawer.stroke = ColorRGBa.BLACK
drawer.circles(contour.segments.map { it.start }, 5.0) drawer.contour(contour)
drawer.stroke = ColorRGBa.GRAY drawer.stroke = ColorRGBa.RED
for (s in contour.segments) {
drawer.lineSegment(s.tunniLine) for (s in contour.segments) {
drawer.fill = ColorRGBa.CYAN drawer.lineSegment(s.start, s.cubic.control[0])
drawer.circle(s.tunniPoint, 5.0) drawer.lineSegment(s.end, s.cubic.control[1])
} }
drawer.fill = ColorRGBa.BLACK
drawer.stroke = null
drawer.circles(contour.segments.map { it.start }, 5.0)
drawer.stroke = ColorRGBa.GRAY
for (s in contour.segments) {
drawer.lineSegment(s.tunniLine)
drawer.fill = ColorRGBa.CYAN
drawer.circle(s.tunniPoint, 5.0)
} }
} }
} }
} }

View File

@@ -12,91 +12,89 @@ import org.openrndr.math.Vector2
import org.openrndr.shape.Segment2D import org.openrndr.shape.Segment2D
import kotlin.math.cos import kotlin.math.cos
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program {
var res = drawer.bounds.offsetEdges(-200.0).contour var res = drawer.bounds.offsetEdges(-200.0).contour
var selectedSegments = emptyList<Segment2D>() var selectedSegments = emptyList<Segment2D>()
var selectedPoints = emptyList<Vector2>() var selectedPoints = emptyList<Vector2>()
val contourSeq = adjustContourSequence(res) { val contourSeq = adjustContourSequence(res) {
sequence { sequence {
for (i in 0 until 1000) { for (i in 0 until 1000) {
selectEdges() selectEdges()
selectVertices((i*7).mod(4)) selectVertices((i * 7).mod(4))
for (v in vertices) { for (v in vertices) {
for (j in 0 until 30) {
v.rotate(45.0/30.0)
yield(status)
}
}
selectVertices((i*3).mod(4))
for (v in vertices) {
yield(status)
}
selectVertices()
selectEdges(i.mod(4))
for (j in 0 until 30) { for (j in 0 until 30) {
for (e in edges) { v.rotate(45.0 / 30.0)
e.withTunniLine(e.tunniLine.position(0.5) + e.tunniLine.normal * cos(i.toDouble() + e.segmentIndex()) * 50.0/30.0) yield(status)
yield(status) }
} }
selectVertices((i * 3).mod(4))
for (v in vertices) {
yield(status)
}
selectVertices()
selectEdges(i.mod(4))
for (j in 0 until 30) {
for (e in edges) {
e.withTunniLine(e.tunniLine.position(0.5) + e.tunniLine.normal * cos(i.toDouble() + e.segmentIndex()) * 50.0 / 30.0)
yield(status)
} }
} }
} }
} }
}
launch { launch {
for (i in contourSeq) { for (i in contourSeq) {
res = i.contour res = i.contour
selectedPoints = i.selectedPoints selectedPoints = i.selectedPoints
selectedSegments = i.selectedSegments selectedSegments = i.selectedSegments
yield() yield()
} }
}
extend {
drawer.clear(ColorRGBa.WHITE)
drawer.stroke = ColorRGBa.BLACK
drawer.contour(res)
drawer.stroke = ColorRGBa.RED
for (s in res.segments) {
drawer.lineSegment(s.start, s.cubic.control[0])
drawer.lineSegment(s.end, s.cubic.control[1])
}
drawer.fill = ColorRGBa.BLACK
drawer.stroke = null
drawer.circles(res.segments.map { it.start }, 5.0)
drawer.stroke = ColorRGBa.GRAY
for (s in res.segments) {
drawer.lineSegment(s.tunniLine)
drawer.fill = ColorRGBa.CYAN
drawer.circle(s.tunniPoint, 5.0)
} }
drawer.stroke = ColorRGBa.MAGENTA
extend { drawer.strokeWeight = 3.0
drawer.clear(ColorRGBa.WHITE) for (s in selectedSegments) {
drawer.stroke = ColorRGBa.BLACK drawer.segment(s)
drawer.contour(res) }
for (p in selectedPoints) {
drawer.stroke = ColorRGBa.RED drawer.circle(p, 5.0)
for (s in res.segments) {
drawer.lineSegment(s.start, s.cubic.control[0])
drawer.lineSegment(s.end, s.cubic.control[1])
}
drawer.fill = ColorRGBa.BLACK
drawer.stroke = null
drawer.circles(res.segments.map { it.start }, 5.0)
drawer.stroke = ColorRGBa.GRAY
for (s in res.segments) {
drawer.lineSegment(s.tunniLine)
drawer.fill = ColorRGBa.CYAN
drawer.circle(s.tunniPoint, 5.0)
}
drawer.stroke = ColorRGBa.MAGENTA
drawer.strokeWeight = 3.0
for (s in selectedSegments) {
drawer.segment(s)
}
for (p in selectedPoints) {
drawer.circle(p, 5.0)
}
} }
} }
} }
} }

View File

@@ -12,33 +12,34 @@ import org.openrndr.shape.Circle
import kotlin.math.sqrt import kotlin.math.sqrt
import kotlin.random.Random import kotlin.random.Random
fun main() { fun main() = application {
application { program {
program { val circles = listOf(
val circles = listOf( Circle(drawer.bounds.center - Vector2(50.0, 0.0), 50.0),
Circle(drawer.bounds.center -Vector2(50.0, 0.0), 50.0), Circle(drawer.bounds.center + Vector2(50.0, 0.0), 50.0),
Circle(drawer.bounds.center + Vector2(50.0, 0.0), 50.0), Circle(drawer.bounds.center + Vector2(0.0, 50.0), 50.0),
Circle(drawer.bounds.center + Vector2(0.0, 50.0), 50.0), Circle(drawer.bounds.center - Vector2(0.0, 50.0), 50.0),
Circle(drawer.bounds.center - Vector2(0.0, 50.0), 50.0), Circle(drawer.bounds.center - Vector2(50.0, 0.0), sqrt(50.0 * 50.0 + 50.0 * 50.0) - 49.9),
Circle(drawer.bounds.center -Vector2(50.0, 0.0), sqrt(50.0*50.0+50.0*50.0)-49.9), Circle(drawer.bounds.center + Vector2(50.0, 0.0), sqrt(50.0 * 50.0 + 50.0 * 50.0) - 49.9),
Circle(drawer.bounds.center +Vector2(50.0, 0.0), sqrt(50.0*50.0+50.0*50.0)-49.9), Circle(drawer.bounds.center - Vector2(0.0, 50.0), sqrt(50.0 * 50.0 + 50.0 * 50.0) - 49.9),
Circle(drawer.bounds.center -Vector2(0.0, 50.0), sqrt(50.0*50.0+50.0*50.0)-49.9), Circle(drawer.bounds.center + Vector2(0.0, 50.0), sqrt(50.0 * 50.0 + 50.0 * 50.0) - 49.9),
Circle(drawer.bounds.center +Vector2(0.0, 50.0), sqrt(50.0*50.0+50.0*50.0)-49.9), ).shuffled()
).shuffled()
val arr = Arrangement(circles) val arr = Arrangement(circles)
extend { extend {
val r = Random(100) val r = Random(100)
drawer.stroke = ColorRGBa.WHITE drawer.stroke = ColorRGBa.WHITE
for (f in arr.boundedFaces) { for (f in arr.boundedFaces) {
drawer.fill = drawer.fill =
rgb(Double.uniform(0.0, 1.0, r), Double.uniform(0.0, 1.0, r), Double.uniform(0.0, 1.0, r)).saturate<OKHSV>(0.25) rgb(
drawer.contour(f.contour) Double.uniform(0.0, 1.0, r),
} Double.uniform(0.0, 1.0, r),
Double.uniform(0.0, 1.0, r)
).saturate<OKHSV>(0.25)
drawer.contour(f.contour)
} }
} }
} }
} }

View File

@@ -15,42 +15,40 @@ import org.openrndr.shape.ShapeContour
* The created contours are horizontal and vertical in "bezier-patch space" but * The created contours are horizontal and vertical in "bezier-patch space" but
* are rendered deformed following the shape of the bezier patch. * are rendered deformed following the shape of the bezier patch.
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program { // helper to get screen locations using normalized uv values
// helper to get screen locations using normalized uv values fun pos(u: Double, v: Double) = drawer.bounds.position(u, v)
fun pos(u: Double, v: Double) = drawer.bounds.position(u, v) val c0 = LineSegment(pos(0.1, 0.1), pos(0.9, 0.1))
val c0 = LineSegment(pos(0.1, 0.1), pos(0.9, 0.1)) val c1 = LineSegment(pos(0.4, 0.3), pos(0.6, 0.4))
val c1 = LineSegment(pos(0.4, 0.3), pos(0.6, 0.4)) val c2 = LineSegment(pos(0.4, 0.7), pos(0.6, 0.6))
val c2 = LineSegment(pos(0.4, 0.7), pos(0.6, 0.6)) val c3 = LineSegment(pos(0.1, 0.9), pos(0.9, 0.9))
val c3 = LineSegment(pos(0.1, 0.9), pos(0.9, 0.9))
val bp = bezierPatch(c0.segment, c1.segment, c2.segment, c3.segment) val bp = bezierPatch(c0.segment, c1.segment, c2.segment, c3.segment)
val bpSub = bp.sub(0.1, 0.1, 0.6,0.6) val bpSub = bp.sub(0.1, 0.1, 0.6, 0.6)
extend { extend {
drawer.clear(ColorRGBa.PINK) drawer.clear(ColorRGBa.PINK)
// Show the line segments that form the bezier patch // Show the line segments that form the bezier patch
drawer.stroke = ColorRGBa.YELLOW drawer.stroke = ColorRGBa.YELLOW
drawer.strokeWeight = 5.0 drawer.strokeWeight = 5.0
drawer.lineSegments(listOf(c0, c1, c2, c3)) drawer.lineSegments(listOf(c0, c1, c2, c3))
drawer.strokeWeight = 1.0 drawer.strokeWeight = 1.0
for (i in 0..50) { for (i in 0..50) {
drawer.stroke = ColorRGBa.BLACK drawer.stroke = ColorRGBa.BLACK
drawer.contour(bp.horizontal(i / 50.0)) drawer.contour(bp.horizontal(i / 50.0))
drawer.contour(bp.vertical(i / 50.0)) drawer.contour(bp.vertical(i / 50.0))
drawer.stroke = ColorRGBa.RED drawer.stroke = ColorRGBa.RED
drawer.contour(bpSub.horizontal(i / 50.0)) drawer.contour(bpSub.horizontal(i / 50.0))
drawer.contour(bpSub.vertical(i / 50.0)) drawer.contour(bpSub.vertical(i / 50.0))
}
} }
} }
} }
} }

View File

@@ -15,25 +15,23 @@ import org.openrndr.shape.ShapeContour
* but one can manually create any other 4-segment closed contour * but one can manually create any other 4-segment closed contour
* to use in bezier patches. * to use in bezier patches.
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program { val c = Circle(width / 2.0, height / 2.0, 350.0).contour
val c = Circle(width / 2.0, height / 2.0, 350.0).contour val bp = bezierPatch(c)
val bp = bezierPatch(c)
extend { extend {
drawer.clear(ColorRGBa.PINK) drawer.clear(ColorRGBa.PINK)
drawer.stroke = ColorRGBa.BLACK drawer.stroke = ColorRGBa.BLACK
for (i in 0..10) { for (i in 0..10) {
drawer.contour(bp.horizontal(i / 10.0)) drawer.contour(bp.horizontal(i / 10.0))
drawer.contour(bp.vertical(i / 10.0)) drawer.contour(bp.vertical(i / 10.0))
}
} }
} }
} }
} }

View File

@@ -15,44 +15,42 @@ import org.openrndr.shape.ShapeContour
* In this case the contours are regular stars and the bezier patch * In this case the contours are regular stars and the bezier patch
* is created using a circular contour with the required 4 segments. * is created using a circular contour with the required 4 segments.
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program { val bp = bezierPatch(
val bp = bezierPatch( Circle(width / 2.0, height / 2.0, 350.0).contour
Circle(width / 2.0, height / 2.0, 350.0).contour )
) val star = regularStarRounded(
val star = regularStarRounded( 7, 30.0, 40.0,
7, 30.0, 40.0, 0.5, 0.5
0.5, 0.5 )
)
extend { extend {
drawer.clear(ColorRGBa.PINK) drawer.clear(ColorRGBa.PINK)
// draw grid // draw grid
for (i in 0..50) { for (i in 0..50) {
drawer.stroke = ColorRGBa.BLACK drawer.stroke = ColorRGBa.BLACK
drawer.contour(bp.horizontal(i / 50.0)) drawer.contour(bp.horizontal(i / 50.0))
drawer.contour(bp.vertical(i / 50.0)) drawer.contour(bp.vertical(i / 50.0))
} }
// draw stars // draw stars
drawer.fill = ColorRGBa.PINK drawer.fill = ColorRGBa.PINK
for (j in 1 until 10) { for (j in 1 until 10) {
for (i in 1 until 10) { for (i in 1 until 10) {
val starMoved = star.transform( val starMoved = star.transform(
transform { transform {
translate(j * width / 10.0, i * height / 10.0) translate(j * width / 10.0, i * height / 10.0)
} }
) )
drawer.contour(bp.distort(starMoved, drawer.bounds)) drawer.contour(bp.distort(starMoved, drawer.bounds))
}
} }
} }
} }
} }
} }

View File

@@ -12,35 +12,33 @@ import org.openrndr.shape.Circle
* You can think of bezierPatch.position() as requesting points * You can think of bezierPatch.position() as requesting points
* in a wavy flag (the bezier patch) using normalized uv coordinates. * in a wavy flag (the bezier patch) using normalized uv coordinates.
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program { val bp = bezierPatch(
val bp = bezierPatch( Circle(drawer.bounds.center, 350.0).contour
Circle(drawer.bounds.center, 350.0).contour //Rectangle.fromCenter(drawer.bounds.center, 550.0).contour
//Rectangle.fromCenter(drawer.bounds.center, 550.0).contour )
)
extend { extend {
drawer.clear(ColorRGBa.PINK) drawer.clear(ColorRGBa.PINK)
drawer.stroke = ColorRGBa.BLACK drawer.stroke = ColorRGBa.BLACK
for (j in 1 until 50 step 2) { for (j in 1 until 50 step 2) {
for (i in 1 until 50 step 2) { for (i in 1 until 50 step 2) {
val u = i / 50.0 val u = i / 50.0
val v = j / 50.0 val v = j / 50.0
val pos = bp.position(u, v) val pos = bp.position(u, v)
val grad = bp.gradient(u, v).normalized * 10.0 val grad = bp.gradient(u, v).normalized * 10.0
val perpendicular = grad.perpendicular() val perpendicular = grad.perpendicular()
drawer.lineSegment(pos - grad, pos + grad) drawer.lineSegment(pos - grad, pos + grad)
drawer.lineSegment(pos - perpendicular, pos + perpendicular) drawer.lineSegment(pos - perpendicular, pos + perpendicular)
//drawer.circle(pos + grad, 3.0) //drawer.circle(pos + grad, 3.0)
}
} }
} }
} }
} }
} }

View File

@@ -3,8 +3,8 @@ package bezierpatch
import org.openrndr.WindowMultisample import org.openrndr.WindowMultisample
import org.openrndr.application import org.openrndr.application
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.extra.shapes.bezierpatches.bezierPatch
import org.openrndr.extra.camera.Orbital import org.openrndr.extra.camera.Orbital
import org.openrndr.extra.shapes.bezierpatches.bezierPatch
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
import org.openrndr.shape.Segment3D import org.openrndr.shape.Segment3D
@@ -19,56 +19,54 @@ import org.openrndr.shape.Segment3D
* The created contours are horizontal and vertical in "bezier-patch space" but * The created contours are horizontal and vertical in "bezier-patch space" but
* are rendered deformed following the shape of the bezier patch. * are rendered deformed following the shape of the bezier patch.
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 multisample = WindowMultisample.SampleCount(8)
multisample = WindowMultisample.SampleCount(8) }
program {
val c0 = Segment3D(Vector3(-5.0, 0.0, -9.0), Vector3(5.0, 0.0, -9.0))
val c1 = Segment3D(Vector3(-5.0, -5.0, -3.0), Vector3(5.0, -5.0, -3.0))
val c2 = Segment3D(Vector3(-5.0, 5.0, 3.0), Vector3(5.0, 5.0, 3.0))
val c3 = Segment3D(Vector3(-5.0, 0.0, 9.0), Vector3(5.0, 0.0, 9.0))
val col = listOf(ColorRGBa.PINK, ColorRGBa.RED, ColorRGBa.BLUE, ColorRGBa.PINK)
val cols = listOf(col, col, col, col)
val bp = bezierPatch(c0, c1, c2, c3).withColors(cols)
val bpSub = bp.sub(0.1, 0.1, 0.6, 0.6)
val cam = Orbital()
extend(cam) {
eye = Vector3(x = 9.9, y = 12.8, z = 6.9)
lookAt = Vector3(x = 1.6, y = -1.9, z = 1.2)
} }
program {
val c0 = Segment3D(Vector3(-5.0, 0.0, -9.0), Vector3(5.0, 0.0, -9.0))
val c1 = Segment3D(Vector3(-5.0, -5.0, -3.0), Vector3(5.0, -5.0, -3.0))
val c2 = Segment3D(Vector3(-5.0, 5.0, 3.0), Vector3(5.0, 5.0, 3.0))
val c3 = Segment3D(Vector3(-5.0, 0.0, 9.0), Vector3(5.0, 0.0, 9.0))
val col = listOf(ColorRGBa.PINK, ColorRGBa.RED, ColorRGBa.BLUE, ColorRGBa.PINK) extend {
val cols = listOf(col, col, col, col) drawer.clear(ColorRGBa.PINK)
val bp = bezierPatch(c0, c1, c2, c3).withColors(cols)
val bpSub = bp.sub(0.1, 0.1, 0.6, 0.6)
val cam = Orbital() drawer.translate(-5.0, 0.0, 0.0)
extend(cam){ // Show the segments that form the bezier patch
eye = Vector3(x=9.9, y=12.8, z=6.9) drawer.stroke = ColorRGBa.YELLOW
lookAt = Vector3(x=1.6, y=-1.9, z=1.2) drawer.strokeWeight = 50.0
drawer.segments(listOf(c0, c1, c2, c3))
// Show the grid
drawer.strokeWeight = 1.0
val n = 10
for (i in 0..n) {
drawer.stroke = ColorRGBa.BLACK
drawer.lineStrip(bp.horizontal(i / n.toDouble()).adaptivePositions(0.01))
drawer.lineStrip(bp.vertical(i / n.toDouble()).adaptivePositions(0.01))
drawer.stroke = ColorRGBa.RED
drawer.lineStrip(bpSub.horizontal(i / n.toDouble()).adaptivePositions(0.01))
drawer.lineStrip(bpSub.vertical(i / n.toDouble()).adaptivePositions(0.01))
} }
extend { // Draw the colored Bezier surface
drawer.clear(ColorRGBa.PINK) drawer.translate(10.0, 0.0, 0.0)
drawer.bezierPatch(bp)
drawer.translate(-5.0, 0.0, 0.0)
// Show the segments that form the bezier patch
drawer.stroke = ColorRGBa.YELLOW
drawer.strokeWeight = 50.0
drawer.segments(listOf(c0, c1, c2, c3))
// Show the grid
drawer.strokeWeight = 1.0
val n = 10
for (i in 0..n) {
drawer.stroke = ColorRGBa.BLACK
drawer.lineStrip(bp.horizontal(i / n.toDouble()).adaptivePositions(0.01))
drawer.lineStrip(bp.vertical(i / n.toDouble()).adaptivePositions(0.01))
drawer.stroke = ColorRGBa.RED
drawer.lineStrip(bpSub.horizontal(i / n.toDouble()).adaptivePositions(0.01))
drawer.lineStrip(bpSub.vertical(i / n.toDouble()).adaptivePositions(0.01))
}
// Draw the colored Bezier surface
drawer.translate(10.0, 0.0, 0.0)
drawer.bezierPatch(bp)
}
} }
} }
} }

View File

@@ -5,33 +5,31 @@ import org.openrndr.color.ColorRGBa
import org.openrndr.extra.shapes.bezierpatches.bezierPatch import org.openrndr.extra.shapes.bezierpatches.bezierPatch
import org.openrndr.shape.Circle import org.openrndr.shape.Circle
fun main() { fun main() = application {
application { program {
program { extend {
extend { drawer.clear(ColorRGBa.PINK)
drawer.clear(ColorRGBa.PINK) val bp = bezierPatch(
val bp = bezierPatch( Circle(width / 2.0, height / 2.0, 200.0).contour
Circle(width/2.0, height/2.0, 200.0).contour ).withColors(
).withColors( listOf(
listOf(
listOf(ColorRGBa.PINK, ColorRGBa.RED, ColorRGBa.BLACK, ColorRGBa.BLUE), listOf(ColorRGBa.PINK, ColorRGBa.RED, ColorRGBa.BLACK, ColorRGBa.BLUE),
listOf(ColorRGBa.RED, ColorRGBa.BLACK, ColorRGBa.BLUE, ColorRGBa.GREEN), listOf(ColorRGBa.RED, ColorRGBa.BLACK, ColorRGBa.BLUE, ColorRGBa.GREEN),
listOf(ColorRGBa.PINK, ColorRGBa.RED, ColorRGBa.WHITE, ColorRGBa.GREEN), listOf(ColorRGBa.PINK, ColorRGBa.RED, ColorRGBa.WHITE, ColorRGBa.GREEN),
listOf(ColorRGBa.BLACK, ColorRGBa.WHITE, ColorRGBa.BLACK, ColorRGBa.BLUE), listOf(ColorRGBa.BLACK, ColorRGBa.WHITE, ColorRGBa.BLACK, ColorRGBa.BLUE),
)
) )
)
drawer.bezierPatch(bp) drawer.bezierPatch(bp)
drawer.fill = null drawer.fill = null
drawer.contour(bp.contour) drawer.contour(bp.contour)
for (i in 0 until 10) { for (i in 0 until 10) {
drawer.contour(bp.horizontal(i/9.0)) drawer.contour(bp.horizontal(i / 9.0))
} }
for (i in 0 until 10) { for (i in 0 until 10) {
drawer.contour(bp.vertical(i/9.0)) drawer.contour(bp.vertical(i / 9.0))
}
} }
} }
} }
} }

View File

@@ -7,43 +7,61 @@ import org.openrndr.extra.color.spaces.toOKLABa
import org.openrndr.extra.shapes.bezierpatches.bezierPatch import org.openrndr.extra.shapes.bezierpatches.bezierPatch
import org.openrndr.shape.Circle import org.openrndr.shape.Circle
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { extend {
extend { drawer.clear(ColorRGBa.BLACK)
drawer.clear(ColorRGBa.BLACK) val bp2 = bezierPatch(
val bp2 = bezierPatch( Circle(width / 2.0 - 180.0, height / 2.0, 170.0).contour
Circle(width/2.0 - 180.0, height/2.0, 170.0).contour ).withColors(
).withColors( listOf(
listOf(
listOf(ColorRGBa.PINK, ColorRGBa.PINK, ColorRGBa.PINK, ColorRGBa.PINK), listOf(ColorRGBa.PINK, ColorRGBa.PINK, ColorRGBa.PINK, ColorRGBa.PINK),
listOf(ColorRGBa.RED, ColorRGBa.RED, ColorRGBa.RED, ColorRGBa.RED), listOf(ColorRGBa.RED, ColorRGBa.RED, ColorRGBa.RED, ColorRGBa.RED),
listOf(ColorRGBa.BLUE, ColorRGBa.BLUE, ColorRGBa.BLUE, ColorRGBa.BLUE), listOf(ColorRGBa.BLUE, ColorRGBa.BLUE, ColorRGBa.BLUE, ColorRGBa.BLUE),
listOf(ColorRGBa.WHITE, ColorRGBa.WHITE, ColorRGBa.WHITE, ColorRGBa.WHITE), listOf(ColorRGBa.WHITE, ColorRGBa.WHITE, ColorRGBa.WHITE, ColorRGBa.WHITE),
)
) )
drawer.bezierPatch(bp2) )
val bp3 = bezierPatch( drawer.bezierPatch(bp2)
Circle(width/2.0 + 180.0, height/2.0, 170.0).contour val bp3 = bezierPatch(
).withColors( Circle(width / 2.0 + 180.0, height / 2.0, 170.0).contour
).withColors(
listOf(
listOf( listOf(
listOf(ColorRGBa.PINK.toOKLABa(), ColorRGBa.PINK.toOKLABa(), ColorRGBa.PINK.toOKLABa(), ColorRGBa.PINK.toOKLABa()), ColorRGBa.PINK.toOKLABa(),
listOf(ColorRGBa.RED.toOKLABa(), ColorRGBa.RED.toOKLABa(), ColorRGBa.RED.toOKLABa(), ColorRGBa.RED.toOKLABa()), ColorRGBa.PINK.toOKLABa(),
listOf(ColorRGBa.BLUE.toOKLABa(), ColorRGBa.BLUE.toOKLABa(), ColorRGBa.BLUE.toOKLABa(), ColorRGBa.BLUE.toOKLABa()), ColorRGBa.PINK.toOKLABa(),
listOf(ColorRGBa.WHITE.toOKLABa(), ColorRGBa.WHITE.toOKLABa(), ColorRGBa.WHITE.toOKLABa(), ColorRGBa.WHITE.toOKLABa()), ColorRGBa.PINK.toOKLABa()
) ),
listOf(
ColorRGBa.RED.toOKLABa(),
ColorRGBa.RED.toOKLABa(),
ColorRGBa.RED.toOKLABa(),
ColorRGBa.RED.toOKLABa()
),
listOf(
ColorRGBa.BLUE.toOKLABa(),
ColorRGBa.BLUE.toOKLABa(),
ColorRGBa.BLUE.toOKLABa(),
ColorRGBa.BLUE.toOKLABa()
),
listOf(
ColorRGBa.WHITE.toOKLABa(),
ColorRGBa.WHITE.toOKLABa(),
ColorRGBa.WHITE.toOKLABa(),
ColorRGBa.WHITE.toOKLABa()
),
) )
drawer.bezierPatch(bp3) )
drawer.bezierPatch(bp3)
drawer.fill = ColorRGBa.WHITE drawer.fill = ColorRGBa.WHITE
drawer.fontMap = loadFont("demo-data/fonts/IBMPlexMono-Regular.ttf", 16.0) drawer.fontMap = loadFont("demo-data/fonts/IBMPlexMono-Regular.ttf", 16.0)
drawer.text("RGB", width/2.0 - 180.0, height/2.0 + 200.0) drawer.text("RGB", width / 2.0 - 180.0, height / 2.0 + 200.0)
drawer.text("OKLab", width/2.0 + 180.0, height/2.0 + 200.0) drawer.text("OKLab", width / 2.0 + 180.0, height / 2.0 + 200.0)
}
} }
} }
} }

View File

@@ -13,49 +13,67 @@ import org.openrndr.shape.Circle
import org.openrndr.shape.Rectangle import org.openrndr.shape.Rectangle
import kotlin.math.min import kotlin.math.min
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { extend {
extend { drawer.clear(ColorRGBa.BLACK)
drawer.clear(ColorRGBa.BLACK) val colors = listOf(
val colors = listOf( listOf(
listOf(ColorRGBa.PINK.toOKLABa(), ColorRGBa.PINK.toOKLABa(), ColorRGBa.PINK.toOKLABa(), ColorRGBa.PINK.toOKLABa()), ColorRGBa.PINK.toOKLABa(),
listOf(ColorRGBa.RED.toOKLABa(), ColorRGBa.RED.toOKLABa(), ColorRGBa.RED.toOKLABa(), ColorRGBa.RED.toOKLABa()), ColorRGBa.PINK.toOKLABa(),
listOf(ColorRGBa.BLUE.toOKLABa(), ColorRGBa.BLUE.toOKLABa(), ColorRGBa.BLUE.toOKLABa(), ColorRGBa.BLUE.toOKLABa()), ColorRGBa.PINK.toOKLABa(),
listOf(ColorRGBa.WHITE.toOKLABa(), ColorRGBa.WHITE.toOKLABa(), ColorRGBa.WHITE.toOKLABa(), ColorRGBa.WHITE.toOKLABa()), ColorRGBa.PINK.toOKLABa()
),
listOf(
ColorRGBa.RED.toOKLABa(),
ColorRGBa.RED.toOKLABa(),
ColorRGBa.RED.toOKLABa(),
ColorRGBa.RED.toOKLABa()
),
listOf(
ColorRGBa.BLUE.toOKLABa(),
ColorRGBa.BLUE.toOKLABa(),
ColorRGBa.BLUE.toOKLABa(),
ColorRGBa.BLUE.toOKLABa()
),
listOf(
ColorRGBa.WHITE.toOKLABa(),
ColorRGBa.WHITE.toOKLABa(),
ColorRGBa.WHITE.toOKLABa(),
ColorRGBa.WHITE.toOKLABa()
),
)
val grid = drawer.bounds.grid(4, 4, marginX = 20.0, marginY = 20.0, gutterX = 10.0, gutterY = 10.0)
val cellWidth = grid[0][0].width
val cellHeight = grid[0][0].height
val a = bezierPatch(Rectangle.fromCenter(Vector2(0.0, 0.0), cellWidth, cellHeight).contour)
.withColors(colors)
val b = bezierPatch(
Circle(0.0, 0.0, min(cellWidth, cellHeight) / 2.0).contour.transform(
buildTransform {
rotate(Vector3.UNIT_Z, 45.0)
}
) )
).withColors(colors)
val grid = drawer.bounds.grid(4,4, marginX = 20.0, marginY = 20.0, gutterX = 10.0, gutterY = 10.0) for (y in grid.indices) {
for (x in grid[y].indices) {
val cellWidth = grid[0][0].width val f = (y * grid[y].size + x).toDouble() / (grid.size * grid[y].size - 1.0)
val cellHeight = grid[0][0].height val blend = a * (1.0 - f) + b * f
drawer.isolated {
val a = bezierPatch(Rectangle.fromCenter(Vector2(0.0, 0.0), cellWidth, cellHeight).contour) drawer.translate(grid[y][x].center)
.withColors(colors) drawer.bezierPatch(blend)
val b = bezierPatch(
Circle(0.0, 0.0, min(cellWidth, cellHeight) / 2.0).contour.transform(
buildTransform {
rotate(Vector3.UNIT_Z, 45.0)
}
)
).withColors(colors)
for (y in grid.indices) {
for (x in grid[y].indices) {
val f = (y * grid[y].size + x).toDouble() / (grid.size * grid[y].size - 1.0)
val blend = a * (1.0 - f) + b * f
drawer.isolated {
drawer.translate(grid[y][x].center)
drawer.bezierPatch(blend)
}
} }
} }
} }
} }
} }
} }

View File

@@ -15,23 +15,21 @@ import org.openrndr.shape.ShapeContour
* but one can manually create any other 4-segment closed contour * but one can manually create any other 4-segment closed contour
* to use in bezier patches. * to use in bezier patches.
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program { val c0 = Circle(width / 3.0, height / 2.0, 150.0).contour
val c0 = Circle(width / 3.0, height / 2.0, 150.0).contour val bp0 = bezierPatch(c0)
val bp0 = bezierPatch(c0)
val c1 = Circle(2.0*width / 3.0, height / 2.0, 150.0).contour val c1 = Circle(2.0 * width / 3.0, height / 2.0, 150.0).contour
val bp1 = bezierPatch(c1) val bp1 = bezierPatch(c1)
extend { extend {
drawer.bezierPatches(listOf(bp0, bp1)) drawer.bezierPatches(listOf(bp0, bp1))
}
} }
} }
} }

View File

@@ -10,28 +10,25 @@ import org.openrndr.shape.Circle
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.cos import kotlin.math.cos
/** /**
* Demonstration of uniform contour blending * Demonstration of uniform contour blending
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { val a = Circle(Vector2.ZERO, 90.0).contour
val a = Circle(Vector2.ZERO, 90.0).contour val b = regularStar(5, 30.0, 90.0, center = Vector2.ZERO, phase = 180.0)
val b = regularStar(5, 30.0, 90.0, center = Vector2.ZERO, phase = 180.0) val blend = a.blend(b)
val blend = a.blend(b) extend {
extend { drawer.bounds.grid(3, 3).flatten().forEachIndexed { index, it ->
drawer.bounds.grid(3, 3).flatten().forEachIndexed { index, it -> drawer.isolated {
drawer.isolated { drawer.translate(it.center)
drawer.translate(it.center) drawer.contour(blend.mix(cos(index * PI * 2.0 / 9.0 + seconds) * 0.5 + 0.5))
drawer.contour(blend.mix(cos(index * PI * 2.0 / 9.0 + seconds) * 0.5 + 0.5))
}
} }
} }
} }
} }
} }

View File

@@ -14,26 +14,24 @@ import kotlin.math.cos
/** /**
* Demonstration of non-uniform contour blending * Demonstration of non-uniform contour blending
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { val a = Circle(Vector2.ZERO, 90.0).contour
val a = Circle(Vector2.ZERO, 90.0).contour val b = regularStar(5, 30.0, 90.0, center = Vector2.ZERO, phase = 180.0)
val b = regularStar(5, 30.0, 90.0, center = Vector2.ZERO, phase = 180.0) val blend = a.blend(b)
val blend = a.blend(b) extend {
extend { drawer.clear(ColorRGBa.WHITE)
drawer.clear(ColorRGBa.WHITE) drawer.fill = ColorRGBa.BLACK
drawer.fill = ColorRGBa.BLACK drawer.bounds.grid(3, 3).flatten().forEachIndexed { index, it ->
drawer.bounds.grid(3, 3).flatten().forEachIndexed { index, it -> drawer.isolated {
drawer.isolated { drawer.translate(it.center)
drawer.translate(it.center) drawer.contour(blend.mix { t -> cos(t * PI * 2.0 + index * PI * 2.0 / 9.0 + seconds) * 0.5 + 0.5 })
drawer.contour(blend.mix { t -> cos(t * PI * 2.0 + index * PI * 2.0 / 9.0 + seconds) * 0.5 + 0.5 })
}
} }
} }
} }
} }
} }

View File

@@ -15,53 +15,50 @@ import org.openrndr.math.Vector3
import org.openrndr.shape.path3D import org.openrndr.shape.path3D
import kotlin.random.Random import kotlin.random.Random
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 multisample = WindowMultisample.SampleCount(4)
multisample = WindowMultisample.SampleCount(4) }
} program {
program { val random = Random(0)
val random = Random(0) val cylinder = cylinderMesh(radius = 0.5, length = 0.1)
val cylinder = cylinderMesh(radius = 0.5, length = 0.1) val p = path3D {
val p = path3D { moveTo(0.0, 0.0, 0.0)
moveTo(0.0, 0.0, 0.0) curveTo(
curveTo( Vector3.uniformRing(0.1, 1.0, random = random) * 10.0,
Vector3.uniformRing(0.1, 1.0, random = random)*10.0, Vector3.uniformRing(0.1, 1.0, random = random) * 10.0,
Vector3.uniformRing(0.1, 1.0, random = random)*10.0, Vector3.uniformRing(0.1, 1.0, random = random) * 10.0
Vector3.uniformRing(0.1, 1.0, random = random)*10.0 )
for (i in 0 until 10) {
continueTo(
Vector3.uniformRing(0.1, 1.0, random = random) * 10.0,
Vector3.uniformRing(0.1, 1.0, random = random) * 10.0
) )
for (i in 0 until 10) {
continueTo(
Vector3.uniformRing(0.1, 1.0, random = random)*10.0,
Vector3.uniformRing(0.1, 1.0, random = random)*10.0
)
}
} }
val pr = p.rectified(0.01, 100.0) }
val pr = p.rectified(0.01, 100.0)
val frames = pr.frames((0 until 100).map { it / 100.0}, Vector3.UNIT_Y, analyticalDirections = false) val frames = pr.frames((0 until 100).map { it / 100.0 }, Vector3.UNIT_Y, analyticalDirections = false)
extend(Orbital()) extend(Orbital())
extend { extend {
drawer.shadeStyle = shadeStyle { drawer.shadeStyle = shadeStyle {
fragmentTransform = """ fragmentTransform = """
x_fill.rgb = vec3(abs(v_viewNormal.z)*0.9+ 0.1); x_fill.rgb = vec3(abs(v_viewNormal.z)*0.9+ 0.1);
""".trimIndent() """.trimIndent()
}
drawer.stroke = ColorRGBa.PINK
drawer.path(p)
for (frame in frames) {
drawer.isolated {
drawer.model = frame
drawer.vertexBuffer(cylinder, DrawPrimitive.TRIANGLES)
} }
drawer.stroke = ColorRGBa.PINK
drawer.path(p)
for (frame in frames) {
drawer.isolated {
drawer.model = frame
drawer.vertexBuffer(cylinder, DrawPrimitive.TRIANGLES)
}
}
} }
} }
} }
} }

View File

@@ -6,20 +6,18 @@ import org.openrndr.extra.noise.uniform
import org.openrndr.extra.shapes.ordering.hilbertOrder import org.openrndr.extra.shapes.ordering.hilbertOrder
import kotlin.random.Random import kotlin.random.Random
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { val points = drawer.bounds.offsetEdges(-20.0).uniform(40, Random(0))
val points = drawer.bounds.offsetEdges(-20.0).uniform(40, Random(0)) val sortedPoints = points.hilbertOrder(bits = 16, scale = 1.0)
val sortedPoints = points.hilbertOrder(bits = 16, scale = 1.0) extend {
extend { drawer.clear(ColorRGBa.PINK)
drawer.clear(ColorRGBa.PINK) drawer.stroke = ColorRGBa.RED
drawer.stroke = ColorRGBa.RED drawer.lineStrip(sortedPoints)
drawer.lineStrip(sortedPoints)
}
} }
} }
} }

View File

@@ -4,26 +4,23 @@ import org.openrndr.application
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.uniform import org.openrndr.extra.noise.uniform
import org.openrndr.extra.shapes.ordering.hilbertOrder import org.openrndr.extra.shapes.ordering.hilbertOrder
import org.openrndr.extra.shapes.ordering.mortonOrder
import kotlin.random.Random import kotlin.random.Random
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { val points = drawer.bounds.offsetEdges(-20.0).uniform(400, Random(0))
val points = drawer.bounds.offsetEdges(-20.0).uniform(400, Random(0)) val sortedPoints0 = points.hilbertOrder(bits = 16, scale = 1.0)
val sortedPoints0 = points.hilbertOrder(bits = 16, scale = 1.0) val sortedPoints1 = points.map { it.xy0 }.hilbertOrder(bits = 10, scale = 1.0).map { it.xy }
val sortedPoints1 = points.map { it.xy0 }.hilbertOrder(bits = 10, scale = 1.0).map { it.xy } extend {
extend { drawer.clear(ColorRGBa.PINK)
drawer.clear(ColorRGBa.PINK) drawer.stroke = ColorRGBa.RED
drawer.stroke = ColorRGBa.RED drawer.lineStrip(sortedPoints0)
drawer.lineStrip(sortedPoints0) drawer.stroke = ColorRGBa.BLUE
drawer.stroke = ColorRGBa.BLUE drawer.lineStrip(sortedPoints1)
drawer.lineStrip(sortedPoints1)
}
} }
} }
} }

View File

@@ -4,38 +4,31 @@ import org.openrndr.application
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.draw.LineJoin import org.openrndr.draw.LineJoin
import org.openrndr.extra.camera.Orbital import org.openrndr.extra.camera.Orbital
import org.openrndr.extra.noise.uniformRing
import org.openrndr.extra.shapes.path3d.projectToContour import org.openrndr.extra.shapes.path3d.projectToContour
import org.openrndr.math.Spherical
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
import org.openrndr.shape.path3D import org.openrndr.shape.path3D
fun main() { fun main() = application {
application { program {
configure { val path = path3D {
width = 720 var p = Vector3(6.0, 0.0, 0.0)
height = 720 moveTo(p)
for (i in 0 until 100) {
p = Spherical((i % 6) * 45.0, (i % 4 + 1) * 30.0 + i * 0.1, 6.0).cartesian
arcTo(5.0, cursor.atan2(p), false, false, p)
}
} }
program { extend(Orbital())
val path = path3D { extend {
var p = Vector3(1.0, 0.0, 0.0) drawer.stroke = ColorRGBa.PINK
moveTo(p * 6.0) drawer.path(path)
for (i in 0 until 400) { val c = path.projectToContour(drawer.projection, drawer.view, width, height)
p += Vector3.uniformRing(0.2, 0.5) drawer.defaults()
p = p.normalized drawer.stroke = ColorRGBa.WHITE
arcTo(5.0, cursor.atan2(p * 6.0), false, false, p * 6.0) drawer.lineJoin = LineJoin.ROUND
} drawer.strokeWeight = 2.0
} drawer.contour(c)
extend(Orbital())
extend {
drawer.stroke = ColorRGBa.PINK
drawer.path(path)
val c = path.projectToContour(drawer.projection, drawer.view, width, height)
drawer.defaults()
drawer.stroke = ColorRGBa.WHITE
drawer.lineJoin = LineJoin.ROUND
drawer.strokeWeight = 2.0
drawer.contour(c)
}
} }
} }
} }

View File

@@ -4,21 +4,19 @@ import org.openrndr.application
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.extra.shapes.primitives.Arc import org.openrndr.extra.shapes.primitives.Arc
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { extend {
extend { val a = Arc(drawer.bounds.center, 100.0, 0.0 + seconds * 36.0, -180.0 + seconds * 36.0)
val a = Arc(drawer.bounds.center, 100.0, 0.0 + seconds * 36.0, -180.0 + seconds * 36.0) drawer.clear(ColorRGBa.PINK)
drawer.clear(ColorRGBa.PINK) drawer.contour(a.contour)
drawer.contour(a.contour) drawer.circle(a.position(0.0), 5.0)
drawer.circle(a.position(0.0), 5.0) drawer.circle(a.position(0.5), 5.0)
drawer.circle(a.position(0.5), 5.0) drawer.circle(a.position(1.0), 5.0)
drawer.circle(a.position(1.0), 5.0)
}
} }
} }
} }

View File

@@ -6,29 +6,27 @@ import org.openrndr.extra.shapes.primitives.Net
import org.openrndr.shape.Circle import org.openrndr.shape.Circle
import kotlin.math.sin import kotlin.math.sin
fun main() { fun main() = application {
application { program {
program { extend {
extend { drawer.clear(ColorRGBa.BLACK)
drawer.clear(ColorRGBa.BLACK) drawer.stroke = ColorRGBa.WHITE
drawer.stroke = ColorRGBa.WHITE drawer.fill = ColorRGBa.PINK
drawer.fill = ColorRGBa.PINK val a = drawer.bounds.position(0.7, 0.5)
val a = drawer.bounds.position(0.7, 0.5) val b = drawer.bounds.position(0.3, 0.5)
val b = drawer.bounds.position(0.3, 0.5) val c = Circle(
val c = Circle( drawer.bounds.position(
drawer.bounds.position( sin(seconds) * 0.35 + 0.5,
sin(seconds) * 0.35 + 0.5, sin(seconds * 2) * 0.25 + 0.5
sin(seconds * 2) * 0.25 + 0.5 ), 50.0
), 50.0 )
) val net = Net(a, b, c)
val net = Net(a, b, c) drawer.circle(a, 10.0)
drawer.circle(a, 10.0) drawer.circle(b, 10.0)
drawer.circle(b, 10.0) drawer.circle(c)
drawer.circle(c)
drawer.strokeWeight = 2.0 drawer.strokeWeight = 2.0
drawer.contour(net.contour) drawer.contour(net.contour)
}
} }
} }
} }

View File

@@ -6,23 +6,21 @@ import org.openrndr.extra.shapes.primitives.Pulley
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.shape.Circle import org.openrndr.shape.Circle
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { extend {
extend { drawer.clear(ColorRGBa.BLACK)
drawer.clear(ColorRGBa.BLACK) drawer.stroke = ColorRGBa.WHITE
drawer.stroke = ColorRGBa.WHITE drawer.fill = ColorRGBa.PINK
drawer.fill = ColorRGBa.PINK val pulley = Pulley(
val pulley = Pulley( Circle(drawer.bounds.center - Vector2(100.0, 100.0), 150.0),
Circle(drawer.bounds.center - Vector2(100.0, 100.0), 150.0), Circle(drawer.bounds.center + Vector2(150.0, 150.0), 75.0)
Circle(drawer.bounds.center + Vector2(150.0, 150.0), 75.0) )
) drawer.contour(pulley.contour)
drawer.contour(pulley.contour)
}
} }
} }
} }

View File

@@ -4,25 +4,23 @@ import org.openrndr.application
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.extra.shapes.primitives.grid import org.openrndr.extra.shapes.primitives.grid
fun main() { fun main() = application {
application { configure {
configure { width = 800
width = 800 height = 800
height = 800 }
} program {
program { extend {
extend { drawer.fill = ColorRGBa.WHITE.opacify(0.25)
drawer.fill = ColorRGBa.WHITE.opacify(0.25) drawer.stroke = ColorRGBa.PINK
drawer.stroke = ColorRGBa.PINK
// Notice the negative gutter in this grid. It creates an // Notice the negative gutter in this grid. It creates an
// overlap between the resulting rectangles. // overlap between the resulting rectangles.
val grid = drawer.bounds.grid(8, 4, 20.0, 20.0, -20.0, -20.0) val grid = drawer.bounds.grid(8, 4, 20.0, 20.0, -20.0, -20.0)
for (cell in grid.flatten()) { for (cell in grid.flatten()) {
drawer.rectangle(cell) drawer.rectangle(cell)
drawer.lineSegment(cell.position(0.0, 0.0), cell.position(1.0, 1.0)) drawer.lineSegment(cell.position(0.0, 0.0), cell.position(1.0, 1.0))
}
} }
} }
} }
} }

View File

@@ -5,35 +5,35 @@ import org.openrndr.color.ColorRGBa
import org.openrndr.extra.noise.Random import org.openrndr.extra.noise.Random
import org.openrndr.extra.shapes.primitives.grid import org.openrndr.extra.shapes.primitives.grid
fun main() { fun main() = application {
application { // Try changing the resolution. The design will use the available space.
// Try changing the resolution. The design will use the available space. configure {
configure { width = 800
width = 800 height = 400
height = 400 }
} program {
program { // By specifying the cell size we make sure the design will
// By specifying the cell size we make sure the design will // contain squares, independently of the window size and its
// contain squares, independently of the window size and its // aspect ratio.
// aspect ratio. val grid = drawer.bounds.grid(
val grid = drawer.bounds.grid(50.0, 50.0, 50.0, 50.0,
20.0, 20.0, 20.0, 20.0).flatten() 20.0, 20.0, 20.0, 20.0
).flatten()
val grid2 = grid.map { rect -> val grid2 = grid.map { rect ->
// Each of these inner grids will occupy the available space // Each of these inner grids will occupy the available space
// in the parent grid cells. Notice how we don't specify cell // in the parent grid cells. Notice how we don't specify cell
// sizes here but counts instead (between 1 and 3 columns and // sizes here but counts instead (between 1 and 3 columns and
// rows) // rows)
val count = Random.int(1, 4) val count = Random.int(1, 4)
rect.grid(count, count, 5.0, 5.0, 5.0, 5.0).flatten() rect.grid(count, count, 5.0, 5.0, 5.0, 5.0).flatten()
}.flatten().filter { Random.bool(0.5)} }.flatten().filter { Random.bool(0.5) }
extend { extend {
drawer.clear(ColorRGBa.PINK) drawer.clear(ColorRGBa.PINK)
drawer.rectangles(grid) drawer.rectangles(grid)
drawer.fill = ColorRGBa.BLACK drawer.fill = ColorRGBa.BLACK
drawer.rectangles(grid2) drawer.rectangles(grid2)
}
} }
} }
} }

View File

@@ -8,33 +8,31 @@ import org.openrndr.extra.shapes.primitives.intersection
* Demonstrate rectangle-rectangle intersection * Demonstrate rectangle-rectangle intersection
* @see <img src="https://raw.githubusercontent.com/openrndr/orx/media/orx-shapes/images/primitives-DemoRectangleIntersection01Kt.png"> * @see <img src="https://raw.githubusercontent.com/openrndr/orx/media/orx-shapes/images/primitives-DemoRectangleIntersection01Kt.png">
*/ */
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { val h = drawer.bounds.offsetEdges(-100.0, -10.0)
val h = drawer.bounds.offsetEdges(-100.0, -10.0) val v = drawer.bounds.offsetEdges(-10.0, -100.0)
val v = drawer.bounds.offsetEdges(-10.0, -100.0)
extend { extend {
drawer.clear(ColorRGBa.WHITE) drawer.clear(ColorRGBa.WHITE)
/** /**
* Find intersection * Find intersection
*/ */
val i = h.intersection(v) val i = h.intersection(v)
drawer.fill = ColorRGBa.RED drawer.fill = ColorRGBa.RED
drawer.rectangle(h) drawer.rectangle(h)
drawer.fill = ColorRGBa.BLUE drawer.fill = ColorRGBa.BLUE
drawer.rectangle(v) drawer.rectangle(v)
drawer.fill = ColorRGBa.BLACK drawer.fill = ColorRGBa.BLACK
drawer.stroke = ColorRGBa.WHITE drawer.stroke = ColorRGBa.WHITE
drawer.rectangle(i) drawer.rectangle(i)
}
} }
} }
} }

View File

@@ -8,24 +8,22 @@ import org.openrndr.math.Vector2
import org.openrndr.shape.Circle import org.openrndr.shape.Circle
import kotlin.random.Random import kotlin.random.Random
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
program {
val points = drawer.bounds.scatter(40.0, distanceToEdge = 150.0, random = Random(0))
val tears = points.map {
Tear(it - Vector2(0.0, 20.0), Circle(it + Vector2(0.0, 20.0), 20.0))
} }
program {
val points = drawer.bounds.scatter(40.0, distanceToEdge = 150.0, random = Random(0))
val tears = points.map {
Tear(it - Vector2(0.0, 20.0), Circle(it + Vector2(0.0, 20.0), 20.0))
}
extend { extend {
drawer.clear(ColorRGBa.BLACK) drawer.clear(ColorRGBa.BLACK)
drawer.fill = ColorRGBa.PINK drawer.fill = ColorRGBa.PINK
drawer.stroke = ColorRGBa.WHITE drawer.stroke = ColorRGBa.WHITE
drawer.contours(tears.map { it.contour }) drawer.contours(tears.map { it.contour })
}
} }
} }
} }

View File

@@ -7,26 +7,24 @@ import org.openrndr.extra.shapes.hobbycurve.hobbyCurve
import org.openrndr.extra.shapes.rectify.rectified import org.openrndr.extra.shapes.rectify.rectified
import kotlin.random.Random import kotlin.random.Random
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { val points = drawer.bounds.scatter(50.0, distanceToEdge = 100.0, random = Random(0))
val points = drawer.bounds.scatter(50.0, distanceToEdge = 100.0, random = Random(0)) val curve = hobbyCurve(points)
val curve = hobbyCurve(points) val rectified = curve.rectified()
val rectified = curve.rectified() extend {
extend { drawer.clear(ColorRGBa.BLACK)
drawer.clear(ColorRGBa.BLACK) drawer.stroke = ColorRGBa.PINK
drawer.stroke = ColorRGBa.PINK drawer.contour(curve)
drawer.contour(curve) drawer.fill = ColorRGBa.RED
drawer.fill = ColorRGBa.RED drawer.circle(curve.position(seconds * 0.05), 10.0)
drawer.circle(curve.position(seconds*0.05), 10.0) drawer.fill = ColorRGBa.GREEN
drawer.fill = ColorRGBa.GREEN drawer.circle(rectified.position(seconds * 0.05), 10.0)
drawer.circle(rectified.position(seconds*0.05), 10.0)
}
} }
} }
} }

View File

@@ -7,29 +7,27 @@ import org.openrndr.extra.shapes.hobbycurve.hobbyCurve
import org.openrndr.extra.shapes.rectify.rectified import org.openrndr.extra.shapes.rectify.rectified
import kotlin.random.Random import kotlin.random.Random
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { val points = drawer.bounds.scatter(80.0, distanceToEdge = 100.0, random = Random(0))
val points = drawer.bounds.scatter(80.0, distanceToEdge = 100.0, random = Random(0)) val curve = hobbyCurve(points, closed = true)
val curve = hobbyCurve(points, closed = true) val rectified = curve.rectified()
val rectified = curve.rectified() extend {
extend { drawer.clear(ColorRGBa.BLACK)
drawer.clear(ColorRGBa.BLACK) drawer.fill = null
drawer.fill = null drawer.stroke = ColorRGBa.GRAY
drawer.stroke = ColorRGBa.GRAY drawer.contour(curve)
drawer.contour(curve) drawer.strokeWeight = 4.0
drawer.strokeWeight = 4.0
drawer.stroke = ColorRGBa.RED drawer.stroke = ColorRGBa.RED
drawer.contour(curve.sub(seconds*0.1, seconds*0.1+0.01)) drawer.contour(curve.sub(seconds * 0.1, seconds * 0.1 + 0.01))
drawer.stroke = ColorRGBa.GREEN drawer.stroke = ColorRGBa.GREEN
drawer.contour(rectified.sub(seconds*0.1, seconds*0.1+0.01)) drawer.contour(rectified.sub(seconds * 0.1, seconds * 0.1 + 0.01))
}
} }
} }
} }

View File

@@ -7,28 +7,26 @@ import org.openrndr.extra.shapes.hobbycurve.hobbyCurve
import org.openrndr.extra.shapes.rectify.rectified import org.openrndr.extra.shapes.rectify.rectified
import kotlin.random.Random import kotlin.random.Random
fun main() { fun main() = application {
application { configure {
configure { width = 720
width = 720 height = 720
height = 720 }
} program {
program { val points = drawer.bounds.scatter(80.0, distanceToEdge = 100.0, random = Random(0))
val points = drawer.bounds.scatter(80.0, distanceToEdge = 100.0, random = Random(0)) val curve = hobbyCurve(points, closed = true)
val curve = hobbyCurve(points, closed = true) val rectified = curve.rectified()
val rectified = curve.rectified() extend {
extend { drawer.clear(ColorRGBa.BLACK)
drawer.clear(ColorRGBa.BLACK) drawer.fill = null
drawer.fill = null drawer.stroke = ColorRGBa.GRAY
drawer.stroke = ColorRGBa.GRAY drawer.contour(curve)
drawer.contour(curve)
val points = (0 until 100).map {
rectified.position(it/100.0)
}
drawer.circles(points, 5.0)
val points = (0 until 100).map {
rectified.position(it / 100.0)
} }
drawer.circles(points, 5.0)
} }
} }
} }

View File

@@ -12,38 +12,35 @@ import org.openrndr.extra.shapes.rectify.rectified
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
import org.openrndr.shape.path3D import org.openrndr.shape.path3D
fun main() = application {
fun main() { configure {
application { width = 720
configure { height = 720
width = 720 multisample = WindowMultisample.SampleCount(4)
height = 720 }
multisample = WindowMultisample.SampleCount(4) program {
val p = path3D {
moveTo(0.0, 0.0, 0.0)
for (i in 0 until 10) {
curveTo(
Vector3.uniformRing(0.1, 1.0) * 10.0,
Vector3.uniformRing(0.1, 1.0) * 10.0,
Vector3.uniformRing(0.1, 1.0) * 10.0
)
}
} }
program { val pr = p.rectified(0.01, 100.0)
val p = path3D { val sphere = sphereMesh(radius = 0.1)
moveTo(0.0, 0.0, 0.0) extend(Orbital())
for (i in 0 until 10) { extend {
curveTo( drawer.stroke = ColorRGBa.PINK
Vector3.uniformRing(0.1, 1.0)*10.0, for (i in 0 until 500) {
Vector3.uniformRing(0.1, 1.0)*10.0, drawer.isolated {
Vector3.uniformRing(0.1, 1.0)*10.0 drawer.translate(pr.position(i / 499.0))
) drawer.vertexBuffer(sphere, DrawPrimitive.TRIANGLES)
} }
} }
val pr = p.rectified(0.01, 100.0) drawer.path(p)
val sphere = sphereMesh(radius = 0.1)
extend(Orbital())
extend {
drawer.stroke = ColorRGBa.PINK
for (i in 0 until 500) {
drawer.isolated {
drawer.translate(pr.position(i/499.0))
drawer.vertexBuffer(sphere, DrawPrimitive.TRIANGLES)
}
}
drawer.path(p)
}
} }
} }
} }

View File

@@ -6,26 +6,23 @@ import org.openrndr.draw.font.loadFace
import org.openrndr.extra.shapes.bounds.bounds import org.openrndr.extra.shapes.bounds.bounds
import org.openrndr.extra.shapes.text.shapesFromText import org.openrndr.extra.shapes.text.shapesFromText
fun main() { fun main() = application {
application { configure {
width = 720
height = 720
}
program {
configure { val face =
width = 720 loadFace("https://github.com/IBM/plex/raw/master/packages/plex-mono/fonts/complete/otf/IBMPlexMono-Bold.otf")
height = 720 val shapes = shapesFromText(face, "SUCH\nVECTOR\nSUCH\nTEXT", 150.0)
}
program {
val face = val bounds = shapes.bounds
loadFace("https://github.com/IBM/plex/raw/master/packages/plex-mono/fonts/complete/otf/IBMPlexMono-Bold.otf") extend {
val shapes = shapesFromText(face, "SUCH\nVECTOR\nSUCH\nTEXT", 150.0) drawer.clear(ColorRGBa.PINK)
drawer.translate(-bounds.corner)
val bounds = shapes.bounds drawer.translate((width - bounds.width) / 2.0, (height - bounds.height) / 2.0)
extend { drawer.shapes(shapes)
drawer.clear(ColorRGBa.PINK)
drawer.translate(-bounds.corner)
drawer.translate((width - bounds.width) / 2.0, (height - bounds.height) / 2.0)
drawer.shapes(shapes)
}
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show More