Compare commits
5 Commits
Prerelease
...
master
Author | SHA1 | Date | |
---|---|---|---|
6a8938305e | |||
42e773b5a1 | |||
25d804ce79 | |||
954b8cb4b5 | |||
cc4773abba |
78
README.md
78
README.md
@@ -0,0 +1,78 @@
|
||||
# mcolor - Maxine's Mean Color Library
|
||||
|
||||
mcolor is a C++20 library designed to provide an efficient suite for color management. Ideal for use in games, console applications, UI, and so forth.
|
||||
|
||||
## Color as a Class
|
||||
|
||||
At its heart, mcolor defines fundamental color structures for clear and concise representation:
|
||||
|
||||
- `Color3`: Represents an RGB color with 8-bit unsigned integer components (uint8_t r, g, b).
|
||||
- `Color4`: Extends Color3 to include an alpha channel (uint8_t r, g, b, a).
|
||||
|
||||
These core types are complemented by a full range of conversion structs, enabling seamless transitions between various color models:
|
||||
|
||||
- `HSV`, `HSVA`: Hue, Saturation, Value (with Alpha)
|
||||
- `RGB`, `RGBA`: Red, Green, Blue (with Alpha) using u8 components.
|
||||
- `RGBf`, `RGBAf`: Red, Green, Blue (with Alpha) using float components.
|
||||
- `LCH`, `LCHA`: Lightness, Chroma, Hue (with Alpha)
|
||||
- `CMYK`: Cyan, Magenta, Yellow, Key (Black)
|
||||
|
||||
The library also includes organized Color Palettes within dedicated namespaces:
|
||||
- `Colors::Primary`, or just `Colors`,
|
||||
- <span style='color: red;'>Colors::Reds</span>
|
||||
- <span style='color: orange;'>Colors::Oranges</span>
|
||||
- <span style='color: yellow;'>Colors::Yellows</span>
|
||||
- <span style='color: green;'>Colors::Greens</span>
|
||||
- <span style='color: cyan;'>Colors::Cyans</span>
|
||||
- <span style='color: blue;'>Colors::Blues</span>
|
||||
- <span style='color: purple;'>Colors::Purples</span>
|
||||
- <span style='color: pink;'>Colors::Pinks</span>
|
||||
- <span style='color: white;'>Colors::Whites</span>
|
||||
- <span style='color: gray;'>Colors::Grays</span>
|
||||
- <span style='color: brown;'>Colors::Browns</span>
|
||||
|
||||
offering a rich set of predefined swatches for immediate use.
|
||||
|
||||
Additionally, we have worked to implement Ansi Escape Codes, console-output utilities, and cross-platform abstraction so that it works the same on Windows and Linux.
|
||||
|
||||
## Usage
|
||||
|
||||
Integrating mcolor into your project is straightforward. Here's a quick sample:
|
||||
|
||||
```cpp
|
||||
int main() {
|
||||
#ifdef WIN32
|
||||
mcolor::windowsSaneify();
|
||||
#endif
|
||||
|
||||
mcolor::printBuiltinColorList();
|
||||
mcolor::printAnsiColorTable();
|
||||
mcolor::printRGBConsoleTest();
|
||||
|
||||
|
||||
for (float i = 0; i < 360; i+=10.f)
|
||||
{
|
||||
HSVA hsva {i, 1.f, 1.f};
|
||||
|
||||
Color4 c = Color4(hsva);
|
||||
|
||||
std::cout << std::format("{}hue:{} rgb: {},{},{} hex: {}", c.ToEscapeCode(), i, c.r, c.g, c.b, c.ToHex()) << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
This library was created by `maxine`, and is currently maintained by Josh O'Leary.
|
||||
|
||||
## Contributing
|
||||
|
||||
Pull requests and issues are always welcome! You know what to do!
|
||||
|
||||
## License
|
||||
|
||||
This work is expressly dedicated to the Public Domain under the Unlicense.
|
||||
|
||||
|
||||
|
@@ -18,7 +18,11 @@ class Color4;
|
||||
|
||||
std::string toEscapeCode(Color4 c, bool bg=false);
|
||||
|
||||
void print_builtin_color_list();
|
||||
namespace mcolor
|
||||
{
|
||||
void printBuiltinColorList();
|
||||
}
|
||||
|
||||
|
||||
/// A type representing a color with alpha.
|
||||
/// Our default format is RGBA with 8 bits-per-channel.
|
||||
@@ -132,10 +136,10 @@ public:
|
||||
LCH ToLCH() const;
|
||||
|
||||
// TODO: Disparate with mcolor::toEscapeCode, resolve.
|
||||
[[nodiscard]] std::string EscapeCode(bool bg = false, bool bold = false);
|
||||
[[nodiscard]] std::string EscapeCode(bool bg = false, bool bold = false) const;
|
||||
|
||||
[[nodiscard]] std::string FGEscapeCode(bool bold = false);
|
||||
[[nodiscard]] std::string BGEscapeCode(bool bold = false);
|
||||
[[nodiscard]] std::string FGEscapeCode(bool bold = false) const;
|
||||
[[nodiscard]] std::string BGEscapeCode(bool bold = false) const;
|
||||
|
||||
|
||||
bool operator==(const Color4& rhs) const;
|
||||
@@ -143,7 +147,7 @@ public:
|
||||
bool operator!=(const Color4& rhs) const;
|
||||
|
||||
|
||||
std::string ToEscapeCode(bool bg = false);
|
||||
std::string ToEscapeCode(bool bg = false) const;
|
||||
};
|
||||
|
||||
inline std::ostream& operator << (std::ostream& os, const Color4& c) {
|
||||
|
@@ -7,7 +7,9 @@
|
||||
#include <cstdint>
|
||||
#include <format>
|
||||
#include <vector>
|
||||
#include "Color3.hpp"
|
||||
#include "Color4.hpp"
|
||||
#include "Colors.hpp"
|
||||
#include "AnsiEscapeCodes.hpp"
|
||||
|
||||
namespace mcolor {
|
||||
@@ -15,9 +17,11 @@ namespace mcolor {
|
||||
|
||||
std::string toEscapeCode(AnsiColor c);
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
/// Performs a hack that allows the windows console to interpret ANSI codes.
|
||||
/// @note This only works on Windows 10 version 1511 and newer.
|
||||
void windowsSaneify();
|
||||
#endif
|
||||
|
||||
|
||||
void printAnsiColorTable();
|
||||
|
||||
|
19
main.cpp
19
main.cpp
@@ -5,11 +5,15 @@
|
||||
#include <Color4.hpp>
|
||||
#include <Colors.hpp>
|
||||
|
||||
std::string fmt_color(const Color4& c)
|
||||
{
|
||||
return std::format("{}hue:{} rgb: {},{},{} hex: {}", c.ToEscapeCode(), c.ToHSV().h, c.r, c.g, c.b, c.ToHex());
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
#ifdef WIN32
|
||||
mcolor::windowsSaneify();
|
||||
#endif
|
||||
mcolor::windowsSaneify();
|
||||
|
||||
|
||||
// TODO: Demo Color Space Math Operations
|
||||
|
||||
@@ -17,10 +21,15 @@ int main()
|
||||
|
||||
// TODO: Demo Color output in console.
|
||||
|
||||
print_builtin_color_list();
|
||||
mcolor::printBuiltinColorList();
|
||||
mcolor::printAnsiColorTable();
|
||||
mcolor::printRGBConsoleTest();
|
||||
|
||||
std::cout << "Color construction from hex codes:" << std::endl;
|
||||
std::cout << fmt_color(Color4::FromHex("#FFFFFF")) << std::endl;
|
||||
std::cout << fmt_color(Color4::FromHex("#F0F0F0")) << std::endl;
|
||||
std::cout << fmt_color(Color4::FromHex("#0F0F0F")) << std::endl;
|
||||
std::cout << fmt_color(Color4::FromHex("#00AAFF")) << std::endl;
|
||||
|
||||
for (float i = 0; i < 360; i+=10.f)
|
||||
{
|
||||
@@ -28,7 +37,7 @@ int main()
|
||||
|
||||
Color4 c = Color4(hsva);
|
||||
|
||||
std::cout << std::format("{}hue:{} rgb: {},{},{}", toEscapeCode(c), i, c.r, c.g, c.b) << std::endl;
|
||||
std::cout << std::format("{}hue:{} rgb: {},{},{} hex: {}", c.ToEscapeCode(), i, c.r, c.g, c.b, c.ToHex()) << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@@ -20,7 +20,7 @@ Color3 Color3::FromHex(const std::string &hexCode) {
|
||||
// TODO: Support 9-character hex codes (with alpha), but raise a warning that suggests using Color4 instead.
|
||||
if (hexCode.length() == 7) {
|
||||
u8 r, g, b;
|
||||
std::sscanf(hexCode.c_str(), "#%02x%02x%02x", &r, &g, &b);
|
||||
std::sscanf(hexCode.c_str(), "#%02hhx%02hhx%02hhx", &r, &g, &b);
|
||||
return {r, g, b};
|
||||
}
|
||||
|
||||
|
@@ -14,7 +14,7 @@ std::string toEscapeCode(Color4 c, bool bg){
|
||||
return std::format("\033[38;2;{};{};{}m", c.r, c.g, c.b);
|
||||
}
|
||||
|
||||
void print_builtin_color_list() {
|
||||
void mcolor::printBuiltinColorList() {
|
||||
#if !defined(WIN32)
|
||||
int i = 0;
|
||||
for (const Color4& color : list) {
|
||||
@@ -114,13 +114,13 @@ Color4 Color4::FromHex(const std::string &hexCode, u8 alpha) {
|
||||
// TODO: Support 9-character hex codes (with alpha), but raise a warning that suggests using FromHexA explicitly instead.
|
||||
if (hexCode.length() == 7) {
|
||||
u8 r, g, b;
|
||||
std::sscanf(hexCode.c_str(), "#%02x%02x%02x", &r, &g, &b);
|
||||
std::sscanf(hexCode.c_str(), "#%02hhx%02hhx%02hhx", &r, &g, &b);
|
||||
return {r, g, b, alpha};
|
||||
}
|
||||
|
||||
if (hexCode.length() == 9) {
|
||||
u8 r, g, b, a;
|
||||
std::sscanf(hexCode.c_str(), "#%02x%02x%02x%02x", &r, &g, &b, &a);
|
||||
std::sscanf(hexCode.c_str(), "#%02hhx%02hhx%02hhx%02hhx", &r, &g, &b, &a);
|
||||
return {r, g, b, a};
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ Color4 Color4::FromHex(const std::string &hexCode, u8 alpha) {
|
||||
Color4 Color4::FromHexA(const std::string &hexACode) {
|
||||
if (hexACode.length() == 9) {
|
||||
u8 r, g, b, a;
|
||||
std::sscanf(hexACode.c_str(), "#%02x%02x%02x%02x", &r, &g, &b, &a);
|
||||
std::sscanf(hexACode.c_str(), "#%02hhx%02hhx%02hhx%02hhx", &r, &g, &b, &a);
|
||||
return {r, g, b, a};
|
||||
}
|
||||
|
||||
@@ -327,18 +327,18 @@ LCH Color4::ToLCH() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string Color4::EscapeCode(bool bg, bool bold) {
|
||||
std::string Color4::EscapeCode(bool bg, bool bold) const {
|
||||
if (bg)
|
||||
return std::format("\033[48;2;{};{};{}m", r, g, b);
|
||||
|
||||
return std::format("\033[38;2;{};{};{}m", r, g, b);
|
||||
}
|
||||
|
||||
std::string Color4::FGEscapeCode(bool bold) {
|
||||
std::string Color4::FGEscapeCode(bool bold) const {
|
||||
return EscapeCode(false, bold);
|
||||
}
|
||||
|
||||
std::string Color4::BGEscapeCode(bool bold) {
|
||||
std::string Color4::BGEscapeCode(bool bold) const {
|
||||
return EscapeCode(true, bold);
|
||||
}
|
||||
|
||||
@@ -355,16 +355,16 @@ bool Color4::operator!=(const Color4& rhs) const
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
std::string Color4::ToEscapeCode(bool bg) {
|
||||
std::string Color4::ToEscapeCode(bool bg) const {
|
||||
if (bg)
|
||||
return std::format("\033[48;2;{};{};{}m", r, g, b);
|
||||
|
||||
return std::format("\033[38;2;{};{};{}m", r, g, b);
|
||||
}
|
||||
|
||||
static std::string decimal_to_hex(int dec)
|
||||
static std::string decimal_to_hex(int dec, int digits = 0)
|
||||
{
|
||||
if (dec < 1) return "00";
|
||||
if (dec < 1) return std::string(digits, '0');
|
||||
|
||||
int hex = dec;
|
||||
std::string hexStr = "";
|
||||
@@ -379,22 +379,33 @@ static std::string decimal_to_hex(int dec)
|
||||
|
||||
dec /= 16;
|
||||
}
|
||||
|
||||
if (digits > 0)
|
||||
{
|
||||
while (hexStr.length() < digits)
|
||||
{
|
||||
hexStr = "0" + hexStr;
|
||||
digits--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return hexStr;
|
||||
}
|
||||
|
||||
|
||||
std::string Color4::ToHex() const {
|
||||
std::string rs = decimal_to_hex(r);
|
||||
std::string gs = decimal_to_hex(g);
|
||||
std::string bs = decimal_to_hex(b);
|
||||
std::string rs = decimal_to_hex(r, 2);
|
||||
std::string gs = decimal_to_hex(g, 2);
|
||||
std::string bs = decimal_to_hex(b, 2);
|
||||
return "#" + rs + gs + bs;
|
||||
}
|
||||
|
||||
std::string Color4::ToHexAlpha() const {
|
||||
std::string rs = decimal_to_hex(r);
|
||||
std::string gs = decimal_to_hex(g);
|
||||
std::string bs = decimal_to_hex(b);
|
||||
std::string as = decimal_to_hex(a);
|
||||
std::string rs = decimal_to_hex(r, 2);
|
||||
std::string gs = decimal_to_hex(g, 2);
|
||||
std::string bs = decimal_to_hex(b, 2);
|
||||
std::string as = decimal_to_hex(a, 2);
|
||||
return "#" + rs + gs + bs + as;
|
||||
}
|
||||
|
||||
|
@@ -26,7 +26,7 @@ namespace mcolor
|
||||
return std::format("\033[{}m", static_cast<typename std::underlying_type<AnsiColor>::type>(c));
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
/*
|
||||
* Beat Windows into submission and make it interpret ansi codes.
|
||||
* Fuck you Microsoft we're doing this the right way.
|
||||
@@ -37,6 +37,7 @@ namespace mcolor
|
||||
* along with any code that is printing the escape codes to a terminal.
|
||||
*/
|
||||
void windowsSaneify() {
|
||||
#ifdef WIN32
|
||||
HANDLE handleOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD consoleMode;
|
||||
GetConsoleMode( handleOut, &consoleMode);
|
||||
@@ -44,8 +45,9 @@ namespace mcolor
|
||||
consoleMode |= DISABLE_NEWLINE_AUTO_RETURN;
|
||||
SetConsoleMode( handleOut , consoleMode );
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void printAnsiColorTable() {
|
||||
std::vector<AnsiColor> ansifg = {
|
||||
|
Reference in New Issue
Block a user