/
ArtemNech
/
simpleOpenGL
Обзор
Документация
Войти
/
ArtemNech
/
simpleOpenGL
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
devOpt
backend/graphics-units/NColor.cpp
260 строк
9 KB
Artem Nechitaylenko
initial
16 май 2026, 12:48
16 май 2026, 12:48
0d3ac6c
Код
Авторство
О чём код?
// // Created by artem on 20.10.25. // // // Created by artem on 20.10.25. // #include "NColor.h" #include <algorithm> #include <sstream> #include <iomanip> #include <cmath> namespace ngraph { // ============ Вспомогательная функция ============ float NColor::hueToRgb(float p, float q, float t) { if (t < 0.0f) t += 1.0f; if (t > 1.0f) t -= 1.0f; if (t < 1.0f / 6.0f) return p + (q - p) * 6.0f * t; if (t < 1.0f / 2.0f) return q; if (t < 2.0f / 3.0f) return p + (q - p) * (2.0f / 3.0f - t) * 6.0f; return p; } // ============ RGB → HSV ============ void NColor::getHsv(int* h, int* s, int* v, int* a) const { float r = m_r / 255.0f; float g = m_g / 255.0f; float b = m_b / 255.0f; float max = std::max({r, g, b}); float min = std::min({r, g, b}); float delta = max - min; // Hue float hue = 0.0f; if (delta > 0.0001f) { if (max == r) { hue = 60.0f * std::fmod((g - b) / delta, 6.0f); } else if (max == g) { hue = 60.0f * ((b - r) / delta + 2.0f); } else { hue = 60.0f * ((r - g) / delta + 4.0f); } } if (hue < 0.0f) hue += 360.0f; // Saturation float sat = (max < 0.0001f) ? 0.0f : (delta / max); // Value float val = max; if (h) *h = static_cast<int>(hue + 0.5f); if (s) *s = static_cast<int>(sat * 255.0f + 0.5f); if (v) *v = static_cast<int>(val * 255.0f + 0.5f); if (a) *a = m_a; } // ============ HSV → RGB ============ void NColor::setHsv(int h, int s, int v, int a) { // Нормализуем диапазоны h = std::clamp(h, 0, 359); s = std::clamp(s, 0, 255); v = std::clamp(v, 0, 255); float hue = h / 360.0f; float sat = s / 255.0f; float val = v / 255.0f; if (sat < 0.0001f) { // Серый (нет насыщенности) auto gray = static_cast<uint8_t>(val * 255.0f + 0.5f); m_r = m_g = m_b = gray; } else { int i = static_cast<int>(hue * 6.0f); float f = hue * 6.0f - i; float p = val * (1.0f - sat); float q = val * (1.0f - sat * f); float t = val * (1.0f - sat * (1.0f - f)); float r, g, b; switch (i % 6) { case 0: r = val; g = t; b = p; break; case 1: r = q; g = val; b = p; break; case 2: r = p; g = val; b = t; break; case 3: r = p; g = q; b = val; break; case 4: r = t; g = p; b = val; break; case 5: r = val; g = p; b = q; break; default: r = g = b = 0; break; } m_r = static_cast<uint8_t>(r * 255.0f + 0.5f); m_g = static_cast<uint8_t>(g * 255.0f + 0.5f); m_b = static_cast<uint8_t>(b * 255.0f + 0.5f); } m_a = static_cast<uint8_t>(a); } // ============ RGB → HSL ============ void NColor::getHsl(int* h, int* s, int* l, int* a) const { float r = m_r / 255.0f; float g = m_g / 255.0f; float b = m_b / 255.0f; float max = std::max({r, g, b}); float min = std::min({r, g, b}); float delta = max - min; float lightness = (max + min) / 2.0f; float hue = 0.0f; float sat = 0.0f; if (delta > 0.0001f) { sat = (lightness < 0.5f) ? (delta / (max + min)) : (delta / (2.0f - max - min)); if (max == r) { hue = 60.0f * std::fmod((g - b) / delta, 6.0f); } else if (max == g) { hue = 60.0f * ((b - r) / delta + 2.0f); } else { hue = 60.0f * ((r - g) / delta + 4.0f); } } if (hue < 0.0f) hue += 360.0f; if (h) *h = static_cast<int>(hue + 0.5f); if (s) *s = static_cast<int>(sat * 255.0f + 0.5f); if (l) *l = static_cast<int>(lightness * 255.0f + 0.5f); if (a) *a = m_a; } // ============ HSL → RGB ============ void NColor::setHsl(int h, int s, int l, int a) { h = std::clamp(h, 0, 359); s = std::clamp(s, 0, 255); l = std::clamp(l, 0, 255); float hue = h / 360.0f; float sat = s / 255.0f; float light = l / 255.0f; if (sat < 0.0001f) { uint8_t gray = static_cast<uint8_t>(light * 255.0f + 0.5f); m_r = m_g = m_b = gray; } else { float q = (light < 0.5f) ? (light * (1.0f + sat)) : (light + sat - light * sat); float p = 2.0f * light - q; float r = hueToRgb(p, q, hue + 1.0f / 3.0f); float g = hueToRgb(p, q, hue); float b = hueToRgb(p, q, hue - 1.0f / 3.0f); m_r = static_cast<uint8_t>(r * 255.0f + 0.5f); m_g = static_cast<uint8_t>(g * 255.0f + 0.5f); m_b = static_cast<uint8_t>(b * 255.0f + 0.5f); } m_a = static_cast<uint8_t>(a); } // ============ lighter ============ NColor NColor::lighter(int factor) const { if (factor <= 0) return NColor(255, 255, 255, m_a); int h, s, v, a; getHsv(&h, &s, &v, &a); v = std::min(v * factor / 100, 255); // При осветлении насыщенность немного снижается s = s * std::max(0, 200 - factor) / 100; NColor result; result.setHsv(h, s, v, a); return result; } // ============ darker ============ NColor NColor::darker(int factor) const { if (factor <= 0) return NColor(0, 0, 0, m_a); int h, s, v, a; getHsv(&h, &s, &v, &a); v = v * 100 / factor; // При затемнении насыщенность может увеличиваться s = std::min(s * factor / 100, 255); NColor result; result.setHsv(h, s, v, a); return result; } // ============ toGrayscale ============ NColor NColor::toGrayscale() const { // Взвешенное по восприятию преобразование uint8_t gray = static_cast<uint8_t>(m_r * 0.299f + m_g * 0.587f + m_b * 0.114f + 0.5f); return NColor(gray, gray, gray, m_a); } // ============ mix ============ NColor NColor::mix(const NColor& other, float ratio) const { ratio = std::clamp(ratio, 0.0f, 1.0f); auto lerp = [ratio](uint8_t a, uint8_t b) -> uint8_t { return static_cast<uint8_t>(a + (b - a) * ratio + 0.5f); }; return NColor( lerp(m_r, other.m_r), lerp(m_g, other.m_g), lerp(m_b, other.m_b), lerp(m_a, other.m_a) ); } // ============ Строковое представление ============ std::string NColor::name() const { std::ostringstream oss; oss << "#" << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << static_cast<int>(m_r) << std::setw(2) << static_cast<int>(m_g) << std::setw(2) << static_cast<int>(m_b); return oss.str(); } std::string NColor::toHex() const { std::ostringstream oss; oss << "#" << std::hex << std::uppercase << std::setfill('0') << std::setw(2) << static_cast<int>(m_r) << std::setw(2) << static_cast<int>(m_g) << std::setw(2) << static_cast<int>(m_b) << std::setw(2) << static_cast<int>(m_a); return oss.str(); } NColor NColor::fromString(const std::string& str) { if (str.empty()) return {}; // Поддержка #RGB, #RRGGBB, #RRGGBBAA if (str[0] == '#') { std::string hex = str.substr(1); if (hex.length() == 3) { uint8_t r = static_cast<uint8_t>(std::stoi(hex.substr(0,1), nullptr, 16) * 17); uint8_t g = static_cast<uint8_t>(std::stoi(hex.substr(1,1), nullptr, 16) * 17); uint8_t b = static_cast<uint8_t>(std::stoi(hex.substr(2,1), nullptr, 16) * 17); return {r, g, b}; } else if (hex.length() >= 6) { uint8_t r = static_cast<uint8_t>(std::stoi(hex.substr(0,2), nullptr, 16)); uint8_t g = static_cast<uint8_t>(std::stoi(hex.substr(2,2), nullptr, 16)); uint8_t b = static_cast<uint8_t>(std::stoi(hex.substr(4,2), nullptr, 16)); uint8_t a = (hex.length() >= 8) ? static_cast<uint8_t>(std::stoi(hex.substr(6,2), nullptr, 16)) : 255; return {r, g, b, a}; } } // TODO: при желании можно добавить именованные цвета ("red", "blue"...) return NColor(); } } // namespace ngraph