godot/core/color.cpp

403 lines
8.1 KiB
C++
Raw Normal View History

2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* color.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
2014-02-10 02:10:30 +01:00
/* */
/* 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 "color_names.inc"
#include "map.h"
2014-02-10 02:10:30 +01:00
#include "math_funcs.h"
#include "print_string.h"
uint32_t Color::to_ARGB32() const {
uint32_t c = (uint8_t)(a * 255);
c <<= 8;
c |= (uint8_t)(r * 255);
c <<= 8;
c |= (uint8_t)(g * 255);
c <<= 8;
c |= (uint8_t)(b * 255);
2014-02-10 02:10:30 +01:00
return c;
}
2017-08-30 20:30:12 +02:00
uint32_t Color::to_ABGR32() const {
uint32_t c = (uint8_t)(a * 255);
c <<= 8;
c |= (uint8_t)(b * 255);
c <<= 8;
c |= (uint8_t)(g * 255);
c <<= 8;
c |= (uint8_t)(r * 255);
return c;
}
2014-02-10 02:10:30 +01:00
uint32_t Color::to_32() const {
uint32_t c = (uint8_t)(a * 255);
c <<= 8;
c |= (uint8_t)(r * 255);
c <<= 8;
c |= (uint8_t)(g * 255);
c <<= 8;
c |= (uint8_t)(b * 255);
2014-02-10 02:10:30 +01:00
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);
2014-02-10 02:10:30 +01:00
float delta = max - min;
if (delta == 0)
2014-02-10 02:10:30 +01:00
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
2014-02-10 02:10:30 +01:00
else
h = 4 + (r - g) / delta; // between magenta & cyan
2016-03-09 00:00:52 +01:00
h /= 6.0;
if (h < 0)
h += 1.0;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
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);
2014-02-10 02:10:30 +01:00
float delta = max - min;
return (max != 0) ? (delta / max) : 0;
2014-02-10 02:10:30 +01:00
}
float Color::get_v() const {
float max = MAX(r, g);
max = MAX(max, b);
2014-02-10 02:10:30 +01:00
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;
2014-02-10 02:10:30 +01:00
if (p_s == 0) {
2014-02-10 02:10:30 +01:00
// 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);
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
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));
2014-02-10 02:10:30 +01:00
switch (i) {
2016-02-18 10:43:04 +01:00
case 0: // Red is the dominant color
2014-02-10 02:10:30 +01:00
r = p_v;
g = t;
b = p;
break;
2016-02-18 10:43:04 +01:00
case 1: // Green is the dominant color
2014-02-10 02:10:30 +01:00
r = q;
g = p_v;
b = p;
break;
2016-03-09 00:00:52 +01:00
case 2:
2014-02-10 02:10:30 +01:00
r = p;
g = p_v;
b = t;
break;
2016-02-18 10:43:04 +01:00
case 3: // Blue is the dominant color
2014-02-10 02:10:30 +01:00
r = p;
g = q;
b = p_v;
break;
case 4:
r = t;
g = p;
b = p_v;
break;
2016-02-18 10:43:04 +01:00
default: // (5) Red is the dominant color
2014-02-10 02:10:30 +01:00
r = p_v;
g = p;
b = q;
break;
}
}
void Color::invert() {
r = 1.0 - r;
g = 1.0 - g;
b = 1.0 - b;
2014-02-10 02:10:30 +01:00
}
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);
2014-02-10 02:10:30 +01:00
}
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;
2014-02-10 02:10:30 +01:00
return Color(r, g, b, a);
2014-02-10 02:10:30 +01:00
}
static float _parse_col(const String &p_str, int p_ofs) {
2014-02-10 02:10:30 +01:00
int ig = 0;
2014-02-10 02:10:30 +01:00
for (int i = 0; i < 2; i++) {
2014-02-10 02:10:30 +01:00
int c = p_str[i + p_ofs];
int v = 0;
2014-02-10 02:10:30 +01:00
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;
2014-02-10 02:10:30 +01:00
} else {
return -1;
}
if (i == 0)
ig += v * 16;
2014-02-10 02:10:30 +01:00
else
ig += v;
2014-02-10 02:10:30 +01:00
}
return ig;
}
Color Color::inverted() const {
Color c = *this;
2014-02-10 02:10:30 +01:00
c.invert();
return c;
}
Color Color::contrasted() const {
Color c = *this;
2014-12-09 05:26:19 +01:00
c.contrast();
2014-02-10 02:10:30 +01:00
return c;
}
Color Color::html(const String &p_color) {
2014-02-10 02:10:30 +01:00
String color = p_color;
if (color.length() == 0)
2014-02-10 02:10:30 +01:00
return Color();
if (color[0] == '#')
color = color.substr(1, color.length() - 1);
2014-02-10 02:10:30 +01:00
bool alpha = false;
2014-02-10 02:10:30 +01:00
if (color.length() == 8) {
alpha = true;
} else if (color.length() == 6) {
alpha = false;
2014-02-10 02:10:30 +01:00
} else {
ERR_EXPLAIN("Invalid Color Code: " + p_color);
2014-02-10 02:10:30 +01:00
ERR_FAIL_V(Color());
}
int a = 255;
2014-02-10 02:10:30 +01:00
if (alpha) {
a = _parse_col(color, 0);
if (a < 0) {
ERR_EXPLAIN("Invalid Color Code: " + p_color);
2014-02-10 02:10:30 +01:00
ERR_FAIL_V(Color());
}
}
int from = alpha ? 2 : 0;
2014-02-10 02:10:30 +01:00
int r = _parse_col(color, from + 0);
if (r < 0) {
ERR_EXPLAIN("Invalid Color Code: " + p_color);
2014-02-10 02:10:30 +01:00
ERR_FAIL_V(Color());
}
int g = _parse_col(color, from + 2);
if (g < 0) {
ERR_EXPLAIN("Invalid Color Code: " + p_color);
2014-02-10 02:10:30 +01:00
ERR_FAIL_V(Color());
}
int b = _parse_col(color, from + 4);
if (b < 0) {
ERR_EXPLAIN("Invalid Color Code: " + p_color);
2014-02-10 02:10:30 +01:00
ERR_FAIL_V(Color());
}
return Color(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
2014-02-10 02:10:30 +01:00
}
bool Color::html_is_valid(const String &p_color) {
2014-02-10 02:10:30 +01:00
String color = p_color;
if (color.length() == 0)
2014-02-10 02:10:30 +01:00
return false;
if (color[0] == '#')
color = color.substr(1, color.length() - 1);
2014-02-10 02:10:30 +01:00
bool alpha = false;
2014-02-10 02:10:30 +01:00
if (color.length() == 8) {
alpha = true;
} else if (color.length() == 6) {
alpha = false;
2014-02-10 02:10:30 +01:00
} else {
return false;
}
int a = 255;
2014-02-10 02:10:30 +01:00
if (alpha) {
a = _parse_col(color, 0);
if (a < 0) {
2014-02-10 02:10:30 +01:00
return false;
}
}
int from = alpha ? 2 : 0;
2014-02-10 02:10:30 +01:00
int r = _parse_col(color, from + 0);
if (r < 0) {
2014-02-10 02:10:30 +01:00
return false;
}
int g = _parse_col(color, from + 2);
if (g < 0) {
2014-02-10 02:10:30 +01:00
return false;
}
int b = _parse_col(color, from + 4);
if (b < 0) {
2014-02-10 02:10:30 +01:00
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());
}
}
2014-02-10 02:10:30 +01:00
String _to_hex(float p_val) {
int v = p_val * 255;
v = CLAMP(v, 0, 255);
2014-02-10 02:10:30 +01:00
String ret;
for (int i = 0; i < 2; i++) {
2014-02-10 02:10:30 +01:00
CharType c[2] = { 0, 0 };
int lv = v & 0xF;
if (lv < 10)
c[0] = '0' + lv;
2014-02-10 02:10:30 +01:00
else
c[0] = 'a' + lv - 10;
2014-02-10 02:10:30 +01:00
v >>= 4;
String cs = (const CharType *)c;
2014-02-10 02:10:30 +01:00
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);
2014-02-10 02:10:30 +01:00
if (p_alpha)
txt = _to_hex(a) + txt;
2014-02-10 02:10:30 +01:00
return txt;
}
float Color::gray() const {
return (r + g + b) / 3.0;
2014-02-10 02:10:30 +01:00
}
Color::operator String() const {
return rtos(r) + ", " + rtos(g) + ", " + rtos(b) + ", " + rtos(a);
2014-02-10 02:10:30 +01:00
}