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>

#include<lexlib/color.h>
#include<lexlib/math.h>
#include<math.h>

// TODO switch to only integer blending
struct LexlibColor16 lexlibColor16Blend(struct LexlibColor16 dst, struct LexlibColor16 src, uint8_t mode){
	struct LexlibColor16 color;

	switch(mode){
		case LEXLIB_NONE:
			return src;
		case LEXLIB_ADD:{
			float alpha = (float)src.a / 65535.0f;
			color.r = lexlibClampi(dst.r + rintf(src.r * alpha), 0, 65535);
			color.g = lexlibClampi(dst.g + rintf(src.g * alpha), 0, 65535);
			color.b = lexlibClampi(dst.b + rintf(src.b * alpha), 0, 65535);
			color.a = dst.a;
			return color;
		}
		case LEXLIB_SUB:{
			float alpha = (float)src.a / 65535.0f;
			color.r = dst.r - (src.r * alpha);
			color.g = dst.g - (src.g * alpha);
			color.b = dst.b - (src.b * alpha);
			color.a = dst.a;
			return color;
		}
		case LEXLIB_MUL:{
			struct LexlibColor16 d = lexlibColor16Premultiply(dst);
			struct LexlibColorF dstf = lexlibColor16ToF(d);
			float alpha = (float)src.a / 65535.0f;
			float alphainv = 1.0f - alpha;
			color.r = lexlibClampi(rintf((src.r * dstf.r) + (dst.r * alphainv)), 0, 65535);
			color.g = lexlibClampi(rintf((src.g * dstf.g) + (dst.g * alphainv)), 0, 65535);
			color.b = lexlibClampi(rintf((src.b * dstf.b) + (dst.b * alphainv)), 0, 65535);
			color.a = lexlibClampi(rintf(((alpha * dstf.a) + (dstf.a * alphainv))) * 65535.0f, 0, 65535);
			return color;
		}
		case LEXLIB_MOD:
			color.r = rintf(src.r * (dst.r / 65535.0f));
			color.g = rintf(src.g * (dst.g / 65535.0f));
			color.b = rintf(src.b * (dst.b / 65535.0f));
			color.a = dst.a;
			return color;
		case LEXLIB_BLEND:{
			float alpha = (float)src.a / 65535.0f;
			float alphainv = 1.0f - alpha;
			color.r = rintf((src.r * alpha) + (dst.r * alphainv));
			color.g = rintf((src.g * alpha) + (dst.g * alphainv));
			color.b = rintf((src.b * alpha) + (dst.b * alphainv));
			color.a = (alpha + (((float)dst.a / 65535.0f) * alphainv)) * 65535.0f;
			return color;
		}
		default:
			return lexlibColor16Blend(dst, src, LEXLIB_ADD);
	}
}

uint16_t lexlibColor16Gray(struct LexlibColor16 color){
	return rintf(
		((color.r * 0.299f)  +
		 (color.g * 0.587f)  +
		 (color.b * 0.114f)) *
		((float)color.a / 65535.0f));
}

struct LexlibColor16 lexlibColor16GrayAlpha(struct LexlibColor16 color){
	color.r = rintf(color.r * 0.299f + color.g * 0.587f + color.b * 0.114f);
	color.g = color.r;
	color.b = color.r;

	return color;
}

struct LexlibColor16 lexlibColor16Premultiply(struct LexlibColor16 color){
	float alpha = color.a / 65535.0f;
	color.r = (uint16_t)rintf(color.r * alpha);
	color.g = (uint16_t)rintf(color.g * alpha);
	color.b = (uint16_t)rintf(color.b * alpha);

	return color;
}

struct LexlibColor lexlibColor16To8(struct LexlibColor16 color){
	return (struct LexlibColor){
		.r = (uint8_t)(color.r / 257),
		.g = (uint8_t)(color.g / 257),
		.b = (uint8_t)(color.b / 257),
		.a = (uint8_t)(color.a / 257),
	};
}

struct LexlibColorF lexlibColor16ToF(struct LexlibColor16 color){
	return (struct LexlibColorF){
		.r = color.r / 65535.0f,
		.g = color.g / 65535.0f,
		.b = color.b / 65535.0f,
		.a = color.a / 65535.0f,
	};
}