/*
 * Copyright 2023 Hartmut Seichter
 *
 * 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.
 *
 */
#ifndef PARADISO_RGBA_HPP
#define PARADISO_RGBA_HPP

#include <paradiso/globals.hpp>

namespace paradiso {
struct RGBA final {
    using value_type = std::uint32_t;
    value_type pixel{0x0};

    static constexpr RGBA from_rgb(uint8_t red, uint8_t green,
                                   uint8_t blue) noexcept {
        return from_rgba(red, green, blue, 0xFF);
    }

    static constexpr RGBA from_rgba(uint8_t red, uint8_t green, uint8_t blue,
                                    uint8_t alpha) noexcept {
        return {.pixel =
                    (value_type)(((((alpha << 8) | blue) << 8) | green) << 8) |
                    red};
    }

    constexpr void to_float(float rgba_f[4]) const noexcept {
        rgba_f[0] = static_cast<float>(this->red()) / 0xFF;
        rgba_f[1] = static_cast<float>(this->green()) / 0xFF;
        rgba_f[2] = static_cast<float>(this->blue()) / 0xFF;
        rgba_f[3] = static_cast<float>(this->alpha()) / 0xFF;
    }

    constexpr uint8_t red() const noexcept { return uint8_t(pixel & 0xFF); }
    constexpr uint8_t green() const noexcept {
        return uint8_t((pixel & 0xFF00) >> 8);
    }
    constexpr uint8_t blue() const noexcept {
        return uint8_t((pixel & 0xFF0000) >> 16);
    }
    constexpr uint8_t alpha() const noexcept {
        return (pixel & 0xFF000000) >> 24;
    }

    constexpr RGBA& set_red(uint8_t v) noexcept {
        pixel = (pixel & 0x00FFFFFF) | (v << 24);
        return *this;
    }

    constexpr RGBA& set_green(uint8_t v) noexcept {
        pixel = (pixel & 0xFF00FFFF) | (v << 16);
        return *this;
    }

    constexpr RGBA& set_blue(uint8_t v) noexcept {
        pixel = (pixel & 0xFFFF00FF) | (v << 8);
        return *this;
    }

    constexpr RGBA& set_alpha(uint8_t v) noexcept {
        pixel = (pixel & 0xFFFFFF00) | v;
        return *this;
    }
};
} // namespace paradiso

#endif