lexlib 2.0.1

library with miscellaneous stuff
Documentation
// Copyright 2023 alexevier <alexevier@proton.me>
// licensed under the zlib license <https://www.zlib.net/zlib_license.html>

use core::ops;
use crate::c;
use crate::color::Color;
use crate::color::Color8;
use crate::color::ColorF;
use crate::color::Color16;
use crate::color::BlendMode;

impl Color<u16> for Color16 {
	#[inline(always)]
	fn r(&self) -> u16 {
		return self.r;
	}

	#[inline(always)]
	fn g(&self) -> u16 {
		return self.g;
	}

	#[inline(always)]
	fn b(&self) -> u16 {
		return self.b;
	}

	#[inline(always)]
	fn a(&self) -> u16 {
		return self.a;
	}

	#[inline(always)]
	fn gray(&self) -> u16 {
		unsafe{c::lexlibColor16Gray(*self)}
	}

	#[inline(always)]
	fn gray_alpha(&self) -> Self {
		unsafe{c::lexlibColor16GrayAlpha(*self)}
	}

	#[inline(always)]
	fn premultiply(&self) -> Self {
		unsafe{c::lexlibColor16Premultiply(*self)}
	}

	#[inline(always)]
	fn blend(&self, src: Self, mode: BlendMode) -> Self {
		unsafe{c::lexlibColor16Blend(*self, src, mode as u8)}
	}

	const MIN: u16 = 0x0000;
	const MAX: u16 = 0xFFFF;

	const BLACK: Self = Self{r: Self::MIN, g: Self::MIN, b: Self::MIN, a: Self::MAX};
	const WHITE: Self = Self{r: Self::MAX, g: Self::MAX, b: Self::MAX, a: Self::MAX};
	const RED:   Self = Self{r: Self::MAX, g: Self::MIN, b: Self::MIN, a: Self::MAX};
	const GREEN: Self = Self{r: Self::MIN, g: Self::MAX, b: Self::MIN, a: Self::MAX};
	const BLUE:  Self = Self{r: Self::MIN, g: Self::MIN, b: Self::MAX, a: Self::MAX};
	const YELLOW:  Self = Self{r: Self::MAX, g: Self::MAX, b: Self::MIN, a: Self::MAX};
	const MAGENTA: Self = Self{r: Self::MAX, g: Self::MIN, b: Self::MAX, a: Self::MAX};
	const CYAN:    Self = Self{r: Self::MIN, g: Self::MAX, b: Self::MAX, a: Self::MAX};
}

impl ops::Add for Color16 {
	/// performs additive blending.
	///
	/// res.rgb = self.rgb + (src.rgb * src.a)<br>
	/// res.a = self.a
	#[inline(always)]
	fn add(self, src: Self) -> Self {
		unsafe{ c::lexlibColor16Blend(self, src, c::LEXLIB_ADD) }
	}

	/// result of color blending
	type Output = Color16;
}

impl ops::Sub for Color16 {
	/// performs subtractive blending.
	///
	/// res.rgb = self.rgb - (src.rgb * src.a)<br>
	/// res.a = self.a
	#[inline(always)]
	fn sub(self, src: Self) -> Self {
		unsafe{ c::lexlibColor16Blend(self, src, c::LEXLIB_SUB) }
	}
	/// result of color blending
	type Output = Color16;
}

impl ops::Mul for Color16 {
	/// performs multiplicative blending.
	///
	/// res.rgb = (src.rgb * self.rgb) + (self.rgb * (1 - src.a))<br>
	/// res.a = (src.a * self.a) + (self.a * (1 - src.a))
	#[inline(always)]
	fn mul(self, src: Self) -> Self {
		unsafe{ c::lexlibColor16Blend(self, src, c::LEXLIB_MUL) }
	}
	/// result of color blending
	type Output = Color16;
}

impl Color16 {
	#[inline(always)]
	pub const fn new(r: u16, g: u16, b: u16, a: u16) -> Self {
		Self{r,g,b,a}
	}

	#[inline(always)]
	pub const fn new_rgb(r: u16, g: u16, b: u16) -> Self {
		Self{r,g,b, a: Self::MAX}
	}

	#[inline(always)]
	pub const fn new_gray(g: u16) -> Self {
		Self{r: g, g: g, b: g, a: Self::MAX}
	}

	/// alpha blending
	///
	/// res.rgb = (src.rgb * src.a) + (self.rgb * (1 - src.a))<br>
	/// res.a = self.a * (1 - src.a)
	#[inline(always)]
	pub fn blend(self, src: Self) -> Self {
		unsafe{ c::lexlibColor16Blend(self, src, c::LEXLIB_BLEND) }
	}

	/// color modulation
	///
	/// res.rgb = src.rgb * self.rgb<br>
	/// res.a = self.a
	#[inline(always)]
	pub fn modulate(self, src: Self) -> Self {
		unsafe{ c::lexlibColor16Blend(self, src, c::LEXLIB_MOD) }
	}
}

impl From<Color8> for Color16 {
	fn from(color: Color8) -> Self {
		Self {
			r: (color.r as u16 * 257),
			g: (color.g as u16 * 257),
			b: (color.b as u16 * 257),
			a: (color.a as u16 * 257),
		}
	}
}

impl From<ColorF> for Color16 {
	fn from(color: ColorF) -> Self {
		Self {
			r: (color.r * Self::MAX as f32) as u16,
			g: (color.g * Self::MAX as f32) as u16,
			b: (color.b * Self::MAX as f32) as u16,
			a: (color.a * Self::MAX as f32) as u16,
		}
	}
}

impl From<[u16; 4]> for Color16 {
	#[inline(always)]
	fn from(val: [u16; 4]) -> Self {
		Self{
			r: val[0],
			g: val[1],
			b: val[2],
			a: val[3],
		}
	}
}

impl From<(u16, u16, u16, u16)> for Color16 {
	#[inline(always)]
	fn from(val: (u16, u16, u16, u16)) -> Self {
		Self{
			r: val.0,
			g: val.1,
			b: val.2,
			a: val.3,
		}
	}
}

#[test]
fn gray(){
	assert_eq!(Color16::new(0xFFFF, 0x0000, 0x0000, 0xFFFF).gray(), 0x4C8B);
	assert_eq!(Color16::new(0x0000, 0xFFFF, 0x0000, 0xFFFF).gray(), 0x9645);
	assert_eq!(Color16::new(0x0000, 0x0000, 0xFFFF, 0xFFFF).gray(), 0x1D2F);
	assert_eq!(Color16::new(0xFFFF, 0xFFFF, 0x0000, 0xFFFF).gray(), 0xE2D0);
	assert_eq!(Color16::new(0xFFFF, 0x0000, 0xFFFF, 0xFFFF).gray(), 0x69BA);
	assert_eq!(Color16::new(0x0000, 0xFFFF, 0xFFFF, 0xFFFF).gray(), 0xB374);
	assert_eq!(Color16::new(0xFFFF, 0xFFFF, 0xFFFF, 0xCCCC).gray(), 0xCCCC);
	assert_eq!(Color16::new(0x2E21, 0x1900, 0xB236, 0xFFFF).gray(), 0x30C9);
}