mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-12 22:56:06 +09:00
117 lines
3.3 KiB
Kotlin
117 lines
3.3 KiB
Kotlin
package net.torvald.colourutil
|
|
|
|
import com.jme3.math.FastMath
|
|
import com.badlogic.gdx.graphics.Color
|
|
|
|
/**
|
|
* A modification of CIEXYZ that is useful for additive mixtures of lights.
|
|
*
|
|
* reference: http://www.brucelindbloom.com/index.html?Equations.html
|
|
*
|
|
* If you're using Mac, you can play around with this colour space with
|
|
* ColorSync Utility's calculator.
|
|
*
|
|
* Created by minjaesong on 2016-09-06.
|
|
*/
|
|
|
|
fun Color.brighterLuv(scale: Float): Color {
|
|
val brighten = scale + 1f
|
|
|
|
val luv = this.toLuv()
|
|
luv.L *= brighten
|
|
return luv.toColor()
|
|
}
|
|
|
|
fun Color.darkerLuv(scale: Float): Color {
|
|
val darken = 1f - scale
|
|
|
|
val luv = this.toLuv()
|
|
luv.L *= darken
|
|
return luv.toColor()
|
|
}
|
|
|
|
/** Tend to have more vivid (or saturated) colour */
|
|
fun cieluv_getGradient(scale: Float, fromCol: Color, toCol: Color): Color {
|
|
val from = fromCol.toLuv()
|
|
val to = toCol.toLuv()
|
|
val newL = FastMath.interpolateLinear(scale, from.L, to.L)
|
|
val newU = FastMath.interpolateLinear(scale, from.u, to.u)
|
|
val newV = FastMath.interpolateLinear(scale, from.v, to.v)
|
|
val newAlpha = FastMath.interpolateLinear(scale, from.alpha, to.alpha)
|
|
|
|
return CIELab(newL, newU, newV, newAlpha).toColor()
|
|
}
|
|
|
|
/**
|
|
* Alpha value will be overwritten to 1.0
|
|
*/
|
|
infix fun Color.additiveLuv(other: Color): Color {
|
|
val rgb = RGB(r, g, b) additiveLuv RGB(other.r, other.g, other.b)
|
|
return Color(rgb.r, rgb.g, rgb.b, a)
|
|
}
|
|
|
|
/**
|
|
* Alpha value will be overwritten to 1.0
|
|
*/
|
|
infix fun RGB.additiveLuv(other: RGB): RGB {
|
|
val thisLuv = this.toXYZ().toLuv()
|
|
val otherLuv = other.toXYZ().toLuv()
|
|
|
|
val newL = 1f - (1f - thisLuv.L) * (1 - otherLuv.L)
|
|
val newU = thisLuv.u.times(otherLuv.L / newL) + otherLuv.u.times(otherLuv.L).times(1f - thisLuv.L).div(newL)
|
|
val newV = thisLuv.v.times(otherLuv.L / newL) + otherLuv.v.times(otherLuv.L).times(1f - thisLuv.L).div(newL)
|
|
|
|
return CIELuv(newL, newU, newV).toRGB()
|
|
}
|
|
|
|
fun CIEXYZ.toLuv(): CIELuv {
|
|
val yRef = Y / D65.Y
|
|
val uPrime = 4f * X / (X + 15f * Y + 3f * Z)
|
|
val vPrime = 9f * Y / (X + 15f * Y + 3f * Z)
|
|
val uRefPrime = 4f * D65.X / (D65.X + 15f * D65.Y + 3f * D65.Z)
|
|
val vRefPrime = 9f * D65.Y / (D65.X + 15f * D65.Y + 3f * D65.Z)
|
|
|
|
val L = if (yRef > epsilon)
|
|
116f * yRef.cbrt() - 16f
|
|
else
|
|
kappa * yRef
|
|
|
|
val u = 13f * L * (uPrime - uRefPrime)
|
|
val v = 13f * L * (vPrime - vRefPrime)
|
|
|
|
return CIELuv(L, u, v, alpha)
|
|
}
|
|
|
|
fun CIELuv.toXYZ(): CIEXYZ {
|
|
val Y = if (L > kappa * epsilon)
|
|
L.plus(16f).div(116f).cube()
|
|
else
|
|
L.div(kappa)
|
|
val uRef = 4f * D65.X / (D65.X + 15f * D65.Y + 3f * D65.Z)
|
|
val vRef = 9f * D65.Y / (D65.X + 15f * D65.Y + 3f * D65.Z)
|
|
val a = (1f / 3f) * (52.times(L) / u.plus(13 * L * uRef)).minus(1f)
|
|
val b = -5f * Y
|
|
val c = -1f / 3f
|
|
val d = Y * (39f.times(L) / v.plus(13f * L * vRef)).minus(5f)
|
|
val X = (d - b) / (a - c)
|
|
val Z = X * a + b
|
|
|
|
return CIEXYZ(X, Y, Z, alpha)
|
|
}
|
|
|
|
private fun Float.cbrt() = FastMath.pow(this, 1f / 3f)
|
|
private fun Float.cube() = this * this * this
|
|
|
|
|
|
fun Color.toLuv() = this.toXYZ().toLuv()
|
|
fun CIELuv.toRGB() = this.toXYZ().toRGB()
|
|
fun CIELuv.toColor() = this.toXYZ().toColor()
|
|
|
|
/**
|
|
* Range:
|
|
* L: 0-100.0
|
|
* u, v: -100+ - 100+
|
|
* (Hundred-based-plus)
|
|
*/
|
|
data class CIELuv(var L: Float = 0f, var u: Float = 0f, var v: Float = 0f, var alpha: Float = 1f)
|