mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-10 02:24:05 +09:00
more testing on skydome / font change
This commit is contained in:
@@ -2,12 +2,6 @@ package net.torvald.colourutil
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.colourutil.CIELChabUtil.toLCh
|
||||
import net.torvald.colourutil.CIELChabUtil.toLab
|
||||
import net.torvald.colourutil.CIELabUtil.toLab
|
||||
import net.torvald.colourutil.CIEXYZUtil.toXYZ
|
||||
import net.torvald.colourutil.CIEXYZUtil.toColor
|
||||
import net.torvald.colourutil.CIELabUtil.toXYZ
|
||||
/**
|
||||
* Cylindrical modification of CIELab colour space
|
||||
*
|
||||
@@ -16,47 +10,46 @@ import net.torvald.colourutil.CIELabUtil.toXYZ
|
||||
* Created by minjaesong on 2016-09-01.
|
||||
*/
|
||||
|
||||
object CIELChabUtil {
|
||||
|
||||
/** Sweet LCh_ab linear gradient */
|
||||
fun getGradient(scale: Float, fromCol: Color, toCol: Color): Color {
|
||||
val from = fromCol.toLCh()
|
||||
val to = toCol.toLCh()
|
||||
val newL = FastMath.interpolateLinear(scale, from.L, to.L)
|
||||
val newC = FastMath.interpolateLinear(scale, from.C, to.C)
|
||||
val newAlpha = FastMath.interpolateLinear(scale, from.alpha, to.alpha)
|
||||
val newH: Float
|
||||
/** Sweet LCh_ab linear gradient */
|
||||
fun cielch_getGradient(scale: Float, fromCol: Color, toCol: Color): Color {
|
||||
val from = fromCol.toLCh()
|
||||
val to = toCol.toLCh()
|
||||
val newL = FastMath.interpolateLinear(scale, from.L, to.L)
|
||||
val newC = FastMath.interpolateLinear(scale, from.C, to.C)
|
||||
val newAlpha = FastMath.interpolateLinear(scale, from.alpha, to.alpha)
|
||||
val newH: Float
|
||||
|
||||
if ((from.h - to.h).abs() == FastMath.PI) // exact opposite colour
|
||||
return CIELabUtil.getGradient(scale, fromCol, toCol)
|
||||
else if ((from.h - to.h).abs() > FastMath.PI) // reflex angle
|
||||
newH = FastMath.interpolateLinear(scale, from.h, to.h + FastMath.TWO_PI)
|
||||
else
|
||||
newH = FastMath.interpolateLinear(scale, from.h, to.h)
|
||||
if ((from.h - to.h).abs() == FastMath.PI) // exact opposite colour
|
||||
return cielab_getGradient(scale, fromCol, toCol)
|
||||
else if ((from.h - to.h).abs() > FastMath.PI) // reflex angle
|
||||
newH = FastMath.interpolateLinear(scale, from.h, to.h + FastMath.TWO_PI)
|
||||
else
|
||||
newH = FastMath.interpolateLinear(scale, from.h, to.h)
|
||||
|
||||
return CIELCh(newL, newC, newH, newAlpha).toColor()
|
||||
}
|
||||
|
||||
fun CIELab.toLCh(): CIELCh {
|
||||
val c = (a.sqr() + b.sqr()).sqrt()
|
||||
val h = FastMath.atan2(b, a)
|
||||
|
||||
return CIELCh(L, c, h, alpha)
|
||||
}
|
||||
|
||||
fun CIELCh.toLab(): CIELab {
|
||||
val a = C * FastMath.cos(h)
|
||||
val b = C * FastMath.sin(h)
|
||||
|
||||
return CIELab(L, a, b, alpha)
|
||||
}
|
||||
|
||||
private fun Float.sqr() = this * this
|
||||
private fun Float.sqrt() = Math.sqrt(this.toDouble()).toFloat()
|
||||
|
||||
private fun Float.abs() = FastMath.abs(this)
|
||||
return CIELCh(newL, newC, newH, newAlpha).toColor()
|
||||
}
|
||||
|
||||
fun CIELab.toLCh(): CIELCh {
|
||||
val c = (a.sqr() + b.sqr()).sqrt()
|
||||
val h = FastMath.atan2(b, a)
|
||||
|
||||
return CIELCh(L, c, h, alpha)
|
||||
}
|
||||
|
||||
fun CIELCh.toLab(): CIELab {
|
||||
val a = C * FastMath.cos(h)
|
||||
val b = C * FastMath.sin(h)
|
||||
|
||||
return CIELab(L, a, b, alpha)
|
||||
}
|
||||
|
||||
private fun Float.sqr() = this * this
|
||||
private fun Float.sqrt() = Math.sqrt(this.toDouble()).toFloat()
|
||||
|
||||
private fun Float.abs() = FastMath.abs(this)
|
||||
|
||||
|
||||
fun Color.toLCh() = this.toXYZ().toLab().toLCh()
|
||||
fun CIELCh.toColor() = this.toLab().toXYZ().toColor()
|
||||
|
||||
|
||||
@@ -2,11 +2,6 @@ package net.torvald.colourutil
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
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
|
||||
|
||||
/**
|
||||
* A modification of CIEXYZ that is useful for surface colours
|
||||
@@ -23,70 +18,69 @@ import net.torvald.colourutil.CIELabUtil.toXYZ
|
||||
*
|
||||
* Created by minjaesong on 2016-09-01.
|
||||
*/
|
||||
object CIELabUtil {
|
||||
fun Color.brighterLab(scale: Float): Color {
|
||||
val brighten = scale + 1f
|
||||
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)
|
||||
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 cielab_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()
|
||||
|
||||
@@ -2,11 +2,6 @@ package net.torvald.colourutil
|
||||
|
||||
import com.jme3.math.FastMath
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.colourutil.CIEXYZUtil.toColor
|
||||
import net.torvald.colourutil.CIEXYZUtil.toRGB
|
||||
import net.torvald.colourutil.CIEXYZUtil.toXYZ
|
||||
import net.torvald.colourutil.CIELuvUtil.toLuv
|
||||
import net.torvald.colourutil.CIELuvUtil.toXYZ
|
||||
|
||||
/**
|
||||
* A modification of CIEXYZ that is useful for additive mixtures of lights.
|
||||
@@ -18,97 +13,96 @@ import net.torvald.colourutil.CIELuvUtil.toXYZ
|
||||
*
|
||||
* Created by minjaesong on 2016-09-06.
|
||||
*/
|
||||
object CIELuvUtil {
|
||||
|
||||
fun Color.brighterLuv(scale: Float): Color {
|
||||
val brighten = scale + 1f
|
||||
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 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
|
||||
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()
|
||||
|
||||
@@ -2,224 +2,225 @@ package net.torvald.colourutil
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-01-12.
|
||||
*/
|
||||
object CIEXYZUtil {
|
||||
|
||||
/**
|
||||
* 0..255 -> 0.0..1.0
|
||||
*/
|
||||
private val rgbLinLUT = FloatArray(256) {
|
||||
val step = it / 255f
|
||||
/**
|
||||
* 0..255 -> 0.0..1.0
|
||||
*/
|
||||
private val rgbLinLUT = FloatArray(256) {
|
||||
val step = it / 255f
|
||||
|
||||
if (step > 0.04045f)
|
||||
((step + 0.055f) / 1.055f).powerOf(2.4f)
|
||||
else step / 12.92f
|
||||
}
|
||||
if (step > 0.04045f)
|
||||
((step + 0.055f) / 1.055f).powerOf(2.4f)
|
||||
else step / 12.92f
|
||||
}
|
||||
|
||||
/**
|
||||
* 0..255 -> 0.0..1.0
|
||||
*/
|
||||
private val rgbUnLinLUT = FloatArray(256) {
|
||||
val step = it / 255f
|
||||
/**
|
||||
* 0..255 -> 0.0..1.0
|
||||
*/
|
||||
private val rgbUnLinLUT = FloatArray(256) {
|
||||
val step = it / 255f
|
||||
|
||||
if (step > 0.0031308f)
|
||||
1.055f * step.powerOf(1f / 2.4f) - 0.055f
|
||||
else
|
||||
step * 12.92f
|
||||
}
|
||||
if (step > 0.0031308f)
|
||||
1.055f * step.powerOf(1f / 2.4f) - 0.055f
|
||||
else
|
||||
step * 12.92f
|
||||
}
|
||||
|
||||
private val rgbToXyzLut_XR = FloatArray(256) { 0.4124564f * (it / 255f) }
|
||||
private val rgbToXyzLut_XR = FloatArray(256) { 0.4124564f * (it / 255f) }
|
||||
|
||||
|
||||
fun Color.brighterXYZ(scale: Float): Color {
|
||||
val xyz = this.toXYZ()
|
||||
xyz.X = xyz.X.times(1f + scale).clampOne()
|
||||
xyz.Y = xyz.Y.times(1f + scale).clampOne()
|
||||
xyz.Z = xyz.Z.times(1f + scale).clampOne()
|
||||
return xyz.toColor()
|
||||
}
|
||||
|
||||
fun Color.darkerXYZ(scale: Float): Color {
|
||||
val xyz = this.toXYZ()
|
||||
xyz.X = xyz.X.times(1f - scale).clampOne()
|
||||
xyz.Y = xyz.Y.times(1f - scale).clampOne()
|
||||
xyz.Z = xyz.Z.times(1f - scale).clampOne()
|
||||
return xyz.toColor()
|
||||
}
|
||||
|
||||
/*@Deprecated("Use one in CIELAB or CIELUV; CIEXYZ is not perceptually uniform")
|
||||
fun getGradient(scale: Float, fromCol: Color, toCol: Color): Color {
|
||||
val from = fromCol.toXYZ()
|
||||
val to = toCol.toXYZ()
|
||||
val newX = FastMath.interpolateLinear(scale, from.X, to.X)
|
||||
val newY = FastMath.interpolateLinear(scale, from.Y, to.Y)
|
||||
val newZ = FastMath.interpolateLinear(scale, from.Z, to.Z)
|
||||
val newAlpha = FastMath.interpolateLinear(scale, from.alpha, to.alpha)
|
||||
|
||||
fun Color.brighterXYZ(scale: Float): Color {
|
||||
val xyz = this.toXYZ()
|
||||
xyz.X = xyz.X.times(1f + scale).clampOne()
|
||||
xyz.Y = xyz.Y.times(1f + scale).clampOne()
|
||||
xyz.Z = xyz.Z.times(1f + scale).clampOne()
|
||||
return xyz.toColor()
|
||||
}
|
||||
return CIEXYZ(newX, newY, newZ, newAlpha).toColor()
|
||||
}*/
|
||||
|
||||
fun Color.darkerXYZ(scale: Float): Color {
|
||||
val xyz = this.toXYZ()
|
||||
xyz.X = xyz.X.times(1f - scale).clampOne()
|
||||
xyz.Y = xyz.Y.times(1f - scale).clampOne()
|
||||
xyz.Z = xyz.Z.times(1f - scale).clampOne()
|
||||
return xyz.toColor()
|
||||
}
|
||||
fun Color.toXYZ(): CIEXYZ = RGB(this).toXYZ()
|
||||
|
||||
/*@Deprecated("Use one in CIELAB or CIELUV; CIEXYZ is not perceptually uniform")
|
||||
fun getGradient(scale: Float, fromCol: Color, toCol: Color): Color {
|
||||
val from = fromCol.toXYZ()
|
||||
val to = toCol.toXYZ()
|
||||
val newX = FastMath.interpolateLinear(scale, from.X, to.X)
|
||||
val newY = FastMath.interpolateLinear(scale, from.Y, to.Y)
|
||||
val newZ = FastMath.interpolateLinear(scale, from.Z, to.Z)
|
||||
val newAlpha = FastMath.interpolateLinear(scale, from.alpha, to.alpha)
|
||||
|
||||
return CIEXYZ(newX, newY, newZ, newAlpha).toColor()
|
||||
}*/
|
||||
|
||||
fun Color.toXYZ(): CIEXYZ = RGB(this).toXYZ()
|
||||
|
||||
/**
|
||||
* "Linearise" the sRGB triads. This use lookup table to speed up calculation.
|
||||
* Integer values (1/255, 2/255, .. , 254/255, 255/255) are accurate but any values in between are
|
||||
* linearly interpolated and thus slightly less accurate. Visually there's little-to-no difference,
|
||||
* but may not optimal for rigorous maths.
|
||||
*/
|
||||
fun RGB.linearise(): RGB {
|
||||
val out = floatArrayOf(0f, 0f, 0f)
|
||||
for (i in 0..2) {
|
||||
val value = when (i) {
|
||||
0 -> this.r
|
||||
1 -> this.g
|
||||
2 -> this.b
|
||||
else -> throw InternalError("Fuck you")
|
||||
}
|
||||
val step = value.clampOne() * 255f // 0.0 .. 255.0
|
||||
val intStep = step.toInt() // 0 .. 255
|
||||
val NeXTSTEP = minOf(intStep + 1, 255) // 1 .. 255
|
||||
|
||||
out[i] = interpolateLinear(step - intStep, rgbLinLUT[intStep], rgbLinLUT[NeXTSTEP])
|
||||
/**
|
||||
* "Linearise" the sRGB triads. This use lookup table to speed up calculation.
|
||||
* Integer values (1/255, 2/255, .. , 254/255, 255/255) are accurate but any values in between are
|
||||
* linearly interpolated and thus slightly less accurate. Visually there's little-to-no difference,
|
||||
* but may not optimal for rigorous maths.
|
||||
*/
|
||||
/*fun RGB.linearise(): RGB {
|
||||
val out = floatArrayOf(0f, 0f, 0f)
|
||||
for (i in 0..2) {
|
||||
val value = when (i) {
|
||||
0 -> this.r
|
||||
1 -> this.g
|
||||
2 -> this.b
|
||||
else -> throw InternalError("Fuck you")
|
||||
}
|
||||
val step = value.clampOne() * 255f // 0.0 .. 255.0
|
||||
val intStep = step.toInt() // 0 .. 255
|
||||
val NeXTSTEP = minOf(intStep + 1, 255) // 1 .. 255
|
||||
|
||||
|
||||
return RGB(out[0], out[1], out[2], alpha)
|
||||
out[i] = interpolateLinear(step - intStep, rgbLinLUT[intStep], rgbLinLUT[NeXTSTEP])
|
||||
}
|
||||
|
||||
/** Suitable for rigorous maths but slower */
|
||||
fun RGB.lineariseSuper(): RGB {
|
||||
val newR = if (r > 0.04045f)
|
||||
((r + 0.055f) / 1.055f).powerOf(2.4f)
|
||||
else r / 12.92f
|
||||
val newG = if (g > 0.04045f)
|
||||
((g + 0.055f) / 1.055f).powerOf(2.4f)
|
||||
else g / 12.92f
|
||||
val newB = if (b > 0.04045f)
|
||||
((b + 0.055f) / 1.055f).powerOf(2.4f)
|
||||
else b / 12.92f
|
||||
|
||||
return RGB(out[0], out[1], out[2], alpha)
|
||||
}*/
|
||||
|
||||
/** Suitable for rigorous maths but slower */
|
||||
fun RGB.linearise(): RGB {
|
||||
val newR = if (r > 0.04045f)
|
||||
((r + 0.055f) / 1.055f).powerOf(2.4f)
|
||||
else r / 12.92f
|
||||
val newG = if (g > 0.04045f)
|
||||
((g + 0.055f) / 1.055f).powerOf(2.4f)
|
||||
else g / 12.92f
|
||||
val newB = if (b > 0.04045f)
|
||||
((b + 0.055f) / 1.055f).powerOf(2.4f)
|
||||
else b / 12.92f
|
||||
|
||||
|
||||
return RGB(newR, newG, newB, alpha)
|
||||
}
|
||||
return RGB(newR, newG, newB, alpha)
|
||||
}
|
||||
|
||||
/**
|
||||
* "Un-linearise" the RGB triads. That is, codes the linear RGB into sRGB. This use lookup table to speed up calculation.
|
||||
* Integer values (1/255, 2/255, .. , 254/255, 255/255) are accurate but any values in between are
|
||||
* linearly interpolated and thus slightly less accurate. Visually there's little-to-no difference,
|
||||
* but may not optimal for rigorous maths.
|
||||
*/
|
||||
fun RGB.unLinearise(): RGB {
|
||||
val out = floatArrayOf(0f, 0f, 0f)
|
||||
for (i in 0..2) {
|
||||
val value = when (i) {
|
||||
0 -> this.r
|
||||
1 -> this.g
|
||||
2 -> this.b
|
||||
else -> throw InternalError("Fuck you")
|
||||
}
|
||||
val step = value.clampOne() * 255f // 0.0 .. 255.0
|
||||
val intStep = step.toInt() // 0 .. 255
|
||||
val NeXTSTEP = minOf(intStep + 1, 255) // 1 .. 255
|
||||
|
||||
out[i] = interpolateLinear(step - intStep, rgbUnLinLUT[intStep], rgbUnLinLUT[NeXTSTEP])
|
||||
/**
|
||||
* "Un-linearise" the RGB triads. That is, codes the linear RGB into sRGB. This use lookup table to speed up calculation.
|
||||
* Integer values (1/255, 2/255, .. , 254/255, 255/255) are accurate but any values in between are
|
||||
* linearly interpolated and thus slightly less accurate. Visually there's little-to-no difference,
|
||||
* but may not optimal for rigorous maths.
|
||||
*/
|
||||
/*fun RGB.unLinearise(): RGB {
|
||||
val out = floatArrayOf(0f, 0f, 0f)
|
||||
for (i in 0..2) {
|
||||
val value = when (i) {
|
||||
0 -> this.r
|
||||
1 -> this.g
|
||||
2 -> this.b
|
||||
else -> throw InternalError("Fuck you")
|
||||
}
|
||||
val step = value.clampOne() * 255f // 0.0 .. 255.0
|
||||
val intStep = step.toInt() // 0 .. 255
|
||||
val NeXTSTEP = minOf(intStep + 1, 255) // 1 .. 255
|
||||
|
||||
|
||||
return RGB(out[0], out[1], out[2], alpha)
|
||||
out[i] = interpolateLinear(step - intStep, rgbUnLinLUT[intStep], rgbUnLinLUT[NeXTSTEP])
|
||||
}
|
||||
|
||||
/** Suitable for rigorous maths but slower */
|
||||
fun RGB.unLineariseSuper(): RGB {
|
||||
val newR = if (r > 0.0031308f)
|
||||
1.055f * r.powerOf(1f / 2.4f) - 0.055f
|
||||
else
|
||||
r * 12.92f
|
||||
val newG = if (g > 0.0031308f)
|
||||
1.055f * g.powerOf(1f / 2.4f) - 0.055f
|
||||
else
|
||||
g * 12.92f
|
||||
val newB = if (b > 0.0031308f)
|
||||
1.055f * b.powerOf(1f / 2.4f) - 0.055f
|
||||
else
|
||||
b * 12.92f
|
||||
|
||||
return RGB(out[0], out[1], out[2], alpha)
|
||||
}*/
|
||||
|
||||
/** Suitable for rigorous maths but slower */
|
||||
fun RGB.unLinearise(): RGB {
|
||||
val newR = if (r > 0.0031308f)
|
||||
1.055f * r.powerOf(1f / 2.4f) - 0.055f
|
||||
else
|
||||
r * 12.92f
|
||||
val newG = if (g > 0.0031308f)
|
||||
1.055f * g.powerOf(1f / 2.4f) - 0.055f
|
||||
else
|
||||
g * 12.92f
|
||||
val newB = if (b > 0.0031308f)
|
||||
1.055f * b.powerOf(1f / 2.4f) - 0.055f
|
||||
else
|
||||
b * 12.92f
|
||||
|
||||
|
||||
return RGB(newR, newG, newB, alpha)
|
||||
return RGB(newR, newG, newB, alpha)
|
||||
}
|
||||
|
||||
fun RGB.toXYZ(): CIEXYZ {
|
||||
val new = this.linearise()
|
||||
|
||||
val x = 0.4124564f * new.r + 0.3575761f * new.g + 0.1804375f * new.b
|
||||
val y = 0.2126729f * new.r + 0.7151522f * new.g + 0.0721750f * new.b
|
||||
val z = 0.0193339f * new.r + 0.1191920f * new.g + 0.9503041f * new.b
|
||||
|
||||
return CIEXYZ(x, y, z, alpha)
|
||||
}
|
||||
|
||||
fun RGB.toColor() = Color(r, g, b, alpha)
|
||||
fun RGB.toCvec() = Cvec(r, g, b, alpha)
|
||||
|
||||
fun CIEXYZ.toRGB(): RGB {
|
||||
val r = 3.2404542f * X - 1.5371385f * Y - 0.4985314f * Z
|
||||
val g = -0.9692660f * X + 1.8760108f * Y + 0.0415560f * Z
|
||||
val b = 0.0556434f * X - 0.2040259f * Y + 1.0572252f * Z
|
||||
|
||||
return RGB(r, g, b, alpha).unLinearise()
|
||||
}
|
||||
|
||||
fun CIEXYZ.toRGBRaw(): RGB {
|
||||
val r = 3.2404542f * X - 1.5371385f * Y - 0.4985314f * Z
|
||||
val g = -0.9692660f * X + 1.8760108f * Y + 0.0415560f * Z
|
||||
val b = 0.0556434f * X - 0.2040259f * Y + 1.0572252f * Z
|
||||
|
||||
return RGB(r, g, b, alpha)
|
||||
}
|
||||
|
||||
fun CIEXYZ.toColor(): Color {
|
||||
val rgb = this.toRGB()
|
||||
return Color(rgb.r, rgb.g, rgb.b, rgb.alpha)
|
||||
}
|
||||
|
||||
fun CIEXYZ.mul(scalar: Float) = CIEXYZ(this.X * scalar, this.Y * scalar, this.Z * scalar, this.alpha)
|
||||
|
||||
fun CIEXYZ.toColorRaw(): Color {
|
||||
val rgb = this.toRGBRaw()
|
||||
return Color(rgb.r, rgb.g, rgb.b, rgb.alpha)
|
||||
}
|
||||
|
||||
fun CIEYXY.toXYZ(): CIEXYZ {
|
||||
return CIEXYZ(x * yy / y, yy, (1f - x - y) * yy / y)
|
||||
}
|
||||
|
||||
fun colourTempToXYZ(temp: Float, Y: Float): CIEXYZ {
|
||||
val x = if (temp < 7000)
|
||||
-4607000000f / FastMath.pow(temp, 3f) + 2967800f / FastMath.pow(temp, 2f) + 99.11f / temp + 0.244063f
|
||||
else
|
||||
-2006400000f / FastMath.pow(temp, 3f) + 1901800f / FastMath.pow(temp, 2f) + 247.48f / temp + 0.237040f
|
||||
|
||||
val y = -3f * FastMath.pow(x, 2f) + 2.870f * x - 0.275f
|
||||
|
||||
return CIEXYZ(x * Y / y, Y, (1 - x - y) * Y / y)
|
||||
}
|
||||
|
||||
private fun Float.powerOf(exp: Float) = FastMath.pow(this, exp)
|
||||
private fun Float.clampOne() = if (this > 1f) 1f else if (this < 0f) 0f else this
|
||||
|
||||
private fun interpolateLinear(scale: Float, startValue: Float, endValue: Float): Float {
|
||||
if (startValue == endValue) {
|
||||
return startValue
|
||||
}
|
||||
|
||||
fun RGB.toXYZ(): CIEXYZ {
|
||||
val new = this.linearise()
|
||||
|
||||
val x = 0.4124564f * new.r + 0.3575761f * new.g + 0.1804375f * new.b
|
||||
val y = 0.2126729f * new.r + 0.7151522f * new.g + 0.0721750f * new.b
|
||||
val z = 0.0193339f * new.r + 0.1191920f * new.g + 0.9503041f * new.b
|
||||
|
||||
return CIEXYZ(x, y, z, alpha)
|
||||
if (scale <= 0f) {
|
||||
return startValue
|
||||
}
|
||||
|
||||
fun CIEXYZ.toRGB(): RGB {
|
||||
val r = 3.2404542f * X - 1.5371385f * Y - 0.4985314f * Z
|
||||
val g = -0.9692660f * X + 1.8760108f * Y + 0.0415560f * Z
|
||||
val b = 0.0556434f * X - 0.2040259f * Y + 1.0572252f * Z
|
||||
|
||||
return RGB(r, g, b, alpha).unLinearise()
|
||||
}
|
||||
|
||||
fun CIEXYZ.toRGBRaw(): RGB {
|
||||
val r = 3.2404542f * X - 1.5371385f * Y - 0.4985314f * Z
|
||||
val g = -0.9692660f * X + 1.8760108f * Y + 0.0415560f * Z
|
||||
val b = 0.0556434f * X - 0.2040259f * Y + 1.0572252f * Z
|
||||
|
||||
return RGB(r, g, b, alpha)
|
||||
}
|
||||
|
||||
fun CIEXYZ.toColor(): Color {
|
||||
val rgb = this.toRGB()
|
||||
return Color(rgb.r, rgb.g, rgb.b, rgb.alpha)
|
||||
}
|
||||
|
||||
fun CIEXYZ.toColorRaw(): Color {
|
||||
val rgb = this.toRGBRaw()
|
||||
return Color(rgb.r, rgb.g, rgb.b, rgb.alpha)
|
||||
}
|
||||
|
||||
fun CIEYXY.toXYZ(): CIEXYZ {
|
||||
return CIEXYZ(x * yy / y, yy, (1f - x - y) * yy / y)
|
||||
}
|
||||
|
||||
fun colourTempToXYZ(temp: Float, Y: Float): CIEXYZ {
|
||||
val x = if (temp < 7000)
|
||||
-4607000000f / FastMath.pow(temp, 3f) + 2967800f / FastMath.pow(temp, 2f) + 99.11f / temp + 0.244063f
|
||||
else
|
||||
-2006400000f / FastMath.pow(temp, 3f) + 1901800f / FastMath.pow(temp, 2f) + 247.48f / temp + 0.237040f
|
||||
|
||||
val y = -3f * FastMath.pow(x, 2f) + 2.870f * x - 0.275f
|
||||
|
||||
return CIEXYZ(x * Y / y, Y, (1 - x - y) * Y / y)
|
||||
}
|
||||
|
||||
private fun Float.powerOf(exp: Float) = FastMath.pow(this, exp)
|
||||
private fun Float.clampOne() = if (this > 1f) 1f else if (this < 0f) 0f else this
|
||||
|
||||
private fun interpolateLinear(scale: Float, startValue: Float, endValue: Float): Float {
|
||||
if (startValue == endValue) {
|
||||
return startValue
|
||||
}
|
||||
if (scale <= 0f) {
|
||||
return startValue
|
||||
}
|
||||
return if (scale >= 1f) {
|
||||
endValue
|
||||
}
|
||||
else (1f - scale) * startValue + scale * endValue
|
||||
return if (scale >= 1f) {
|
||||
endValue
|
||||
}
|
||||
else (1f - scale) * startValue + scale * endValue
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package net.torvald.colourutil
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.colourutil.CIEXYZUtil.toColor
|
||||
import net.torvald.terrarum.GdxColorMap
|
||||
import net.torvald.terrarum.ModMgr
|
||||
|
||||
@@ -24,5 +23,5 @@ object ColourTemp {
|
||||
/** returns CIExyY-based colour converted to slick.color
|
||||
* @param CIE_Y 0.0 - 1.0+ */
|
||||
operator fun invoke(temp: Float, CIE_Y: Float): Color =
|
||||
CIEXYZUtil.colourTempToXYZ(temp, CIE_Y).toColor()
|
||||
colourTempToXYZ(temp, CIE_Y).toColor()
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package net.torvald.colourutil
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.colourutil.CIEXYZUtil.linearise
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-07-26.
|
||||
|
||||
Reference in New Issue
Block a user