mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
107 lines
3.3 KiB
Kotlin
107 lines
3.3 KiB
Kotlin
package net.torvald.colourutil
|
|
|
|
import com.jme3.math.FastMath
|
|
import net.torvald.colourutil.CIELabUtil.toLab
|
|
import net.torvald.colourutil.CIEXYZUtil.toColor
|
|
import net.torvald.colourutil.CIEXYZUtil.toRGB
|
|
import net.torvald.colourutil.CIEXYZUtil.toXYZ
|
|
import net.torvald.colourutil.CIELabUtil.toXYZ
|
|
import com.badlogic.gdx.graphics.Color
|
|
|
|
/**
|
|
* A modification of CIEXYZ that is useful for surface colours
|
|
*
|
|
* If you are trying to mix some colour with other, especially one that
|
|
* requires additive mixing (such as illuminant), USE CIELuvUtil, this is
|
|
* not for you.
|
|
*
|
|
* RGB in this code is always sRGB.
|
|
* 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-01.
|
|
*/
|
|
object CIELabUtil {
|
|
fun Color.brighterLab(scale: Float): Color {
|
|
val brighten = scale + 1f
|
|
|
|
val lab = this.toLab()
|
|
lab.L *= brighten
|
|
return lab.toColor()
|
|
}
|
|
|
|
fun Color.darkerLab(scale: Float): Color {
|
|
val darken = 1f - scale
|
|
|
|
val lab = this.toLab()
|
|
lab.L *= darken
|
|
return lab.toColor()
|
|
}
|
|
|
|
/** Tend to have more natural (or less saturated) colour */
|
|
fun getGradient(scale: Float, fromCol: Color, toCol: Color): Color {
|
|
val from = fromCol.toLab()
|
|
val to = toCol.toLab()
|
|
val newL = FastMath.interpolateLinear(scale, from.L, to.L)
|
|
val newA = FastMath.interpolateLinear(scale, from.a, to.a)
|
|
val newB = FastMath.interpolateLinear(scale, from.b, to.b)
|
|
val newAlpha = FastMath.interpolateLinear(scale, from.alpha, to.alpha)
|
|
|
|
return CIELab(newL, newA, newB, newAlpha).toColor()
|
|
}
|
|
|
|
fun CIEXYZ.toLab(): CIELab {
|
|
val x = pivotXYZ(X / D65.X)
|
|
val y = pivotXYZ(Y / D65.Y)
|
|
val z = pivotXYZ(Z / D65.Z)
|
|
|
|
val L = Math.max(0f, 116 * y - 16)
|
|
val a = 500 * (x - y)
|
|
val b = 200 * (y - z)
|
|
|
|
return CIELab(L, a, b, alpha)
|
|
}
|
|
|
|
fun CIELab.toXYZ(): CIEXYZ {
|
|
val y = L.plus(16).div(116f)
|
|
val x = a / 500f + y
|
|
val z = y - b / 200f
|
|
|
|
val x3 = x.cube()
|
|
val z3 = z.cube()
|
|
|
|
return CIEXYZ(
|
|
D65.X * if (x3 > epsilon) x3 else (x - 16f / 116f) / 7.787f,
|
|
D65.Y * if (L > kappa * epsilon) (L.plus(16f) / 116f).cube() else L / kappa,
|
|
D65.Z * if (z3 > epsilon) z3 else (z - 16f / 116f) / 7.787f,
|
|
alpha
|
|
)
|
|
}
|
|
|
|
private fun pivotXYZ(n: Float) = if (n > epsilon) n.cbrt() else (kappa * n + 16f) / 116f
|
|
|
|
private fun Float.cbrt() = FastMath.pow(this, 1f / 3f)
|
|
private fun Float.cube() = this * this * this
|
|
private fun Float.powerOf(exp: Float) = FastMath.pow(this, exp)
|
|
}
|
|
|
|
fun Color.toLab() = this.toXYZ().toLab()
|
|
fun RGB.toLab() = this.toXYZ().toLab()
|
|
fun CIELab.toColor() = this.toXYZ().toColor()
|
|
fun CIELab.toRGB() = this.toXYZ().toRGB()
|
|
|
|
internal val D65 = CIEXYZ(0.95047f, 1f, 1.08883f) // D50 in this case will make the colour excessively blue, dunno why tho
|
|
const val epsilon = 216f/24389f
|
|
const val kappa = 24389f/27f
|
|
|
|
/**
|
|
* Range:
|
|
* L: 0-100.0
|
|
* u, v: -100+ - 100+
|
|
* (Hundred-based-plus)
|
|
*/
|
|
data class CIELab(var L: Float = 0f, var a: Float = 0f, var b: Float = 0f, var alpha: Float = 1f)
|
|
|