[orx-color] Color model changes (#246)
This commit is contained in:
@@ -5,8 +5,6 @@ package org.openrndr.extras.color.presets
|
||||
import org.openrndr.color.ColorRGBa
|
||||
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.ANTIQUE_WHITE by lazy { rgb(0.980392, 0.921569, 0.843137) }
|
||||
val ColorRGBa.Companion.AQUA by lazy { rgb(0.0, 1.0, 1.0) }
|
||||
|
||||
71
orx-color/src/commonMain/kotlin/spaces/ColorHPLUVa.kt
Normal file
71
orx-color/src/commonMain/kotlin/spaces/ColorHPLUVa.kt
Normal 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)
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package org.openrndr.extra.color.spaces
|
||||
|
||||
import org.openrndr.color.*
|
||||
import org.openrndr.math.Vector4
|
||||
import org.openrndr.math.map
|
||||
import org.openrndr.math.mixAngle
|
||||
import kotlin.math.*
|
||||
|
||||
@@ -9,10 +11,10 @@ private val m = arrayOf(
|
||||
doubleArrayOf(-0.96924363628087, 1.87596750150772, 0.041555057407175),
|
||||
doubleArrayOf(0.055630079696993, -0.20397695888897, 1.056971514242878))
|
||||
|
||||
private val kappa = 903.2962962
|
||||
private val epsilon = 0.0088564516
|
||||
private const val kappa = 903.2962962
|
||||
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 sub1 = (L + 16).pow(3.0) / 1560896
|
||||
val sub2 = if (sub1 > epsilon) sub1 else L / kappa
|
||||
@@ -47,11 +49,11 @@ private class Length(val length: Double) {
|
||||
val greaterEqualZero: Boolean = length >= 0
|
||||
}
|
||||
|
||||
private fun maxSafeChromaForL(L100: Double): Double {
|
||||
internal fun maxSafeChromaForL(L100: Double): Double {
|
||||
val bounds = getBounds(L100)
|
||||
var min = Double.MAX_VALUE
|
||||
for (i in 0..1) {
|
||||
val m1 = bounds!![i][0]
|
||||
val m1 = bounds[i][0]
|
||||
val b1 = bounds[i][1]
|
||||
val line = doubleArrayOf(m1, b1)
|
||||
val x = intersectLineLine(line, doubleArrayOf(-1 / m1, 0.0))
|
||||
@@ -61,11 +63,11 @@ private fun maxSafeChromaForL(L100: Double): Double {
|
||||
return min
|
||||
}
|
||||
|
||||
fun maxChromaForLH(L100: Double, H: Double): Double {
|
||||
private fun maxChromaForLH(L100: Double, H: Double): Double {
|
||||
val hrad = H / 360 * PI * 2
|
||||
val bounds = getBounds(L100)
|
||||
var min = Double.MAX_VALUE
|
||||
for (bound in bounds!!) {
|
||||
for (bound in bounds) {
|
||||
val length: Length = lengthOfRayUntilIntersect(hrad, bound)
|
||||
if (length.greaterEqualZero) {
|
||||
min = min(min, length.length)
|
||||
@@ -77,35 +79,37 @@ fun maxChromaForLH(L100: Double, H: Double): Double {
|
||||
/**
|
||||
* HSLUV color space
|
||||
*/
|
||||
data class ColorHSLUVa(val h: Double, val s: Double, val l: Double, val a: Double = 1.0) :
|
||||
ConvertibleToColorRGBa,
|
||||
data class ColorHSLUVa(val h: Double, val s: Double, val l: Double, override val alpha: Double = 1.0) :
|
||||
ColorModel<ColorHSLUVa>,
|
||||
HueShiftableColor<ColorHSLUVa>,
|
||||
SaturatableColor<ColorHSLUVa>,
|
||||
ShadableColor<ColorHSLUVa>,
|
||||
OpacifiableColor<ColorHSLUVa>,
|
||||
AlgebraicColor<ColorHSLUVa> {
|
||||
|
||||
@Deprecated("Legacy alpha parameter name", ReplaceWith("alpha"))
|
||||
val a = alpha
|
||||
|
||||
fun toLCHUVa(): ColorLCHUVa {
|
||||
|
||||
val l100 = l * 100.0
|
||||
val s100 = s * 100.0
|
||||
|
||||
if (l100 > 99.9999999) {
|
||||
ColorLCHUVa(100.0, 0.0, h, a)
|
||||
ColorLCHUVa(100.0, 0.0, h, alpha)
|
||||
}
|
||||
|
||||
if (l100 < 0.00000001) {
|
||||
ColorLCHUVa(0.0, 0.0, h, a)
|
||||
ColorLCHUVa(0.0, 0.0, h, alpha)
|
||||
}
|
||||
val max100 = maxChromaForLH(l100, h)
|
||||
|
||||
val c: Double = max100 / 100 * s100
|
||||
|
||||
return ColorLCHUVa(l100, c, h, a)
|
||||
return ColorLCHUVa(l100, c, h, alpha)
|
||||
}
|
||||
|
||||
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))
|
||||
@@ -118,16 +122,18 @@ data class ColorHSLUVa(val h: Double, val s: Double, val l: Double, val a: Doubl
|
||||
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 toVector4(): Vector4 = Vector4(h, s, l, alpha)
|
||||
|
||||
}
|
||||
|
||||
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),
|
||||
(1.0 - sx) * left.s + sx * right.s,
|
||||
(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):
|
||||
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 {
|
||||
internal fun map(x: Double, a: Double, b: Double, c: Double, d: Double): Double {
|
||||
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 {
|
||||
val l100 = l
|
||||
|
||||
@@ -301,4 +182,3 @@ fun ColorLCHUVa.toHSLUVa(): ColorHSLUVa {
|
||||
}
|
||||
|
||||
fun ColorRGBa.toHSLUVa(): ColorHSLUVa = toLCHUVa().toHSLUVa()
|
||||
fun ColorRGBa.toHPLUVa(): ColorHPLUVa = toLCHUVa().toHPLUVa()
|
||||
@@ -1,16 +1,16 @@
|
||||
package org.openrndr.extra.color.spaces
|
||||
|
||||
import org.openrndr.color.*
|
||||
import org.openrndr.math.Vector4
|
||||
import org.openrndr.math.mixAngle
|
||||
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>,
|
||||
OpacifiableColor<ColorOKHSLa>,
|
||||
SaturatableColor<ColorOKHSLa>,
|
||||
ShadableColor<ColorOKHSLa>,
|
||||
AlgebraicColor<ColorOKHSLa>,
|
||||
ConvertibleToColorRGBa {
|
||||
AlgebraicColor<ColorOKHSLa> {
|
||||
|
||||
companion object {
|
||||
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 {
|
||||
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) {
|
||||
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 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()
|
||||
}
|
||||
|
||||
override fun shiftHue(shiftInDegrees: Double): ColorOKHSLa {
|
||||
return copy(h = h + shiftInDegrees)
|
||||
}
|
||||
override fun shiftHue(shiftInDegrees: Double): ColorOKHSLa = copy(h = h + shiftInDegrees)
|
||||
|
||||
override fun opacify(factor: Double): ColorOKHSLa {
|
||||
return copy(a = a * factor)
|
||||
}
|
||||
override fun opacify(factor: Double): ColorOKHSLa = copy(alpha = alpha * factor)
|
||||
|
||||
override fun saturate(factor: Double): ColorOKHSLa {
|
||||
return copy(s = s * factor)
|
||||
}
|
||||
override fun saturate(factor: Double): ColorOKHSLa = copy(s = s * factor)
|
||||
|
||||
override fun shade(factor: Double): ColorOKHSLa {
|
||||
return copy(l = l * factor)
|
||||
}
|
||||
override fun shade(factor: Double): ColorOKHSLa = copy(l = l * factor)
|
||||
|
||||
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) =
|
||||
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 {
|
||||
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,
|
||||
(1.0 - sx) * s + sx * other.s,
|
||||
(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)
|
||||
@@ -1,16 +1,16 @@
|
||||
package org.openrndr.extra.color.spaces
|
||||
|
||||
import org.openrndr.color.*
|
||||
import org.openrndr.math.Vector4
|
||||
import org.openrndr.math.mixAngle
|
||||
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>,
|
||||
OpacifiableColor<ColorOKHSVa>,
|
||||
SaturatableColor<ColorOKHSVa>,
|
||||
ShadableColor<ColorOKHSVa>,
|
||||
AlgebraicColor<ColorOKHSVa>,
|
||||
ConvertibleToColorRGBa {
|
||||
AlgebraicColor<ColorOKHSVa> {
|
||||
|
||||
companion object {
|
||||
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 {
|
||||
val a_ = cos(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;
|
||||
|
||||
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)
|
||||
|
||||
// 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()
|
||||
}
|
||||
|
||||
override fun shiftHue(shiftInDegrees: Double): ColorOKHSVa {
|
||||
return copy(h = h + shiftInDegrees)
|
||||
}
|
||||
|
||||
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 shiftHue(shiftInDegrees: Double): ColorOKHSVa = 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 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) =
|
||||
copy(h = h + right.h, s = s + right.s, v = v + right.v, a = a + right.a)
|
||||
|
||||
override fun times(scale: Double): ColorOKHSVa = copy(h = h * scale, s = s * scale, v = v * scale, a = a * scale)
|
||||
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 mix(other: ColorOKHSVa, factor: Double): ColorOKHSVa {
|
||||
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),
|
||||
(1.0 - sx) * s + sx * other.s,
|
||||
(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)
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.openrndr.extra.color.spaces
|
||||
|
||||
import org.openrndr.color.*
|
||||
import org.openrndr.math.CastableToVector4
|
||||
import org.openrndr.math.Vector4
|
||||
import kotlin.math.pow
|
||||
|
||||
@@ -11,11 +10,9 @@ import kotlin.math.pow
|
||||
* [a] = red (-1.0) to green (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) :
|
||||
ConvertibleToColorRGBa,
|
||||
CastableToVector4,
|
||||
data class ColorOKLABa(val l: Double, val a: Double, val b: Double, override val alpha: Double = 1.0) :
|
||||
ColorModel<ColorOKLABa>,
|
||||
ShadableColor<ColorOKLABa>,
|
||||
OpacifiableColor<ColorOKLABa>,
|
||||
AlgebraicColor<ColorOKLABa> {
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
package org.openrndr.extra.color.spaces
|
||||
|
||||
import org.openrndr.color.*
|
||||
import org.openrndr.math.asDegrees
|
||||
import org.openrndr.math.asRadians
|
||||
import org.openrndr.math.mixAngle
|
||||
import org.openrndr.math.*
|
||||
import kotlin.math.*
|
||||
|
||||
/**
|
||||
* Color in cylindrical OKLab space
|
||||
*/
|
||||
data class ColorOKLCHa(val l: Double, val c: Double, val h: Double, val a: Double = 1.0) : ConvertibleToColorRGBa,
|
||||
OpacifiableColor<ColorOKLCHa>,
|
||||
data class ColorOKLCHa(val l: Double, val c: Double, val h: Double, override val alpha: Double = 1.0) :
|
||||
ColorModel<ColorOKLCHa>,
|
||||
ShadableColor<ColorOKLCHa>,
|
||||
HueShiftableColor<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 shiftHue(shiftInDegrees: Double) = copy(h = h + shiftInDegrees)
|
||||
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 minus(right: ColorOKLCHa) = copy(l = l - right.l, c = c - right.c, h = h - right.h, a = a - right.a)
|
||||
override fun times(scale: Double) = copy(l = l * scale, c = c * scale, h = h * scale, a = a * scale)
|
||||
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, alpha = a - right.a)
|
||||
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)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
66
orx-color/src/commonMain/kotlin/spaces/ColorXSLUVa.kt
Normal file
66
orx-color/src/commonMain/kotlin/spaces/ColorXSLUVa.kt
Normal 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()
|
||||
@@ -194,7 +194,7 @@ class GUI(val baseColor:ColorRGBa = ColorRGBa.GRAY, val defaultStyles: List<Styl
|
||||
this.width = 100.percent
|
||||
this.display = Display.FLEX
|
||||
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") {
|
||||
@@ -213,7 +213,7 @@ class GUI(val baseColor:ColorRGBa = ColorRGBa.GRAY, val defaultStyles: List<Styl
|
||||
this.paddingRight = 10.px
|
||||
this.marginRight = 2.px
|
||||
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
|
||||
|
||||
//<editor-fold desc="1) setup control style">
|
||||
@@ -881,7 +881,7 @@ class GUI(val baseColor:ColorRGBa = ColorRGBa.GRAY, val defaultStyles: List<Styl
|
||||
}
|
||||
ParameterType.Color -> {
|
||||
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,
|
||||
(1.0 - strength) * currentValue.g + randomValue.g * strength,
|
||||
(1.0 - strength) * currentValue.b + randomValue.b * strength)
|
||||
|
||||
@@ -86,7 +86,7 @@ open class Keyframer {
|
||||
}
|
||||
|
||||
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 =
|
||||
ColorRGBa(getValue(0), getValue(1), getValue(2), getValue(3))
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ class RabbitControlServer(private val showQRUntilClientConnects: Boolean = true,
|
||||
ParameterType.Color -> {
|
||||
val param = rabbitServer.createRGBAParameter(it.label)
|
||||
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
|
||||
}
|
||||
ParameterType.Vector2 -> {
|
||||
|
||||
Reference in New Issue
Block a user