/* +-------------------------------------------------------+ ____/ \____ /| Open source game framework licensed to freely use, | \ / / | copy, and modify, created for dank.game | +--\ ^__^ /--+ | | | ~/ \~ | | Download at https://open.shampoo.ooo/shampoo/spacebox | | ~~~~~~~~~~~~ | +-------------------------------------------------------+ | SPACE ~~~~~ | / | ~~~~~~~ BOX |/ +-------------*/ #include "Color.hpp" sb::Color::Color() : sb::Color(0, 0, 0, 0) {} sb::Color::Color(const SDL_Color& color) : sb::Color(color.r, color.g, color.b, color.a) {}; void sb::Color::percent(float red, float green, float blue) { r = std::round(255.0f * red); g = std::round(255.0f * green); b = std::round(255.0f * blue); } void sb::Color::percent(float red, float green, float blue, float alpha) { a = std::round(255.0f * alpha); sb::Color::percent(red, green, blue); } void sb::Color::hsv(float hue, float saturation, float value) { float red_percent, green_percent, blue_percent; HSVtoRGB(red_percent, green_percent, blue_percent, hue, saturation, value); sb::Color::percent(red_percent, green_percent, blue_percent); } float sb::Color::hue() const { float hue, saturation, value; float red_percent = r / 255.0f, green_percent = g / 255.0f, blue_percent = b / 255.0f; RGBtoHSV(red_percent, green_percent, blue_percent, hue, saturation, value); return hue; } void sb::Color::shift_hue(float offset) { float hue, saturation, value; float red_percent = r / 255.0f, green_percent = g / 255.0f, blue_percent = b / 255.0f; RGBtoHSV(red_percent, green_percent, blue_percent, hue, saturation, value); hue = std::fmod(hue + offset, 360.0f); HSVtoRGB(red_percent, green_percent, blue_percent, hue, saturation, value); percent(red_percent, green_percent, blue_percent); } sb::Color::operator std::uint32_t() const { SDL_PixelFormat* format = SDL_AllocFormat(SDL_PIXELFORMAT_RGBA32); std::uint32_t pixel = SDL_MapRGBA(format, r, g, b, a); SDL_FreeFormat(format); return pixel; } sb::Color::operator std::uint16_t() const { SDL_PixelFormat* format = SDL_AllocFormat(SDL_PIXELFORMAT_RGBA4444); std::uint16_t pixel = SDL_MapRGBA(format, r, g, b, a); SDL_FreeFormat(format); return pixel; } sb::Color::operator std::uint8_t() const { SDL_PixelFormat* format = SDL_AllocFormat(SDL_PIXELFORMAT_RGB332); std::uint8_t pixel = SDL_MapRGBA(format, r, g, b, a); SDL_FreeFormat(format); return pixel; } bool sb::Color::operator==(const sb::Color& color) const { return r == color.r && g == color.g && b == color.b && a == color.a; } bool sb::Color::operator!=(const sb::Color& color) const { return !(*this == color); } bool sb::Color::operator<(const sb::Color& color) const { return r < color.r || g < color.g || b < color.b || a < color.a; } glm::vec4 sb::Color::normal() const { return glm::vec4{r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f}; } std::ostream& std::operator<<(std::ostream& out, const sb::Color& color) { float h, s, v; RGBtoHSV(color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, h, s, v); out << "{r=" << static_cast(color.r) << ", g=" << static_cast(color.g) << ", b=" << static_cast(color.b) << ", a= " << static_cast(color.a) << ", h=" << h << ", s=" << s << ", v=" << v << "}"; return out; } /* The following copyright applies to RGBtoHSV and HSVtoRGB: */ // // Copyright (c) 2014, Jan Winkler // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of Universität Bremen nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. /*! \brief Convert RGB to HSV color space Converts a given set of RGB values `r', `g', `b' into HSV coordinates. The input RGB values are in the range [0, 1], and the output HSV values are in the ranges h = [0, 360], and s, v = [0, 1], respectively. \param fR Red component, used as input, range: [0, 1] \param fG Green component, used as input, range: [0, 1] \param fB Blue component, used as input, range: [0, 1] \param fH Hue component, used as output, range: [0, 360] \param fS Hue component, used as output, range: [0, 1] \param fV Hue component, used as output, range: [0, 1] */ void RGBtoHSV(const float& fR, const float& fG, const float& fB, float& fH, float& fS, float& fV) { float fCMax = std::max(std::max(fR, fG), fB); float fCMin = std::min(std::min(fR, fG), fB); float fDelta = fCMax - fCMin; if(fDelta > 0) { if(fCMax == fR) { fH = 60 * (std::fmod(((fG - fB) / fDelta), 6)); } else if(fCMax == fG) { fH = 60 * (((fB - fR) / fDelta) + 2); } else if(fCMax == fB) { fH = 60 * (((fR - fG) / fDelta) + 4); } if(fCMax > 0) { fS = fDelta / fCMax; } else { fS = 0; } fV = fCMax; } else { fH = 0; fS = 0; fV = fCMax; } if(fH < 0) { fH = 360 + fH; } } /*! \brief Convert HSV to RGB color space Converts a given set of HSV values `h', `s', `v' into RGB coordinates. The output RGB values are in the range [0, 1], and the input HSV values are in the ranges h = [0, 360], and s, v = [0, 1], respectively. \param fR Red component, used as output, range: [0, 1] \param fG Green component, used as output, range: [0, 1] \param fB Blue component, used as output, range: [0, 1] \param fH Hue component, used as input, range: [0, 360] \param fS Hue component, used as input, range: [0, 1] \param fV Hue component, used as input, range: [0, 1] */ void HSVtoRGB(float& fR, float& fG, float& fB, const float& fH, const float& fS, const float& fV) { float fC = fV * fS; // Chroma float fHPrime = std::fmod(fH / 60.0, 6); float fX = fC * (1 - std::fabs(std::fmod(fHPrime, 2) - 1)); float fM = fV - fC; if(0 <= fHPrime && fHPrime < 1) { fR = fC; fG = fX; fB = 0; } else if(1 <= fHPrime && fHPrime < 2) { fR = fX; fG = fC; fB = 0; } else if(2 <= fHPrime && fHPrime < 3) { fR = 0; fG = fC; fB = fX; } else if(3 <= fHPrime && fHPrime < 4) { fR = 0; fG = fX; fB = fC; } else if(4 <= fHPrime && fHPrime < 5) { fR = fX; fG = 0; fB = fC; } else if(5 <= fHPrime && fHPrime < 6) { fR = fC; fG = 0; fB = fX; } else { fR = 0; fG = 0; fB = 0; } fR += fM; fG += fM; fB += fM; }