From 7004536dd4c08b7ea86232f5c1f9884f5cacf265 Mon Sep 17 00:00:00 2001 From: Abe Pazos Date: Tue, 25 Aug 2020 08:56:26 +0200 Subject: [PATCH] Tweak demos (#146) --- .../src/demo/kotlin/DemoCircleBatch02.kt | 33 ++++++-- orx-color/src/demo/kotlin/DemoColorRange01.kt | 82 ++++++------------- orx-color/src/demo/kotlin/DemoHSLUV01.kt | 37 +++++++-- orx-color/src/demo/kotlin/DemoHistogram01.kt | 45 ++++++++-- orx-color/src/demo/kotlin/DemoHistogram02.kt | 9 +- 5 files changed, 123 insertions(+), 83 deletions(-) diff --git a/openrndr-demos/src/demo/kotlin/DemoCircleBatch02.kt b/openrndr-demos/src/demo/kotlin/DemoCircleBatch02.kt index d56c51f6..b07a947e 100644 --- a/openrndr-demos/src/demo/kotlin/DemoCircleBatch02.kt +++ b/openrndr-demos/src/demo/kotlin/DemoCircleBatch02.kt @@ -1,27 +1,42 @@ import org.openrndr.application import org.openrndr.color.ColorRGBa import org.openrndr.draw.circleBatch +import org.openrndr.draw.shadeStyle /* -This program demonstrates creating "pre-baked" batches of circles. Batches can have varying fill, stroke and -strokeWeight settings. +This program demonstrates creating "pre-baked" batches of circles. +Batches can have varying fill, stroke and strokeWeight settings. -Batches are (currently) static but stored in GPU memory. Batches are fast to draw. - */ +Batches are (currently) static but stored in GPU memory but can be +animated using a vertex shader. Batches are fast to draw. +*/ fun main() = application { program { - val batch = drawer.circleBatch { - this.fill = ColorRGBa.PINK - for (i in 0 until 100) { - this.strokeWeight = Math.random() * 5.0 - this.circle(Math.random() * width, Math.random() * height, 50.0 * Math.random() + 50.0 ) + for (i in 0 until 2000) { + fill = ColorRGBa.PINK.shade(Math.random()) + strokeWeight = Math.random() * 5 + circle(width * 0.5, height * 0.5, 20 * Math.random() + 5) } } extend { drawer.clear(ColorRGBa.GRAY) + + // The following optional shadeStyle animates the batch + // by using polar coordinates: + // sets angle and radius based on time and shape ID. + drawer.shadeStyle = shadeStyle { + vertexTransform = """ + float a = c_instance + p_time * 0.1; + float r = 200 + 100 * sin(a * 0.998); + x_position.x += r * sin(a); + x_position.y += r * cos(a); + """.trimIndent() + parameter("time", seconds) + } + drawer.circles(batch) } } diff --git a/orx-color/src/demo/kotlin/DemoColorRange01.kt b/orx-color/src/demo/kotlin/DemoColorRange01.kt index 70f16d37..17d47401 100644 --- a/orx-color/src/demo/kotlin/DemoColorRange01.kt +++ b/orx-color/src/demo/kotlin/DemoColorRange01.kt @@ -1,12 +1,14 @@ -// Create a simple rectangle composition based on colors sampled from image +// Comparison of color lists generated by interpolating from +// PINK to BLUE in different color models import org.openrndr.application import org.openrndr.color.ColorRGBa -import org.openrndr.draw.isolated import org.openrndr.extensions.SingleScreenshot import org.openrndr.extras.color.palettes.rangeTo -import org.openrndr.extras.color.presets.CORAL import org.openrndr.extras.color.spaces.toHSLUVa +import org.openrndr.math.Vector2 +import org.openrndr.math.map +import org.openrndr.shape.Rectangle fun main() = application { program { @@ -16,60 +18,28 @@ fun main() = application { this.outputFile = System.getProperty("screenshotPath") } } + val numColors = 10 + val colorLists = listOf( + ColorRGBa.PINK..ColorRGBa.BLUE.toHSVa() blend numColors, + ColorRGBa.PINK..ColorRGBa.BLUE blend numColors, + ColorRGBa.PINK..ColorRGBa.BLUE.toHSLUVa() blend numColors, + ColorRGBa.PINK..ColorRGBa.BLUE.toXSVa() blend numColors, + ColorRGBa.PINK..ColorRGBa.BLUE.toLUVa() blend numColors, + ColorRGBa.PINK..ColorRGBa.BLUE.toLCHUVa() blend numColors + ) extend { - - drawer.isolated { - for (c in ColorRGBa.PINK..ColorRGBa.BLUE.toHSVa() blend 10) { - drawer.fill = c - drawer.rectangle(0.0, 0.0, 40.0, 40.0) - drawer.translate(0.0, 40.0) - } - } - drawer.translate(50.0, 0.0) - drawer.isolated { - for (c in ColorRGBa.PINK..ColorRGBa.BLUE blend 10) { - drawer.fill = c - drawer.rectangle(0.0, 0.0, 40.0, 40.0) - drawer.translate(0.0, 40.0) - } - } - drawer.translate(50.0, 0.0) - - drawer.isolated { - for (c in ColorRGBa.PINK..ColorRGBa.BLUE.toHSLUVa() blend 10) { - drawer.fill = c.toSRGB() - drawer.rectangle(0.0, 0.0, 40.0, 40.0) - drawer.translate(0.0, 40.0) - } - } - - drawer.translate(50.0, 0.0) - - drawer.isolated { - for (c in ColorRGBa.PINK..ColorRGBa.BLUE.toXSVa() blend 10) { - drawer.fill = c.toSRGB() - drawer.rectangle(0.0, 0.0, 40.0, 40.0) - drawer.translate(0.0, 40.0) - } - } - - drawer.translate(50.0, 0.0) - - drawer.isolated { - for (c in ColorRGBa.PINK..ColorRGBa.BLUE.toLUVa() blend 10) { - drawer.fill = c.toSRGB() - drawer.rectangle(0.0, 0.0, 40.0, 40.0) - drawer.translate(0.0, 40.0) - } - } - - drawer.translate(50.0, 0.0) - - drawer.isolated { - for (c in ColorRGBa.PINK..ColorRGBa.BLUE.toLCHUVa() blend 10) { - drawer.fill = c.toSRGB() - drawer.rectangle(0.0, 0.0, 40.0, 40.0) - drawer.translate(0.0, 40.0) + drawer.clear(ColorRGBa.WHITE) + drawer.stroke = null + colorLists.forEachIndexed { listId, colorList -> + val x = map(0.0, 2.0, + width * 0.2, width * 0.8, listId % 3.0) + val y = map(0.0, 1.0, + height * 0.3, height * 0.7, (listId / 3) * 1.0) + colorList.forEachIndexed { colorId, color -> + drawer.fill = color + drawer.rectangle( + Rectangle.fromCenter(Vector2(x, y), + 180.0 - colorId * 150.0 / numColors)) } } } diff --git a/orx-color/src/demo/kotlin/DemoHSLUV01.kt b/orx-color/src/demo/kotlin/DemoHSLUV01.kt index 1c0b22ec..54fa0fed 100644 --- a/orx-color/src/demo/kotlin/DemoHSLUV01.kt +++ b/orx-color/src/demo/kotlin/DemoHSLUV01.kt @@ -1,9 +1,15 @@ // Draw rectangles shaded in RGB and HSLUV space import org.openrndr.application +import org.openrndr.color.ColorHSLa import org.openrndr.color.ColorRGBa +import org.openrndr.color.rgb +import org.openrndr.draw.isolated +import org.openrndr.draw.loadFont import org.openrndr.extensions.SingleScreenshot -import org.openrndr.extras.color.spaces.toHSLUVa +import org.openrndr.extras.color.spaces.ColorHSLUVa +import org.openrndr.math.Vector2 +import org.openrndr.shape.Rectangle fun main() { application { @@ -14,16 +20,33 @@ fun main() { this.outputFile = System.getProperty("screenshotPath") } } + val font = loadFont("demo-data/fonts/IBMPlexMono-Regular.ttf", 26.0) extend { - val color = ColorRGBa.PINK drawer.stroke = null - for (i in 0 until 10) { - drawer.fill = color.shade(1.0 - i / 10.0) - drawer.rectangle(100.0, 100.0 + i * 20.0, 100.0, 20.0) + drawer.clear(rgb(0.3)) + val s = mouse.position.x / width + val l = mouse.position.y / height + for (a in 0 until 360 step 12) { + val pos = Vector2(0.0, 110.0) + drawer.isolated { + translate(bounds.center) + rotate(a * 1.0) - drawer.fill = color.toHSLUVa().shade(1.0 - i / 10.0).toRGBa().toSRGB() - drawer.rectangle(200.0, 100.0 + i * 20.0, 100.0, 20.0) + fill = ColorHSLUVa(a * 1.0, s, l).toRGBa().toSRGB() + rectangle(Rectangle(pos * 1.2, 40.0, 300.0)) + + fill = ColorHSLa(a * 1.0, s, l).toRGBa() + rectangle(Rectangle.fromCenter(pos, 30.0, 60.0)) + } } + drawer.fontMap = font + drawer.fill = if(l > 0.8) ColorRGBa.BLACK else ColorRGBa.WHITE + drawer.text("HSLa", width * 0.48, height * 0.73) + drawer.text("HSLUVa", width * 0.8, height * 0.52) + drawer.text("hue: 0 to 360, " + + "saturation: ${String.format("%.02f", s)}, " + + "lightness: ${String.format("%.02f", l)}", + 30.0, 460.0) } } } diff --git a/orx-color/src/demo/kotlin/DemoHistogram01.kt b/orx-color/src/demo/kotlin/DemoHistogram01.kt index 022db2bd..527fcda4 100644 --- a/orx-color/src/demo/kotlin/DemoHistogram01.kt +++ b/orx-color/src/demo/kotlin/DemoHistogram01.kt @@ -13,18 +13,45 @@ fun main() = application { this.outputFile = System.getProperty("screenshotPath") } } + val useColors = 32 val image = loadImage("demo-data/images/image-001.png") - val histogram = calculateHistogramRGB(image) - val colors = histogram.sortedColors() + + val histogram = calculateHistogramRGB(image, binCount = 8) + print("Histogram using ${histogram.binCount} bins per RGB channel") + + val colorsSortedByFreq = histogram.sortedColors() + println(" therefore it contains ${colorsSortedByFreq.size} colors.") + + val topColors = colorsSortedByFreq.subList(0, useColors) + print("\nWe will use the most common $useColors") + + val topColorsSortedByLuminosity = topColors.sortedBy { + it.first.toHSLa().l + } + println(" and sort them by luminosity.") + + val topColorsFreqSum = topColors.sumByDouble { it.second } + println("\nThose top $useColors colors represent " + + String.format("%.02f", 100 * topColorsFreqSum) + + "% of the image colors.") + extend { - drawer.image(image) - for (i in 0 until 32) { - drawer.fill = colors[i].first - drawer.stroke = null - drawer.rectangle(i * (width/32.0), height-16.0, width/32.0, 16.0) - } + drawer.stroke = null + var x = 0.0 + topColorsSortedByLuminosity.forEachIndexed { i, (color, freq) -> + drawer.fill = color + // draw horizontal bars + drawer.rectangle(x, 2.0, width.toDouble(), 16.0) + x += width * freq / topColorsFreqSum + + // draw vertical bars + drawer.rectangle(i * width / useColors.toDouble() + 2.0, + height - 2.0, + width / useColors.toDouble() - 4.0, + -height * freq / topColorsFreqSum) + } } } -} \ No newline at end of file +} diff --git a/orx-color/src/demo/kotlin/DemoHistogram02.kt b/orx-color/src/demo/kotlin/DemoHistogram02.kt index 99826f8a..251a6507 100644 --- a/orx-color/src/demo/kotlin/DemoHistogram02.kt +++ b/orx-color/src/demo/kotlin/DemoHistogram02.kt @@ -17,15 +17,20 @@ fun main() = application { val image = loadImage("demo-data/images/image-001.png") // -- here we use non-uniform weighting, such that bright colors are prioritized val histogram = calculateHistogramRGB(image, weighting = { - ((r+g+b)/3.0).pow(2.4) + ((r + g + b) / 3.0).pow(2.4) }) val colors = histogram.sortedColors() + // .subList(0, 32).sortedBy { it.first.toHSLa().h } // sort by hue + extend { drawer.image(image) for (i in 0 until 32) { drawer.fill = colors[i].first drawer.stroke = null - drawer.rectangle(i * (width / 32.0), height - 16.0, width / 32.0, 16.0) + drawer.rectangle(i * width / 32.0 + 2.0, + height - 2.0, + width / 32.0 - 4.0, + -16.0) } } }