[orx-shadestyle] Fix COVER and CONTAIN fit modes for BOUNDS units in GradientBase
This commit is contained in:
@@ -0,0 +1,120 @@
|
|||||||
|
package org.openrndr.extra.shadestyles.fills.gradients
|
||||||
|
|
||||||
|
import org.openrndr.color.AlgebraicColor
|
||||||
|
import org.openrndr.color.ConvertibleToColorRGBa
|
||||||
|
import org.openrndr.draw.ShadeStyle
|
||||||
|
import org.openrndr.extra.color.phrases.linearRgbToOklabPhrase
|
||||||
|
import org.openrndr.extra.color.phrases.oklabToLinearRgbPhrase
|
||||||
|
import org.openrndr.extra.shadestyles.fills.FillFit
|
||||||
|
import org.openrndr.extra.shadestyles.fills.FillUnits
|
||||||
|
import org.openrndr.extra.shadestyles.fills.SpreadMethod
|
||||||
|
import org.openrndr.extra.shadestyles.generateColorTransform
|
||||||
|
import org.openrndr.math.CastableToVector4
|
||||||
|
import org.openrndr.math.Vector4
|
||||||
|
import kotlin.math.PI
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
class GradientBaseStructure(
|
||||||
|
val gradientFunction: String,
|
||||||
|
val domainWarpFunction: String,
|
||||||
|
val levelWarpFunction: String
|
||||||
|
)
|
||||||
|
|
||||||
|
open class GradientBase<C>(
|
||||||
|
colorType: KClass<C>,
|
||||||
|
colors: Array<Vector4>,
|
||||||
|
points: Array<Double> = Array(colors.size) { it / (colors.size - 1.0) },
|
||||||
|
structure: GradientBaseStructure
|
||||||
|
) : ShadeStyle()
|
||||||
|
where C : ConvertibleToColorRGBa, C : AlgebraicColor<C>, C : CastableToVector4 {
|
||||||
|
|
||||||
|
var quantization: Int by Parameter()
|
||||||
|
var colors: Array<Vector4> by Parameter()
|
||||||
|
var points: Array<Double> by Parameter()
|
||||||
|
var spreadMethod: Int by Parameter()
|
||||||
|
var fillUnits: Int by Parameter()
|
||||||
|
var fillFit: Int by Parameter()
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.quantization = 0
|
||||||
|
this.colors = colors
|
||||||
|
this.points = points
|
||||||
|
this.fillUnits = FillUnits.BOUNDS.ordinal
|
||||||
|
this.spreadMethod = SpreadMethod.PAD.ordinal
|
||||||
|
this.fillFit = FillFit.STRETCH.ordinal
|
||||||
|
fragmentPreamble = """
|
||||||
|
|vec2 rotate2D(vec2 x, float angle){
|
||||||
|
| float rad = angle / 180.0 * $PI;
|
||||||
|
| mat2 m = mat2(cos(rad),-sin(rad), sin(rad),cos(rad));
|
||||||
|
| return m * x;
|
||||||
|
|}
|
||||||
|
|$oklabToLinearRgbPhrase
|
||||||
|
|$linearRgbToOklabPhrase
|
||||||
|
|${structure.gradientFunction}
|
||||||
|
|${structure.domainWarpFunction}
|
||||||
|
|${structure.levelWarpFunction}
|
||||||
|
|""".trimMargin()
|
||||||
|
|
||||||
|
fragmentTransform = """
|
||||||
|
vec2 coord = vec2(0.0);
|
||||||
|
|
||||||
|
if (p_fillUnits == 0) { // BOUNDS
|
||||||
|
coord = c_boundsPosition.xy;
|
||||||
|
if (p_fillFit == 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_fillFit == 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_fillUnits == 1) { // WORLD
|
||||||
|
coord = v_worldPosition.xy;
|
||||||
|
} else if (p_fillUnits == 2) { // VIEW
|
||||||
|
coord = v_viewPosition.xy;
|
||||||
|
} else if (p_fillUnits == 3) { // SCREEN
|
||||||
|
coord = c_screenPosition.xy;
|
||||||
|
coord.y = u_viewDimensions.y - coord.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
coord = domainWarp(coord);
|
||||||
|
|
||||||
|
float f = gradientFunction(coord);
|
||||||
|
f = levelWarp(coord, f);
|
||||||
|
|
||||||
|
if (p_quantization != 0) {
|
||||||
|
f = floor(f * float(p_quantization)) / (float(p_quantization) - 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_spreadMethod == 0) { // PAD
|
||||||
|
f = clamp(f, 0.0, 1.0);
|
||||||
|
} else if (p_spreadMethod == 1) { // REFLECT
|
||||||
|
f = 2.0 * abs(f / 2.0 - floor(f / 2.0 + 0.5));
|
||||||
|
} else if (p_spreadMethod == 2) { // REPEAT
|
||||||
|
f = mod(f, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (i < p_points_SIZE - 1 && f >= p_points[i+1]) { i++; }
|
||||||
|
|
||||||
|
vec4 color0 = p_colors[i];
|
||||||
|
vec4 color1 = p_colors[i+1];
|
||||||
|
|
||||||
|
float g = (f - p_points[i]) / (p_points[i+1] - p_points[i]);
|
||||||
|
vec4 gradient = mix(color0, color1, clamp(g, 0.0, 1.0));
|
||||||
|
|
||||||
|
${generateColorTransform(colorType)}
|
||||||
|
x_fill *= gradient;
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,124 +2,11 @@ package org.openrndr.extra.shadestyles.fills.gradients
|
|||||||
|
|
||||||
import org.openrndr.color.AlgebraicColor
|
import org.openrndr.color.AlgebraicColor
|
||||||
import org.openrndr.color.ConvertibleToColorRGBa
|
import org.openrndr.color.ConvertibleToColorRGBa
|
||||||
import org.openrndr.draw.ShadeStyle
|
|
||||||
import org.openrndr.extra.color.phrases.linearRgbToOklabPhrase
|
|
||||||
import org.openrndr.extra.color.phrases.oklabToLinearRgbPhrase
|
|
||||||
import org.openrndr.extra.shadestyles.fills.FillFit
|
|
||||||
import org.openrndr.extra.shadestyles.fills.FillUnits
|
|
||||||
import org.openrndr.extra.shadestyles.fills.SpreadMethod
|
|
||||||
import org.openrndr.extra.shadestyles.generateColorTransform
|
|
||||||
import org.openrndr.math.CastableToVector4
|
import org.openrndr.math.CastableToVector4
|
||||||
import org.openrndr.math.Vector2
|
import org.openrndr.math.Vector2
|
||||||
import org.openrndr.math.Vector4
|
import org.openrndr.math.Vector4
|
||||||
import kotlin.math.PI
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
||||||
class GradientBaseStructure(
|
|
||||||
val gradientFunction: String,
|
|
||||||
val domainWarpFunction: String,
|
|
||||||
val levelWarpFunction: String
|
|
||||||
)
|
|
||||||
|
|
||||||
open class GradientBase<C>(
|
|
||||||
colorType: KClass<C>,
|
|
||||||
colors: Array<Vector4>,
|
|
||||||
points: Array<Double> = Array(colors.size) { it / (colors.size - 1.0) },
|
|
||||||
structure: GradientBaseStructure
|
|
||||||
) : ShadeStyle()
|
|
||||||
where C : ConvertibleToColorRGBa, C : AlgebraicColor<C>, C : CastableToVector4 {
|
|
||||||
|
|
||||||
var quantization: Int by Parameter()
|
|
||||||
var colors: Array<Vector4> by Parameter()
|
|
||||||
var points: Array<Double> by Parameter()
|
|
||||||
var spreadMethod: Int by Parameter()
|
|
||||||
var fillUnits: Int by Parameter()
|
|
||||||
var fillFit: Int by Parameter()
|
|
||||||
|
|
||||||
init {
|
|
||||||
this.quantization = 0
|
|
||||||
this.colors = colors
|
|
||||||
this.points = points
|
|
||||||
this.fillUnits = FillUnits.BOUNDS.ordinal
|
|
||||||
this.spreadMethod = SpreadMethod.PAD.ordinal
|
|
||||||
this.fillFit = FillFit.STRETCH.ordinal
|
|
||||||
fragmentPreamble = """
|
|
||||||
|vec2 rotate2D(vec2 x, float angle){
|
|
||||||
| float rad = angle / 180.0 * $PI;
|
|
||||||
| mat2 m = mat2(cos(rad),-sin(rad), sin(rad),cos(rad));
|
|
||||||
| return m * x;
|
|
||||||
|}
|
|
||||||
|$oklabToLinearRgbPhrase
|
|
||||||
|$linearRgbToOklabPhrase
|
|
||||||
|${structure.gradientFunction}
|
|
||||||
|${structure.domainWarpFunction}
|
|
||||||
|${structure.levelWarpFunction}
|
|
||||||
|""".trimMargin()
|
|
||||||
|
|
||||||
fragmentTransform = """
|
|
||||||
vec2 coord = vec2(0.0);
|
|
||||||
|
|
||||||
if (p_fillUnits == 0) { // BOUNDS
|
|
||||||
coord = c_boundsPosition.xy;
|
|
||||||
if (p_fillFit == 1) { // COVER
|
|
||||||
float mx = max(c_boundsSize.x, c_boundsSize.y);
|
|
||||||
float ar = mx / min(c_boundsSize.x, c_boundsSize.y);
|
|
||||||
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_fillFit == 2) { // CONTAIN
|
|
||||||
float mx = max(c_boundsSize.x, c_boundsSize.y);
|
|
||||||
float ar = min(c_boundsSize.x, c_boundsSize.y) / mx;
|
|
||||||
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_fillUnits == 1) { // WORLD
|
|
||||||
coord = v_worldPosition.xy;
|
|
||||||
} else if (p_fillUnits == 2) { // VIEW
|
|
||||||
coord = v_viewPosition.xy;
|
|
||||||
} else if (p_fillUnits == 3) { // SCREEN
|
|
||||||
coord = c_screenPosition.xy;
|
|
||||||
coord.y = u_viewDimensions.y - coord.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
coord = domainWarp(coord);
|
|
||||||
|
|
||||||
float f = gradientFunction(coord);
|
|
||||||
f = levelWarp(coord, f);
|
|
||||||
|
|
||||||
if (p_quantization != 0) {
|
|
||||||
f = floor(f * float(p_quantization)) / (float(p_quantization) - 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p_spreadMethod == 0) { // PAD
|
|
||||||
f = clamp(f, 0.0, 1.0);
|
|
||||||
} else if (p_spreadMethod == 1) { // REFLECT
|
|
||||||
f = 2.0 * abs(f / 2.0 - floor(f / 2.0 + 0.5));
|
|
||||||
} else if (p_spreadMethod == 2) { // REPEAT
|
|
||||||
f = mod(f, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
while (i < p_points_SIZE - 1 && f >= p_points[i+1]) { i++; }
|
|
||||||
|
|
||||||
vec4 color0 = p_colors[i];
|
|
||||||
vec4 color1 = p_colors[i+1];
|
|
||||||
|
|
||||||
float g = (f - p_points[i]) / (p_points[i+1] - p_points[i]);
|
|
||||||
vec4 gradient = mix(color0, color1, clamp(g, 0.0, 1.0));
|
|
||||||
|
|
||||||
${generateColorTransform(colorType)}
|
|
||||||
x_fill *= gradient;
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open class LinearGradient<C>(
|
open class LinearGradient<C>(
|
||||||
colorType: KClass<C>,
|
colorType: KClass<C>,
|
||||||
start: Vector2 = Vector2.ZERO,
|
start: Vector2 = Vector2.ZERO,
|
||||||
@@ -127,7 +14,7 @@ open class LinearGradient<C>(
|
|||||||
colors: Array<Vector4>,
|
colors: Array<Vector4>,
|
||||||
points: Array<Double> = Array(colors.size) { it / (colors.size - 1.0) },
|
points: Array<Double> = Array(colors.size) { it / (colors.size - 1.0) },
|
||||||
structure: GradientBaseStructure,
|
structure: GradientBaseStructure,
|
||||||
) : GradientBase<C>(
|
) : GradientBase<C>(
|
||||||
colorType,
|
colorType,
|
||||||
colors,
|
colors,
|
||||||
points,
|
points,
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package gradients
|
||||||
|
|
||||||
|
import org.openrndr.application
|
||||||
|
import org.openrndr.color.ColorRGBa
|
||||||
|
import org.openrndr.extra.color.spaces.OKHSV
|
||||||
|
import org.openrndr.extra.color.tools.shiftHue
|
||||||
|
import org.openrndr.extra.shadestyles.fills.FillFit
|
||||||
|
import org.openrndr.extra.shadestyles.fills.SpreadMethod
|
||||||
|
import org.openrndr.extra.shadestyles.fills.gradients.gradient
|
||||||
|
import org.openrndr.extra.shapes.primitives.grid
|
||||||
|
import org.openrndr.extra.shapes.primitives.placeIn
|
||||||
|
import org.openrndr.math.Vector2
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
application {
|
||||||
|
configure {
|
||||||
|
width = 720
|
||||||
|
height = 720
|
||||||
|
}
|
||||||
|
program {
|
||||||
|
extend {
|
||||||
|
val grid = drawer.bounds.grid(3, 3)
|
||||||
|
|
||||||
|
for ((index, row) in grid.withIndex()) {
|
||||||
|
drawer.shadeStyle = gradient<ColorRGBa> {
|
||||||
|
for (i in 0..10) {
|
||||||
|
stops[i / 10.0] = ColorRGBa.RED.shiftHue<OKHSV>(i * 36.0)
|
||||||
|
|
||||||
|
}
|
||||||
|
spreadMethod = SpreadMethod.PAD
|
||||||
|
this.fillFit = FillFit.entries[index]
|
||||||
|
radial {
|
||||||
|
center = Vector2(0.5, 0.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((x, cell) in row.withIndex()) {
|
||||||
|
val paddedCell = cell.offsetEdges(-10.0)
|
||||||
|
when (x) {
|
||||||
|
0 -> drawer.rectangle(paddedCell.sub(0.0..0.5, 0.0..1.0).placeIn(paddedCell))
|
||||||
|
1 -> drawer.rectangle(paddedCell)
|
||||||
|
2 -> drawer.rectangle(paddedCell.sub(0.0..1.0, 0.0..0.5).placeIn(paddedCell))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user