[orx-color] Add OKHSLa, OKHSVa

This commit is contained in:
Edwin Jakobs
2021-10-21 23:03:07 +02:00
parent 9921857007
commit 9608946d35
17 changed files with 551 additions and 20 deletions

View File

@@ -1,7 +1,7 @@
package org.openrndr.extras.color.palettes package org.openrndr.extras.color.palettes
import org.openrndr.color.* import org.openrndr.color.*
import org.openrndr.extras.color.spaces.* import org.openrndr.extra.color.spaces.*
fun <T> colorSequence(vararg offsets: Pair<Double, T>): ColorSequence fun <T> colorSequence(vararg offsets: Pair<Double, T>): ColorSequence

View File

@@ -1,4 +1,4 @@
package org.openrndr.extras.color.spaces package org.openrndr.extra.color.spaces
import org.openrndr.color.* import org.openrndr.color.*
import org.openrndr.math.mixAngle import org.openrndr.math.mixAngle

View File

@@ -0,0 +1,124 @@
package org.openrndr.extra.color.spaces
import org.openrndr.color.*
import kotlin.math.*
data class ColorOKHSLa(val h: Double, val s: Double, val l: Double, val a: Double = 1.0) :
HueShiftableColor<ColorOKHSLa>,
OpacifiableColor<ColorOKHSLa>,
SaturatableColor<ColorOKHSLa>,
ShadableColor<ColorOKHSLa>,
ConvertibleToColorRGBa {
companion object {
fun fromColorRGBa(c: ColorRGBa): ColorOKHSLa {
val lab = c.toOKLABa()
val C = sqrt(lab.a * lab.a + lab.b * lab.b);
val a_ = lab.a / C;
val b_ = lab.b / C;
val L = lab.l
val h = 0.5 + 0.5 * atan2(-lab.b, -lab.a) / PI;
val Cs = get_Cs(L, a_, b_)
val C_0 = Cs[0];
val C_mid = Cs[1];
val C_max = Cs[2];
val s = if (C < C_mid) {
val k_0 = 0;
val k_1 = 0.8 * C_0;
val k_2 = (1 - k_1 / C_mid);
val t = (C - k_0) / (k_1 + k_2 * (C - k_0));
t * 0.8;
} else {
val k_0 = C_mid;
val k_1 = 0.2 * C_mid * C_mid * 1.25 * 1.25 / C_0;
val k_2 = (1 - (k_1) / (C_max - C_mid));
val t = (C - k_0) / (k_1 + k_2 * (C - k_0));
0.8 + 0.2 * t;
}
val l = toe(L);
return ColorOKHSLa(h, s, l, c.a)
}
}
override fun toRGBa(): ColorRGBa {
if (l == 1.0)
{
ColorRGBa(1.0, 1.0, 1.0, a)
}
else if (l == 0.0)
{
ColorRGBa(0.0, 0.0, 0.0, a)
}
val a_ = cos(2*PI*h);
val b_ = sin(2*PI*h);
val L = toe_inv(l);
val Cs = get_Cs(L, a_, b_);
val C_0 = Cs[0];
val C_mid = Cs[1];
val C_max = Cs[2];
//let C, t, k_0, k_1, k_2;
val C: Double
val t: Double
val k_0: Double
val k_1: Double
val k_2: Double
if (s < 0.8)
{
t = 1.25*s;
k_0 = 0.0
k_1 = 0.8*C_0;
k_2 = (1-k_1/C_mid);
}
else
{
t = 5*(s-0.8);
k_0 = C_mid;
k_1 = 0.2*C_mid*C_mid*1.25*1.25/C_0;
k_2 = (1 - (k_1)/(C_max - C_mid));
}
C = k_0 + t*k_1/(1-k_2*t);
// If we would only use one of the Cs:
//C = s*C_0;
//C = s*1.25*C_mid;
//C = s*C_max;
// let rgb = oklab_to_linear_srgb(L, C*a_, C*b_);
// return [
// 255*srgb_transfer_function(rgb[0]),
// 255*srgb_transfer_function(rgb[1]),
// 255*srgb_transfer_function(rgb[2]),
// ]
return ColorOKLABa(L, C * a_, C * b_).toRGBa().toSRGB()
}
override fun shiftHue(shiftInDegrees: Double): ColorOKHSLa {
val normalizedShift = shiftInDegrees / 360.0
return copy(h = h + normalizedShift)
}
override fun opacify(factor: Double): ColorOKHSLa {
return copy(a = a * factor)
}
override fun saturate(factor: Double): ColorOKHSLa {
return copy(s = s * factor)
}
override fun shade(factor: Double): ColorOKHSLa {
return copy(l = l * factor)
}
}
fun ColorRGBa.toOKHSLa() : ColorOKHSLa = ColorOKHSLa.fromColorRGBa(this)

View File

@@ -0,0 +1,114 @@
package org.openrndr.extra.color.spaces
import org.openrndr.color.*
import kotlin.math.*
data class ColorOKHSVa(val h: Double, val s: Double, val v: Double, val a: Double = 1.0) :
HueShiftableColor<ColorOKHSVa>,
OpacifiableColor<ColorOKHSVa>,
SaturatableColor<ColorOKHSVa>,
ShadableColor<ColorOKHSVa>,
ConvertibleToColorRGBa {
companion object {
fun fromColorRGBa(c: ColorRGBa): ColorOKHSVa {
val lab = c.toOKLABa()
var C = sqrt(lab.a * lab.a + lab.b * lab.b);
val a_ = lab.a / C;
val b_ = lab.b / C;
var L = lab.l
val h = 0.5 + 0.5 * atan2(-lab.b, -lab.a) / PI;
val ST_max = get_ST_max(a_, b_);
val S_max = ST_max[0];
val S_0 = 0.5;
val T = ST_max[1];
val k = 1 - S_0 / S_max;
val t = T / (C + L * T);
val L_v = t * L;
val C_v = t * C;
val L_vt = toe_inv(L_v);
val C_vt = C_v * L_vt / L_v;
val rgb_scale = ColorOKLABa(L_vt, a_ * C_vt, b_ * C_vt, c.a).toRGBa().toLinear()
val scale_L = (1.0 / (max(rgb_scale.r, rgb_scale.g, rgb_scale.b, 0.0))).pow(1.0 / 3.0)
L = L / scale_L;
C = C / scale_L;
C = C * toe(L) / L;
L = toe(L);
val v = L / L_v;
val s = (S_0 + T) * C_v / ((T * S_0) + T * k * C_v)
return ColorOKHSVa(h, s, v, c.a)
}
}
override fun toRGBa(): ColorRGBa {
val a_ = cos(2 * PI * h)
val b_ = sin(2 * PI * h)
val ST_max = get_ST_max(a_, b_)
val S_max = ST_max[0];
val S_0 = 0.5;
val T = ST_max[1];
val k = 1 - S_0 / S_max;
val L_v = 1 - s * S_0 / (S_0 + T - T * k * s)
val C_v = s * T * S_0 / (S_0 + T - T * k * s)
var L = v * L_v;
var C = v * C_v;
// to present steps along the way
//L = v;
//C = v*s*S_max;
//L = v*(1 - s*S_max/(S_max+T));
//C = v*s*S_max*T/(S_max+T);
val L_vt = toe_inv(L_v);
val C_vt = C_v * L_vt / L_v;
val L_new = toe_inv(L); // * L_v/L_vt;
C = C * L_new / L;
L = L_new;
val rgb_scale =
ColorOKLABa(L_vt, a_ * C_vt, b_ * C_vt, a).toRGBa().toLinear()// oklab_to_linear_srgb(L_vt,a_*C_vt,b_*C_vt);
val scale_L = (1.0 / (max(rgb_scale.r, rgb_scale.g, rgb_scale.b, 0.0))).pow(1.0 / 3.0)
// remove to see effect without rescaling
L *= scale_L;
C *= scale_L;
return ColorOKLABa(L, C * a_, C * b_).toRGBa().toSRGB()
}
override fun shiftHue(shiftInDegrees: Double): ColorOKHSVa {
val normalizedShift = shiftInDegrees/360.0
return copy(h = h + normalizedShift)
}
override fun opacify(factor: Double): ColorOKHSVa {
return copy(a = a * factor)
}
override fun saturate(factor: Double): ColorOKHSVa {
return copy(s = s * factor)
}
override fun shade(factor: Double): ColorOKHSVa {
return copy(v = v * factor)
}
}
fun ColorRGBa.toOKHSVa() : ColorOKHSVa = ColorOKHSVa.fromColorRGBa(this)

View File

@@ -1,4 +1,4 @@
package org.openrndr.extras.color.spaces package org.openrndr.extra.color.spaces
import org.openrndr.color.* import org.openrndr.color.*
import org.openrndr.math.CastableToVector4 import org.openrndr.math.CastableToVector4

View File

@@ -1,4 +1,4 @@
package org.openrndr.extras.color.spaces package org.openrndr.extra.color.spaces
import org.openrndr.color.* import org.openrndr.color.*
import org.openrndr.math.asDegrees import org.openrndr.math.asDegrees

View File

@@ -0,0 +1,264 @@
package org.openrndr.extra.color.spaces
import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow
import kotlin.math.sqrt
// verbatim copies of https://github.com/bottosson/bottosson.github.io/blob/master/misc/colorpicker/colorconversion.js
internal fun max(a: Double, b: Double, c: Double, d: Double): Double {
return max(max(a, b), max(c, d))
}
fun toe(x: Double): Double {
val k_1 = 0.206
val k_2 = 0.03
val k_3 = (1 + k_1) / (1 + k_2)
return 0.5 * (k_3 * x - k_1 + sqrt((k_3 * x - k_1) * (k_3 * x - k_1) + 4 * k_2 * k_3 * x))
}
fun toe_inv(x: Double): Double {
val k_1 = 0.206
val k_2 = 0.03
val k_3 = (1 + k_1) / (1 + k_2)
return (x * x + k_1 * x) / (k_3 * (x + k_2))
}
internal fun compute_max_saturation(a: Double, b: Double): Double {
// Max saturation will be when one of r, g or b goes below zero.
// Select different coefficients depending on which component goes below zero first
val k0: Double
val k1: Double
val k2: Double
val k3: Double
val k4: Double
val wl: Double
val wm: Double
val ws: Double
if (-1.88170328 * a - 0.80936493 * b > 1) {
// Red component
k0 = +1.19086277; k1 = +1.76576728; k2 = +0.59662641; k3 = +0.75515197; k4 = +0.56771245
wl = +4.0767416621; wm = -3.3077115913; ws = +0.2309699292
} else if (1.81444104 * a - 1.19445276 * b > 1) {
// Green component
k0 = +0.73956515; k1 = -0.45954404; k2 = +0.08285427; k3 = +0.12541070; k4 = +0.14503204
wl = -1.2684380046; wm = +2.6097574011; ws = -0.3413193965
} else {
// Blue component
k0 = +1.35733652; k1 = -0.00915799; k2 = -1.15130210; k3 = -0.50559606; k4 = +0.00692167
wl = -0.0041960863; wm = -0.7034186147; ws = +1.7076147010
}
// Approximate max saturation using a polynomial:
val S = k0 + k1 * a + k2 * b + k3 * a * a + k4 * a * b
// Do one step Halley's method to get closer
// this gives an error less than 10e6, except for some blue hues where the dS/dh is close to infinite
// this should be sufficient for most applications, otherwise do two/three steps
val k_l = +0.3963377774 * a + 0.2158037573 * b
val k_m = -0.1055613458 * a - 0.0638541728 * b
val k_s = -0.0894841775 * a - 1.2914855480 * b
return run {
val l_ = 1 + S * k_l
val m_ = 1 + S * k_m
val s_ = 1 + S * k_s
val l = l_ * l_ * l_
val m = m_ * m_ * m_
val s = s_ * s_ * s_
val l_dS = 3 * k_l * l_ * l_
val m_dS = 3 * k_m * m_ * m_
val s_dS = 3 * k_s * s_ * s_
val l_dS2 = 6 * k_l * k_l * l_
val m_dS2 = 6 * k_m * k_m * m_
val s_dS2 = 6 * k_s * k_s * s_
val f = wl * l + wm * m + ws * s
val f1 = wl * l_dS + wm * m_dS + ws * s_dS
val f2 = wl * l_dS2 + wm * m_dS2 + ws * s_dS2
S - f * f1 / (f1 * f1 - 0.5 * f * f2)
}
}
internal fun find_cusp(a: Double, b: Double): DoubleArray {
// First, find the maximum saturation (saturation S = C/L)
val S_cusp = compute_max_saturation(a, b)
val rgb_at_max = ColorOKLABa(1.0, S_cusp * a, S_cusp * b).toRGBa().toLinear()
val L_cusp = (1.0 / max(max(rgb_at_max.r, rgb_at_max.g), rgb_at_max.b)).pow(1.0 / 3.0)
val C_cusp = L_cusp * S_cusp
return doubleArrayOf(L_cusp, C_cusp)
}
internal fun get_ST_max(a: Double, b: Double, cusp: DoubleArray? = null): DoubleArray {
val cusp = cusp ?: find_cusp(a, b)
val L = cusp[0]
val C = cusp[1]
return doubleArrayOf(C / L, C / (1.0 - L))
}
fun get_ST_mid(a_: Double, b_: Double): DoubleArray {
val S = 0.11516993 + 1 / (
+7.44778970 + 4.15901240 * b_
+ a_ * (-2.19557347 + 1.75198401 * b_
+ a_ * (-2.13704948 - 10.02301043 * b_
+ a_ * (-4.24894561 + 5.38770819 * b_ + 4.69891013 * a_
)))
)
val T = 0.11239642 + 1 / (
+1.61320320 - 0.68124379 * b_
+ a_ * (+0.40370612 + 0.90148123 * b_
+ a_ * (-0.27087943 + 0.61223990 * b_
+ a_ * (+0.00299215 - 0.45399568 * b_ - 0.14661872 * a_
)))
)
return doubleArrayOf(S, T)
}
fun get_Cs(L: Double, a_: Double, b_: Double): DoubleArray {
val cusp = find_cusp(a_, b_)
val C_max = find_gamut_intersection(a_, b_, L, 1.0, L, cusp)
val ST_max = get_ST_max(a_, b_, cusp)
val S_mid = 0.11516993 + 1 / (
+7.44778970 + 4.15901240 * b_
+ a_ * (-2.19557347 + 1.75198401 * b_
+ a_ * (-2.13704948 - 10.02301043 * b_
+ a_ * (-4.24894561 + 5.38770819 * b_ + 4.69891013 * a_
)))
)
val T_mid = 0.11239642 + 1 / (
+1.61320320 - 0.68124379 * b_
+ a_ * (+0.40370612 + 0.90148123 * b_
+ a_ * (-0.27087943 + 0.61223990 * b_
+ a_ * (+0.00299215 - 0.45399568 * b_ - 0.14661872 * a_
)))
)
val k: Double = C_max / min((L * ST_max[0]), (1 - L) * ST_max[1])
val C_mid: Double
run {
val C_a = L * S_mid
val C_b = (1 - L) * T_mid
C_mid = (0.9 * k) * sqrt(sqrt(1 / (1 / (C_a * C_a * C_a * C_a) + 1 / (C_b * C_b * C_b * C_b))))
}
val C_0: Double
run {
val C_a = L * 0.4
val C_b = (1 - L) * 0.8
C_0 = sqrt(1 / (1 / (C_a * C_a) + 1 / (C_b * C_b)))
}
return doubleArrayOf(C_0, C_mid, C_max)
}
fun find_gamut_intersection(
a: Double,
b: Double,
L1: Double,
C1: Double,
L0: Double,
cusp: DoubleArray? = null
): Double {
val cusp = cusp ?: find_cusp(a, b)
// Find the intersection for upper and lower half seprately
var t: Double
if (((L1 - L0) * cusp[1] - (cusp[0] - L0) * C1) <= 0) {
// Lower half
t = cusp[1] * L0 / (C1 * cusp[0] + cusp[1] * (L0 - L1))
} else {
// Upper half
// First intersect with triangle
t = cusp[1] * (L0 - 1) / (C1 * (cusp[0] - 1) + cusp[1] * (L0 - L1))
// Then one step Halley's method
run {
val dL = L1 - L0
val dC = C1
val k_l = +0.3963377774 * a + 0.2158037573 * b
val k_m = -0.1055613458 * a - 0.0638541728 * b
val k_s = -0.0894841775 * a - 1.2914855480 * b
val l_dt = dL + dC * k_l
val m_dt = dL + dC * k_m
val s_dt = dL + dC * k_s;
// If higher accuracy is required, 2 or 3 iterations of the following block can be used:
{
val L = L0 * (1 - t) + t * L1
val C = t * C1
val l_ = L + C * k_l
val m_ = L + C * k_m
val s_ = L + C * k_s
val l = l_ * l_ * l_
val m = m_ * m_ * m_
val s = s_ * s_ * s_
val ldt = 3 * l_dt * l_ * l_
val mdt = 3 * m_dt * m_ * m_
val sdt = 3 * s_dt * s_ * s_
val ldt2 = 6 * l_dt * l_dt * l_
val mdt2 = 6 * m_dt * m_dt * m_
val sdt2 = 6 * s_dt * s_dt * s_
val r = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s - 1
val r1 = 4.0767416621 * ldt - 3.3077115913 * mdt + 0.2309699292 * sdt
val r2 = 4.0767416621 * ldt2 - 3.3077115913 * mdt2 + 0.2309699292 * sdt2
val u_r = r1 / (r1 * r1 - 0.5 * r * r2)
var t_r = -r * u_r
val g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s - 1
val g1 = -1.2684380046 * ldt + 2.6097574011 * mdt - 0.3413193965 * sdt
val g2 = -1.2684380046 * ldt2 + 2.6097574011 * mdt2 - 0.3413193965 * sdt2
val u_g = g1 / (g1 * g1 - 0.5 * g * g2)
var t_g = -g * u_g
val b = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s - 1
val b1 = -0.0041960863 * ldt - 0.7034186147 * mdt + 1.7076147010 * sdt
val b2 = -0.0041960863 * ldt2 - 0.7034186147 * mdt2 + 1.7076147010 * sdt2
val u_b = b1 / (b1 * b1 - 0.5 * b * b2)
var t_b = -b * u_b
t_r = if (u_r >= 0) t_r else 10e5
t_g = if (u_g >= 0) t_g else 10e5
t_b = if (u_b >= 0) t_b else 10e5
t += min(t_r, min(t_g, t_b))
}
}
}
return t
}

View File

@@ -3,7 +3,7 @@ import org.openrndr.color.ColorRGBa
import org.openrndr.draw.* import org.openrndr.draw.*
import org.openrndr.extensions.SingleScreenshot import org.openrndr.extensions.SingleScreenshot
import org.openrndr.extras.camera.Orbital import org.openrndr.extras.camera.Orbital
import org.openrndr.extras.color.spaces.ColorOKLCHa import org.openrndr.extra.color.spaces.ColorOKLCHa
import org.openrndr.extras.meshgenerators.sphereMesh import org.openrndr.extras.meshgenerators.sphereMesh
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
import kotlin.math.cos import kotlin.math.cos

View File

@@ -3,7 +3,7 @@ import org.openrndr.color.ColorRGBa
import org.openrndr.draw.* import org.openrndr.draw.*
import org.openrndr.extensions.SingleScreenshot import org.openrndr.extensions.SingleScreenshot
import org.openrndr.extras.camera.Orbital import org.openrndr.extras.camera.Orbital
import org.openrndr.extras.color.spaces.ColorOKLCHa import org.openrndr.extra.color.spaces.ColorOKLCHa
import org.openrndr.extras.meshgenerators.sphereMesh import org.openrndr.extras.meshgenerators.sphereMesh
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3
import kotlin.math.cos import kotlin.math.cos

View File

@@ -5,7 +5,7 @@ import org.openrndr.application
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.extensions.SingleScreenshot import org.openrndr.extensions.SingleScreenshot
import org.openrndr.extras.color.palettes.rangeTo import org.openrndr.extras.color.palettes.rangeTo
import org.openrndr.extras.color.spaces.toHSLUVa import org.openrndr.extra.color.spaces.toHSLUVa
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.math.map import org.openrndr.math.map
import org.openrndr.shape.Rectangle import org.openrndr.shape.Rectangle

View File

@@ -7,7 +7,7 @@ import org.openrndr.extensions.SingleScreenshot
import org.openrndr.extras.color.palettes.colorSequence import org.openrndr.extras.color.palettes.colorSequence
import org.openrndr.extras.color.palettes.rangeTo import org.openrndr.extras.color.palettes.rangeTo
import org.openrndr.extras.color.presets.CORAL import org.openrndr.extras.color.presets.CORAL
import org.openrndr.extras.color.spaces.toHSLUVa import org.openrndr.extra.color.spaces.toHSLUVa
fun main() = application { fun main() = application {
program { program {

View File

@@ -3,10 +3,10 @@ import org.openrndr.color.ColorRGBa
import org.openrndr.draw.loadFont import org.openrndr.draw.loadFont
import org.openrndr.extensions.SingleScreenshot import org.openrndr.extensions.SingleScreenshot
import org.openrndr.extras.color.palettes.rangeTo import org.openrndr.extras.color.palettes.rangeTo
import org.openrndr.extras.color.spaces.toHSLUVa import org.openrndr.extra.color.spaces.toHSLUVa
import org.openrndr.extras.color.spaces.toOKLABa import org.openrndr.extra.color.spaces.toOKLABa
import org.openrndr.extras.color.spaces.toOKLCHa import org.openrndr.extra.color.spaces.toOKLCHa
import org.openrndr.extras.color.spaces.toXSLUVa import org.openrndr.extra.color.spaces.toXSLUVa
fun main() { fun main() {
application { application {

View File

@@ -6,10 +6,10 @@ import org.openrndr.draw.loadFont
import org.openrndr.extensions.SingleScreenshot import org.openrndr.extensions.SingleScreenshot
import org.openrndr.extras.camera.Orbital import org.openrndr.extras.camera.Orbital
import org.openrndr.extras.color.palettes.rangeTo import org.openrndr.extras.color.palettes.rangeTo
import org.openrndr.extras.color.spaces.toHSLUVa import org.openrndr.extra.color.spaces.toHSLUVa
import org.openrndr.extras.color.spaces.toOKLABa import org.openrndr.extra.color.spaces.toOKLABa
import org.openrndr.extras.color.spaces.toOKLCHa import org.openrndr.extra.color.spaces.toOKLCHa
import org.openrndr.extras.color.spaces.toXSLUVa import org.openrndr.extra.color.spaces.toXSLUVa
import org.openrndr.extras.meshgenerators.sphereMesh import org.openrndr.extras.meshgenerators.sphereMesh
import org.openrndr.math.Vector3 import org.openrndr.math.Vector3

View File

@@ -7,7 +7,7 @@ import org.openrndr.color.rgb
import org.openrndr.draw.isolated import org.openrndr.draw.isolated
import org.openrndr.draw.loadFont import org.openrndr.draw.loadFont
import org.openrndr.extensions.SingleScreenshot import org.openrndr.extensions.SingleScreenshot
import org.openrndr.extras.color.spaces.ColorHSLUVa import org.openrndr.extra.color.spaces.ColorHSLUVa
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import org.openrndr.shape.Rectangle import org.openrndr.shape.Rectangle

View File

@@ -3,7 +3,7 @@
import org.openrndr.application import org.openrndr.application
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.extensions.SingleScreenshot import org.openrndr.extensions.SingleScreenshot
import org.openrndr.extras.color.spaces.toHSLUVa import org.openrndr.extra.color.spaces.toHSLUVa
import org.openrndr.math.Polar import org.openrndr.math.Polar
import org.openrndr.math.Vector2 import org.openrndr.math.Vector2
import kotlin.math.sqrt import kotlin.math.sqrt

View File

@@ -0,0 +1,29 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.color.spaces.ColorOKHSLa
import org.openrndr.extra.color.spaces.ColorOKHSVa
fun main() = application {
program {
extend {
val c = ColorRGBa.GREEN
val okhsv = ColorOKHSVa.fromColorRGBa(c)
val hsv = c.toHSVa()
val hsl = c.toHSLa()
val okhsl = ColorOKHSLa.fromColorRGBa(c)
for (i in 0 until 36) {
drawer.fill = okhsv.shiftHue(i * 10.0).saturate(1.0).toRGBa()
drawer.rectangle(i * 10.0, 40.0, 10.0, 10.0)
drawer.fill = hsv.shiftHue(i * 10.0).saturate(1.0).toRGBa()
drawer.rectangle(i * 10.0, 60.0, 10.0, 10.0)
drawer.fill = okhsl.shiftHue(i * 10.0).saturate(1.0).toRGBa()
drawer.rectangle(i * 10.0, 80.0, 10.0, 10.0)
drawer.fill = hsl.shiftHue(i * 10.0).saturate(1.0).toRGBa()
drawer.rectangle(i * 10.0, 100.0, 10.0, 10.0)
}
}
}
}

View File

@@ -3,8 +3,8 @@
import org.openrndr.application import org.openrndr.application
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.extensions.SingleScreenshot import org.openrndr.extensions.SingleScreenshot
import org.openrndr.extras.color.spaces.ColorXSLUVa import org.openrndr.extra.color.spaces.ColorXSLUVa
import org.openrndr.extras.color.spaces.toHSLUVa import org.openrndr.extra.color.spaces.toHSLUVa
import org.openrndr.math.Polar import org.openrndr.math.Polar
import org.openrndr.shape.contour import org.openrndr.shape.contour