From 885b9e54a4b16b50259e628f5ae06206d33c9a69 Mon Sep 17 00:00:00 2001 From: Edwin Jakobs Date: Mon, 27 Jun 2022 07:50:48 +0200 Subject: [PATCH] [orx-jumpflood] Add cropping for NPOT inputs --- .../src/main/kotlin/DirectionalField.kt | 58 ++++++++++++++++--- .../src/main/kotlin/DistanceField.kt | 45 +++++++++++++- 2 files changed, 93 insertions(+), 10 deletions(-) diff --git a/orx-jumpflood/src/main/kotlin/DirectionalField.kt b/orx-jumpflood/src/main/kotlin/DirectionalField.kt index f106842f..bcdea827 100644 --- a/orx-jumpflood/src/main/kotlin/DirectionalField.kt +++ b/orx-jumpflood/src/main/kotlin/DirectionalField.kt @@ -7,6 +7,11 @@ import org.openrndr.draw.colorBuffer 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("Directional field") class DirectionalField : Filter() { @@ -24,23 +29,62 @@ class DirectionalField : Filter() { private val decodeFilter = PixelDirection() + private var fit: ColorBuffer? = null + override fun apply(source: Array, target: Array) { + 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 + thresholded?.destroy() + thresholded = null + contoured?.destroy() + contoured = null + jumpFlooder?.destroy() + jumpFlooder = null + } + } + + if (fit == null) { + fit = colorBuffer(advisedSize, advisedSize) + } + + 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 (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(source[0], thresholded!!) + thresholdFilter.apply(fit!!, thresholded!!) contourFilter.apply(thresholded!!, contoured!!) val result = jumpFlooder!!.jumpFlood(contoured!!) - decodeFilter.originalSize = Vector2(target[0].width * 1.0, target[0].height * 1.0) + decodeFilter.originalSize = Vector2(advisedSize.toDouble(), advisedSize.toDouble()) decodeFilter.distanceScale = distanceScale - decodeFilter.apply(result, result) - result.copyTo(target[0]) + 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)) + } + + override fun destroy() { + thresholdFilter.destroy() + contourFilter.destroy() + fit?.destroy() + thresholded?.destroy() + contoured?.destroy() + jumpFlooder?.destroy() } } \ No newline at end of file diff --git a/orx-jumpflood/src/main/kotlin/DistanceField.kt b/orx-jumpflood/src/main/kotlin/DistanceField.kt index 88cd86d1..72e207fe 100644 --- a/orx-jumpflood/src/main/kotlin/DistanceField.kt +++ b/orx-jumpflood/src/main/kotlin/DistanceField.kt @@ -4,9 +4,15 @@ import org.openrndr.draw.ColorBuffer import org.openrndr.draw.ColorFormat import org.openrndr.draw.Filter import org.openrndr.draw.colorBuffer +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("Distance field") class DistanceField : Filter() { @@ -24,9 +30,38 @@ class DistanceField : Filter() { private val decodeFilter = PixelDistance() + private var fit: ColorBuffer? = null + + @BooleanParameter("signed distance") var signedDistance = true override fun apply(source: Array, target: Array) { + 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 + thresholded?.destroy() + thresholded = null + contoured?.destroy() + contoured = null + jumpFlooder?.destroy() + jumpFlooder = null + } + } + + if (fit == null) { + fit = colorBuffer(advisedSize, advisedSize) + } + + 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 (thresholded == null) { thresholded = colorBuffer(target[0].width, target[0].height, format = ColorFormat.R) } @@ -37,14 +72,18 @@ class DistanceField : Filter() { jumpFlooder = JumpFlooder(target[0].width, target[0].height) } thresholdFilter.threshold = threshold - thresholdFilter.apply(source[0], thresholded!!) + thresholdFilter.apply(fit!!, thresholded!!) contourFilter.apply(thresholded!!, contoured!!) val result = jumpFlooder!!.jumpFlood(contoured!!) decodeFilter.signedDistance = signedDistance - decodeFilter.originalSize = Vector2(target[0].width * 1.0, target[0].height * 1.0) + decodeFilter.originalSize = Vector2(advisedSize.toDouble(), advisedSize.toDouble()) decodeFilter.distanceScale = distanceScale decodeFilter.signedBit = false decodeFilter.apply(arrayOf(result, thresholded!!), arrayOf(result)) - result.copyTo(target[0]) + 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) + ) + } } \ No newline at end of file