[orx-jumpflood] Make module multiplatform
This commit is contained in:
188
orx-jumpflood/src/commonMain/kotlin/JumpFlood.kt
Normal file
188
orx-jumpflood/src/commonMain/kotlin/JumpFlood.kt
Normal file
@@ -0,0 +1,188 @@
|
||||
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.jumpflood.*
|
||||
|
||||
import org.openrndr.math.Vector2
|
||||
import kotlin.math.*
|
||||
|
||||
class EncodePoints : Filter(filterShaderFromCode(jf_encode_points, "encode-points"))
|
||||
|
||||
class EncodeSubpixel : Filter(filterShaderFromCode(jf_encode_subpixel, "encode-subpixel")) {
|
||||
var threshold by parameters
|
||||
|
||||
init {
|
||||
threshold = 0.5
|
||||
}
|
||||
}
|
||||
|
||||
class JumpFlood : Filter(filterShaderFromCode(jf_jumpflood, "jumpflood")) {
|
||||
var maxSteps: Int by parameters
|
||||
var step: Int by parameters
|
||||
}
|
||||
|
||||
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(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)
|
||||
signedBit = true
|
||||
signedDistance = false
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
threshold = 0.5
|
||||
}
|
||||
}
|
||||
|
||||
class AlphaThreshold : Filter(filterShaderFromCode(jf_alpha_threshold, "alpha-threshold")) {
|
||||
var threshold: Double by parameters
|
||||
|
||||
init {
|
||||
threshold = 0.5
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val encodePoints by lazy { persistent { EncodePoints() } }
|
||||
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 passthrough by lazy { persistent { Passthrough() } }
|
||||
|
||||
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(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)
|
||||
)
|
||||
|
||||
|
||||
val final = colorBuffer(squareDim, squareDim, format = format, type = type)
|
||||
|
||||
private val square = colorBuffer(squareDim, squareDim, format = ColorFormat.RGBa, type = type).apply {
|
||||
fill(ColorRGBa.BLACK.opacify(0.0))
|
||||
}
|
||||
|
||||
|
||||
fun jumpFlood(input: ColorBuffer): ColorBuffer {
|
||||
if (input.width != width || input.height != height) {
|
||||
throw IllegalArgumentException("dimensions mismatch")
|
||||
}
|
||||
|
||||
input.copyTo(square)
|
||||
encodePoints.apply(square, coordinates[0])
|
||||
|
||||
jumpFlood.maxSteps = exp
|
||||
for (i in 0 until exp) {
|
||||
jumpFlood.step = i
|
||||
jumpFlood.apply(coordinates[i % 2], coordinates[(i + 1) % 2])
|
||||
}
|
||||
|
||||
coordinates[exp % 2].copyTo(final)
|
||||
|
||||
return final
|
||||
}
|
||||
|
||||
fun destroy() {
|
||||
coordinates.forEach { it.destroy() }
|
||||
square.destroy()
|
||||
final.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
preprocess.apply(bitmap, _result)
|
||||
|
||||
val encoded = _jumpFlooder.jumpFlood(_result)
|
||||
|
||||
decoder.parameters["originalSize"] = Vector2(_jumpFlooder.squareDim.toDouble(), _jumpFlooder.squareDim.toDouble())
|
||||
decoder.apply(arrayOf(encoded, bitmap), _result)
|
||||
if (jumpFlooder == null) {
|
||||
_jumpFlooder.destroy()
|
||||
}
|
||||
return _result
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
): ColorBuffer = encodeDecodeBitmap(passthrough, passthrough, bitmap, jumpFlooder, result)
|
||||
|
||||
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
|
||||
): ColorBuffer = encodeDecodeBitmap(contourPoints, pixelDirection, bitmap, jumpFlooder, result)
|
||||
Reference in New Issue
Block a user