1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 21:42:51 -05:00
Files
DankMaterialShell/core/internal/server/wayland/gamma.go
2025-12-09 09:44:16 -05:00

168 lines
3.5 KiB
Go

package wayland
import (
"math"
)
type GammaRamp struct {
Red []uint16
Green []uint16
Blue []uint16
}
type rgb struct {
r, g, b float64
}
type xyz struct {
x, y, z float64
}
func illuminantD(temp int) (float64, float64, bool) {
var x float64
switch {
case temp >= 2500 && temp <= 7000:
t := float64(temp)
x = 0.244063 + 0.09911e3/t + 2.9678e6/(t*t) - 4.6070e9/(t*t*t)
case temp > 7000 && temp <= 25000:
t := float64(temp)
x = 0.237040 + 0.24748e3/t + 1.9018e6/(t*t) - 2.0064e9/(t*t*t)
default:
return 0, 0, false
}
y := -3*(x*x) + 2.870*x - 0.275
return x, y, true
}
func planckianLocus(temp int) (float64, float64, bool) {
var x, y float64
switch {
case temp >= 1667 && temp <= 4000:
t := float64(temp)
x = -0.2661239e9/(t*t*t) - 0.2343589e6/(t*t) + 0.8776956e3/t + 0.179910
if temp <= 2222 {
y = -1.1064814*(x*x*x) - 1.34811020*(x*x) + 2.18555832*x - 0.20219683
} else {
y = -0.9549476*(x*x*x) - 1.37418593*(x*x) + 2.09137015*x - 0.16748867
}
case temp > 4000 && temp < 25000:
t := float64(temp)
x = -3.0258469e9/(t*t*t) + 2.1070379e6/(t*t) + 0.2226347e3/t + 0.240390
y = 3.0817580*(x*x*x) - 5.87338670*(x*x) + 3.75112997*x - 0.37001483
default:
return 0, 0, false
}
return x, y, true
}
func srgbGamma(value, gamma float64) float64 {
if value <= 0.0031308 {
return 12.92 * value
}
return math.Pow(1.055*value, 1.0/gamma) - 0.055
}
func clamp01(v float64) float64 {
switch {
case v > 1.0:
return 1.0
case v < 0.0:
return 0.0
default:
return v
}
}
func xyzToSRGB(c xyz) rgb {
return rgb{
r: srgbGamma(clamp01(3.2404542*c.x-1.5371385*c.y-0.4985314*c.z), 2.2),
g: srgbGamma(clamp01(-0.9692660*c.x+1.8760108*c.y+0.0415560*c.z), 2.2),
b: srgbGamma(clamp01(0.0556434*c.x-0.2040259*c.y+1.0572252*c.z), 2.2),
}
}
func normalizeRGB(c *rgb) {
maxw := math.Max(c.r, math.Max(c.g, c.b))
if maxw > 0 {
c.r /= maxw
c.g /= maxw
c.b /= maxw
}
}
func calcWhitepoint(temp int) rgb {
if temp == 6500 {
return rgb{r: 1.0, g: 1.0, b: 1.0}
}
var wp xyz
switch {
case temp >= 25000:
x, y, _ := illuminantD(25000)
wp.x = x
wp.y = y
case temp >= 4000:
x, y, _ := illuminantD(temp)
wp.x = x
wp.y = y
case temp >= 2500:
x1, y1, _ := illuminantD(temp)
x2, y2, _ := planckianLocus(temp)
factor := float64(4000-temp) / 1500.0
sineFactor := (math.Cos(math.Pi*factor) + 1.0) / 2.0
wp.x = x1*sineFactor + x2*(1.0-sineFactor)
wp.y = y1*sineFactor + y2*(1.0-sineFactor)
default:
t := temp
if t < 1667 {
t = 1667
}
x, y, _ := planckianLocus(t)
wp.x = x
wp.y = y
}
wp.z = 1.0 - wp.x - wp.y
wpRGB := xyzToSRGB(wp)
normalizeRGB(&wpRGB)
return wpRGB
}
func GenerateGammaRamp(size uint32, temp int, gamma float64) GammaRamp {
ramp := GammaRamp{
Red: make([]uint16, size),
Green: make([]uint16, size),
Blue: make([]uint16, size),
}
wp := calcWhitepoint(temp)
for i := uint32(0); i < size; i++ {
val := float64(i) / float64(size-1)
ramp.Red[i] = uint16(clamp01(math.Pow(val*wp.r, 1.0/gamma)) * 65535.0)
ramp.Green[i] = uint16(clamp01(math.Pow(val*wp.g, 1.0/gamma)) * 65535.0)
ramp.Blue[i] = uint16(clamp01(math.Pow(val*wp.b, 1.0/gamma)) * 65535.0)
}
return ramp
}
func GenerateIdentityRamp(size uint32) GammaRamp {
ramp := GammaRamp{
Red: make([]uint16, size),
Green: make([]uint16, size),
Blue: make([]uint16, size),
}
for i := uint32(0); i < size; i++ {
val := uint16((float64(i) / float64(size-1)) * 65535.0)
ramp.Red[i] = val
ramp.Green[i] = val
ramp.Blue[i] = val
}
return ramp
}