[orx-color] Color model changes (#246)

This commit is contained in:
Vechro
2022-07-11 16:40:05 +03:00
committed by GitHub
parent 82502d9d54
commit 5b7327eda1
11 changed files with 218 additions and 217 deletions

View File

@@ -5,8 +5,6 @@ package org.openrndr.extras.color.presets
import org.openrndr.color.ColorRGBa import org.openrndr.color.ColorRGBa
import org.openrndr.color.rgb import org.openrndr.color.rgb
val ColorRGBa.Companion.CYAN by lazy { rgb(0.0, 1.0, 1.0) }
val ColorRGBa.Companion.MAGENTA by lazy { rgb(1.0, 0.0, 1.0) }
val ColorRGBa.Companion.ALICE_BLUE by lazy { rgb(0.941176, 0.972549, 1.0) } val ColorRGBa.Companion.ALICE_BLUE by lazy { rgb(0.941176, 0.972549, 1.0) }
val ColorRGBa.Companion.ANTIQUE_WHITE by lazy { rgb(0.980392, 0.921569, 0.843137) } val ColorRGBa.Companion.ANTIQUE_WHITE by lazy { rgb(0.980392, 0.921569, 0.843137) }
val ColorRGBa.Companion.AQUA by lazy { rgb(0.0, 1.0, 1.0) } val ColorRGBa.Companion.AQUA by lazy { rgb(0.0, 1.0, 1.0) }

View File

@@ -0,0 +1,71 @@
package org.openrndr.extra.color.spaces
import org.openrndr.color.*
import org.openrndr.math.Vector4
import org.openrndr.math.mixAngle
data class ColorHPLUVa(val h: Double, val s: Double, val l: Double, override val alpha: Double = 1.0) :
ColorModel<ColorHPLUVa>,
HueShiftableColor<ColorHPLUVa>,
SaturatableColor<ColorHPLUVa>,
ShadableColor<ColorHPLUVa>,
AlgebraicColor<ColorHPLUVa> {
fun toLCHUVa(): ColorLCHUVa {
val l1 = l
if (l1 > 0.9999999) {
return ColorLCHUVa(100.0, 0.0, h)
}
if (l1 < 0.00000001) {
return ColorLCHUVa(0.0, 0.0, h)
}
val l100 = l1 * 100.0
val max100 = maxSafeChromaForL(l100)
val c100 = max100 * s
return ColorLCHUVa(l100, c100, h)
}
override fun shiftHue(shiftInDegrees: Double): ColorHPLUVa = copy(h = h + (shiftInDegrees))
override fun shade(factor: Double): ColorHPLUVa = copy(l = l * factor)
override fun saturate(factor: Double): ColorHPLUVa = copy(s = s * factor)
override fun toRGBa(): ColorRGBa = toLCHUVa().toRGBa()
override fun opacify(factor: Double) = copy(alpha = alpha * factor)
override fun minus(right: ColorHPLUVa) = copy(h = h - right.h, s = s - right.s, l = l - right.l, alpha = alpha - right.alpha)
override fun plus(right: ColorHPLUVa) = copy(h = h + right.h, s = s + right.s, l = l + right.l, alpha = alpha + right.alpha)
override fun times(scale: Double) = copy(h = h * scale, s = s * scale, l = l * scale, alpha = alpha * scale)
override fun mix(other: ColorHPLUVa, factor: Double) = mix(this, other, factor)
override fun toVector4(): Vector4 = Vector4(h, s, l, alpha)
}
fun mix(left: ColorHPLUVa, right: ColorHPLUVa, x: Double): ColorHPLUVa {
val sx = x.coerceIn(0.0, 1.0)
return ColorHPLUVa(
mixAngle(left.h, right.h, sx),
(1.0 - sx) * left.s + sx * right.s,
(1.0 - sx) * left.l + sx * right.l,
(1.0 - sx) * left.alpha + sx * right.alpha)
}
fun ColorRGBa.toHPLUVa(): ColorHPLUVa = toLCHUVa().toHPLUVa()
fun ColorLCHUVa.toHPLUVa(): ColorHPLUVa {
val l100 = l
if (l100 > 99.9999999) {
return ColorHPLUVa(h, 0.0, 1.0)
}
if (l100 < 0.00000001) {
return ColorHPLUVa(h, 0.0, 0.0)
}
val max100 = maxSafeChromaForL(l)
val s1 = c / max100
return ColorHPLUVa(h, s1, l100 / 100.0)
}

View File

@@ -1,6 +1,8 @@
package org.openrndr.extra.color.spaces package org.openrndr.extra.color.spaces
import org.openrndr.color.* import org.openrndr.color.*
import org.openrndr.math.Vector4
import org.openrndr.math.map
import org.openrndr.math.mixAngle import org.openrndr.math.mixAngle
import kotlin.math.* import kotlin.math.*
@@ -9,10 +11,10 @@ private val m = arrayOf(
doubleArrayOf(-0.96924363628087, 1.87596750150772, 0.041555057407175), doubleArrayOf(-0.96924363628087, 1.87596750150772, 0.041555057407175),
doubleArrayOf(0.055630079696993, -0.20397695888897, 1.056971514242878)) doubleArrayOf(0.055630079696993, -0.20397695888897, 1.056971514242878))
private val kappa = 903.2962962 private const val kappa = 903.2962962
private val epsilon = 0.0088564516 private const val epsilon = 0.0088564516
private fun getBounds(L: Double): List<DoubleArray>? { private fun getBounds(L: Double): List<DoubleArray> {
val result = ArrayList<DoubleArray>() val result = ArrayList<DoubleArray>()
val sub1 = (L + 16).pow(3.0) / 1560896 val sub1 = (L + 16).pow(3.0) / 1560896
val sub2 = if (sub1 > epsilon) sub1 else L / kappa val sub2 = if (sub1 > epsilon) sub1 else L / kappa
@@ -47,11 +49,11 @@ private class Length(val length: Double) {
val greaterEqualZero: Boolean = length >= 0 val greaterEqualZero: Boolean = length >= 0
} }
private fun maxSafeChromaForL(L100: Double): Double { internal fun maxSafeChromaForL(L100: Double): Double {
val bounds = getBounds(L100) val bounds = getBounds(L100)
var min = Double.MAX_VALUE var min = Double.MAX_VALUE
for (i in 0..1) { for (i in 0..1) {
val m1 = bounds!![i][0] val m1 = bounds[i][0]
val b1 = bounds[i][1] val b1 = bounds[i][1]
val line = doubleArrayOf(m1, b1) val line = doubleArrayOf(m1, b1)
val x = intersectLineLine(line, doubleArrayOf(-1 / m1, 0.0)) val x = intersectLineLine(line, doubleArrayOf(-1 / m1, 0.0))
@@ -61,11 +63,11 @@ private fun maxSafeChromaForL(L100: Double): Double {
return min return min
} }
fun maxChromaForLH(L100: Double, H: Double): Double { private fun maxChromaForLH(L100: Double, H: Double): Double {
val hrad = H / 360 * PI * 2 val hrad = H / 360 * PI * 2
val bounds = getBounds(L100) val bounds = getBounds(L100)
var min = Double.MAX_VALUE var min = Double.MAX_VALUE
for (bound in bounds!!) { for (bound in bounds) {
val length: Length = lengthOfRayUntilIntersect(hrad, bound) val length: Length = lengthOfRayUntilIntersect(hrad, bound)
if (length.greaterEqualZero) { if (length.greaterEqualZero) {
min = min(min, length.length) min = min(min, length.length)
@@ -77,35 +79,37 @@ fun maxChromaForLH(L100: Double, H: Double): Double {
/** /**
* HSLUV color space * HSLUV color space
*/ */
data class ColorHSLUVa(val h: Double, val s: Double, val l: Double, val a: Double = 1.0) : data class ColorHSLUVa(val h: Double, val s: Double, val l: Double, override val alpha: Double = 1.0) :
ConvertibleToColorRGBa, ColorModel<ColorHSLUVa>,
HueShiftableColor<ColorHSLUVa>, HueShiftableColor<ColorHSLUVa>,
SaturatableColor<ColorHSLUVa>, SaturatableColor<ColorHSLUVa>,
ShadableColor<ColorHSLUVa>, ShadableColor<ColorHSLUVa>,
OpacifiableColor<ColorHSLUVa>,
AlgebraicColor<ColorHSLUVa> { AlgebraicColor<ColorHSLUVa> {
@Deprecated("Legacy alpha parameter name", ReplaceWith("alpha"))
val a = alpha
fun toLCHUVa(): ColorLCHUVa { fun toLCHUVa(): ColorLCHUVa {
val l100 = l * 100.0 val l100 = l * 100.0
val s100 = s * 100.0 val s100 = s * 100.0
if (l100 > 99.9999999) { if (l100 > 99.9999999) {
ColorLCHUVa(100.0, 0.0, h, a) ColorLCHUVa(100.0, 0.0, h, alpha)
} }
if (l100 < 0.00000001) { if (l100 < 0.00000001) {
ColorLCHUVa(0.0, 0.0, h, a) ColorLCHUVa(0.0, 0.0, h, alpha)
} }
val max100 = maxChromaForLH(l100, h) val max100 = maxChromaForLH(l100, h)
val c: Double = max100 / 100 * s100 val c: Double = max100 / 100 * s100
return ColorLCHUVa(l100, c, h, a) return ColorLCHUVa(l100, c, h, alpha)
} }
fun toXSLUVa() : ColorXSLUVa { fun toXSLUVa() : ColorXSLUVa {
return ColorXSLUVa(hueToX(h), s, l, a) return ColorXSLUVa(hueToX(h), s, l, alpha)
} }
override fun shiftHue(shiftInDegrees: Double) = copy(h = h + (shiftInDegrees)) override fun shiftHue(shiftInDegrees: Double) = copy(h = h + (shiftInDegrees))
@@ -118,16 +122,18 @@ data class ColorHSLUVa(val h: Double, val s: Double, val l: Double, val a: Doubl
return toLCHUVa().toRGBa() return toLCHUVa().toRGBa()
} }
override fun opacify(factor: Double) = copy(a = a * factor) override fun opacify(factor: Double) = copy(alpha = alpha * factor)
override fun minus(right: ColorHSLUVa) = copy(h = h - right.h, s = s - right.s, l = l - right.l, a = a - right.a) override fun minus(right: ColorHSLUVa) = copy(h = h - right.h, s = s - right.s, l = l - right.l, alpha = alpha - right.alpha)
override fun plus(right: ColorHSLUVa) = copy(h = h + right.h, s = s + right.s, l = l + right.l, a = a + right.a) override fun plus(right: ColorHSLUVa) = copy(h = h + right.h, s = s + right.s, l = l + right.l, alpha = alpha + right.alpha)
override fun times(scale: Double) = copy(h = h * scale, s = s * scale, l = l * scale, a = a * scale) override fun times(scale: Double) = copy(h = h * scale, s = s * scale, l = l * scale, alpha = alpha * scale)
override fun mix(other: ColorHSLUVa, factor: Double) = mix(this, other, factor) override fun mix(other: ColorHSLUVa, factor: Double) = mix(this, other, factor)
override fun toVector4(): Vector4 = Vector4(h, s, l, alpha)
} }
fun mix(left: ColorHSLUVa, right: ColorHSLUVa, x: Double): ColorHSLUVa { fun mix(left: ColorHSLUVa, right: ColorHSLUVa, x: Double): ColorHSLUVa {
@@ -136,51 +142,10 @@ fun mix(left: ColorHSLUVa, right: ColorHSLUVa, x: Double): ColorHSLUVa {
mixAngle(left.h, right.h, sx), mixAngle(left.h, right.h, sx),
(1.0 - sx) * left.s + sx * right.s, (1.0 - sx) * left.s + sx * right.s,
(1.0 - sx) * left.l + sx * right.l, (1.0 - sx) * left.l + sx * right.l,
(1.0 - sx) * left.a + sx * right.a) (1.0 - sx) * left.alpha + sx * right.alpha)
} }
data class ColorXSLUVa(val x: Double, val s: Double, val l: Double, val a: Double): internal fun map(x: Double, a: Double, b: Double, c: Double, d: Double): Double {
ConvertibleToColorRGBa,
HueShiftableColor<ColorXSLUVa>,
SaturatableColor<ColorXSLUVa>,
ShadableColor<ColorXSLUVa>,
OpacifiableColor<ColorXSLUVa>,
AlgebraicColor<ColorXSLUVa> {
override fun shiftHue(shiftInDegrees: Double) = copy(x = x + (shiftInDegrees))
override fun shade(factor: Double) = copy(l = l * factor)
override fun saturate(factor: Double) = copy(s = s * factor)
override fun toRGBa(): ColorRGBa {
return toHSLUVa().toRGBa()
}
fun toHSLUVa(): ColorHSLUVa = ColorHSLUVa(xToHue(x), s, l, a)
override fun opacify(factor: Double) = copy(a = a * factor)
override fun minus(right: ColorXSLUVa) = copy(x = x - right.x, s = s - right.s, l = l - right.l, a = a - right.a)
override fun plus(right: ColorXSLUVa) = copy(x = x + right.x, s = s + right.s, l = l + right.l, a = a + right.a)
override fun times(scale: Double) = copy(x = x * scale, s = s * scale, l = l * scale, a = a * scale)
override fun mix(other: ColorXSLUVa, factor: Double) = mix(this, other, factor)
}
fun ColorRGBa.toXSLUVa() = toHSLUVa().toXSLUVa()
fun mix(left: ColorXSLUVa, right: ColorXSLUVa, x: Double): ColorXSLUVa {
val sx = x.coerceIn(0.0, 1.0)
return ColorXSLUVa(
mixAngle(left.x, right.x, sx),
(1.0 - sx) * left.s + sx * right.s,
(1.0 - sx) * left.l + sx * right.l,
(1.0 - sx) * left.a + sx * right.a)
}
private fun map(x: Double, a: Double, b: Double, c: Double, d: Double): Double {
return ((x - a) / (b - a)) * (d - c) + c return ((x - a) / (b - a)) * (d - c) + c
} }
@@ -201,90 +166,6 @@ private fun hueToX(hue:Double): Double {
} }
} }
private fun xToHue(x:Double) : Double {
val x = x % 360.0
return if (0.0 <= x && x < 60.0) {
map(x, 0.0, 60.0, 0.0, 35.0)
} else if (60.0 <= x && x < 120.0) {
map(x, 60.0, 120.0, 35.0, 60.0)
} else if (120.0 <= x && x < 180.0) {
map(x, 120.0, 180.0, 60.0, 135.0)
} else if (180.0 <= x && x < 240.0) {
map(x, 180.0, 240.0, 135.0, 225.0)
} else if (240.0 <= x && x < 300.0) {
map(x, 240.0, 300.0, 225.0, 275.0)
} else {
map(x, 300.0, 360.0, 276.0, 360.0)
}
}
data class ColorHPLUVa(val h: Double, val s: Double, val l: Double, val a: Double = 1.0) :
ConvertibleToColorRGBa,
HueShiftableColor<ColorHPLUVa>,
SaturatableColor<ColorHPLUVa>,
ShadableColor<ColorHPLUVa>,
OpacifiableColor<ColorHPLUVa>,
AlgebraicColor<ColorHPLUVa> {
fun toLCHUVa(): ColorLCHUVa {
val l1 = l
if (l1 > 0.9999999) {
return ColorLCHUVa(100.0, 0.0, h)
}
if (l1 < 0.00000001) {
return ColorLCHUVa(0.0, 0.0, h)
}
val l100 = l1 * 100.0
val max100 = maxSafeChromaForL(l100)
val c100 = max100 * s
return ColorLCHUVa(l100, c100, h)
}
override fun shiftHue(shiftInDegrees: Double): ColorHPLUVa {
return copy(h = h + (shiftInDegrees))
}
override fun shade(factor: Double): ColorHPLUVa = copy(l = l * factor)
override fun saturate(factor: Double): ColorHPLUVa = copy(s = s * factor)
override fun toRGBa(): ColorRGBa = toLCHUVa().toRGBa()
override fun opacify(factor: Double) = copy(a = a * factor)
override fun minus(right: ColorHPLUVa) = copy(h = h - right.h, s = s - right.s, l = l - right.l, a = a - right.a)
override fun plus(right: ColorHPLUVa) = copy(h = h + right.h, s = s + right.s, l = l + right.l, a = a + right.a)
override fun times(scale: Double) = copy(h = h * scale, s = s * scale, l = l * scale, a = a * scale)
override fun mix(other: ColorHPLUVa, factor: Double) = mix(this, other, factor)
}
fun mix(left: ColorHPLUVa, right: ColorHPLUVa, x: Double): ColorHPLUVa {
val sx = x.coerceIn(0.0, 1.0)
return ColorHPLUVa(
mixAngle(left.h, right.h, sx),
(1.0 - sx) * left.s + sx * right.s,
(1.0 - sx) * left.l + sx * right.l,
(1.0 - sx) * left.a + sx * right.a)
}
fun ColorLCHUVa.toHPLUVa(): ColorHPLUVa {
val l100 = l
if (l100 > 99.9999999) {
return ColorHPLUVa(h, 0.0, 1.0)
}
if (l100 < 0.00000001) {
return ColorHPLUVa(h, 0.0, 0.0)
}
val max100 = maxSafeChromaForL(l)
val s1 = c / max100
return ColorHPLUVa(h, s1, l100 / 100.0)
}
fun ColorLCHUVa.toHSLUVa(): ColorHSLUVa { fun ColorLCHUVa.toHSLUVa(): ColorHSLUVa {
val l100 = l val l100 = l
@@ -301,4 +182,3 @@ fun ColorLCHUVa.toHSLUVa(): ColorHSLUVa {
} }
fun ColorRGBa.toHSLUVa(): ColorHSLUVa = toLCHUVa().toHSLUVa() fun ColorRGBa.toHSLUVa(): ColorHSLUVa = toLCHUVa().toHSLUVa()
fun ColorRGBa.toHPLUVa(): ColorHPLUVa = toLCHUVa().toHPLUVa()

View File

@@ -1,16 +1,16 @@
package org.openrndr.extra.color.spaces package org.openrndr.extra.color.spaces
import org.openrndr.color.* import org.openrndr.color.*
import org.openrndr.math.Vector4
import org.openrndr.math.mixAngle import org.openrndr.math.mixAngle
import kotlin.math.* import kotlin.math.*
data class ColorOKHSLa(val h: Double, val s: Double, val l: Double, val a: Double = 1.0) : data class ColorOKHSLa(val h: Double, val s: Double, val l: Double, override val alpha: Double = 1.0) :
ColorModel<ColorOKHSLa>,
HueShiftableColor<ColorOKHSLa>, HueShiftableColor<ColorOKHSLa>,
OpacifiableColor<ColorOKHSLa>,
SaturatableColor<ColorOKHSLa>, SaturatableColor<ColorOKHSLa>,
ShadableColor<ColorOKHSLa>, ShadableColor<ColorOKHSLa>,
AlgebraicColor<ColorOKHSLa>, AlgebraicColor<ColorOKHSLa> {
ConvertibleToColorRGBa {
companion object { companion object {
fun fromColorRGBa(c: ColorRGBa): ColorOKHSLa { fun fromColorRGBa(c: ColorRGBa): ColorOKHSLa {
@@ -48,11 +48,14 @@ data class ColorOKHSLa(val h: Double, val s: Double, val l: Double, val a: Doubl
} }
} }
@Deprecated("Legacy alpha parameter name", ReplaceWith("alpha"))
val a = alpha
override fun toRGBa(): ColorRGBa { override fun toRGBa(): ColorRGBa {
if (l == 1.0) { if (l == 1.0) {
ColorRGBa(1.0, 1.0, 1.0, a) ColorRGBa(1.0, 1.0, 1.0, alpha)
} else if (l == 0.0) { } else if (l == 0.0) {
ColorRGBa(0.0, 0.0, 0.0, a) ColorRGBa(0.0, 0.0, 0.0, alpha)
} }
val a_ = cos(2 * PI * h / 360.0); val a_ = cos(2 * PI * h / 360.0);
val b_ = sin(2 * PI * h / 360.0); val b_ = sin(2 * PI * h / 360.0);
@@ -97,29 +100,21 @@ data class ColorOKHSLa(val h: Double, val s: Double, val l: Double, val a: Doubl
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).toRGBa().toSRGB()
} }
override fun shiftHue(shiftInDegrees: Double): ColorOKHSLa { override fun shiftHue(shiftInDegrees: Double): ColorOKHSLa = copy(h = h + shiftInDegrees)
return copy(h = h + shiftInDegrees)
}
override fun opacify(factor: Double): ColorOKHSLa { override fun opacify(factor: Double): ColorOKHSLa = copy(alpha = alpha * factor)
return copy(a = a * factor)
}
override fun saturate(factor: Double): ColorOKHSLa { override fun saturate(factor: Double): ColorOKHSLa = copy(s = s * factor)
return copy(s = s * factor)
}
override fun shade(factor: Double): ColorOKHSLa { override fun shade(factor: Double): ColorOKHSLa = copy(l = l * factor)
return copy(l = l * factor)
}
override fun minus(right: ColorOKHSLa) = override fun minus(right: ColorOKHSLa) =
copy(h = h - right.h, s = s - right.s, l = l - right.l, a = a - right.a) copy(h = h - right.h, s = s - right.s, l = l - right.l, alpha = alpha - right.alpha)
override fun plus(right: ColorOKHSLa) = override fun plus(right: ColorOKHSLa) =
copy(h = h + right.h, s = s + right.s, l = l + right.l, a = a + right.a) 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, a = a * 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 { override fun mix(other: ColorOKHSLa, factor: Double): ColorOKHSLa {
val sx = factor.coerceIn(0.0, 1.0) val sx = factor.coerceIn(0.0, 1.0)
@@ -127,10 +122,11 @@ data class ColorOKHSLa(val h: Double, val s: Double, val l: Double, val a: Doubl
mixAngle(h, other.h, sx) / 360.0, mixAngle(h, other.h, sx) / 360.0,
(1.0 - sx) * s + sx * other.s, (1.0 - sx) * s + sx * other.s,
(1.0 - sx) * l + sx * other.l, (1.0 - sx) * l + sx * other.l,
(1.0 - sx) * a + sx * other.a (1.0 - sx) * alpha + sx * other.alpha
) )
} }
override fun toVector4(): Vector4 = Vector4(h, s, l, alpha)
} }
fun ColorRGBa.toOKHSLa(): ColorOKHSLa = ColorOKHSLa.fromColorRGBa(this) fun ColorRGBa.toOKHSLa(): ColorOKHSLa = ColorOKHSLa.fromColorRGBa(this)

View File

@@ -1,16 +1,16 @@
package org.openrndr.extra.color.spaces package org.openrndr.extra.color.spaces
import org.openrndr.color.* import org.openrndr.color.*
import org.openrndr.math.Vector4
import org.openrndr.math.mixAngle import org.openrndr.math.mixAngle
import kotlin.math.* import kotlin.math.*
data class ColorOKHSVa(val h: Double, val s: Double, val v: Double, val a: Double = 1.0) : data class ColorOKHSVa(val h: Double, val s: Double, val v: Double, override val alpha: Double = 1.0) :
ColorModel<ColorOKHSVa>,
HueShiftableColor<ColorOKHSVa>, HueShiftableColor<ColorOKHSVa>,
OpacifiableColor<ColorOKHSVa>,
SaturatableColor<ColorOKHSVa>, SaturatableColor<ColorOKHSVa>,
ShadableColor<ColorOKHSVa>, ShadableColor<ColorOKHSVa>,
AlgebraicColor<ColorOKHSVa>, AlgebraicColor<ColorOKHSVa> {
ConvertibleToColorRGBa {
companion object { companion object {
fun fromColorRGBa(c: ColorRGBa): ColorOKHSVa { fun fromColorRGBa(c: ColorRGBa): ColorOKHSVa {
@@ -51,6 +51,9 @@ data class ColorOKHSVa(val h: Double, val s: Double, val v: Double, val a: Doubl
} }
} }
@Deprecated("Legacy alpha parameter name", ReplaceWith("alpha"))
val a = alpha
override fun toRGBa(): ColorRGBa { override fun toRGBa(): ColorRGBa {
val a_ = cos(2 * PI * h / 360.0) val a_ = cos(2 * PI * h / 360.0)
val b_ = sin(2 * PI * h / 360.0) val b_ = sin(2 * PI * h / 360.0)
@@ -81,7 +84,7 @@ data class ColorOKHSVa(val h: Double, val s: Double, val v: Double, val a: Doubl
L = L_new; L = L_new;
val rgb_scale = 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); 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) 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 // remove to see effect without rescaling
@@ -94,29 +97,15 @@ data class ColorOKHSVa(val h: Double, val s: Double, val v: Double, val a: Doubl
if (C == C) C * b_ else 0.0).toRGBa().toSRGB() if (C == C) C * b_ else 0.0).toRGBa().toSRGB()
} }
override fun shiftHue(shiftInDegrees: Double): ColorOKHSVa { override fun shiftHue(shiftInDegrees: Double): ColorOKHSVa = copy(h = h + shiftInDegrees)
return copy(h = h + shiftInDegrees) override fun opacify(factor: Double): ColorOKHSVa = copy(alpha = alpha * factor)
} override fun saturate(factor: Double): ColorOKHSVa = copy(s = s * factor)
override fun shade(factor: Double): ColorOKHSVa = copy(v = v * factor)
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)
}
override fun minus(right: ColorOKHSVa) = override fun minus(right: ColorOKHSVa) =
copy(h = h - right.h, s = s - right.s, v = v - right.v, a = a - right.a) copy(h = h - right.h, s = s - right.s, v = v - right.v, alpha = alpha - right.alpha)
override fun plus(right: ColorOKHSVa) = override fun plus(right: ColorOKHSVa) =
copy(h = h + right.h, s = s + right.s, v = v + right.v, a = a + right.a) copy(h = h + right.h, s = s + right.s, v = v + right.v, alpha = alpha + right.alpha)
override fun times(scale: Double): ColorOKHSVa = copy(h = h * scale, s = s * scale, v = v * scale, alpha = alpha * scale)
override fun times(scale: Double): ColorOKHSVa = copy(h = h * scale, s = s * scale, v = v * scale, a = a * scale)
override fun mix(other: ColorOKHSVa, factor: Double): ColorOKHSVa { override fun mix(other: ColorOKHSVa, factor: Double): ColorOKHSVa {
val sx = factor.coerceIn(0.0, 1.0) val sx = factor.coerceIn(0.0, 1.0)
@@ -124,9 +113,11 @@ data class ColorOKHSVa(val h: Double, val s: Double, val v: Double, val a: Doubl
mixAngle(h, other.h, sx), mixAngle(h, other.h, sx),
(1.0 - sx) * s + sx * other.s, (1.0 - sx) * s + sx * other.s,
(1.0 - sx) * v + sx * other.v, (1.0 - sx) * v + sx * other.v,
(1.0 - sx) * a + sx * other.a (1.0 - sx) * alpha + sx * other.alpha
) )
} }
override fun toVector4(): Vector4 = Vector4(h, s, v, alpha)
} }
fun ColorRGBa.toOKHSVa(): ColorOKHSVa = ColorOKHSVa.fromColorRGBa(this) fun ColorRGBa.toOKHSVa(): ColorOKHSVa = ColorOKHSVa.fromColorRGBa(this)

View File

@@ -1,7 +1,6 @@
package org.openrndr.extra.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.Vector4 import org.openrndr.math.Vector4
import kotlin.math.pow import kotlin.math.pow
@@ -11,11 +10,9 @@ import kotlin.math.pow
* [a] = red (-1.0) to green (1.0), * [a] = red (-1.0) to green (1.0),
* [b] = yellow (-1.0) to blue (1.0). * [b] = yellow (-1.0) to blue (1.0).
*/ */
data class ColorOKLABa(val l: Double, val a: Double, val b: Double, val alpha: Double = 1.0) : data class ColorOKLABa(val l: Double, val a: Double, val b: Double, override val alpha: Double = 1.0) :
ConvertibleToColorRGBa, ColorModel<ColorOKLABa>,
CastableToVector4,
ShadableColor<ColorOKLABa>, ShadableColor<ColorOKLABa>,
OpacifiableColor<ColorOKLABa>,
AlgebraicColor<ColorOKLABa> { AlgebraicColor<ColorOKLABa> {
companion object { companion object {

View File

@@ -1,16 +1,14 @@
package org.openrndr.extra.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.*
import org.openrndr.math.asRadians
import org.openrndr.math.mixAngle
import kotlin.math.* import kotlin.math.*
/** /**
* Color in cylindrical OKLab space * Color in cylindrical OKLab space
*/ */
data class ColorOKLCHa(val l: Double, val c: Double, val h: Double, val a: Double = 1.0) : ConvertibleToColorRGBa, data class ColorOKLCHa(val l: Double, val c: Double, val h: Double, override val alpha: Double = 1.0) :
OpacifiableColor<ColorOKLCHa>, ColorModel<ColorOKLCHa>,
ShadableColor<ColorOKLCHa>, ShadableColor<ColorOKLCHa>,
HueShiftableColor<ColorOKLCHa>, HueShiftableColor<ColorOKLCHa>,
SaturatableColor<ColorOKLCHa>, SaturatableColor<ColorOKLCHa>,
@@ -30,14 +28,17 @@ data class ColorOKLCHa(val l: Double, val c: Double, val h: Double, val a: Doubl
} }
} }
override fun opacify(factor: Double) = copy(a = a * factor) @Deprecated("Legacy alpha parameter name", ReplaceWith("alpha"))
val a = alpha
override fun opacify(factor: Double) = copy(alpha = a * factor)
override fun shade(factor: Double) = copy(l = l * factor) override fun shade(factor: Double) = copy(l = l * factor)
override fun shiftHue(shiftInDegrees: Double) = copy(h = h + shiftInDegrees) override fun shiftHue(shiftInDegrees: Double) = copy(h = h + shiftInDegrees)
override fun saturate(factor: Double) = copy(c = c * factor) override fun saturate(factor: Double) = copy(c = c * factor)
override fun plus(right: ColorOKLCHa) = copy(l = l + right.l, c = c + right.c, h = h + right.h, a = a + right.a) override fun plus(right: ColorOKLCHa) = copy(l = l + right.l, c = c + right.c, h = h + right.h, alpha = a + right.a)
override fun minus(right: ColorOKLCHa) = copy(l = l - right.l, c = c - right.c, h = h - right.h, a = a - right.a) override fun minus(right: ColorOKLCHa) = copy(l = l - right.l, c = c - right.c, h = h - right.h, alpha = a - right.a)
override fun times(scale: Double) = copy(l = l * scale, c = c * scale, h = h * scale, a = a * scale) override fun times(scale: Double) = copy(l = l * scale, c = c * scale, h = h * scale, alpha = a * scale)
override fun mix(other: ColorOKLCHa, factor: Double) = mix(this, other, factor) override fun mix(other: ColorOKLCHa, factor: Double) = mix(this, other, factor)
fun toOKLABa(): ColorOKLABa { fun toOKLABa(): ColorOKLABa {
@@ -46,7 +47,8 @@ data class ColorOKLCHa(val l: Double, val c: Double, val h: Double, val a: Doubl
return ColorOKLABa(l, a, b, alpha = this.a) return ColorOKLABa(l, a, b, alpha = this.a)
} }
override fun toRGBa() = toOKLABa().toRGBa() override fun toRGBa(): ColorRGBa = toOKLABa().toRGBa()
override fun toVector4(): Vector4 = Vector4(l, c, h, alpha)
} }
fun mix(left: ColorOKLCHa, right: ColorOKLCHa, x: Double): ColorOKLCHa { fun mix(left: ColorOKLCHa, right: ColorOKLCHa, x: Double): ColorOKLCHa {

View File

@@ -0,0 +1,66 @@
package org.openrndr.extra.color.spaces
import org.openrndr.color.*
import org.openrndr.math.Vector4
import org.openrndr.math.mixAngle
data class ColorXSLUVa(val x: Double, val s: Double, val l: Double, override val alpha: Double = 1.0) :
ColorModel<ColorXSLUVa>,
HueShiftableColor<ColorXSLUVa>,
SaturatableColor<ColorXSLUVa>,
ShadableColor<ColorXSLUVa>,
AlgebraicColor<ColorXSLUVa> {
@Deprecated("Legacy alpha parameter name", ReplaceWith("alpha"))
val a = alpha
override fun shiftHue(shiftInDegrees: Double) = copy(x = x + (shiftInDegrees))
override fun shade(factor: Double) = copy(l = l * factor)
override fun saturate(factor: Double) = copy(s = s * factor)
override fun toRGBa(): ColorRGBa = toHSLUVa().toRGBa()
fun toHSLUVa(): ColorHSLUVa = ColorHSLUVa(xToHue(x), s, l, alpha)
override fun opacify(factor: Double) = copy(alpha = alpha * factor)
override fun minus(right: ColorXSLUVa) = copy(x = x - right.x, s = s - right.s, l = l - right.l, alpha = alpha - right.alpha)
override fun plus(right: ColorXSLUVa) = copy(x = x + right.x, s = s + right.s, l = l + right.l, alpha = alpha + right.alpha)
override fun times(scale: Double) = copy(x = x * scale, s = s * scale, l = l * scale, alpha = alpha * scale)
override fun mix(other: ColorXSLUVa, factor: Double) = mix(this, other, factor)
override fun toVector4(): Vector4 = Vector4(x, s, l, alpha)
}
private fun xToHue(x:Double) : Double {
val x = x % 360.0
return if (0.0 <= x && x < 60.0) {
map(x, 0.0, 60.0, 0.0, 35.0)
} else if (60.0 <= x && x < 120.0) {
map(x, 60.0, 120.0, 35.0, 60.0)
} else if (120.0 <= x && x < 180.0) {
map(x, 120.0, 180.0, 60.0, 135.0)
} else if (180.0 <= x && x < 240.0) {
map(x, 180.0, 240.0, 135.0, 225.0)
} else if (240.0 <= x && x < 300.0) {
map(x, 240.0, 300.0, 225.0, 275.0)
} else {
map(x, 300.0, 360.0, 276.0, 360.0)
}
}
fun mix(left: ColorXSLUVa, right: ColorXSLUVa, x: Double): ColorXSLUVa {
val sx = x.coerceIn(0.0, 1.0)
return ColorXSLUVa(
mixAngle(left.x, right.x, sx),
(1.0 - sx) * left.s + sx * right.s,
(1.0 - sx) * left.l + sx * right.l,
(1.0 - sx) * left.alpha + sx * right.alpha)
}
fun ColorRGBa.toXSLUVa() = toHSLUVa().toXSLUVa()

View File

@@ -194,7 +194,7 @@ class GUI(val baseColor:ColorRGBa = ColorRGBa.GRAY, val defaultStyles: List<Styl
this.width = 100.percent this.width = 100.percent
this.display = Display.FLEX this.display = Display.FLEX
this.flexDirection = FlexDirection.Row this.flexDirection = FlexDirection.Row
this.background = Color.RGBa(baseColor.copy(a = 0.99)) this.background = Color.RGBa(baseColor.copy(alpha = 0.99))
} }
styleSheet(has class_ "collapsed") { styleSheet(has class_ "collapsed") {
@@ -213,7 +213,7 @@ class GUI(val baseColor:ColorRGBa = ColorRGBa.GRAY, val defaultStyles: List<Styl
this.paddingRight = 10.px this.paddingRight = 10.px
this.marginRight = 2.px this.marginRight = 2.px
this.height = 100.percent this.height = 100.percent
this.background = Color.RGBa(baseColor.copy(a = 0.99)) this.background = Color.RGBa(baseColor.copy(alpha = 0.99))
this.overflow = Overflow.Scroll this.overflow = Overflow.Scroll
//<editor-fold desc="1) setup control style"> //<editor-fold desc="1) setup control style">
@@ -881,7 +881,7 @@ class GUI(val baseColor:ColorRGBa = ColorRGBa.GRAY, val defaultStyles: List<Styl
} }
ParameterType.Color -> { ParameterType.Color -> {
val currentValue = (parameter.property as KMutableProperty1<Any, ColorRGBa>).get(labeledObject.obj) val currentValue = (parameter.property as KMutableProperty1<Any, ColorRGBa>).get(labeledObject.obj)
val randomValue = ColorRGBa(Math.random(), Math.random(), Math.random(), currentValue.a) val randomValue = ColorRGBa(Math.random(), Math.random(), Math.random(), currentValue.alpha)
val newValue = ColorRGBa((1.0 - strength) * currentValue.r + randomValue.r * strength, val newValue = ColorRGBa((1.0 - strength) * currentValue.r + randomValue.r * strength,
(1.0 - strength) * currentValue.g + randomValue.g * strength, (1.0 - strength) * currentValue.g + randomValue.g * strength,
(1.0 - strength) * currentValue.b + randomValue.b * strength) (1.0 - strength) * currentValue.b + randomValue.b * strength)

View File

@@ -86,7 +86,7 @@ open class Keyframer {
} }
inner class RGBaChannel(keys: Array<String>, defaultValue: ColorRGBa = ColorRGBa.WHITE) : inner class RGBaChannel(keys: Array<String>, defaultValue: ColorRGBa = ColorRGBa.WHITE) :
CompoundChannel(keys, arrayOf(defaultValue.r, defaultValue.g, defaultValue.b, defaultValue.a)) { CompoundChannel(keys, arrayOf(defaultValue.r, defaultValue.g, defaultValue.b, defaultValue.alpha)) {
operator fun getValue(keyframer: Keyframer, property: KProperty<*>): ColorRGBa = operator fun getValue(keyframer: Keyframer, property: KProperty<*>): ColorRGBa =
ColorRGBa(getValue(0), getValue(1), getValue(2), getValue(3)) ColorRGBa(getValue(0), getValue(1), getValue(2), getValue(3))
} }

View File

@@ -217,7 +217,7 @@ class RabbitControlServer(private val showQRUntilClientConnects: Boolean = true,
ParameterType.Color -> { ParameterType.Color -> {
val param = rabbitServer.createRGBAParameter(it.label) val param = rabbitServer.createRGBAParameter(it.label)
val c = (it.property as KMutableProperty1<Any, ColorRGBa>).get(objectWithParameters) val c = (it.property as KMutableProperty1<Any, ColorRGBa>).get(objectWithParameters)
param.value = Color(c.r.toFloat(), c.g.toFloat(), c.b.toFloat(), c.a.toFloat()) param.value = Color(c.r.toFloat(), c.g.toFloat(), c.b.toFloat(), c.alpha.toFloat())
param param
} }
ParameterType.Vector2 -> { ParameterType.Vector2 -> {