github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/pixel/cmc/color.go (about)

     1  package main
     2  
     3  import "math"
     4  
     5  type RGBA uint32
     6  type RGB struct{ R, G, B uint8 }
     7  type HSL struct{ H, S, L float32 }
     8  
     9  func (rgba RGBA) RGBA() (r, g, b, a uint32) {
    10  	r = uint32(rgba >> 24 & 0xFF)
    11  	g = uint32(rgba >> 16 & 0xFF)
    12  	b = uint32(rgba >> 8 & 0xFF)
    13  	a = uint32(rgba >> 0 & 0xFF)
    14  	r |= r << 8
    15  	g |= g << 8
    16  	b |= b << 8
    17  	a |= a << 8
    18  	return
    19  }
    20  
    21  func (rgb RGB) RGBA() (r, g, b, a uint32) {
    22  	r, g, b = uint32(rgb.R), uint32(rgb.G), uint32(rgb.B)
    23  	r |= r << 8
    24  	g |= g << 8
    25  	b |= b << 8
    26  	a = 0xFFFF
    27  	return
    28  }
    29  
    30  func (hsl HSL) RGBA() (r, g, b, a uint32) {
    31  	r1, g1, b1, _ := hsla(hsl.H, hsl.S, hsl.L, 1)
    32  	return sat16(r1), sat16(g1), sat16(b1), 0xFFFF
    33  }
    34  
    35  func hue(v1, v2, h float32) float32 {
    36  	if h < 0 {
    37  		h += 1
    38  	}
    39  	if h > 1 {
    40  		h -= 1
    41  	}
    42  	if 6*h < 1 {
    43  		return v1 + (v2-v1)*6*h
    44  	} else if 2*h < 1 {
    45  		return v2
    46  	} else if 3*h < 2 {
    47  		return v1 + (v2-v1)*(2.0/3.0-h)*6
    48  	}
    49  
    50  	return v1
    51  }
    52  
    53  func hsla(h, s, l, a float32) (r, g, b, ra float32) {
    54  	if s == 0 {
    55  		return l, l, l, a
    56  	}
    57  
    58  	h = float32(math.Mod(float64(h), TAU) / TAU)
    59  
    60  	var v2 float32
    61  	if l < 0.5 {
    62  		v2 = l * (1 + s)
    63  	} else {
    64  		v2 = (l + s) - s*l
    65  	}
    66  
    67  	v1 := 2*l - v2
    68  	r = hue(v1, v2, h+1.0/3.0)
    69  	g = hue(v1, v2, h)
    70  	b = hue(v1, v2, h-1.0/3.0)
    71  	ra = a
    72  
    73  	return
    74  }
    75  
    76  // sat16 converts 0..1 float32 to 0..0xFFFF uint32
    77  func sat16(v float32) uint32 {
    78  	v = v * 0xFFFF
    79  	if v >= 0xFFFF {
    80  		return 0xFFFF
    81  	} else if v <= 0 {
    82  		return 0
    83  	}
    84  	return uint32(v) & 0xFFFF
    85  }
    86  
    87  // sat8 converts 0..1 float32 to 0..0xFF uint8
    88  func sat8(v float32) uint8 {
    89  	v = v * 0xFF
    90  	if v >= 0xFF {
    91  		return 0xFF
    92  	} else if v <= 0 {
    93  		return 0
    94  	}
    95  	return uint8(v) & 0xFF
    96  }