[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.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.Vector2
|
||||
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 = 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>(
|
||||
colorType: KClass<C>,
|
||||
start: Vector2 = Vector2.ZERO,
|
||||
@@ -127,7 +14,7 @@ open class LinearGradient<C>(
|
||||
colors: Array<Vector4>,
|
||||
points: Array<Double> = Array(colors.size) { it / (colors.size - 1.0) },
|
||||
structure: GradientBaseStructure,
|
||||
) : GradientBase<C>(
|
||||
) : GradientBase<C>(
|
||||
colorType,
|
||||
colors,
|
||||
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