[orx-shade-styles] Add advanced clip-based shade styles and demos
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
package org.openrndr.extra.shadestyles.fills.clip
|
||||
|
||||
import org.openrndr.draw.ShadeStyle
|
||||
|
||||
class ClipbaseStructure(
|
||||
val clipFunction: String,
|
||||
val domainWarpFunction: String
|
||||
)
|
||||
|
||||
class ClipBase(structure: ClipbaseStructure) : ShadeStyle() {
|
||||
var clipUnits: Int by Parameter()
|
||||
var clipFit: Int by Parameter()
|
||||
|
||||
init {
|
||||
fragmentPreamble = """
|
||||
${structure.domainWarpFunction}
|
||||
${structure.clipFunction}
|
||||
""".trimIndent()
|
||||
|
||||
fragmentTransform = """vec2 coord = vec2(0.0);
|
||||
if (p_clipUnits == 0) { // BOUNDS
|
||||
coord = c_boundsPosition.xy;
|
||||
|
||||
if (p_clipFit == 1) { // COVER
|
||||
float mx = max(c_boundsSize.x, c_boundsSize.y);
|
||||
float ar = min(c_boundsSize.x, c_boundsSize.y) / mx;
|
||||
if (c_boundsSize.x == mx) {
|
||||
coord.y = (coord.y - 0.5) * ar + 0.5;
|
||||
} else {
|
||||
coord.x = (coord.x - 0.5) * ar + 0.5;
|
||||
}
|
||||
} else if (p_clipFit == 2) { // CONTAIN
|
||||
float mx = max(c_boundsSize.x, c_boundsSize.y);
|
||||
float ar = mx / min(c_boundsSize.x, c_boundsSize.y);
|
||||
if (c_boundsSize.y == mx) {
|
||||
coord.y = (coord.y - 0.5) * ar + 0.5;
|
||||
} else {
|
||||
coord.x = (coord.x - 0.5) * ar + 0.5;
|
||||
}
|
||||
}
|
||||
} else if (p_clipUnits == 1) { // WORLD
|
||||
coord = v_worldPosition.xy;
|
||||
} else if (p_clipUnits == 2) { // VIEW
|
||||
coord = v_viewPosition.xy;
|
||||
} else if (p_clipUnits == 3) { // SCREEN
|
||||
coord = c_screenPosition.xy;
|
||||
coord.y = u_viewDimensions.y - coord.y;
|
||||
}
|
||||
coord = clipDomainWarp(coord);
|
||||
coord = (p_clipTransform * vec4(coord, 0.0, 1.0)).xy;
|
||||
|
||||
float mask = clipMask(coord);
|
||||
if (p_clipInvert) {
|
||||
mask = -mask;
|
||||
}
|
||||
|
||||
float maskWidth = abs(fwidth(mask));
|
||||
float maskFiltered = clamp(p_clipFloor +
|
||||
p_clipBlend *
|
||||
smoothstep(maskWidth * 0.5, -maskWidth * 0.5 - p_clipFeather, mask - p_clipOuter) *
|
||||
smoothstep(-maskWidth * 0.5, maskWidth * 0.5 + p_clipFeather, mask - p_clipInner),
|
||||
|
||||
0.0, 1.0);
|
||||
x_fill.a *= maskFiltered;
|
||||
x_stroke.a *= maskFiltered;
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
350
orx-shade-styles/src/commonMain/kotlin/fills/clip/ClipBuilder.kt
Normal file
350
orx-shade-styles/src/commonMain/kotlin/fills/clip/ClipBuilder.kt
Normal file
@@ -0,0 +1,350 @@
|
||||
package org.openrndr.extra.shadestyles.fills.clip
|
||||
|
||||
import org.openrndr.draw.ObservableHashmap
|
||||
import org.openrndr.draw.StyleParameters
|
||||
import org.openrndr.extra.shaderphrases.sdf.sdEllipsePhrase
|
||||
import org.openrndr.extra.shaderphrases.sdf.sdStarPhrase
|
||||
import org.openrndr.extra.shadestyles.fills.FillFit
|
||||
import org.openrndr.extra.shadestyles.fills.FillUnits
|
||||
import org.openrndr.math.Matrix44
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector4
|
||||
import org.openrndr.shape.Rectangle
|
||||
|
||||
class ClipBuilder : StyleParameters {
|
||||
override var parameterTypes: ObservableHashmap<String, String> = ObservableHashmap(mutableMapOf()) {}
|
||||
override var parameterValues: MutableMap<String, Any> = mutableMapOf()
|
||||
override var textureBaseIndex: Int = 2
|
||||
|
||||
/**
|
||||
* Specifies the outer threshold for the clipping effect in rendering.
|
||||
*
|
||||
* Default value is `0.0`.
|
||||
*/
|
||||
var clipOuter: Double by Parameter("clipOuter", initialValue = 0.0)
|
||||
|
||||
|
||||
/**
|
||||
* Defines the inner boundary threshold for applying a clipping mask.
|
||||
*
|
||||
* The initial value is set to a very large negative number
|
||||
* (-1E12) to enable a wide default range.
|
||||
*/
|
||||
var clipInner: Double by Parameter("clipInner", initialValue = -1E12)
|
||||
|
||||
/**
|
||||
* Specifies the coordinate space used for defining clip shapes.
|
||||
* The value can be one of the `FillUnits` enum constants, such as:
|
||||
* - `BOUNDS`: The coordinate space is based on the local bounds of the object.
|
||||
* - `WORLD`: The coordinate space is based on the world position.
|
||||
* - `VIEW`: The coordinate space is based on the view or camera position.
|
||||
* - `SCREEN`: The coordinate space is based on the screen space.
|
||||
*
|
||||
* Determines how the clip shapes are positioned and sized relative to the object being clipped.
|
||||
* The default value is `BOUNDS`.
|
||||
*/
|
||||
var clipUnits: FillUnits = FillUnits.BOUNDS
|
||||
|
||||
/**
|
||||
* Defines the strategy for fitting a clip shape to its bounds.
|
||||
*
|
||||
* This property determines how the clip shape will be scaled or resized to fit
|
||||
* within a bounding area. The possible values are specified by the [FillFit]
|
||||
* enumeration:
|
||||
*
|
||||
* - [FillFit.STRETCH]: Stretches the clip shape to fully cover the bounds, ignoring original aspect ratio.
|
||||
* - [FillFit.COVER]: Scales the clip shape to completely cover the bounds while maintaining its aspect ratio.
|
||||
* - [FillFit.CONTAIN]: Scales the clip shape to fully fit within the bounds while preserving its aspect ratio.
|
||||
*
|
||||
* The default fit mode is [FillFit.STRETCH].
|
||||
*/
|
||||
var clipFit: FillFit = FillFit.STRETCH
|
||||
/**
|
||||
* Represents the GLSL function used to define the clipping mask for a shader.
|
||||
*
|
||||
* The `clipMaskFunction` defines a GLSL function `clipMask` that takes a `vec2` coordinate as input
|
||||
* and outputs a `float` value. The function is intended to determine how the clipping is applied
|
||||
* based on the input coordinate. The return value typically indicates the mask's boundaries, such
|
||||
* as a signed distance to a shape.
|
||||
*
|
||||
* This property can be customized to define various shapes for clipping masks by overwriting it
|
||||
* with specific GLSL code.
|
||||
*
|
||||
* The default implementation of the `clipMaskFunction` always returns `-1.0`, meaning no clipping is
|
||||
* applied unless overridden.
|
||||
*/
|
||||
var clipMaskFunction = """float clipMask(vec2 coord) { return -1.0; }"""
|
||||
|
||||
/**
|
||||
* A variable containing a GLSL function as a string that defines a domain warping operation
|
||||
* applied to coordinates. Domain warping is typically used to introduce variations or distortions
|
||||
* in patterns by altering the input space over which a procedure operates.
|
||||
*
|
||||
* This variable is used in the shader preamble and the transformation process to
|
||||
* modify the coordinate system. By default, the `clipDomainWarp` function returns the input
|
||||
* coordinates unchanged, maintaining an identity operation.
|
||||
*
|
||||
* Developers can override this string with a custom GLSL function to create
|
||||
* specific domain warping effects suited for their application.
|
||||
*/
|
||||
var domainWarpFunction = """vec2 clipDomainWarp(vec2 coord) { return coord; }"""
|
||||
|
||||
/**
|
||||
* Specifies the feathering amount applied to the edges of the clipping mask.
|
||||
* Feathering softens the transition between clipped and unclipped regions, creating a smoother boundary.
|
||||
* The value represents the width of the feathering effect, with `0.0` indicating no feathering.
|
||||
*
|
||||
* A larger value will result in a broader and more gradual transition.
|
||||
*/
|
||||
var feather: Double by Parameter("clipFeather", 0.0)
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether the current clipping mask should be inverted.
|
||||
*
|
||||
* When set to `true`, the areas outside of the defined clip mask are rendered instead of the areas inside.
|
||||
* This parameter is useful for reversing the functionality of a clipping mask,
|
||||
* such as highlighting areas outside a specified region or shape.
|
||||
*/
|
||||
var invert: Boolean by Parameter("clipInvert", false)
|
||||
|
||||
var floor: Double by Parameter("clipFloor", 0.0)
|
||||
var blend: Double by Parameter("clipBlend", 1.0)
|
||||
var clipTransform: Matrix44 by Parameter("clipTransform", Matrix44.IDENTITY)
|
||||
|
||||
private fun structure(): ClipbaseStructure {
|
||||
return ClipbaseStructure(
|
||||
clipMaskFunction,
|
||||
domainWarpFunction
|
||||
)
|
||||
}
|
||||
|
||||
fun build(): ClipBase {
|
||||
val clipBase = ClipBase(structure())
|
||||
clipBase.parameterTypes.putAll(parameterTypes)
|
||||
clipBase.parameterValues.putAll(parameterValues)
|
||||
clipBase.clipUnits = clipUnits.ordinal
|
||||
clipBase.clipFit = clipFit.ordinal
|
||||
return clipBase
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a circular clipping mask to the current clip context.
|
||||
*
|
||||
* This method configures a circular clipping region with customizable properties
|
||||
* defined within the provided builder. The circle is defined by its radius and center.
|
||||
*
|
||||
* @param builder a lambda with receiver scope of [CircleClipBuilder] allowing configuration
|
||||
* of the circle's attributes such as radius and center position.
|
||||
*/
|
||||
fun circle(builder: CircleClipBuilder.() -> Unit) {
|
||||
CircleClipBuilder(this).apply(builder)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a rectangular clipping mask within the current clip context.
|
||||
*
|
||||
* This method allows setting up a rectangular clipping region with customizable
|
||||
* properties defined inside the provided builder.
|
||||
*
|
||||
* @param builder a lambda with receiver scope of [RectangleClipBuilder], allowing
|
||||
* configuration of the rectangle's attributes such as position
|
||||
* and dimensions.
|
||||
*/
|
||||
fun rectangle(builder: RectangleClipBuilder.() -> Unit) {
|
||||
val b = RectangleClipBuilder(this)
|
||||
b.apply(builder)
|
||||
b.clipRectangle = Vector4(b.rectangle.x, b.rectangle.y, b.rectangle.width, b.rectangle.height)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a star-shaped clipping mask to the current clip context.
|
||||
*
|
||||
* This method configures a clipping region in the shape of a star with customizable
|
||||
* properties defined within the provided builder. The star is defined by its radius,
|
||||
* center, number of sides, and sharpness.
|
||||
*
|
||||
* @param builder a lambda with receiver scope of [StarClipBuilder], allowing configuration
|
||||
* of the star's attributes such as radius, center, sides, and sharpness.
|
||||
*/
|
||||
fun star(builder: StarClipBuilder.() -> Unit) {
|
||||
val b = StarClipBuilder(this)
|
||||
b.builder()
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a line-shaped clipping mask to the current clip context.
|
||||
*
|
||||
* This method configures a linear clipping region with customizable properties
|
||||
* defined within the provided builder. The line is determined by its direction
|
||||
* and center point.
|
||||
*
|
||||
* @param builder a lambda with receiver scope of [LineClipBuilder] allowing
|
||||
* configuration of the line's attributes such as direction and center position.
|
||||
*/
|
||||
fun line(builder: LineClipBuilder.() -> Unit) {
|
||||
val b = LineClipBuilder(this)
|
||||
b.builder()
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an elliptical clipping mask to the current clip context.
|
||||
*
|
||||
* This method configures an elliptical clipping region with customizable properties
|
||||
* defined within the provided builder. The ellipse is characterized by its horizontal
|
||||
* and vertical radii, as well as its center position.
|
||||
*
|
||||
* @param builder a lambda with receiver scope of [EllipseClipBuilder], allowing
|
||||
* configuration of the ellipse's attributes such as radiusX, radiusY,
|
||||
* and center position.
|
||||
*/
|
||||
fun ellipse(builder: EllipseClipBuilder.() -> Unit) {
|
||||
val b = EllipseClipBuilder(this)
|
||||
b.builder()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CircleClipBuilder(builder: ClipBuilder) {
|
||||
/**
|
||||
* Defines the radius of the circular clipping mask.
|
||||
*
|
||||
* The default value is 0.5.
|
||||
*/
|
||||
var radius: Double by builder.Parameter("clipRadius", 0.5)
|
||||
|
||||
|
||||
/**
|
||||
* Specifies the center of the circular clipping mask in normalized coordinates.
|
||||
*
|
||||
* The center is represented as a [Vector2], where the default value is (0.5, 0.5),
|
||||
* positioning the clipping mask at the center of the target area.
|
||||
*/
|
||||
var center: Vector2 by builder.Parameter("clipCenter", Vector2(0.5, 0.5))
|
||||
|
||||
init {
|
||||
builder.clipMaskFunction = """
|
||||
float clipMask(vec2 coord) {
|
||||
float d = distance(coord, p_clipCenter);
|
||||
return d - p_clipRadius;
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
class RectangleClipBuilder(builder: ClipBuilder) {
|
||||
/**
|
||||
* Represents a rectangular clipping region with configurable properties such as
|
||||
* position and dimensions. The rectangle is defined by its coordinates (x, y),
|
||||
* width, and height.
|
||||
*/
|
||||
var rectangle = Rectangle(0.0, 0.0, 1.0, 1.0)
|
||||
internal var clipRectangle: Vector4 by builder.Parameter("clipRectangle")
|
||||
|
||||
init {
|
||||
builder.clipMaskFunction = """
|
||||
float clipMask(vec2 coord) {
|
||||
vec2 center = p_clipRectangle.xy + p_clipRectangle.zw * 0.5;
|
||||
vec2 d2 = abs(coord - center) - p_clipRectangle.zw * 0.5;
|
||||
return max(d2.x, d2.y);
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
class StarClipBuilder(builder: ClipBuilder) {
|
||||
/**
|
||||
* Defines the radius of the star-shaped clip mask.
|
||||
*/
|
||||
var radius: Double by builder.Parameter("clipRadius", 0.5)
|
||||
|
||||
/**
|
||||
* Defines the center point of the star-shaped clip mask as a 2D vector.
|
||||
*/
|
||||
var center: Vector2 by builder.Parameter("clipCenter", Vector2(0.5, 0.5))
|
||||
var sides: Int by builder.Parameter("clipSides", 5)
|
||||
var sharpness: Double by builder.Parameter("clipSharpness", 0.0)
|
||||
|
||||
init {
|
||||
builder.clipMaskFunction = """$sdStarPhrase
|
||||
float clipMask(vec2 coord) {
|
||||
float d = sdStar(coord - p_clipCenter, p_clipRadius, p_clipSides, p_clipSharpness);
|
||||
return d;
|
||||
}""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
class EllipseClipBuilder(builder: ClipBuilder) {
|
||||
/**
|
||||
* Defines the horizontal radius of the elliptical clipping region.
|
||||
*
|
||||
* Defaults to `0.5`.
|
||||
*/
|
||||
var radiusX: Double by builder.Parameter("clipRadiusX", 0.5)
|
||||
|
||||
|
||||
/**
|
||||
* Defines the vertical radius of the elliptical clipping region.
|
||||
*
|
||||
* Defaults to `0.5`.
|
||||
*/
|
||||
var radiusY: Double by builder.Parameter("clipRadiusY", 0.5)
|
||||
|
||||
/**
|
||||
* The center of the clipping ellipse.
|
||||
*
|
||||
* Defaults to (0.5, 0.5)
|
||||
*/
|
||||
var center: Vector2 by builder.Parameter("clipCenter", Vector2(0.5, 0.5))
|
||||
|
||||
init {
|
||||
builder.clipMaskFunction = """$sdEllipsePhrase
|
||||
float clipMask(vec2 coord) {
|
||||
vec2 d0 = (coord - p_clipCenter);
|
||||
float d = sdEllipse(d0, vec2(p_clipRadiusX, p_clipRadiusY));
|
||||
return d;
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class LineClipBuilder(builder: ClipBuilder) {
|
||||
/**
|
||||
* Represents the direction vector used for clipping operations in the `LineClipBuilder`.
|
||||
* This value determines the directional component for the clipping mask calculation,
|
||||
* normalized within the shader implementation.
|
||||
*
|
||||
* The default value is `Vector2.UNIT_Y`.
|
||||
*/
|
||||
var direction: Vector2 by builder.Parameter("clipDirection", Vector2.UNIT_Y)
|
||||
/**
|
||||
* Represents the center point used as a reference for clipping operations in the `LineClipBuilder`.
|
||||
* This variable defines the central coordinate for the clipping mask relative to the drawable area.
|
||||
* It is typically normalized within the range [0.0, 1.0], where `Vector2(0.5, 0.5)` corresponds to
|
||||
* the center of the drawable area.
|
||||
*
|
||||
* The default value is `Vector2(0.5, 0.5)`.
|
||||
*/
|
||||
var center: Vector2 by builder.Parameter("clipCenter", Vector2(0.5, 0.5))
|
||||
|
||||
init {
|
||||
builder.clipMaskFunction = """
|
||||
float clipMask(vec2 coord) {
|
||||
vec2 dir = normalize(p_clipDirection);
|
||||
float distance = dot(dir, coord - p_clipCenter);
|
||||
return distance;
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and configures a `ClipBase` object using the specified builder.
|
||||
*
|
||||
* @param builder A lambda function used to define the properties of the `ClipBuilder`.
|
||||
* @return A `ClipBase` instance configured with the specified properties.
|
||||
*/
|
||||
fun clip(builder: ClipBuilder.() -> Unit): ClipBase {
|
||||
return ClipBuilder().apply(builder).build()
|
||||
}
|
||||
53
orx-shade-styles/src/jvmDemo/kotlin/clip/DemoClip01.kt
Normal file
53
orx-shade-styles/src/jvmDemo/kotlin/clip/DemoClip01.kt
Normal file
@@ -0,0 +1,53 @@
|
||||
package clip
|
||||
|
||||
import org.openrndr.application
|
||||
import org.openrndr.draw.loadImage
|
||||
import org.openrndr.extra.imageFit.imageFit
|
||||
import org.openrndr.extra.shadestyles.fills.FillFit
|
||||
import org.openrndr.extra.shadestyles.fills.clip.clip
|
||||
import org.openrndr.extra.shapes.primitives.grid
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.transforms.transform
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
|
||||
fun main() = application {
|
||||
configure {
|
||||
width = 720
|
||||
height = 720
|
||||
}
|
||||
|
||||
program {
|
||||
var gf = 0.0
|
||||
mouse.buttonDown.listen {
|
||||
gf = 0.5 - gf
|
||||
}
|
||||
|
||||
val image = loadImage("demo-data/images/image-001.png")
|
||||
extend {
|
||||
|
||||
val grid = drawer.bounds.grid(3, 3)
|
||||
for ((index, cell) in grid.flatten().withIndex()) {
|
||||
|
||||
drawer.shadeStyle = clip {
|
||||
clipFit = FillFit.CONTAIN
|
||||
feather = gf
|
||||
|
||||
clipTransform = transform {
|
||||
translate(Vector2(0.5, 0.5))
|
||||
rotate(36.0 * seconds)
|
||||
translate(Vector2(-0.5, -0.5))
|
||||
}
|
||||
|
||||
star {
|
||||
radius = 0.5
|
||||
center = Vector2(0.5, 0.5)
|
||||
sharpness = cos( 2 * PI * index / 9.0 + seconds) * 0.25 + 0.5
|
||||
sides = 24
|
||||
}
|
||||
}
|
||||
drawer.imageFit(image, cell)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
61
orx-shade-styles/src/jvmDemo/kotlin/clip/DemoClip02.kt
Normal file
61
orx-shade-styles/src/jvmDemo/kotlin/clip/DemoClip02.kt
Normal file
@@ -0,0 +1,61 @@
|
||||
package clip
|
||||
|
||||
import org.openrndr.application
|
||||
import org.openrndr.draw.loadImage
|
||||
import org.openrndr.extra.imageFit.imageFit
|
||||
import org.openrndr.extra.shadestyles.fills.FillFit
|
||||
import org.openrndr.extra.shadestyles.fills.clip.clip
|
||||
import org.openrndr.extra.shapes.primitives.grid
|
||||
import org.openrndr.extra.shapes.primitives.placeIn
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.transforms.transform
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
|
||||
fun main() = application {
|
||||
configure {
|
||||
width = 720
|
||||
height = 720
|
||||
}
|
||||
|
||||
program {
|
||||
var gf = 0.0
|
||||
mouse.buttonDown.listen {
|
||||
gf = 0.1 - gf
|
||||
}
|
||||
|
||||
val image = loadImage("demo-data/images/image-001.png")
|
||||
extend {
|
||||
|
||||
val grid = drawer.bounds.grid(3, 3)
|
||||
for ((index, cell) in grid.flatten().withIndex()) {
|
||||
|
||||
drawer.shadeStyle = clip {
|
||||
clipFit = FillFit.entries[index/3]
|
||||
feather = gf
|
||||
|
||||
clipTransform = transform {
|
||||
translate(Vector2(0.5, 0.5))
|
||||
rotate(36.0 * seconds)
|
||||
translate(Vector2(-0.5, -0.5))
|
||||
}
|
||||
|
||||
star {
|
||||
radius = 0.5
|
||||
center = Vector2(0.5, 0.5)
|
||||
sharpness = cos( 2 * PI * index / 9.0 + seconds) * 0.25 + 0.5
|
||||
sides = 24
|
||||
}
|
||||
}
|
||||
|
||||
val acell = when(val i = index%3) {
|
||||
1 -> cell.sub(0.0..0.5, 0.0..1.0)
|
||||
2 -> cell.sub(0.0..1.0, 0.0..0.5)
|
||||
else -> cell
|
||||
}
|
||||
|
||||
drawer.imageFit(image, acell.placeIn(cell))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
59
orx-shade-styles/src/jvmDemo/kotlin/clip/DemoClip03.kt
Normal file
59
orx-shade-styles/src/jvmDemo/kotlin/clip/DemoClip03.kt
Normal file
@@ -0,0 +1,59 @@
|
||||
package clip
|
||||
|
||||
import org.openrndr.application
|
||||
import org.openrndr.draw.loadImage
|
||||
import org.openrndr.extra.imageFit.imageFit
|
||||
import org.openrndr.extra.shadestyles.fills.FillFit
|
||||
import org.openrndr.extra.shadestyles.fills.clip.clip
|
||||
import org.openrndr.extra.shapes.primitives.grid
|
||||
import org.openrndr.extra.shapes.primitives.placeIn
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.transforms.transform
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
|
||||
fun main() = application {
|
||||
configure {
|
||||
width = 720
|
||||
height = 720
|
||||
}
|
||||
|
||||
program {
|
||||
var gf = 0.0
|
||||
mouse.buttonDown.listen {
|
||||
gf = 0.1 - gf
|
||||
}
|
||||
|
||||
val image = loadImage("demo-data/images/image-001.png")
|
||||
extend {
|
||||
|
||||
val grid = drawer.bounds.grid(3, 3)
|
||||
for ((index, cell) in grid.flatten().withIndex()) {
|
||||
|
||||
drawer.shadeStyle = clip {
|
||||
clipFit = FillFit.entries[index/3]
|
||||
feather = gf
|
||||
|
||||
clipTransform = transform {
|
||||
translate(Vector2(0.5, 0.5))
|
||||
rotate(36.0 * seconds)
|
||||
translate(Vector2(-0.5, -0.5))
|
||||
}
|
||||
|
||||
ellipse {
|
||||
radiusX = 0.5
|
||||
radiusY = 0.25
|
||||
}
|
||||
}
|
||||
|
||||
val acell = when(val i = index%3) {
|
||||
1 -> cell.sub(0.0..0.5, 0.0..1.0)
|
||||
2 -> cell.sub(0.0..1.0, 0.0..0.5)
|
||||
else -> cell
|
||||
}
|
||||
|
||||
drawer.imageFit(image, acell.placeIn(cell))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user