[orx-jumpflood] Make module multiplatform

This commit is contained in:
Edwin Jakobs
2023-01-12 15:54:53 +01:00
parent 58d15a1e8b
commit e27f7eb4cb
51 changed files with 571 additions and 177 deletions

View File

@@ -18,6 +18,7 @@ def multiplatformModules = [
"orx-fx",
"orx-gradient-descent",
"orx-image-fit",
"orx-jumpflood",
"orx-no-clear",
"orx-noise",
"orx-parameters",

View File

@@ -1,15 +1,69 @@
import ScreenshotsHelper.collectScreenshots
plugins {
org.openrndr.extra.convention.`kotlin-jvm`
org.openrndr.extra.convention.`kotlin-multiplatform`
}
dependencies {
implementation(project(":orx-fx"))
implementation(project(":orx-parameters"))
implementation(libs.openrndr.application)
implementation(libs.openrndr.math)
demoImplementation(project(":orx-noise"))
demoImplementation(project(":orx-jvm:orx-gui"))
demoImplementation(project(":orx-compositor"))
demoImplementation(libs.openrndr.svg)
demoImplementation(libs.openrndr.ffmpeg)
val embedShaders = tasks.register<EmbedShadersTask>("embedShaders") {
inputDir.set(file("$projectDir/src/shaders/glsl"))
outputDir.set(file("$buildDir/generated/shaderKotlin"))
defaultPackage.set("org.openrndr.extra.jumpflood")
defaultVisibility.set("internal")
namePrefix.set("jf_")
}.get()
kotlin {
jvm {
@Suppress("UNUSED_VARIABLE")
val demo by compilations.getting {
// TODO: Move demos to /jvmDemo
defaultSourceSet {
kotlin.srcDir("src/demo/kotlin")
}
collectScreenshots { }
}
}
sourceSets {
val shaderKotlin by creating {
this.kotlin.srcDir(embedShaders.outputDir)
}
@Suppress("UNUSED_VARIABLE")
val commonMain by getting {
dependencies {
implementation(project(":orx-parameters"))
implementation(project(":orx-fx"))
implementation(libs.openrndr.application)
implementation(libs.openrndr.draw)
implementation(libs.openrndr.filter)
implementation(libs.kotlin.reflect)
api(shaderKotlin.kotlin)
}
dependsOn(shaderKotlin)
}
@Suppress("UNUSED_VARIABLE")
val jvmTest by getting {
dependencies {
implementation(libs.spek.dsl)
implementation(libs.kluent)
}
}
@Suppress("UNUSED_VARIABLE")
val jvmDemo by getting {
dependencies {
implementation(project(":orx-color"))
implementation(project(":orx-fx"))
implementation(project(":orx-noise"))
implementation(project(":orx-jumpflood"))
implementation(project(":orx-compositor"))
implementation(project(":orx-jvm:orx-gui"))
implementation(libs.openrndr.svg)
}
}
}
}

View File

@@ -0,0 +1,123 @@
package org.openrndr.extra.jumpfill
import org.openrndr.draw.*
import org.openrndr.extra.fx.blend.Passthrough
import org.openrndr.extra.parameters.BooleanParameter
import org.openrndr.extra.parameters.Description
import org.openrndr.extra.parameters.DoubleParameter
import org.openrndr.math.Vector2
import org.openrndr.shape.IntRectangle
import kotlin.math.ceil
import kotlin.math.log2
import kotlin.math.max
import kotlin.math.pow
@Description("Clustered field")
class ClusteredField(decodeMode: DecodeMode = DecodeMode.DIRECTION,
private val outputDistanceToContours: Boolean = true) : Filter1to1() {
@DoubleParameter("threshold", 0.0, 1.0)
var threshold = 0.5
@DoubleParameter("distance scale", 0.0, 1.0)
var distanceScale = 1.0
@BooleanParameter("normalized distance")
var normalizedDistance = false
@BooleanParameter("unit direction")
var unitDirection = false
@BooleanParameter("flip v direction")
var flipV = true
private val encodeFilter = EncodePoints()
private var encoded: ColorBuffer? = null
private val contourFilter = IdContourPoints()
private var contoured: ColorBuffer? = null
private var jumpFlooder: JumpFlooder? = null
private val decodeFilter = PixelDirection(decodeMode)
private var fit: ColorBuffer? = null
override fun apply(source: Array<ColorBuffer>, target: Array<ColorBuffer>) {
val advisedWidth = 2.0.pow(ceil(log2(source[0].effectiveWidth.toDouble()))).toInt()
val advisedHeight = 2.0.pow(ceil(log2(source[0].effectiveHeight.toDouble()))).toInt()
val advisedSize = max(advisedWidth, advisedHeight)
fit?.let {
if (it.effectiveWidth != advisedSize || it.effectiveHeight != advisedSize) {
it.destroy()
fit = null
encoded?.destroy()
encoded = null
contoured?.destroy()
contoured = null
jumpFlooder?.destroy()
jumpFlooder = null
}
}
if (fit == null) {
fit = colorBuffer(advisedSize, advisedSize, type=ColorType.FLOAT32)
}
source[0].copyTo(
fit!!,
sourceRectangle = IntRectangle(0, 0, source[0].effectiveWidth, source[0].effectiveHeight),
targetRectangle = IntRectangle(
0,
advisedSize - source[0].effectiveHeight,
source[0].effectiveWidth,
source[0].effectiveHeight
)
)
if (encoded == null) {
encoded = colorBuffer(advisedSize, advisedSize, format = ColorFormat.RGBa, type = ColorType.FLOAT32)
}
if (jumpFlooder == null) {
jumpFlooder = JumpFlooder(advisedSize, advisedSize, encodePoints = Passthrough())
}
if (outputDistanceToContours && contoured == null) {
contoured = colorBuffer(advisedSize, advisedSize, type = ColorType.FLOAT32)
}
encodeFilter.apply(fit!!, encoded!!)
var result = jumpFlooder!!.jumpFlood(encoded!!)
if (outputDistanceToContours) {
contourFilter.apply(result, contoured!!)
result = jumpFlooder!!.jumpFlood(contoured!!)
}
decodeFilter.outputIds = true
decodeFilter.originalSize = Vector2(source[0].width.toDouble(), source[0].height.toDouble())
decodeFilter.distanceScale = distanceScale
decodeFilter.normalizedDistance = normalizedDistance
decodeFilter.unitDirection = unitDirection
decodeFilter.flipV = flipV
decodeFilter.apply(arrayOf(result, encoded!!), arrayOf(result))
result.copyTo(
target[0],
sourceRectangle = IntRectangle(
0,
advisedSize - source[0].effectiveHeight,
source[0].effectiveWidth,
source[0].effectiveHeight
),
targetRectangle = IntRectangle(0, 0, source[0].effectiveWidth, source[0].effectiveHeight)
)
}
override fun destroy() {
encodeFilter.destroy()
contourFilter.destroy()
fit?.destroy()
encoded?.destroy()
contoured?.destroy()
jumpFlooder?.destroy()
}
}

View File

@@ -1,9 +1,7 @@
package org.openrndr.extra.jumpfill
import org.openrndr.draw.ColorBuffer
import org.openrndr.draw.ColorFormat
import org.openrndr.draw.Filter
import org.openrndr.draw.colorBuffer
import org.openrndr.draw.*
import org.openrndr.extra.parameters.BooleanParameter
import org.openrndr.extra.parameters.Description
import org.openrndr.extra.parameters.DoubleParameter
import org.openrndr.math.Vector2
@@ -14,13 +12,22 @@ import kotlin.math.max
import kotlin.math.pow
@Description("Directional field")
class DirectionalField : Filter() {
class DirectionalField : Filter1to1() {
@DoubleParameter("threshold", 0.0, 1.0)
var threshold = 0.5
@DoubleParameter("distance scale", 0.0, 1.0)
var distanceScale = 1.0
@BooleanParameter("normalized distance")
var normalizedDistance = false
@BooleanParameter("unit direction")
var unitDirection = false
@BooleanParameter("flip v direction")
var flipV = true
private val thresholdFilter = Threshold()
private var thresholded: ColorBuffer? = null
private val contourFilter = ContourPoints()
@@ -71,8 +78,11 @@ class DirectionalField : Filter() {
thresholdFilter.apply(fit!!, thresholded!!)
contourFilter.apply(thresholded!!, contoured!!)
val result = jumpFlooder!!.jumpFlood(contoured!!)
decodeFilter.originalSize = Vector2(advisedSize.toDouble(), advisedSize.toDouble())
decodeFilter.originalSize = Vector2(source[0].width.toDouble(), source[0].height.toDouble())
decodeFilter.distanceScale = distanceScale
decodeFilter.normalizedDistance = normalizedDistance
decodeFilter.unitDirection = unitDirection
decodeFilter.flipV = flipV
decodeFilter.apply(arrayOf(result, thresholded!!), arrayOf(result))
result.copyTo(target[0],
sourceRectangle = IntRectangle(0, advisedSize-source[0].effectiveHeight, source[0].effectiveWidth, source[0].effectiveHeight),

View File

@@ -1,9 +1,6 @@
package org.openrndr.extra.jumpfill
import org.openrndr.draw.ColorBuffer
import org.openrndr.draw.ColorFormat
import org.openrndr.draw.Filter
import org.openrndr.draw.colorBuffer
import org.openrndr.draw.*
import org.openrndr.extra.parameters.BooleanParameter
import org.openrndr.extra.parameters.Description
import org.openrndr.extra.parameters.DoubleParameter
@@ -15,7 +12,7 @@ import kotlin.math.max
import kotlin.math.pow
@Description("Distance field")
class DistanceField : Filter() {
class DistanceField : Filter1to1() {
@DoubleParameter("threshold", 0.0, 1.0)
var threshold = 0.5
@@ -63,27 +60,25 @@ class DistanceField : Filter() {
)
if (thresholded == null) {
thresholded = colorBuffer(target[0].width, target[0].height, format = ColorFormat.R)
thresholded = colorBuffer(advisedSize, advisedSize, format = ColorFormat.R)
}
if (contoured == null) {
contoured = colorBuffer(target[0].width, target[0].height, format = ColorFormat.R)
contoured = colorBuffer(advisedSize, advisedSize, format = ColorFormat.R)
}
if (jumpFlooder == null) {
jumpFlooder = JumpFlooder(target[0].width, target[0].height)
jumpFlooder = JumpFlooder(advisedSize, advisedSize)
}
thresholdFilter.threshold = threshold
thresholdFilter.apply(fit!!, thresholded!!)
contourFilter.apply(thresholded!!, contoured!!)
val result = jumpFlooder!!.jumpFlood(contoured!!)
decodeFilter.signedDistance = signedDistance
decodeFilter.originalSize = Vector2(advisedSize.toDouble(), advisedSize.toDouble())
decodeFilter.originalSize = Vector2(source[0].width.toDouble(), source[0].height.toDouble())
decodeFilter.distanceScale = distanceScale
decodeFilter.signedBit = false
decodeFilter.apply(arrayOf(result, thresholded!!), arrayOf(result))
result.copyTo(target[0],
sourceRectangle = IntRectangle(0, advisedSize-source[0].effectiveHeight, source[0].effectiveWidth, source[0].effectiveHeight),
targetRectangle = IntRectangle(0, 0, source[0].effectiveWidth, source[0].effectiveHeight)
)
}
}

View File

@@ -3,46 +3,61 @@ package org.openrndr.extra.jumpfill
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.*
import org.openrndr.extra.fx.blend.Passthrough
import org.openrndr.extra.parameters.Description
import org.openrndr.extra.parameters.DoubleParameter
import org.openrndr.extra.jumpflood.*
import org.openrndr.math.Vector2
import org.openrndr.resourceUrl
import kotlin.math.ceil
import kotlin.math.max
import kotlin.math.pow
import kotlin.math.*
class EncodePoints : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/encode-points.frag")))
class EncodePoints : Filter(filterShaderFromCode(jf_encode_points, "encode-points"))
class EncodeSubpixel : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/encode-subpixel.frag"))) {
class EncodeSubpixel : Filter(filterShaderFromCode(jf_encode_subpixel, "encode-subpixel")) {
var threshold by parameters
init {
threshold = 0.5
}
}
class JumpFlood : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/jumpflood.frag"))) {
class JumpFlood : Filter(filterShaderFromCode(jf_jumpflood, "jumpflood")) {
var maxSteps: Int by parameters
var step: Int by parameters
}
class PixelDirection : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/pixel-direction.frag"))) {
enum class DecodeMode(val shaderDefine: String) {
DISTANCE("OUTPUT_DISTANCE"),
DIRECTION("OUTPUT_DIRECTION")
}
class PixelDirection(val decodeMode: DecodeMode = DecodeMode.DIRECTION) :
Filter(
filterShaderFromCode(
"#define ${decodeMode.shaderDefine}\n $jf_pixel_direction",
"pixel-direction")
) {
var distanceScale: Double by parameters
var originalSize: Vector2 by parameters
var normalizedDistance: Boolean by parameters
var unitDirection: Boolean by parameters
var flipV: Boolean by parameters
var outputIds: Boolean by parameters
init {
distanceScale = 1.0
originalSize = Vector2(512.0, 512.0)
normalizedDistance = false
unitDirection = false
flipV = true
outputIds = false
}
}
class PixelDistance : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/pixel-distance.frag"))) {
class PixelDistance : Filter(filterShaderFromCode(jf_pixel_distance, "pixel-distance")) {
var distanceScale: Double by parameters
var originalSize: Vector2 by parameters
var signedBit: Boolean by parameters
var signedDistance: Boolean by parameters
init {
distanceScale = 1.0
originalSize = Vector2(512.0, 512.0)
@@ -51,8 +66,12 @@ class PixelDistance : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/pixel
}
}
class ContourPoints : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/contour-points.frag")))
class Threshold : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/threshold.frag"))) {
class ContourPoints : Filter(filterShaderFromCode(jf_contour_points, "contour-points"))
class IdContourPoints : Filter(filterShaderFromCode(jf_id_contours, "id-contour-points"))
class Threshold : Filter(filterShaderFromCode(jf_threshold, "threshold")) {
var threshold: Double by parameters
init {
@@ -60,7 +79,7 @@ class Threshold : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/threshold
}
}
class AlphaThreshold : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/alpha-threshold.frag"))) {
class AlphaThreshold : Filter(filterShaderFromCode(jf_alpha_threshold, "alpha-threshold")) {
var threshold: Double by parameters
init {
@@ -70,23 +89,27 @@ class AlphaThreshold : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/alph
private val encodePoints by lazy { persistent { EncodePoints() } }
private val pixelDistance by lazy { persistent { PixelDistance() } }
private val pixelDistance by lazy { persistent { PixelDistance() } }
private val pixelDirection by lazy { persistent { PixelDirection() } }
private val contourPoints by lazy { persistent { ContourPoints() } }
private val threshold by lazy { persistent { Threshold() } }
private val threshold by lazy { persistent { Threshold() } }
private val passthrough by lazy { persistent { Passthrough() } }
class JumpFlooder(val width: Int, val height: Int, format: ColorFormat = ColorFormat.RGB, type: ColorType = ColorType.FLOAT32,
val encodePoints: Filter = EncodePoints()) {
class JumpFlooder(
val width: Int, val height: Int, format: ColorFormat = ColorFormat.RGBa, type: ColorType = ColorType.FLOAT32,
val encodePoints: Filter = EncodePoints()
) {
private val dimension = max(width, height)
private val exp = ceil(Math.log(dimension.toDouble()) / Math.log(2.0)).toInt()
private val exp = ceil(log2(dimension.toDouble())).toInt()
val squareDim = 2.0.pow(exp.toDouble()).toInt()
val jumpFlood = JumpFlood()
private val coordinates =
listOf(colorBuffer(squareDim, squareDim, format = format, type = type),
colorBuffer(squareDim, squareDim, format = format, type = type))
listOf(
colorBuffer(squareDim, squareDim, format = format, type = type),
colorBuffer(squareDim, squareDim, format = format, type = type)
)
val final = colorBuffer(squareDim, squareDim, format = format, type = type)
@@ -122,9 +145,10 @@ class JumpFlooder(val width: Int, val height: Int, format: ColorFormat = ColorFo
}
}
private fun encodeDecodeBitmap(preprocess: Filter, decoder: Filter, bitmap: ColorBuffer,
jumpFlooder: JumpFlooder? = null,
result: ColorBuffer? = null
private fun encodeDecodeBitmap(
preprocess: Filter, decoder: Filter, bitmap: ColorBuffer,
jumpFlooder: JumpFlooder? = null,
result: ColorBuffer? = null
): ColorBuffer {
val _jumpFlooder = jumpFlooder ?: JumpFlooder(bitmap.width, bitmap.height)
val _result = result ?: colorBuffer(bitmap.width, bitmap.height, type = ColorType.FLOAT16)
@@ -145,17 +169,20 @@ private fun encodeDecodeBitmap(preprocess: Filter, decoder: Filter, bitmap: Colo
* Creates a color buffer containing the coordinates of the nearest centroids
* @param bitmap a ColorBuffer with centroids in red (> 0)
*/
fun centroidsFromBitmap(bitmap: ColorBuffer,
jumpFlooder: JumpFlooder? = null,
result: ColorBuffer? = null
fun centroidsFromBitmap(
bitmap: ColorBuffer,
jumpFlooder: JumpFlooder? = null,
result: ColorBuffer? = null
): ColorBuffer = encodeDecodeBitmap(passthrough, passthrough, bitmap, jumpFlooder, result)
fun distanceFieldFromBitmap(bitmap: ColorBuffer,
jumpFlooder: JumpFlooder? = null,
result: ColorBuffer? = null
fun distanceFieldFromBitmap(
bitmap: ColorBuffer,
jumpFlooder: JumpFlooder? = null,
result: ColorBuffer? = null
): ColorBuffer = encodeDecodeBitmap(contourPoints, pixelDistance, bitmap, jumpFlooder, result)
fun directionFieldFromBitmap(bitmap: ColorBuffer,
jumpFlooder: JumpFlooder? = null,
result: ColorBuffer? = null
fun directionFieldFromBitmap(
bitmap: ColorBuffer,
jumpFlooder: JumpFlooder? = null,
result: ColorBuffer? = null
): ColorBuffer = encodeDecodeBitmap(contourPoints, pixelDirection, bitmap, jumpFlooder, result)

View File

@@ -3,14 +3,14 @@ package org.openrndr.extra.jumpfill.draw
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.ColorBuffer
import org.openrndr.draw.Filter
import org.openrndr.draw.filterShaderFromUrl
import org.openrndr.draw.filterShaderFromCode
import org.openrndr.extra.jumpflood.jf_sdf_stroke_fill
import org.openrndr.extra.parameters.ColorParameter
import org.openrndr.extra.parameters.Description
import org.openrndr.extra.parameters.DoubleParameter
import org.openrndr.resourceUrl
@Description("SDF stroke and fill")
class SDFStrokeFill : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/draw/sdf-stroke-fill.frag"))) {
class SDFStrokeFill : Filter(filterShaderFromCode(jf_sdf_stroke_fill, "sdf-stroke-fill")) {
@DoubleParameter("stroke weight", 0.0, 20.0, order = 0)
var strokeWeight: Double by parameters

View File

@@ -4,12 +4,13 @@ import org.openrndr.draw.*
import org.openrndr.extra.jumpfill.EncodeSubpixel
import org.openrndr.extra.jumpfill.JumpFlooder
import org.openrndr.extra.jumpfill.PixelDirection
import org.openrndr.extra.jumpflood.jf_inner_bevel
import org.openrndr.extra.parameters.Description
import org.openrndr.extra.parameters.DoubleParameter
import org.openrndr.math.Vector2
import org.openrndr.resourceUrl
private class InnerBevelFilter : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/fx/inner-bevel.frag"))) {
private class InnerBevelFilter : Filter(filterShaderFromCode(jf_inner_bevel, "inner-bevel")) {
var angle: Double by parameters
var width: Double by parameters

View File

@@ -5,13 +5,14 @@ import org.openrndr.draw.*
import org.openrndr.extra.jumpfill.EncodeSubpixel
import org.openrndr.extra.jumpfill.JumpFlooder
import org.openrndr.extra.jumpfill.PixelDirection
import org.openrndr.extra.jumpflood.jf_inner_glow
import org.openrndr.extra.parameters.ColorParameter
import org.openrndr.extra.parameters.Description
import org.openrndr.extra.parameters.DoubleParameter
import org.openrndr.math.Vector2
import org.openrndr.resourceUrl
private class InnerGlowFilter : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/fx/inner-glow.frag"))) {
private class InnerGlowFilter : Filter(filterShaderFromCode(jf_inner_glow, "inner-glow")) {
var angle: Double by parameters
var width: Double by parameters
@@ -31,7 +32,7 @@ private class InnerGlowFilter : Filter(filterShaderFromUrl(resourceUrl("/shaders
}
@Description("Inner glow")
class InnerGlow : Filter() {
class InnerGlow : Filter1to1() {
@DoubleParameter("width", 0.0, 50.0)
var width = 5.0

View File

@@ -4,12 +4,13 @@ import org.openrndr.draw.*
import org.openrndr.extra.jumpfill.EncodeSubpixel
import org.openrndr.extra.jumpfill.JumpFlooder
import org.openrndr.extra.jumpfill.PixelDirection
import org.openrndr.extra.jumpflood.jf_inpaint
import org.openrndr.extra.parameters.Description
import org.openrndr.extra.parameters.DoubleParameter
import org.openrndr.math.Vector2
import org.openrndr.resourceUrl
private class InpaintFilter : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/fx/inpaint.frag"))) {
private class InpaintFilter : Filter(filterShaderFromCode(jf_inpaint, "inpaint")) {
var noise: Double by parameters
var imageOpacity: Double by parameters

View File

@@ -5,13 +5,14 @@ import org.openrndr.draw.*
import org.openrndr.extra.jumpfill.EncodeSubpixel
import org.openrndr.extra.jumpfill.JumpFlooder
import org.openrndr.extra.jumpfill.PixelDirection
import org.openrndr.extra.jumpflood.jf_outer_glow
import org.openrndr.extra.parameters.ColorParameter
import org.openrndr.extra.parameters.Description
import org.openrndr.extra.parameters.DoubleParameter
import org.openrndr.math.Vector2
import org.openrndr.resourceUrl
private class OuterGlowFilter : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/fx/outer-glow.frag"))) {
private class OuterGlowFilter : Filter(filterShaderFromCode(jf_outer_glow, "outer-glow")) {
var angle: Double by parameters
var width: Double by parameters

View File

@@ -3,6 +3,7 @@ package org.openrndr.extra.jumpfill.fx
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.*
import org.openrndr.extra.jumpfill.*
import org.openrndr.extra.jumpflood.jf_skeleton
import org.openrndr.extra.parameters.ColorParameter
import org.openrndr.extra.parameters.Description
@@ -10,7 +11,7 @@ import org.openrndr.extra.parameters.DoubleParameter
import org.openrndr.math.Vector2
import org.openrndr.resourceUrl
private class SkeletonFilter : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/fx/skeleton.frag"))) {
private class SkeletonFilter : Filter(filterShaderFromCode(jf_skeleton, "skeleton")) {
var skeletonColor: ColorRGBa by parameters
var foregroundColor: ColorRGBa by parameters
var backgroundColor: ColorRGBa by parameters

View File

@@ -3,6 +3,7 @@ package org.openrndr.extra.jumpfill.fx
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.*
import org.openrndr.extra.jumpfill.*
import org.openrndr.extra.jumpflood.jf_straight_skeleton
import org.openrndr.extra.parameters.ColorParameter
import org.openrndr.extra.parameters.Description
@@ -11,7 +12,7 @@ import org.openrndr.math.Vector2
import org.openrndr.resourceUrl
import kotlin.math.sqrt
private class StraightSkeletonFilter : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/fx/straight-skeleton.frag"))) {
private class StraightSkeletonFilter : Filter(filterShaderFromCode(jf_straight_skeleton, "straight-skeleton")) {
var angleThreshold: Double by parameters
var skeletonColor: ColorRGBa by parameters
var foregroundColor: ColorRGBa by parameters

View File

@@ -3,12 +3,13 @@ package org.openrndr.extra.jumpfill.ops
import org.openrndr.draw.ColorBuffer
import org.openrndr.draw.ColorType
import org.openrndr.draw.Filter
import org.openrndr.draw.filterShaderFromUrl
import org.openrndr.draw.filterShaderFromCode
import org.openrndr.extra.jumpflood.*
import org.openrndr.extra.parameters.Description
import org.openrndr.extra.parameters.DoubleParameter
import org.openrndr.resourceUrl
class SDFSmoothUnion : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/ops/sdf-smooth-union.frag"))) {
class SDFSmoothUnion : Filter(filterShaderFromCode(jf_sdf_smooth_union, "sdf-smooth-union")) {
var radius: Double by parameters
init {
@@ -23,7 +24,7 @@ class SDFSmoothUnion : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/ops/
}
}
class SDFSmoothIntersection : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/ops/sdf-smooth-intersection.frag"))) {
class SDFSmoothIntersection : Filter(filterShaderFromCode(jf_sdf_smooth_intersection, "sdf-smooth-intersection")) {
var radius: Double by parameters
init {
@@ -38,7 +39,7 @@ class SDFSmoothIntersection : Filter(filterShaderFromUrl(resourceUrl("/shaders/g
}
}
@Description("SDF smooth difference")
class SDFSmoothDifference : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/ops/sdf-smooth-difference.frag"))) {
class SDFSmoothDifference : Filter(filterShaderFromCode(jf_sdf_smooth_difference, "sdf-smooth-differecnce")) {
@DoubleParameter("smooth radius", 0.0, 200.0, order = 0)
var radius: Double by parameters
@@ -54,7 +55,7 @@ class SDFSmoothDifference : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3
}
}
class SDFRound : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/ops/sdf-round.frag"))) {
class SDFRound : Filter(filterShaderFromCode(jf_sdf_round, "sdf-round")) {
@DoubleParameter("rounding radius", 0.0, 200.0, order = 0)
var radius: Double by parameters
@@ -70,7 +71,7 @@ class SDFRound : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/ops/sdf-ro
}
}
class SDFOnion : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/ops/sdf-onion.frag"))) {
class SDFOnion : Filter(filterShaderFromCode(jf_sdf_onion, "sdf-onion")) {
var radius: Double by parameters
init {
@@ -85,7 +86,7 @@ class SDFOnion : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/ops/sdf-on
}
}
class SDFBlend : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/ops/sdf-blend.frag"))) {
class SDFBlend : Filter(filterShaderFromCode(jf_sdf_blend, "sdf-blend")) {
var factor: Double by parameters
init {
@@ -98,5 +99,4 @@ class SDFBlend : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/ops/sdf-bl
}
super.apply(source, target)
}
}

View File

@@ -1,6 +1,5 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extensions.SingleScreenshot
import org.openrndr.extra.compositor.compose
import org.openrndr.extra.compositor.draw
import org.openrndr.extra.compositor.layer
@@ -10,11 +9,6 @@ import org.openrndr.extra.jumpfill.fx.InnerGlow
fun main() = application {
program {
if (System.getProperty("takeScreenshot") == "true") {
extend(SingleScreenshot()) {
this.outputFile = System.getProperty("screenshotPath")
}
}
val c = compose {
layer {
post(Checkers())

View File

@@ -10,11 +10,6 @@ import org.openrndr.extra.jumpfill.fx.InnerGlow
fun main() = application {
program {
if (System.getProperty("takeScreenshot") == "true") {
extend(SingleScreenshot()) {
this.outputFile = System.getProperty("screenshotPath")
}
}
val c = compose {
layer {
post(Checkers())

View File

@@ -20,11 +20,6 @@ fun main() {
sdf.setShapes(shapes)
sdf.apply(emptyArray(), df)
if (System.getProperty("takeScreenshot") == "true") {
extend(SingleScreenshot()) {
this.outputFile = System.getProperty("screenshotPath")
}
}
extend {
if(mouse.pressedButtons.isEmpty())
drawer.image(df)

View File

@@ -33,12 +33,6 @@ fun main() {
val strokeFill = SDFStrokeFill()
// -- this block is for automation purposes only
if (System.getProperty("takeScreenshot") == "true") {
extend(SingleScreenshot()) {
this.outputFile = System.getProperty("screenshotPath")
}
}
extend {
drawer.clear(ColorRGBa.PINK)

View File

@@ -8,7 +8,6 @@ import org.openrndr.extra.fx.distort.FluidDistort
import org.openrndr.extra.jumpfill.ShapeSDF
import org.openrndr.extra.jumpfill.draw.SDFStrokeFill
import org.openrndr.extra.jumpfill.ops.*
import org.openrndr.math.transforms.transform
import org.openrndr.svg.loadSVG
fun main() {
@@ -36,11 +35,6 @@ fun main() {
val strokeFill = SDFStrokeFill()
if (System.getProperty("takeScreenshot") == "true") {
extend(SingleScreenshot()) {
this.outputFile = System.getProperty("screenshotPath")
}
}
extend {
drawer.clear(ColorRGBa.PINK)

View File

@@ -40,11 +40,6 @@ fun main() {
val strokeFill = SDFStrokeFill()
gui.add(perturb)
if (System.getProperty("takeScreenshot") == "true") {
extend(SingleScreenshot()) {
this.outputFile = System.getProperty("screenshotPath")
}
}
extend(gui)
extend {
drawer.clear(ColorRGBa.PINK)

View File

@@ -3,7 +3,6 @@ import org.openrndr.color.ColorRGBa
import org.openrndr.draw.ColorFormat
import org.openrndr.draw.ColorType
import org.openrndr.draw.colorBuffer
import org.openrndr.extensions.SingleScreenshot
import org.openrndr.extra.fx.distort.Perturb
import org.openrndr.extra.gui.GUI
import org.openrndr.extra.jumpfill.ShapeSDF
@@ -49,12 +48,6 @@ fun main() {
gui.add(strokeFill)
gui.add(difference)
if (System.getProperty("takeScreenshot") == "true") {
extend(SingleScreenshot()) {
this.outputFile = System.getProperty("screenshotPath")
}
}
extend(gui)
extend {
drawer.clear(ColorRGBa.PINK)

View File

@@ -22,11 +22,6 @@ fun main() {
colorBuffer()
}
val field = input.colorBuffer(0).createEquivalent(type = ColorType.FLOAT32)
if (System.getProperty("takeScreenshot") == "true") {
extend(SingleScreenshot()) {
this.outputFile = System.getProperty("screenshotPath")
}
}
extend {
drawer.isolatedWithTarget(input) {
// -- draw something interesting

View File

@@ -5,7 +5,6 @@ import org.openrndr.draw.createEquivalent
import org.openrndr.draw.isolatedWithTarget
import org.openrndr.draw.renderTarget
import org.openrndr.extensions.SingleScreenshot
import org.openrndr.extra.jumpfill.fx.StraightSkeleton
import org.openrndr.extra.noise.simplex
@@ -16,12 +15,6 @@ fun main() {
height = 720
}
program {
if (System.getProperty("takeScreenshot") == "true") {
extend(SingleScreenshot()) {
this.outputFile = System.getProperty("screenshotPath")
}
}
val straightSkeleton = StraightSkeleton()
val input = renderTarget(width, height) {
colorBuffer()

View File

@@ -0,0 +1,68 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.*
import org.openrndr.extra.fx.blend.Passthrough
import org.openrndr.extra.jumpfill.EncodePoints
import org.openrndr.extra.jumpfill.IdContourPoints
import org.openrndr.extra.jumpfill.JumpFlooder
import kotlin.math.cos
fun main() = application {
configure {
width = 512
height = 512
}
program {
val rt = renderTarget(512, 512, 1.0) {
colorBuffer(type = ColorType.FLOAT32)
}
val encoder = EncodePoints()
val jf = JumpFlooder(512, 512, encodePoints = Passthrough())
val jf2 = JumpFlooder(512, 512, encodePoints = Passthrough())
val idcontours = IdContourPoints()
val contoured = colorBuffer(512, 512, type = ColorType.FLOAT32)
extend {
fun plot(x: Double, y: Double, id: Double) {
drawer.fill = ColorRGBa(id, 0.0, 0.0, 1.0)
drawer.point(x, y)
}
drawer.isolatedWithTarget(rt) {
drawer.clear(ColorRGBa(-1.0, -1.0, -1.0, 0.0))
val o = cos(seconds) * 200.0 + 200.0
for (i in 0 until 20) {
plot(o + 100.0 + i * 4, 100.0, 0.25)
}
for (i in 0 until 20) {
plot(200.0 + i * 4, 150.0 + i, 0.5)
}
for (i in 0 until 20) {
plot(300.0 + i * 4, 250.0 + i, 0.7)
}
for (i in 0 until 20) {
plot(400.0 + i * 4, 250.0 + i, 0.75)
}
}
encoder.apply(rt.colorBuffer(0), rt.colorBuffer(0))
val flooded = jf.jumpFlood(rt.colorBuffer(0))
drawer.image(flooded)
idcontours.apply(flooded, contoured)
drawer.image(contoured)
val flooded2 = jf2.jumpFlood(contoured)
drawer.image(flooded2, 512.0, 0.0)
drawer.shadeStyle = shadeStyle {
fragmentTransform = """
float d = length(va_texCoord0.xy - x_fill.xy);
x_fill = vec4(d,d,x_fill.z, 1.0);
""".trimIndent()
}
drawer.image(flooded2, 0.0, 0.0)
}
}
}

View File

@@ -0,0 +1,55 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.*
import org.openrndr.extra.jumpfill.*
import kotlin.math.cos
fun main() = application {
configure {
width = 512
height = 512
}
program {
val rt = renderTarget(512, 512, 1.0) {
colorBuffer(type = ColorType.FLOAT32)
}
val flowfield = colorBuffer(512, 512, type = ColorType.FLOAT32)
val cluster = ClusteredField(decodeMode = DecodeMode.DISTANCE, outputDistanceToContours = true)
cluster.normalizedDistance = true
extend {
fun plot(x: Double, y: Double, id: Double) {
drawer.fill = ColorRGBa(id, 0.0, 0.0, 1.0)
drawer.point(x, y)
}
drawer.isolatedWithTarget(rt) {
drawer.clear(ColorRGBa(-1.0, -1.0, -1.0, 0.0))
val o = cos(seconds) * 200.0 + 200.0
for (i in 0 until 20) {
plot(o + 100.0 + i * 4, 100.0, 0.25)
}
for (i in 0 until 20) {
plot(200.0 + i * 4, 150.0 + i, 0.5)
}
for (i in 0 until 20) {
plot(300.0 + i * 4, 250.0 + i, 0.7)
}
for (i in 0 until 20) {
plot(400.0 + i * 4, 250.0 + i, 0.75)
}
}
cluster.apply(rt.colorBuffer(0), flowfield)
drawer.drawStyle.colorMatrix = tint(ColorRGBa(10.0, 10.0, 1.0))
drawer.image(flowfield)
}
}
}

View File

@@ -0,0 +1,43 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.draw.*
import org.openrndr.extra.fx.blend.Passthrough
import org.openrndr.extra.jumpfill.*
import org.openrndr.extra.noise.scatter
import org.openrndr.extra.noise.uniformRing
import org.openrndr.math.Vector2
fun main() = application {
configure {
width = 720
height = 720
}
program {
val rt = renderTarget(720, 720, 1.0) {
colorBuffer(type = ColorType.FLOAT32)
}
val flowfield = colorBuffer(width, height, type = ColorType.FLOAT32)
val cluster = ClusteredField(decodeMode = DecodeMode.DISTANCE, outputDistanceToContours = true)
cluster.normalizedDistance = true
extend {
drawer.isolatedWithTarget(rt) {
drawer.ortho(rt)
drawer.clear(ColorRGBa(-1.0, -1.0, -1.0, 0.0))
val points = drawer.bounds.scatter(20.0)
drawer.points {
for ((index, point) in points.withIndex()) {
fill = ColorRGBa((index+1.0)/points.size, 0.0, 0.0, 1.0)
for (i in 0 until 30) {
point(point + Vector2.uniformRing(15.0, 25.0)* Vector2(1.0, 1.0))
}
}
}
}
cluster.apply(rt.colorBuffer(0), flowfield)
drawer.drawStyle.colorMatrix = tint(ColorRGBa(100.0, 100.0, 0.0))
drawer.image(flowfield)
}
}
}

View File

@@ -1,6 +1,7 @@
package org.openrndr.extra.jumpfill
import org.openrndr.draw.*
import org.openrndr.extra.jumpflood.jf_shape_sdf
import org.openrndr.extra.parameters.BooleanParameter
import org.openrndr.math.Matrix44
import org.openrndr.math.Vector4
@@ -9,7 +10,7 @@ import org.openrndr.shape.Shape
import org.openrndr.shape.ShapeContour
class ShapeSDF : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/shape-sdf.frag"))) {
class ShapeSDF : Filter(filterShaderFromCode(jf_shape_sdf, "shape-sdf")) {
private val fromBuffer = bufferTexture(1024, format = ColorFormat.RGBa, type = ColorType.FLOAT32)
private val toBuffer = bufferTexture(1024, format = ColorFormat.RGBa, type = ColorType.FLOAT32)
private var segmentCount = 0
@@ -23,10 +24,10 @@ class ShapeSDF : Filter(filterShaderFromUrl(resourceUrl("/shaders/gl3/shape-sdf.
private var modelViewMatrixInverse by parameters
var modelViewMatrix = Matrix44.IDENTITY
set(value) {
modelViewMatrixInverse = modelViewMatrix.inversed
field = value
}
set(value) {
modelViewMatrixInverse = modelViewMatrix.inversed
field = value
}
init {
useUV = false

View File

@@ -1,21 +0,0 @@
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform vec2 originalSize;
uniform vec2 directionalField;
uniform float distanceScale;
in vec2 v_texCoord0;
out vec4 o_color;
void main() {
vec2 sizeDF = textureSize(tex0, 0); // this is always square
vec2 sizeTF = textureSize(tex1, 0); // this can be non-square
vec2 pixelPosition = v_texCoord0;
vec2 centroidPixelPosition = texture(tex0, v_texCoord0).xy;
vec2 pixelDistance = (centroidPixelPosition - pixelPosition) * sizeDF * vec2(1.0, -1.0);
vec2 dfTf = sizeDF / sizeTF; // texture adjusment factor
float threshold = texture(tex1, v_texCoord0 * dfTf).r;
o_color = vec4(pixelDistance * distanceScale, threshold, 1.0);
}

View File

@@ -4,10 +4,10 @@ in vec2 v_texCoord0;
out vec4 o_color;
void main() {
vec2 stepSize = 1.0 / textureSize(tex0, 0);
vec2 stepSize = 1.0 / vec2(textureSize(tex0, 0));
float ref = step(0.5 , texture(tex0, v_texCoord0).r);
float laplacian = -4 * ref;
float laplacian = -4.0 * ref;
laplacian += step(0.5, texture(tex0, v_texCoord0 + vec2(stepSize.x, 0.0)).r);
laplacian += step(0.5, texture(tex0, v_texCoord0 - vec2(stepSize.x, 0.0)).r);

View File

@@ -13,7 +13,7 @@ float zd(float d) {
}
void main() {
vec2 stepSize = 1.0 / textureSize(tex0, 0);
vec2 stepSize = 1.0 / vec2(textureSize(tex0, 0));
float ref = step(threshold, texture(tex0, v_texCoord0).a);

View File

@@ -0,0 +1,25 @@
uniform sampler2D tex0;
in vec2 v_texCoord0;
out vec4 o_color;
void main() {
vec4 colorMask = vec4(0.0, 0.0, 1.0, 0.0);
vec2 stepSize = 1.0 / vec2(textureSize(tex0, 0));
vec4 ref = texture(tex0, v_texCoord0);
float laplacian = 0.0;
laplacian += abs(texture(tex0, v_texCoord0 + vec2(stepSize.x, 0.0)).b-ref.b);
laplacian += abs(texture(tex0, v_texCoord0 - vec2(stepSize.x, 0.0)).b-ref.b);
laplacian += abs(texture(tex0, v_texCoord0 + vec2(0.0, stepSize.y)).b-ref.b);
laplacian += abs(texture(tex0, v_texCoord0 - vec2(0.0, stepSize.y)).b-ref.b);
float contour = step(0.0, laplacian);
if (laplacian > 0.001) {
o_color = vec4(v_texCoord0.x, v_texCoord0.y, ref.b, 1.0);
} else {
o_color = vec4(-1.0, -1.0, -1.0, 1.0);
}
}

View File

@@ -22,7 +22,7 @@ void main() {
vec4 color = texture(tex0, v_texCoord0);
vec2 step = 1.0 / textureSize(tex0, 0);
vec2 step = 1.0 / vec2(textureSize(tex0, 0));
vec2 distance = vec2(0.0);
float totalWeight = 0.0;

View File

@@ -18,7 +18,7 @@ vec2 hash22(vec2 p) {
void main() {
vec4 original = texture(tex0, v_texCoord0);
vec2 step = 1.0 / textureSize(tex0, 0);
vec2 step = 1.0 / vec2(textureSize(tex0, 0));
vec2 distance = texture(tex1, v_texCoord0).rg;
float d = length(distance);
vec2 n = normalize(distance);

View File

@@ -18,7 +18,7 @@ vec2 hash22(vec2 p) {
void main() {
vec4 original = texture(tex0, v_texCoord0);
vec2 ts = textureSize(tex0, 0);
vec2 ts = vec2(textureSize(tex0, 0));
vec2 step = 1.0 / ts;
vec2 distance = texture(tex1, v_texCoord0).rg;

View File

@@ -7,13 +7,13 @@ uniform int step;
out vec4 o_color;
void main() {
float stepwidth = 1.0 / pow(2.0, min(maxSteps, step+1));
float stepwidth = 1.0 / pow(2.0, min(float(maxSteps), float(step+1)));
float bestDistance = 999999.0;
vec2 bestCoord = vec2(-1.0);
float bestDistance = 1E10;
vec2 bestCoord = vec2(-100.0);
vec2 bestColor = vec2(-1.0);
vec2 is = vec2(1.0) / textureSize(tex0, 0);
vec2 is = vec2(1.0) / vec2(textureSize(tex0, 0));
float found = 0.0;
for (int y = -1; y <= 1; ++y) {
@@ -23,7 +23,7 @@ void main() {
vec2 seedCoord = data.xy;
vec2 seedColor = data.zw;
float dist = length(seedCoord - v_texCoord0);
if ((seedCoord.x >= 0.0 || seedCoord.y >= 0.0) && dist < bestDistance)
if ((seedCoord.x >= 0.0 && seedCoord.y >= 0.0) && dist <= bestDistance)
{
found = 1.0;
bestDistance = dist;

View File

@@ -18,7 +18,7 @@ vec2 hash22(vec2 p) {
void main() {
vec4 original = texture(tex0, v_texCoord0);
vec2 step = 1.0 / textureSize(tex0, 0);
vec2 step = 1.0 / vec2(textureSize(tex0, 0));
vec2 distance = texture(tex1, v_texCoord0).rg;
float d = length(distance);
vec2 n = normalize(distance);

View File

@@ -0,0 +1,59 @@
/*
use #define OUTPUT_DISTANCE to output distance
use #define OUTPUT_DIRECTION to output direction
*/
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform vec2 originalSize;
uniform vec2 directionalField;
uniform float distanceScale;
uniform bool normalizedDistance;
uniform bool unitDirection;
uniform bool flipV;
uniform bool outputIds;
in vec2 v_texCoord0;
out vec4 o_color;
void main() {
vec2 sizeDF = vec2(textureSize(tex0, 0)); // this is always square
vec2 sizeTF = vec2(textureSize(tex1, 0)); // this can be non-square
vec2 pixelPosition = v_texCoord0;
vec4 textureData = texture(tex0, v_texCoord0);
vec2 centroidPixelPosition = textureData.xy;
vec2 pixelDistance = (centroidPixelPosition - pixelPosition) * sizeDF;
if (flipV) {
pixelDistance *= vec2(1.0, -1.0);
}
if (unitDirection) {
float length = length(pixelDistance);
if (length >= 1E-6) {
pixelDistance /= length;
}
}
vec2 dfTf = sizeDF / sizeTF; // texture adjusment factor
float outputData = (!outputIds) ? texture(tex1, v_texCoord0 * dfTf).r : textureData.b;
#ifdef OUTPUT_DIRECTION
if (!normalizedDistance) {
o_color = vec4(pixelDistance * distanceScale, outputData, 1.0);
} else if (!unitDirection) {
o_color = vec4(pixelDistance / originalSize, outputData, 1.0);
}
#else
if (!normalizedDistance) {
o_color = vec4( length(pixelDistance * distanceScale).xx, outputData, 1.0);
} else if (!unitDirection) {
o_color = vec4( length(pixelDistance / originalSize).xx, outputData, 1.0);
}
#endif
}

View File

@@ -11,8 +11,8 @@ in vec2 v_texCoord0;
out vec4 o_color;
void main() {
vec2 sizeDF = textureSize(tex0, 0); // this is always square
vec2 sizeTF = textureSize(tex1, 0); // this can be non-square
vec2 sizeDF = vec2(textureSize(tex0, 0)); // this is always square
vec2 sizeTF = vec2(textureSize(tex1, 0)); // this can be non-square
vec2 pixelPosition = v_texCoord0;
vec2 centroidPixelPosition = texture(tex0, v_texCoord0).xy;

View File

@@ -92,7 +92,7 @@ void main() {
vec2 fixDistance = vec2(1.0);
if (useUV) {
vec2 o = 0.5 / textureSize(tex0, 0);
vec2 o = 0.5 / vec2(textureSize(tex0, 0));
uv = texture(tex0, v_texCoord0 + o).xy;
if (rectify) {
fixDistance = (fwidth(uv))*vec2(1280.0, 720.0);

View File

@@ -10,7 +10,7 @@ out vec4 o_color;
void main() {
float centerDistance = texture(tex0, v_texCoord0).r;
vec2 step = 1.0 / textureSize(tex0, 0);
vec2 step = 1.0 / vec2(textureSize(tex0, 0));
float minDistance = 1000.0;

View File

@@ -11,7 +11,7 @@ out vec4 o_color;
void main() {
vec4 ct = texture(tex0, v_texCoord0);
vec2 cd = normalize(ct.xy);
vec2 step = 1.0 / textureSize(tex0, 0);
vec2 step = 1.0 / vec2(textureSize(tex0, 0));
float minDistance = 1000.0;