Compare commits
4 Commits
01815dfde5
...
09b6481136
| Author | SHA1 | Date | |
|---|---|---|---|
| 09b6481136 | |||
| 2999362194 | |||
| 2d9eda7a47 | |||
| 36e06f767b |
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "types.h"
|
||||
#include "types/types.h"
|
||||
|
||||
template <typename E>
|
||||
struct is_flag_enum : std::false_type {
|
||||
|
||||
104
src/core/logger.cpp
Normal file
104
src/core/logger.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "logger.h"
|
||||
|
||||
#include <spdlog/async.h>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/sinks/basic_file_sink.h>
|
||||
#include <spdlog/sinks/rotating_file_sink.h>
|
||||
|
||||
mirai::logger::logger(logger_config config) : config_(config){
|
||||
sinks_.clear();
|
||||
|
||||
if (config_.console_enabled) {
|
||||
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
|
||||
console_sink->set_level(to_spdlog_level(config_.level));
|
||||
sinks_.push_back(console_sink);
|
||||
}
|
||||
|
||||
if (config_.file_enabled) {
|
||||
auto log_dir = config_.file_path.parent_path();
|
||||
if (!log_dir.empty() && !std::filesystem::exists(log_dir)) {
|
||||
std::filesystem::create_directory(log_dir);
|
||||
}
|
||||
|
||||
if (config_.file_rotation_enabled) {
|
||||
auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
|
||||
config_.file_path.string(),
|
||||
config_.max_file_size,
|
||||
config_.max_files
|
||||
);
|
||||
file_sink->set_level(to_spdlog_level(config_.level));
|
||||
sinks_.push_back(file_sink);
|
||||
} else {
|
||||
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(
|
||||
config_.file_path.string(),
|
||||
true
|
||||
);
|
||||
file_sink->set_level(to_spdlog_level(config_.level));
|
||||
sinks_.push_back(file_sink);
|
||||
}
|
||||
}
|
||||
|
||||
if (config_.async_enabled) {
|
||||
// 初始化异步日志线程池
|
||||
spdlog::init_thread_pool(config_.async_queue_size, 1);
|
||||
spdlog_logger_ = std::make_shared<spdlog::async_logger>(
|
||||
config_.name,
|
||||
sinks_.begin(),
|
||||
sinks_.end(),
|
||||
spdlog::thread_pool(),
|
||||
spdlog::async_overflow_policy::block
|
||||
);
|
||||
} else {
|
||||
spdlog_logger_ = std::make_shared<spdlog::logger>(
|
||||
config_.name,
|
||||
sinks_.begin(),
|
||||
sinks_.end()
|
||||
);
|
||||
}
|
||||
|
||||
// 设置日志级别
|
||||
spdlog_logger_->set_level(to_spdlog_level(config_.level));
|
||||
|
||||
// 设置日志格式
|
||||
spdlog_logger_->set_pattern(config_.pattern);
|
||||
|
||||
// 设置刷新策略
|
||||
spdlog_logger_->flush_on(spdlog::level::warn);
|
||||
|
||||
// 注册到 spdlog
|
||||
spdlog::register_logger(spdlog_logger_);
|
||||
}
|
||||
|
||||
mirai::logger::~logger() {
|
||||
if (spdlog_logger_) {
|
||||
spdlog_logger_->flush();
|
||||
spdlog::drop(spdlog_logger_->name());
|
||||
}
|
||||
}
|
||||
|
||||
void mirai::logger::set_level(log_level level) {
|
||||
config_.level = level;
|
||||
if (spdlog_logger_) {
|
||||
spdlog_logger_->set_level(to_spdlog_level(level));
|
||||
}
|
||||
for (auto& sink : sinks_) {
|
||||
sink->set_level(to_spdlog_level(level));
|
||||
}
|
||||
}
|
||||
|
||||
void mirai::logger::set_pattern(const std::string& pattern) {
|
||||
config_.pattern = pattern;
|
||||
if (spdlog_logger_) {
|
||||
spdlog_logger_->set_pattern(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
bool mirai::logger::should_log(log_level level) const noexcept {
|
||||
return spdlog_logger_ && spdlog_logger_->should_log(to_spdlog_level(level));
|
||||
}
|
||||
|
||||
void mirai::logger::flush() {
|
||||
if (spdlog_logger_) {
|
||||
spdlog_logger_->flush();
|
||||
}
|
||||
}
|
||||
347
src/core/logger.h
Normal file
347
src/core/logger.h
Normal file
@@ -0,0 +1,347 @@
|
||||
#pragma once
|
||||
#include <filesystem>
|
||||
#include <source_location>
|
||||
#include <string_view>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "types/types.h"
|
||||
|
||||
namespace mirai {
|
||||
enum class log_level : u8 {
|
||||
trace = 0,
|
||||
debug = 1,
|
||||
info = 2,
|
||||
warn = 3,
|
||||
error = 4,
|
||||
critical = 5,
|
||||
off = 6
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr std::string_view log_level_to_string(log_level level) noexcept {
|
||||
switch (level) {
|
||||
case log_level::trace: return "trace";
|
||||
case log_level::debug: return "debug";
|
||||
case log_level::info: return "info";
|
||||
case log_level::warn: return "warn";
|
||||
case log_level::error: return "error";
|
||||
case log_level::critical: return "critical";
|
||||
case log_level::off: return "off";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr spdlog::level::level_enum to_spdlog_level(log_level level) noexcept {
|
||||
switch (level) {
|
||||
case log_level::trace: return spdlog::level::trace;
|
||||
case log_level::debug: return spdlog::level::debug;
|
||||
case log_level::info: return spdlog::level::info;
|
||||
case log_level::warn: return spdlog::level::warn;
|
||||
case log_level::error: return spdlog::level::err;
|
||||
case log_level::critical: return spdlog::level::critical;
|
||||
case log_level::off: return spdlog::level::off;
|
||||
default: return spdlog::level::info;
|
||||
}
|
||||
}
|
||||
|
||||
struct logger_config {
|
||||
std::string name{"mirai"};
|
||||
log_level level{log_level::info};
|
||||
bool console_enabled{true};
|
||||
bool file_enabled{true};
|
||||
std::filesystem::path file_path{"logs/mirai.log"};
|
||||
bool file_rotation_enabled{true};
|
||||
size_type max_file_size{10 * 1024 * 1024}; // 10 MB
|
||||
size_type max_files{5};
|
||||
std::string pattern{"[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] [%t] %v"};
|
||||
bool include_source_location{true};
|
||||
bool async_enabled{false};
|
||||
size_type async_queue_size{8192};
|
||||
};
|
||||
|
||||
class logger {
|
||||
public:
|
||||
explicit logger(logger_config config = {});
|
||||
~logger();
|
||||
|
||||
logger(const logger&) = delete;
|
||||
logger& operator=(const logger&) = delete;
|
||||
|
||||
[[nodiscard]] const auto& name() const noexcept { return config_.name; }
|
||||
[[nodiscard]] auto level() const noexcept { return config_.level; }
|
||||
void set_level(log_level level);
|
||||
void set_pattern(const std::string& pattern);
|
||||
[[nodiscard]] bool should_log(log_level level) const noexcept;
|
||||
void flush();
|
||||
|
||||
template <typename... Args>
|
||||
void trace(fmt::format_string<Args...> fmt, Args&&... args) {
|
||||
log(log_level::trace, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void debug(fmt::format_string<Args...> fmt, Args&&... args) {
|
||||
log(log_level::debug, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void info(fmt::format_string<Args...> fmt, Args&&... args) {
|
||||
log(log_level::info, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void warn(fmt::format_string<Args...> fmt, Args&&... args) {
|
||||
log(log_level::warn, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void error(fmt::format_string<Args...> fmt, Args&&... args) {
|
||||
log(log_level::error, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void critical(fmt::format_string<Args...> fmt, Args&&... args) {
|
||||
log(log_level::critical, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void log(log_level level, fmt::format_string<Args...> fmt, Args&&... args) {
|
||||
if (should_log(level)) {
|
||||
spdlog_logger_->log(to_spdlog_level(level), fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void log_with_location(
|
||||
log_level level,
|
||||
const std::source_location& location,
|
||||
fmt::format_string<Args...> fmt,
|
||||
Args&&... args
|
||||
) {
|
||||
if (should_log(level)) {
|
||||
std::string message = fmt::format(fmt, std::forward<Args>(args)...);
|
||||
std::string full_message = fmt::format(
|
||||
"{} [{}:{}:{}]",
|
||||
message,
|
||||
location.file_name(),
|
||||
location.line(),
|
||||
location.function_name()
|
||||
);
|
||||
spdlog_logger_->log(to_spdlog_level(level), "{}", full_message);
|
||||
}
|
||||
}
|
||||
private:
|
||||
logger_config config_;
|
||||
std::shared_ptr<spdlog::logger> spdlog_logger_;
|
||||
std::vector<spdlog::sink_ptr> sinks_;
|
||||
};
|
||||
|
||||
inline auto& get_global_logger_ref() {
|
||||
static std::shared_ptr<logger> instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
inline auto& get_global_logger_mutex() {
|
||||
static std::mutex mutex;
|
||||
return mutex;
|
||||
}
|
||||
|
||||
inline void init_logger(const logger_config& config = logger_config{}) {
|
||||
std::lock_guard lock(get_global_logger_mutex());
|
||||
get_global_logger_ref() = std::make_shared<logger>(config);
|
||||
}
|
||||
|
||||
inline void shutdown_logger() {
|
||||
std::lock_guard lock(get_global_logger_mutex());
|
||||
if (auto& logger = get_global_logger_ref()) {
|
||||
logger->flush();
|
||||
logger.reset();
|
||||
}
|
||||
spdlog::shutdown();
|
||||
}
|
||||
|
||||
inline auto get_logger() {
|
||||
std::lock_guard lock(get_global_logger_mutex());
|
||||
auto& logger = get_global_logger_ref();
|
||||
if (!logger) {
|
||||
// 自动初始化默认日志器
|
||||
logger = std::make_shared<mirai::logger>();}
|
||||
return logger;
|
||||
}
|
||||
|
||||
inline void set_log_level(log_level level) {
|
||||
if (auto logger = get_logger()) {
|
||||
logger->set_level(level);
|
||||
}
|
||||
}
|
||||
|
||||
inline void flush_logger() {
|
||||
if (auto logger = get_logger()) {
|
||||
logger->flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 记录 trace 级别日志
|
||||
* @tparam Args 参数类型
|
||||
* @param fmt 格式字符串
|
||||
* @param args 格式参数
|
||||
*/
|
||||
template<typename... Args>
|
||||
void log_trace(fmt::format_string<Args...> fmt, Args&&... args) {
|
||||
if (auto logger = get_logger()) {
|
||||
logger->trace(fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 记录 debug 级别日志
|
||||
* @tparam Args 参数类型
|
||||
* @param fmt 格式字符串
|
||||
* @param args 格式参数
|
||||
*/
|
||||
template<typename... Args>
|
||||
void log_debug(fmt::format_string<Args...> fmt, Args&&... args) {
|
||||
if (auto logger = get_logger()) {
|
||||
logger->debug(fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 记录 info 级别日志
|
||||
* @tparam Args 参数类型
|
||||
* @param fmt 格式字符串
|
||||
* @param args 格式参数
|
||||
*/
|
||||
template<typename... Args>
|
||||
void log_info(fmt::format_string<Args...> fmt, Args&&... args) {
|
||||
if (auto logger = get_logger()) {
|
||||
logger->info(fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 记录 warn 级别日志
|
||||
* @tparam Args 参数类型
|
||||
* @param fmt 格式字符串
|
||||
* @param args 格式参数
|
||||
*/
|
||||
template<typename... Args>
|
||||
void log_warn(fmt::format_string<Args...> fmt, Args&&... args) {
|
||||
if (auto logger = get_logger()) {
|
||||
logger->warn(fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 记录 error 级别日志
|
||||
* @tparam Args 参数类型
|
||||
* @param fmt 格式字符串
|
||||
* @param args 格式参数
|
||||
*/
|
||||
template<typename... Args>
|
||||
void log_error(fmt::format_string<Args...> fmt, Args&&... args) {
|
||||
if (auto logger = get_logger()) {
|
||||
logger->error(fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 记录 critical 级别日志
|
||||
* @tparam Args 参数类型
|
||||
* @param fmt 格式字符串
|
||||
* @param args 格式参数
|
||||
*/
|
||||
template<typename... Args>
|
||||
void log_critical(fmt::format_string<Args...> fmt, Args&&... args) {
|
||||
if (auto logger = get_logger()) {
|
||||
logger->critical(fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @def MIRAI_LOG_TRACE(...)
|
||||
* @brief 记录 trace 级别日志
|
||||
*/
|
||||
#define MIRAI_LOG_TRACE(...) ::mirai::log_trace(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @def MIRAI_LOG_DEBUG(...)
|
||||
* @brief 记录 debug 级别日志
|
||||
*/
|
||||
#define MIRAI_LOG_DEBUG(...) ::mirai::log_debug(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @def MIRAI_LOG_INFO(...)
|
||||
* @brief 记录 info 级别日志
|
||||
*/
|
||||
#define MIRAI_LOG_INFO(...) ::mirai::log_info(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @def MIRAI_LOG_WARN(...)
|
||||
* @brief 记录 warn 级别日志
|
||||
*/
|
||||
#define MIRAI_LOG_WARN(...) ::mirai::log_warn(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @def MIRAI_LOG_ERROR(...)
|
||||
* @brief 记录 error 级别日志
|
||||
*/
|
||||
#define MIRAI_LOG_ERROR(...) ::mirai::log_error(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @def MIRAI_LOG_CRITICAL(...)
|
||||
* @brief 记录 critical 级别日志
|
||||
*/
|
||||
#define MIRAI_LOG_CRITICAL(...) ::mirai::log_critical(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @def MIRAI_LOG(level, ...)
|
||||
* @brief 记录指定级别的日志
|
||||
*/
|
||||
#define MIRAI_LOG(level, ...) \
|
||||
do { \
|
||||
if (auto _logger = ::mirai::get_logger()) { \
|
||||
_logger->log(level, __VA_ARGS__); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
/**
|
||||
* @def MIRAI_LOG_IF(condition, level, ...)
|
||||
* @brief 条件日志记录
|
||||
*/
|
||||
#define MIRAI_LOG_IF(condition, level, ...) \
|
||||
do { \
|
||||
if (condition) { \
|
||||
MIRAI_LOG(level, __VA_ARGS__); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
// Debug 模式专用日志宏
|
||||
#if MIRAI_DEBUG
|
||||
|
||||
/**
|
||||
* @def MIRAI_DLOG_TRACE(...)
|
||||
* @brief Debug 模式 trace 日志
|
||||
*/
|
||||
#define MIRAI_DLOG_TRACE(...) MIRAI_LOG_TRACE(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @def MIRAI_DLOG_DEBUG(...)
|
||||
* @brief Debug 模式 debug 日志
|
||||
*/
|
||||
#define MIRAI_DLOG_DEBUG(...) MIRAI_LOG_DEBUG(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @def MIRAI_DLOG_INFO(...)
|
||||
* @brief Debug 模式 info 日志
|
||||
*/
|
||||
#define MIRAI_DLOG_INFO(...) MIRAI_LOG_INFO(__VA_ARGS__)
|
||||
|
||||
#else
|
||||
|
||||
#define MIRAI_DLOG_TRACE(...) ((void)0)
|
||||
#define MIRAI_DLOG_DEBUG(...) ((void)0)
|
||||
#define MIRAI_DLOG_INFO(...) ((void)0)
|
||||
|
||||
#endif
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "types.h"
|
||||
#include "types/types.h"
|
||||
#include "property.h"
|
||||
|
||||
namespace mirai {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <string_view>
|
||||
|
||||
#include "flag_enum.h"
|
||||
#include "types.h"
|
||||
#include "types/types.h"
|
||||
|
||||
namespace mirai {
|
||||
class object;
|
||||
|
||||
203
src/types/color.h
Normal file
203
src/types/color.h
Normal file
@@ -0,0 +1,203 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace mirai {
|
||||
/**
|
||||
* @brief 颜色类型 (RGBA)
|
||||
*/
|
||||
template<typename T = f32>
|
||||
struct color {
|
||||
T r{0.0}; ///< 红色分量 (0-1)
|
||||
T g{0.0}; ///< 绿色分量 (0-1)
|
||||
T b{0.0}; ///< 蓝色分量 (0-1)
|
||||
T a{1.0}; ///< 透明度 (0-1)
|
||||
|
||||
constexpr color() noexcept = default;
|
||||
|
||||
constexpr color(T r_, T g_, T b_, T a_ = 1.0) noexcept : r(r_), g(g_), b(b_), a(a_) {
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr color operator+(const color& other) const noexcept {
|
||||
return color{r + other.r, g + other.g, b + other.b, a + other.a};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr color operator-(const color& other) const noexcept {
|
||||
return color{r - other.r, g - other.g, b - other.b, a - other.a};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr color operator*(f64 scalar) const noexcept {
|
||||
return color{r * scalar, g * scalar, b * scalar, a * scalar};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(const color& other) const noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief 从 RGB 整数值创建颜色
|
||||
* @param r_ 红色 (0-255)
|
||||
* @param g_ 绿色 (0-255)
|
||||
* @param b_ 蓝色 (0-255)
|
||||
* @param a_ 透明度 (0-255)
|
||||
* @return 颜色对象
|
||||
*/
|
||||
[[nodiscard]] static constexpr color from_rgb(u8 r_, u8 g_, u8 b_, u8 a_ = 255) noexcept {
|
||||
return color{
|
||||
static_cast<T>(r_) / 255.0,
|
||||
static_cast<T>(g_) / 255.0,
|
||||
static_cast<T>(b_) / 255.0,
|
||||
static_cast<T>(a_) / 255.0
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从十六进制值创建颜色
|
||||
* @param hex 十六进制值 (0xRRGGBB 或 0xRRGGBBAA)
|
||||
* @return 颜色对象
|
||||
*/
|
||||
[[nodiscard]] static constexpr color from_hex(u32 hex) noexcept {
|
||||
if (hex <= 0xFFFFFF) {
|
||||
// 0xRRGGBB 格式
|
||||
return from_rgb(
|
||||
static_cast<u8>((hex >> 16) & 0xFF),
|
||||
static_cast<u8>((hex >> 8) & 0xFF),
|
||||
static_cast<u8>(hex & 0xFF)
|
||||
);
|
||||
}
|
||||
// 0xRRGGBBAA 格式
|
||||
return from_rgb(
|
||||
static_cast<u8>((hex >> 24) & 0xFF),
|
||||
static_cast<u8>((hex >> 16) & 0xFF),
|
||||
static_cast<u8>((hex >> 8) & 0xFF),
|
||||
static_cast<u8>(hex & 0xFF)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从 32 位 RGBA 整数创建
|
||||
* @param rgba 0xRRGGBBAA 格式的颜色值
|
||||
* @return 颜色对象
|
||||
*/
|
||||
[[nodiscard]] static constexpr color from_rgba(u32 rgba) noexcept {
|
||||
return color{
|
||||
static_cast<f32>((rgba >> 24) & 0xFF) / 255.0f,
|
||||
static_cast<f32>((rgba >> 16) & 0xFF) / 255.0f,
|
||||
static_cast<f32>((rgba >> 8) & 0xFF) / 255.0f,
|
||||
static_cast<f32>(rgba & 0xFF) / 255.0f
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从 32 位 ARGB 整数创建
|
||||
* @param argb 0xAARRGGBB 格式的颜色值
|
||||
* @return 颜色对象
|
||||
*/
|
||||
[[nodiscard]] static constexpr color from_argb(u32 argb) noexcept {
|
||||
return color{
|
||||
static_cast<f32>((argb >> 16) & 0xFF) / 255.0f,
|
||||
static_cast<f32>((argb >> 8) & 0xFF) / 255.0f,
|
||||
static_cast<f32>(argb & 0xFF) / 255.0f,
|
||||
static_cast<f32>((argb >> 24) & 0xFF) / 255.0f
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从 HSL 创建颜色
|
||||
* @param h 色相 [0.0, 360.0)
|
||||
* @param s 饱和度 [0.0, 1.0]
|
||||
* @param l 亮度 [0.0, 1.0]
|
||||
* @param a 透明度 [0.0, 1.0]
|
||||
* @return 颜色对象
|
||||
*/
|
||||
[[nodiscard]] static color from_hsl(f32 h, f32 s, f32 l, f32 a = 1.0f) noexcept {
|
||||
f32 c = (1.0f - std::fabs(2.0f * l - 1.0f)) * s;
|
||||
f32 x = c * (1.0f - std::fabs(std::fmod(h / 60.0f, 2.0f) - 1.0f));
|
||||
f32 m = l - c / 2.0f;
|
||||
|
||||
f32 r1 = 0.0f, g1 = 0.0f, b1 = 0.0f;
|
||||
|
||||
if (h >= 0.0f && h < 60.0f) {
|
||||
r1 = c; g1 = x; b1 = 0.0f;
|
||||
}
|
||||
else if (h >= 60.0f && h < 120.0f) {
|
||||
r1 = x; g1 = c; b1 = 0.0f;
|
||||
}
|
||||
else if (h >= 120.0f && h < 180.0f) {
|
||||
r1 = 0.0f; g1 = c; b1 = x;
|
||||
}
|
||||
else if (h >= 180.0f && h < 240.0f) {
|
||||
r1 = 0.0f; g1 = x; b1 = c;
|
||||
}
|
||||
else if (h >= 240.0f && h < 300.0f) {
|
||||
r1 = x; g1 = 0.0f; b1 = c;
|
||||
}
|
||||
else if (h >= 300.0f && h < 360.0f) {
|
||||
r1 = c; g1 = 0.0f; b1 = x;
|
||||
}
|
||||
|
||||
return color{
|
||||
r1 + m,
|
||||
g1 + m,
|
||||
b1 + m,
|
||||
a
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 转换为 32 位 RGBA 整数
|
||||
* @return 0xRRGGBBAA 格式的颜色值
|
||||
*/
|
||||
[[nodiscard]] constexpr u32 to_rgba() const noexcept {
|
||||
return (static_cast<u32>(r * 255.0f) << 24) |
|
||||
(static_cast<u32>(g * 255.0f) << 16) |
|
||||
(static_cast<u32>(b * 255.0f) << 8) |
|
||||
static_cast<u32>(a * 255.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 转换为 32 位 ARGB 整数
|
||||
* @return 0xAARRGGBB 格式的颜色值
|
||||
*/
|
||||
[[nodiscard]] constexpr u32 to_argb() const noexcept {
|
||||
return (static_cast<u32>(a * 255.0f) << 24) |
|
||||
(static_cast<u32>(r * 255.0f) << 16) |
|
||||
(static_cast<u32>(g * 255.0f) << 8) |
|
||||
static_cast<u32>(b * 255.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 颜色混合
|
||||
* @param other 另一个颜色
|
||||
* @param t 混合因子 [0.0, 1.0]
|
||||
* @return 混合后的颜色
|
||||
*/
|
||||
[[nodiscard]] constexpr color lerp(const color& other, f32 t) const noexcept {
|
||||
return color{
|
||||
r + (other.r - r) * t,
|
||||
g + (other.g - g) * t,
|
||||
b + (other.b - b) * t,
|
||||
a + (other.a - a) * t
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 使用指定透明度创建新颜色
|
||||
* @param alpha 新的透明度值
|
||||
* @return 新颜色
|
||||
*/
|
||||
[[nodiscard]] constexpr color with_alpha(f32 alpha) const noexcept {
|
||||
return color{r, g, b, alpha};
|
||||
}
|
||||
|
||||
// 预定义颜色
|
||||
[[nodiscard]] static constexpr color white() noexcept { return color{1.0, 1.0, 1.0, 1.0}; }
|
||||
[[nodiscard]] static constexpr color black() noexcept { return color{0.0, 0.0, 0.0, 1.0}; }
|
||||
[[nodiscard]] static constexpr color red() noexcept { return color{1.0, 0.0, 0.0, 1.0}; }
|
||||
[[nodiscard]] static constexpr color green() noexcept { return color{0.0, 1.0, 0.0, 1.0}; }
|
||||
[[nodiscard]] static constexpr color blue() noexcept { return color{0.0, 0.0, 1.0, 1.0}; }
|
||||
[[nodiscard]] static constexpr color transparent() noexcept { return color{0.0, 0.0, 0.0, 0.0}; }
|
||||
[[nodiscard]] static constexpr color yellow() noexcept { return color{1.0, 1.0, 0.0, 1.0}; }
|
||||
[[nodiscard]] static constexpr color cyan() noexcept { return color{0.0, 1.0, 1.0, 1.0}; }
|
||||
[[nodiscard]] static constexpr color magenta() noexcept { return color{1.0, 0.0, 1.0, 1.0}; }
|
||||
[[nodiscard]] static constexpr color gray() noexcept { return color{0.5, 0.5, 0.5, 1.0}; }
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user