haxepunk/utils/Color.hx
package haxepunk.utils;
import haxepunk.math.MathUtil;
/**
* An abstract with various color utility functions.
* @since 4.0.0
**/
abstract Color(UInt) from UInt to UInt
{
public static inline var White:Color = 0xffffff;
public static inline var Black:Color = 0x000000;
/**
* Linear interpolation between two colors.
* @param fromColor First color.
* @param toColor Second color.
* @param t Interpolation value. Clamped to the range [0, 1].
* return RGB component-interpolated color value.
*/
public static inline function colorLerp(fromColor:Color, toColor:Color, t:Float=1):Color
{
if (t <= 0)
{
return fromColor;
}
else if (t >= 1)
{
return toColor;
}
else
{
var a:Int = fromColor.a,
r:Int = fromColor.r,
g:Int = fromColor.g,
b:Int = fromColor.b,
dA:Int = toColor.a - a,
dR:Int = toColor.r - r,
dG:Int = toColor.g - g,
dB:Int = toColor.b - b;
a += Std.int(dA * t);
r += Std.int(dR * t);
g += Std.int(dG * t);
b += Std.int(dB * t);
return a << 24 | r << 16 | g << 8 | b;
}
}
/**
* Creates a color value by combining the chosen RGB values.
* @param R The red value of the color, from 0 to 255.
* @param G The green value of the color, from 0 to 255.
* @param B The blue value of the color, from 0 to 255.
* @return The color.
*/
public static inline function getColorRGB(r:Int=0, g:Int=0, b:Int=0):Color
{
return (r & 0xff) << 16 | (g & 0xff) << 8 | (b & 0xff);
}
public static inline function getColorRGBFloat(r:Float, g:Float, b:Float):Color
{
inline function intColor(v:Float):Color
{
var c = Std.int(v * 0x100);
return MathUtil.iclamp(c, 0, 0xff);
}
return getColorRGB(intColor(r), intColor(g), intColor(b));
}
/**
* Creates a color value with the chosen HSV values.
* @param h The hue of the color (from 0 to 1).
* @param s The saturation of the color (from 0 to 1).
* @param v The value of the color (from 0 to 1).
* @return The color Int.
*/
public static function getColorHSV(h:Float, s:Float, v:Float):Color
{
h = Std.int(h * 360);
var hi:Int = Math.floor(h / 60) % 6,
f:Float = h / 60 - Math.floor(h / 60),
p:Float = (v * (1 - s)),
q:Float = (v * (1 - f * s)),
t:Float = (v * (1 - (1 - f) * s));
switch (hi)
{
case 0: return Std.int(v * 255) << 16 | Std.int(t * 255) << 8 | Std.int(p * 255);
case 1: return Std.int(q * 255) << 16 | Std.int(v * 255) << 8 | Std.int(p * 255);
case 2: return Std.int(p * 255) << 16 | Std.int(v * 255) << 8 | Std.int(t * 255);
case 3: return Std.int(p * 255) << 16 | Std.int(q * 255) << 8 | Std.int(v * 255);
case 4: return Std.int(t * 255) << 16 | Std.int(p * 255) << 8 | Std.int(v * 255);
case 5: return Std.int(v * 255) << 16 | Std.int(p * 255) << 8 | Std.int(q * 255);
default: return 0;
}
return 0;
}
public var r(get, never):UInt;
public var g(get, never):UInt;
public var b(get, never):UInt;
public var a(get, never):UInt;
public var red(get, never):Float;
public var green(get, never):Float;
public var blue(get, never):Float;
public var alpha(get, never):Float;
inline function get_r():UInt return (this >> 16) & 0xff;
inline function get_g():UInt return (this >> 8) & 0xff;
inline function get_b():UInt return this & 0xff;
inline function get_a():UInt return (this >> 24) & 0xff;
inline function get_red():Float return r / 0xff;
inline function get_green():Float return g / 0xff;
inline function get_blue():Float return b / 0xff;
inline function get_alpha():Float return a / 0xff;
public inline function withAlpha(a:Float):Color
{
var alpha = if (a <= 0) // fully transparent
{
0;
}
else if (a >= 1) // fully opaque
{
0xFF << 24;
}
else // somewhere in-between
{
(Std.int(0xff * a) << 24);
};
return (this & 0xffffff) | alpha;
}
/**
* Finds the hue factor of a color.
* @return The hue value (from 0 to 1).
*/
public inline function getHue():Float
{
var h:Int = (this >> 16) & 0xFF;
var s:Int = (this >> 8) & 0xFF;
var v:Int = this & 0xFF;
var max:Int = Std.int(Math.max(h, Math.max(s, v)));
var min:Int = Std.int(Math.min(h, Math.min(s, v)));
var hue:Float = 0;
if (max == min)
{
hue = 0;
}
else if (max == h)
{
hue = (60 * (s - v) / (max - min) + 360) % 360;
}
else if (max == s)
{
hue = (60 * (v - h) / (max - min) + 120);
}
else if (max == v)
{
hue = (60 * (h - s) / (max - min) + 240);
}
return hue / 360;
}
/**
* Finds the saturation factor of a color.
* @return The saturation value (from 0 to 1).
*/
public inline function getSaturation():Float
{
var h:Int = (this >> 16) & 0xFF;
var s:Int = (this >> 8) & 0xFF;
var v:Int = this & 0xFF;
var max:Int = Std.int(Math.max(h, Math.max(s, v)));
if (max == 0)
{
return 0;
}
else
{
var min:Int = Std.int(Math.min(h, Math.min(s, v)));
return (max - min) / max;
}
}
/**
* Finds the value factor of a color.
* @return The value value (from 0 to 1).
*/
public inline function getValue():Float
{
var h:Int = (this >> 16) & 0xFF;
var s:Int = (this >> 8) & 0xFF;
var v:Int = this & 0xFF;
return Std.int(Math.max(h, Math.max(s, v))) / 255;
}
public inline function getLuminance():Float
{
return (0.2126 * red + 0.7152 * green + 0.0722 * blue);
}
/**
* Shortcut to lerp between this color and another.
*
* @param toColor Second color.
* @param t Interpolation value. Clamped to the range [0, 1].
*/
public inline function lerp(toColor:Color, t:Float = 1):Color
{
return colorLerp(this, toColor, t);
}
public inline function multiply(other:Color):Color
{
return getColorRGBFloat(red * other.red, green * other.green, blue * other.blue);
}
public inline function toARGB(alpha:Float):UInt
{
alpha = MathUtil.clamp(alpha, 0, 1);
return (Std.int(0xff * alpha) << 24) | this;
}
}