From 2fdda2bf374d7184383c23f5149d7e6ceabaee63 Mon Sep 17 00:00:00 2001 From: vechro Date: Sat, 13 Aug 2022 07:45:47 +0300 Subject: [PATCH] Clean up orx-color ColorOKHSLa#toRGBa result will now always be in SRGB linearity and will include the alpha value of the receiver. ColorOKLABa#toRGBa result now includes the alpha value of the receiver --- .../commonMain/kotlin/spaces/ColorOKHSLa.kt | 108 +++++++++--------- .../commonMain/kotlin/spaces/ColorOKHSVa.kt | 67 +++++------ .../commonMain/kotlin/spaces/ColorOKLABa.kt | 24 ++-- .../src/commonMain/kotlin/spaces/OKHelpers.kt | 2 + 4 files changed, 101 insertions(+), 100 deletions(-) diff --git a/orx-color/src/commonMain/kotlin/spaces/ColorOKHSLa.kt b/orx-color/src/commonMain/kotlin/spaces/ColorOKHSLa.kt index c20c3d98..6e3af127 100644 --- a/orx-color/src/commonMain/kotlin/spaces/ColorOKHSLa.kt +++ b/orx-color/src/commonMain/kotlin/spaces/ColorOKHSLa.kt @@ -5,6 +5,7 @@ import org.openrndr.math.Vector4 import org.openrndr.math.mixAngle import kotlin.math.* +@Suppress("LocalVariableName") data class ColorOKHSLa(val h: Double, val s: Double, val l: Double, override val alpha: Double = 1.0) : ColorModel, HueShiftableColor, @@ -15,36 +16,37 @@ data class ColorOKHSLa(val h: Double, val s: Double, val l: Double, override val 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 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 c0 = cs[0]; - val cMid = cs[1]; - val cMax = cs[2]; + val h = 0.5 + 0.5 * atan2(-lab.b, -lab.a) / PI + val (c0, cMid, cMax) = get_Cs(L, a_, b_) val s = if (C < cMid) { - val k0 = 0; - val k1 = 0.8 * c0; - val k2 = (1 - k1 / cMid); + val k0 = 0 + val k1 = 0.8 * c0 + val k2 = (1 - k1 / cMid) - val t = (C - k0) / (k1 + k2 * (C - k0)); - t * 0.8; + val t = (C - k0) / (k1 + k2 * (C - k0)) + t * 0.8 } else { - val k0 = cMid; - val k1 = 0.2 * cMid * cMid * 1.25 * 1.25 / c0; - val k2 = (1 - (k1) / (cMax - cMid)); + val k0 = cMid + val k1 = 0.2 * cMid * cMid * 1.25 * 1.25 / c0 + val k2 = (1 - (k1) / (cMax - cMid)) - val t = (C - k0) / (k1 + k2 * (C - k0)); - 0.8 + 0.2 * t; + val t = (C - k0) / (k1 + k2 * (C - k0)) + 0.8 + 0.2 * t } - val l = toe(L); - return ColorOKHSLa(h * 360.0, if (s == s) s else 0.0, if (l == l) l else 0.0, c.a) + val l = toe(L) + return ColorOKHSLa( + h * 360.0, + if (s == s) s else 0.0, + if (l == l) l else 0.0, + c.alpha + ) } } @@ -52,52 +54,43 @@ data class ColorOKHSLa(val h: Double, val s: Double, val l: Double, override val val a = alpha override fun toRGBa(): ColorRGBa { - if (l == 1.0) { - ColorRGBa(1.0, 1.0, 1.0, alpha) - } else if (l == 0.0) { - ColorRGBa(0.0, 0.0, 0.0, alpha) + if (l == 0.0 || l == 1.0) { + return ColorRGBa(l, l, l, alpha, Linearity.SRGB) } - val a_ = cos(2 * PI * h / 360.0); - val b_ = sin(2 * PI * h / 360.0); - val L = toeInv(l); + val a_ = cos(2 * PI * h / 360.0) + val b_ = sin(2 * PI * h / 360.0) + val L = toeInv(l) - val Cs = get_Cs(L, a_, b_); - val C_0 = Cs[0]; - val C_mid = Cs[1]; - val C_max = Cs[2]; + 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); + val C = if (s < 0.8) { + val t = 1.25 * s + val k_0 = 0.0 + val k_1 = 0.8 * C_0 + val k_2 = (1 - k_1 / C_mid) + k_0 + t * k_1 / (1 - k_2 * t) } 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)); + val t = 5 * (s - 0.8) + 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)) + k_0 + t * k_1 / (1 - k_2 * t) } - 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(if (L == L) L else 0.0, if (C == C) C * a_ else 0.0, if (C == C) C * b_ else 0.0).toRGBa().toSRGB() + return ColorOKLABa( + if (L == L) L else 0.0, + if (C == C) C * a_ else 0.0, + if (C == C) C * b_ else 0.0, + alpha + ).toRGBa().toSRGB() } override fun shiftHue(shiftInDegrees: Double): ColorOKHSLa = copy(h = h + shiftInDegrees) @@ -114,7 +107,8 @@ data class ColorOKHSLa(val h: Double, val s: Double, val l: Double, override val override fun plus(right: ColorOKHSLa) = copy(h = h + right.h, s = s + right.s, l = l + right.l, alpha = alpha + right.alpha) - override fun times(scale: Double): ColorOKHSLa = copy(h = h * scale, s = s * scale, l = l * scale, alpha = alpha * scale) + override fun times(scale: Double): ColorOKHSLa = + copy(h = h * scale, s = s * scale, l = l * scale, alpha = alpha * scale) override fun mix(other: ColorOKHSLa, factor: Double): ColorOKHSLa { val sx = factor.coerceIn(0.0, 1.0) diff --git a/orx-color/src/commonMain/kotlin/spaces/ColorOKHSVa.kt b/orx-color/src/commonMain/kotlin/spaces/ColorOKHSVa.kt index 5e57d135..e693bd43 100644 --- a/orx-color/src/commonMain/kotlin/spaces/ColorOKHSVa.kt +++ b/orx-color/src/commonMain/kotlin/spaces/ColorOKHSVa.kt @@ -5,6 +5,7 @@ import org.openrndr.math.Vector4 import org.openrndr.math.mixAngle import kotlin.math.* +@Suppress("LocalVariableName") data class ColorOKHSVa(val h: Double, val s: Double, val v: Double, override val alpha: Double = 1.0) : ColorModel, HueShiftableColor, @@ -15,39 +16,39 @@ data class ColorOKHSVa(val h: Double, val s: Double, val v: Double, override val companion object { fun fromColorRGBa(c: ColorRGBa): ColorOKHSVa { val lab = c.toOKLABa() - var C = sqrt(lab.a * lab.a + lab.b * lab.b); + var C = sqrt(lab.a * lab.a + lab.b * lab.b) val a_ = if (C != 0.0) lab.a / C else 0.0 val b_ = if (C != 0.0) lab.b / C else 0.0 var L = lab.l - val h = 0.5 + 0.5 * atan2(-lab.b, -lab.a) / PI; + 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 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 = if (S_max != 0.0) (1 - S_0 / S_max) else 0.0 - val t = T / (C + L * T); - val L_v = t * L; - val C_v = t * C; + val t = T / (C + L * T) + val L_v = t * L + val C_v = t * C - val L_vt = toeInv(L_v); - val C_vt = C_v * L_vt / L_v; + val L_vt = toeInv(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 rgb_scale = ColorOKLABa(L_vt, a_ * C_vt, b_ * C_vt, c.alpha).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; + L /= scale_L + C /= scale_L - C = C * toe(L) / L; - L = toe(L); + C = C * toe(L) / L + L = toe(L) - val v = L / L_v; + val v = L / L_v val s = (S_0 + T) * C_v / ((T * S_0) + T * k * C_v) - return ColorOKHSVa(h * 360.0, if (s == s) s else 0.0, if (v==v) v else 0.0, c.a) + return ColorOKHSVa(h * 360.0, if (s == s) s else 0.0, if (v == v) v else 0.0, c.alpha) } } @@ -59,16 +60,16 @@ data class ColorOKHSVa(val h: Double, val s: Double, val v: Double, override val val b_ = sin(2 * PI * h / 360.0) 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 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; + var L = v * L_v + var C = v * C_v // to present steps along the way //L = v; @@ -76,25 +77,27 @@ data class ColorOKHSVa(val h: Double, val s: Double, val v: Double, override val //L = v*(1 - s*S_max/(S_max+T)); //C = v*s*S_max*T/(S_max+T); - val L_vt = toeInv(L_v); - val C_vt = C_v * L_vt / L_v; + val L_vt = toeInv(L_v) + val C_vt = C_v * L_vt / L_v - val L_new = toeInv(L); // * L_v/L_vt; - C = C * L_new / L; - L = L_new; + val L_new = toeInv(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, alpha).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; + L *= scale_L + C *= scale_L return ColorOKLABa( if (L == L) L else 0.0, if (C == C) C * a_ else 0.0, - if (C == C) C * b_ else 0.0).toRGBa().toSRGB() + if (C == C) C * b_ else 0.0, + alpha + ).toRGBa().toSRGB() } override fun shiftHue(shiftInDegrees: Double): ColorOKHSVa = copy(h = h + shiftInDegrees) diff --git a/orx-color/src/commonMain/kotlin/spaces/ColorOKLABa.kt b/orx-color/src/commonMain/kotlin/spaces/ColorOKLABa.kt index 9a34b47b..ac91e9bd 100644 --- a/orx-color/src/commonMain/kotlin/spaces/ColorOKLABa.kt +++ b/orx-color/src/commonMain/kotlin/spaces/ColorOKLABa.kt @@ -10,6 +10,7 @@ import kotlin.math.pow * [a] = red (-1.0) to green (1.0), * [b] = yellow (-1.0) to blue (1.0). */ +@Suppress("LocalVariableName") data class ColorOKLABa(val l: Double, val a: Double, val b: Double, override val alpha: Double = 1.0) : ColorModel, ShadableColor, @@ -19,19 +20,19 @@ data class ColorOKLABa(val l: Double, val a: Double, val b: Double, override val fun fromRGBa(rgba: ColorRGBa): ColorOKLABa { // based on https://bottosson.github.io/posts/oklab/ val c = rgba.toLinear() - val l = 0.4122214708 * c.r + 0.5363325363 * c.g + 0.0514459929f * c.b - val m = 0.2119034982 * c.r + 0.6806995451 * c.g + 0.1073969566f * c.b - val s = 0.0883024619 * c.r + 0.2817188376 * c.g + 0.6299787005f * c.b + val l = 0.4122214708 * c.r + 0.5363325363 * c.g + 0.0514459929 * c.b + val m = 0.2119034982 * c.r + 0.6806995451 * c.g + 0.1073969566 * c.b + val s = 0.0883024619 * c.r + 0.2817188376 * c.g + 0.6299787005 * c.b val lnl = l.pow(1.0 / 3.0) val mnl = m.pow(1.0 / 3.0) val snl = s.pow(1.0 / 3.0) - val L = 0.2104542553f * lnl + 0.7936177850f * mnl - 0.0040720468f * snl - val a = 1.9779984951f * lnl - 2.4285922050f * mnl + 0.4505937099f * snl - val b = 0.0259040371f * lnl + 0.7827717662f * mnl - 0.8086757660f * snl + val L = 0.2104542553 * lnl + 0.7936177850 * mnl - 0.0040720468 * snl + val a = 1.9779984951 * lnl - 2.4285922050 * mnl + 0.4505937099 * snl + val b = 0.0259040371 * lnl + 0.7827717662 * mnl - 0.8086757660 * snl - return ColorOKLABa(L, a, b, alpha = c.a) + return ColorOKLABa(L, a, b, c.alpha) } } @@ -46,10 +47,11 @@ data class ColorOKLABa(val l: Double, val a: Double, val b: Double, override val val s = snl * snl * snl return ColorRGBa( - 4.0767416621 * l - 3.3077115913 * m + 0.2309699292f * s, - -1.2684380046 * l + 2.6097574011 * m - 0.3413193965f * s, - -0.0041960863 * l - 0.7034186147 * m + 1.7076147010f * s, - alpha, linearity = Linearity.LINEAR + 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s, + -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s, + -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s, + alpha, + Linearity.LINEAR ) } diff --git a/orx-color/src/commonMain/kotlin/spaces/OKHelpers.kt b/orx-color/src/commonMain/kotlin/spaces/OKHelpers.kt index 2be2795c..c8256529 100644 --- a/orx-color/src/commonMain/kotlin/spaces/OKHelpers.kt +++ b/orx-color/src/commonMain/kotlin/spaces/OKHelpers.kt @@ -1,3 +1,5 @@ +@file:Suppress("FunctionName", "LocalVariableName") + package org.openrndr.extra.color.spaces