123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654 |
- /*************************************************************************/
- /* color.cpp */
- /*************************************************************************/
- /* This file is part of: */
- /* GODOT ENGINE */
- /* https://godotengine.org */
- /*************************************************************************/
- /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
- /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
- /* */
- /* Permission is hereby granted, free of charge, to any person obtaining */
- /* a copy of this software and associated documentation files (the */
- /* "Software"), to deal in the Software without restriction, including */
- /* without limitation the rights to use, copy, modify, merge, publish, */
- /* distribute, sublicense, and/or sell copies of the Software, and to */
- /* permit persons to whom the Software is furnished to do so, subject to */
- /* the following conditions: */
- /* */
- /* The above copyright notice and this permission notice shall be */
- /* included in all copies or substantial portions of the Software. */
- /* */
- /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
- /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
- /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
- /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
- /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
- /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
- /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
- /*************************************************************************/
- #include "color.h"
- #include "core/color_names.inc"
- #include "core/map.h"
- #include "core/math/math_funcs.h"
- #include "core/print_string.h"
- uint32_t Color::to_argb32() const {
- uint32_t c = (uint8_t)Math::round(a * 255);
- c <<= 8;
- c |= (uint8_t)Math::round(r * 255);
- c <<= 8;
- c |= (uint8_t)Math::round(g * 255);
- c <<= 8;
- c |= (uint8_t)Math::round(b * 255);
- return c;
- }
- uint32_t Color::to_abgr32() const {
- uint32_t c = (uint8_t)Math::round(a * 255);
- c <<= 8;
- c |= (uint8_t)Math::round(b * 255);
- c <<= 8;
- c |= (uint8_t)Math::round(g * 255);
- c <<= 8;
- c |= (uint8_t)Math::round(r * 255);
- return c;
- }
- uint32_t Color::to_rgba32() const {
- uint32_t c = (uint8_t)Math::round(r * 255);
- c <<= 8;
- c |= (uint8_t)Math::round(g * 255);
- c <<= 8;
- c |= (uint8_t)Math::round(b * 255);
- c <<= 8;
- c |= (uint8_t)Math::round(a * 255);
- return c;
- }
- uint64_t Color::to_abgr64() const {
- uint64_t c = (uint16_t)Math::round(a * 65535);
- c <<= 16;
- c |= (uint16_t)Math::round(b * 65535);
- c <<= 16;
- c |= (uint16_t)Math::round(g * 65535);
- c <<= 16;
- c |= (uint16_t)Math::round(r * 65535);
- return c;
- }
- uint64_t Color::to_argb64() const {
- uint64_t c = (uint16_t)Math::round(a * 65535);
- c <<= 16;
- c |= (uint16_t)Math::round(r * 65535);
- c <<= 16;
- c |= (uint16_t)Math::round(g * 65535);
- c <<= 16;
- c |= (uint16_t)Math::round(b * 65535);
- return c;
- }
- uint64_t Color::to_rgba64() const {
- uint64_t c = (uint16_t)Math::round(r * 65535);
- c <<= 16;
- c |= (uint16_t)Math::round(g * 65535);
- c <<= 16;
- c |= (uint16_t)Math::round(b * 65535);
- c <<= 16;
- c |= (uint16_t)Math::round(a * 65535);
- return c;
- }
- float Color::get_h() const {
- float min = MIN(r, g);
- min = MIN(min, b);
- float max = MAX(r, g);
- max = MAX(max, b);
- float delta = max - min;
- if (delta == 0)
- return 0;
- float h;
- if (r == max)
- h = (g - b) / delta; // between yellow & magenta
- else if (g == max)
- h = 2 + (b - r) / delta; // between cyan & yellow
- else
- h = 4 + (r - g) / delta; // between magenta & cyan
- h /= 6.0;
- if (h < 0)
- h += 1.0;
- return h;
- }
- float Color::get_s() const {
- float min = MIN(r, g);
- min = MIN(min, b);
- float max = MAX(r, g);
- max = MAX(max, b);
- float delta = max - min;
- return (max != 0) ? (delta / max) : 0;
- }
- float Color::get_v() const {
- float max = MAX(r, g);
- max = MAX(max, b);
- return max;
- }
- void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) {
- int i;
- float f, p, q, t;
- a = p_alpha;
- if (p_s == 0) {
- // acp_hromatic (grey)
- r = g = b = p_v;
- return;
- }
- p_h *= 6.0;
- p_h = Math::fmod(p_h, 6);
- i = Math::floor(p_h);
- f = p_h - i;
- p = p_v * (1 - p_s);
- q = p_v * (1 - p_s * f);
- t = p_v * (1 - p_s * (1 - f));
- switch (i) {
- case 0: // Red is the dominant color
- r = p_v;
- g = t;
- b = p;
- break;
- case 1: // Green is the dominant color
- r = q;
- g = p_v;
- b = p;
- break;
- case 2:
- r = p;
- g = p_v;
- b = t;
- break;
- case 3: // Blue is the dominant color
- r = p;
- g = q;
- b = p_v;
- break;
- case 4:
- r = t;
- g = p;
- b = p_v;
- break;
- default: // (5) Red is the dominant color
- r = p_v;
- g = p;
- b = q;
- break;
- }
- }
- void Color::invert() {
- r = 1.0 - r;
- g = 1.0 - g;
- b = 1.0 - b;
- }
- void Color::contrast() {
- r = Math::fmod(r + 0.5, 1.0);
- g = Math::fmod(g + 0.5, 1.0);
- b = Math::fmod(b + 0.5, 1.0);
- }
- Color Color::hex(uint32_t p_hex) {
- float a = (p_hex & 0xFF) / 255.0;
- p_hex >>= 8;
- float b = (p_hex & 0xFF) / 255.0;
- p_hex >>= 8;
- float g = (p_hex & 0xFF) / 255.0;
- p_hex >>= 8;
- float r = (p_hex & 0xFF) / 255.0;
- return Color(r, g, b, a);
- }
- Color Color::hex64(uint64_t p_hex) {
- float a = (p_hex & 0xFFFF) / 65535.0;
- p_hex >>= 16;
- float b = (p_hex & 0xFFFF) / 65535.0;
- p_hex >>= 16;
- float g = (p_hex & 0xFFFF) / 65535.0;
- p_hex >>= 16;
- float r = (p_hex & 0xFFFF) / 65535.0;
- return Color(r, g, b, a);
- }
- Color Color::from_rgbe9995(uint32_t p_rgbe) {
- float r = p_rgbe & 0x1ff;
- float g = (p_rgbe >> 9) & 0x1ff;
- float b = (p_rgbe >> 18) & 0x1ff;
- float e = (p_rgbe >> 27);
- float m = Math::pow(2, e - 15.0 - 9.0);
- float rd = r * m;
- float gd = g * m;
- float bd = b * m;
- return Color(rd, gd, bd, 1.0f);
- }
- static float _parse_col(const String &p_str, int p_ofs) {
- int ig = 0;
- for (int i = 0; i < 2; i++) {
- int c = p_str[i + p_ofs];
- int v = 0;
- if (c >= '0' && c <= '9') {
- v = c - '0';
- } else if (c >= 'a' && c <= 'f') {
- v = c - 'a';
- v += 10;
- } else if (c >= 'A' && c <= 'F') {
- v = c - 'A';
- v += 10;
- } else {
- return -1;
- }
- if (i == 0)
- ig += v * 16;
- else
- ig += v;
- }
- return ig;
- }
- Color Color::inverted() const {
- Color c = *this;
- c.invert();
- return c;
- }
- Color Color::contrasted() const {
- Color c = *this;
- c.contrast();
- return c;
- }
- Color Color::html(const String &p_color) {
- String color = p_color;
- if (color.length() == 0)
- return Color();
- if (color[0] == '#')
- color = color.substr(1, color.length() - 1);
- if (color.length() == 3 || color.length() == 4) {
- String exp_color;
- for (int i = 0; i < color.length(); i++) {
- exp_color += color[i];
- exp_color += color[i];
- }
- color = exp_color;
- }
- bool alpha = false;
- if (color.length() == 8) {
- alpha = true;
- } else if (color.length() == 6) {
- alpha = false;
- } else {
- ERR_EXPLAIN("Invalid Color Code: " + p_color);
- ERR_FAIL_V(Color());
- }
- int a = 255;
- if (alpha) {
- a = _parse_col(color, 0);
- if (a < 0) {
- ERR_EXPLAIN("Invalid Color Code: " + p_color);
- ERR_FAIL_V(Color());
- }
- }
- int from = alpha ? 2 : 0;
- int r = _parse_col(color, from + 0);
- if (r < 0) {
- ERR_EXPLAIN("Invalid Color Code: " + p_color);
- ERR_FAIL_V(Color());
- }
- int g = _parse_col(color, from + 2);
- if (g < 0) {
- ERR_EXPLAIN("Invalid Color Code: " + p_color);
- ERR_FAIL_V(Color());
- }
- int b = _parse_col(color, from + 4);
- if (b < 0) {
- ERR_EXPLAIN("Invalid Color Code: " + p_color);
- ERR_FAIL_V(Color());
- }
- return Color(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
- }
- bool Color::html_is_valid(const String &p_color) {
- String color = p_color;
- if (color.length() == 0)
- return false;
- if (color[0] == '#')
- color = color.substr(1, color.length() - 1);
- bool alpha = false;
- if (color.length() == 8) {
- alpha = true;
- } else if (color.length() == 6) {
- alpha = false;
- } else {
- return false;
- }
- int a = 255;
- if (alpha) {
- a = _parse_col(color, 0);
- if (a < 0) {
- return false;
- }
- }
- int from = alpha ? 2 : 0;
- int r = _parse_col(color, from + 0);
- if (r < 0) {
- return false;
- }
- int g = _parse_col(color, from + 2);
- if (g < 0) {
- return false;
- }
- int b = _parse_col(color, from + 4);
- if (b < 0) {
- return false;
- }
- return true;
- }
- Color Color::named(const String &p_name) {
- if (_named_colors.empty()) _populate_named_colors(); // from color_names.inc
- String name = p_name;
- // Normalize name
- name = name.replace(" ", "");
- name = name.replace("-", "");
- name = name.replace("_", "");
- name = name.replace("'", "");
- name = name.replace(".", "");
- name = name.to_lower();
- const Map<String, Color>::Element *color = _named_colors.find(name);
- if (color) {
- return color->value();
- } else {
- ERR_EXPLAIN("Invalid Color Name: " + p_name);
- ERR_FAIL_V(Color());
- }
- }
- String _to_hex(float p_val) {
- int v = Math::round(p_val * 255);
- v = CLAMP(v, 0, 255);
- String ret;
- for (int i = 0; i < 2; i++) {
- CharType c[2] = { 0, 0 };
- int lv = v & 0xF;
- if (lv < 10)
- c[0] = '0' + lv;
- else
- c[0] = 'a' + lv - 10;
- v >>= 4;
- String cs = (const CharType *)c;
- ret = cs + ret;
- }
- return ret;
- }
- String Color::to_html(bool p_alpha) const {
- String txt;
- txt += _to_hex(r);
- txt += _to_hex(g);
- txt += _to_hex(b);
- if (p_alpha)
- txt = _to_hex(a) + txt;
- return txt;
- }
- Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) const {
- p_h = Math::fmod(p_h * 360.0f, 360.0f);
- if (p_h < 0.0)
- p_h += 360.0f;
- const float h_ = p_h / 60.0f;
- const float c = p_v * p_s;
- const float x = c * (1.0f - Math::abs(Math::fmod(h_, 2.0f) - 1.0f));
- float r, g, b;
- switch ((int)h_) {
- case 0: {
- r = c;
- g = x;
- b = 0;
- } break;
- case 1: {
- r = x;
- g = c;
- b = 0;
- } break;
- case 2: {
- r = 0;
- g = c;
- b = x;
- } break;
- case 3: {
- r = 0;
- g = x;
- b = c;
- } break;
- case 4: {
- r = x;
- g = 0;
- b = c;
- } break;
- case 5: {
- r = c;
- g = 0;
- b = x;
- } break;
- default: {
- r = 0;
- g = 0;
- b = 0;
- } break;
- }
- const float m = p_v - c;
- return Color(m + r, m + g, m + b, p_a);
- }
- // FIXME: Remove once Godot 3.1 has been released
- float Color::gray() const {
- ERR_EXPLAIN("Color.gray() is deprecated and will be removed in a future version. Use Color.get_v() for a better grayscale approximation.");
- WARN_DEPRECATED
- return (r + g + b) / 3.0;
- }
- Color::operator String() const {
- return rtos(r) + ", " + rtos(g) + ", " + rtos(b) + ", " + rtos(a);
- }
- Color Color::operator+(const Color &p_color) const {
- return Color(
- r + p_color.r,
- g + p_color.g,
- b + p_color.b,
- a + p_color.a);
- }
- void Color::operator+=(const Color &p_color) {
- r = r + p_color.r;
- g = g + p_color.g;
- b = b + p_color.b;
- a = a + p_color.a;
- }
- Color Color::operator-(const Color &p_color) const {
- return Color(
- r - p_color.r,
- g - p_color.g,
- b - p_color.b,
- a - p_color.a);
- }
- void Color::operator-=(const Color &p_color) {
- r = r - p_color.r;
- g = g - p_color.g;
- b = b - p_color.b;
- a = a - p_color.a;
- }
- Color Color::operator*(const Color &p_color) const {
- return Color(
- r * p_color.r,
- g * p_color.g,
- b * p_color.b,
- a * p_color.a);
- }
- Color Color::operator*(const real_t &rvalue) const {
- return Color(
- r * rvalue,
- g * rvalue,
- b * rvalue,
- a * rvalue);
- }
- void Color::operator*=(const Color &p_color) {
- r = r * p_color.r;
- g = g * p_color.g;
- b = b * p_color.b;
- a = a * p_color.a;
- }
- void Color::operator*=(const real_t &rvalue) {
- r = r * rvalue;
- g = g * rvalue;
- b = b * rvalue;
- a = a * rvalue;
- }
- Color Color::operator/(const Color &p_color) const {
- return Color(
- r / p_color.r,
- g / p_color.g,
- b / p_color.b,
- a / p_color.a);
- }
- Color Color::operator/(const real_t &rvalue) const {
- return Color(
- r / rvalue,
- g / rvalue,
- b / rvalue,
- a / rvalue);
- }
- void Color::operator/=(const Color &p_color) {
- r = r / p_color.r;
- g = g / p_color.g;
- b = b / p_color.b;
- a = a / p_color.a;
- }
- void Color::operator/=(const real_t &rvalue) {
- if (rvalue == 0) {
- r = 1.0;
- g = 1.0;
- b = 1.0;
- a = 1.0;
- } else {
- r = r / rvalue;
- g = g / rvalue;
- b = b / rvalue;
- a = a / rvalue;
- }
- };
- Color Color::operator-() const {
- return Color(
- 1.0 - r,
- 1.0 - g,
- 1.0 - b,
- 1.0 - a);
- }
|