color从字符串初始化,在CMake中添加资源文件
This commit is contained in:
parent
1c3aee5ca1
commit
fe1ca8998c
@ -30,17 +30,22 @@ else ()
|
||||
endif ()
|
||||
add_definitions(-DMIRAGE_HDR_FORMAT=${MIRAGE_HDR_FORMAT} -DMIRAGE_PIXEL_FORMAT=${MIRAGE_PIXEL_FORMAT})
|
||||
|
||||
# 配置输出目录
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(MIRAGE_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
include(cmake/retrieve_files.cmake)
|
||||
include(cmake/detect_os.cmake)
|
||||
include(cmake/config_macos.cmake)
|
||||
include(cmake/compile_shaders.cmake)
|
||||
include(cmake/mingw_dll.cmake)
|
||||
include(cmake/mirage_utils.cmake)
|
||||
|
||||
# 配置输出目录
|
||||
configure_project_defaults()
|
||||
|
||||
# --- 设置项目根目录变量 ---
|
||||
# **定义项目源代码根目录变量**:
|
||||
# CMAKE_CURRENT_SOURCE_DIR 在根 CMakeLists.txt 中即为项目源代码的根目录
|
||||
# 使用 PARENT_SCOPE 使该变量在调用此函数的 CMakeLists.txt 文件中也可用
|
||||
set(MIRAGE_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
message(STATUS "mirage 项目根源目录 (MIRAGE_ROOT_DIR) 设置为: ${MIRAGE_ROOT_DIR}")
|
||||
|
||||
# 如果是Debug模式, 添加宏定义
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
|
44
cmake/mirage_utils.cmake
Normal file
44
cmake/mirage_utils.cmake
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
# 定义一个函数来配置项目的默认设置
|
||||
# 这包括设置输出目录和项目根目录变量
|
||||
function(configure_project_defaults)
|
||||
# 检查是否在顶层 CMakeLists.txt 中调用 (可选但推荐)
|
||||
# 确保 CMAKE_SOURCE_DIR 和 CMAKE_CURRENT_SOURCE_DIR 相同
|
||||
if(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
message(WARNING "configure_project_defaults() 应该在项目的根 CMakeLists.txt 中调用。")
|
||||
# 如果您确实需要在子目录中设置不同的根目录,请调整此逻辑
|
||||
endif()
|
||||
|
||||
# --- 配置输出目录 ---
|
||||
# 使用 CMAKE_BINARY_DIR 作为基础构建目录
|
||||
# ${CMAKE_BINARY_DIR} 指向您配置 CMake 时指定的构建目录
|
||||
# 例如,在 CLion 中通常是 cmake-build-debug 或 cmake-build-release
|
||||
# 如果手动运行 cmake ..,它就是您运行 cmake 命令的目录
|
||||
|
||||
# **设置可执行文件输出路径**:
|
||||
# 对于单配置生成器 (如 Makefiles, Ninja), 可执行文件将位于 <build>/bin/
|
||||
# 对于多配置生成器 (如 Visual Studio, Xcode), CMake 通常会自动在此路径下附加配置名称
|
||||
# (例如 <build>/bin/Debug/, <build>/bin/Release/)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin CACHE PATH "Directory for runtime executables")
|
||||
message(STATUS "运行时输出目录设置为: ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
|
||||
|
||||
# **设置库文件输出路径 (共享库和静态库)**:
|
||||
# 规则同上,库文件将位于 <build>/lib/ 或 <build>/lib/<Config>/
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib CACHE PATH "Directory for shared libraries")
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib CACHE PATH "Directory for static libraries")
|
||||
message(STATUS "库输出目录设置为: ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
|
||||
message(STATUS "存档输出目录设置为: ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}")
|
||||
|
||||
# --- 提示 ---
|
||||
# 这种全局设置输出目录的方法对于中小型项目是常见的。
|
||||
# 对于更复杂的项目或需要更细粒度控制的情况,可以考虑为每个目标(target)单独设置输出目录属性:
|
||||
# 例如:
|
||||
# add_executable(my_app main.cpp)
|
||||
# set_target_properties(my_app PROPERTIES
|
||||
# RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/executables"
|
||||
# )
|
||||
# add_library(my_lib STATIC my_lib.cpp)
|
||||
# set_target_properties(my_lib PROPERTIES
|
||||
# ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/static_libs"
|
||||
# )
|
||||
endfunction()
|
@ -155,4 +155,85 @@ function(retrieve_files path out_files)
|
||||
|
||||
# 合并结果到输出变量
|
||||
set(${out_files} ${${out_files}} ${temp_files} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
#[=======================================================================[
|
||||
用于添加资源文件并在编译后复制到目标文件 (可执行文件或库) 所在目录
|
||||
参数:
|
||||
TARGET_NAME: 目标 (可执行文件或库) 的名称
|
||||
RESOURCE_FILE_PATHS - 一个或多个要复制的资源文件的路径 (可以是相对或绝对路径)
|
||||
#]=======================================================================]
|
||||
function(add_resources TARGET_NAME)
|
||||
# 获取 TARGET_NAME 之后的所有参数作为资源文件列表
|
||||
set(RESOURCE_FILES ${ARGN})
|
||||
|
||||
# 检查目标是否存在 (可选,但推荐)
|
||||
if(NOT TARGET ${TARGET_NAME})
|
||||
message(FATAL_ERROR "目标 '${TARGET_NAME}' 不存在,无法添加资源。")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# **获取目标可执行文件的输出目录** (只需执行一次)
|
||||
# 对于多配置生成器 (如 Visual Studio, Xcode),使用 $<TARGET_FILE_DIR:TARGET_NAME>
|
||||
# 对于单配置生成器 (如 Makefiles, Ninja),使用 CMAKE_RUNTIME_OUTPUT_DIRECTORY 或 $<TARGET_FILE_DIR:TARGET_NAME>
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
set(DESTINATION_DIR "$<TARGET_FILE_DIR:${TARGET_NAME}>")
|
||||
else()
|
||||
if(CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
||||
set(DESTINATION_DIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
|
||||
else()
|
||||
# 使用 $<TARGET_FILE_DIR:TARGET_NAME> 通常更健壮
|
||||
set(DESTINATION_DIR "$<TARGET_FILE_DIR:${TARGET_NAME}>")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# **遍历所有传入的资源文件**
|
||||
foreach(RESOURCE_FILE ${RESOURCE_FILES})
|
||||
set(ABS_RESOURCE_FILE "") # 重置/初始化
|
||||
|
||||
# **处理相对路径和绝对路径,并检查文件是否存在**
|
||||
if(IS_ABSOLUTE "${RESOURCE_FILE}")
|
||||
# 如果是绝对路径,直接检查是否存在
|
||||
if(EXISTS "${RESOURCE_FILE}")
|
||||
set(ABS_RESOURCE_FILE "${RESOURCE_FILE}")
|
||||
else()
|
||||
message(WARNING "资源文件未找到 (绝对路径,将跳过): ${RESOURCE_FILE}")
|
||||
continue() # 处理下一个文件
|
||||
endif()
|
||||
else()
|
||||
# 如果是相对路径,相对于当前 CMakeLists.txt 文件所在目录解析
|
||||
set(TEMP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_FILE}")
|
||||
if(EXISTS "${TEMP_PATH}")
|
||||
set(ABS_RESOURCE_FILE "${TEMP_PATH}")
|
||||
else()
|
||||
message(WARNING "资源文件未找到 (相对路径,将跳过): ${RESOURCE_FILE} (相对于: ${CMAKE_CURRENT_SOURCE_DIR})")
|
||||
continue() # 处理下一个文件
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# **检查是否是文件而非目录** (copy_if_different 用于文件)
|
||||
if(IS_DIRECTORY "${ABS_RESOURCE_FILE}")
|
||||
message(WARNING "提供的资源是一个目录,而非文件 (将跳过): ${ABS_RESOURCE_FILE}. 请使用其他方法复制目录。")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# **获取资源文件的文件名部分**
|
||||
get_filename_component(RESOURCE_FILENAME "${ABS_RESOURCE_FILE}" NAME)
|
||||
|
||||
# **为每个文件添加自定义构建后命令**
|
||||
add_custom_command(
|
||||
TARGET ${TARGET_NAME} # 关联到目标
|
||||
POST_BUILD # 在目标构建完成后执行
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different # 使用 cmake 内建命令复制文件 (仅在文件不同时复制)
|
||||
"${ABS_RESOURCE_FILE}" # 源文件 (绝对路径)
|
||||
"${DESTINATION_DIR}/${RESOURCE_FILENAME}" # **目标路径** (可执行文件目录 + 文件名)
|
||||
COMMENT "正在复制资源 ${RESOURCE_FILENAME} 到 ${TARGET_NAME} 的输出目录" # 构建时显示的注释
|
||||
VERBATIM # 确保特殊字符被正确处理
|
||||
)
|
||||
|
||||
# (可选) 将资源文件添加到目标源文件中,以便在某些 IDE 中显示
|
||||
# 注意:如果文件不在源目录树下,某些 IDE 可能不会正确显示
|
||||
# target_sources(${TARGET_NAME} PRIVATE "${ABS_RESOURCE_FILE}")
|
||||
|
||||
endforeach()
|
||||
endfunction()
|
@ -11,6 +11,10 @@
|
||||
int main(int argc, char* argv[]) {
|
||||
mirage_app::get().init();
|
||||
|
||||
auto c1 = linear_color::from_string("#FF0000");
|
||||
auto c2 = linear_color::from_string("rgb(255, 0, 0)");
|
||||
auto c3 = linear_color::from_string("rgba(255, 0, 0, 255)");
|
||||
|
||||
auto& manager = font_manager::instance();
|
||||
manager.add_font(L"C:/Users/46944/AppData/Local/Microsoft/Windows/Fonts/MapleMono-NF-CN-Regular.ttf");
|
||||
manager.add_font(L"C:/Windows/Fonts/msyh.ttc");
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "window/mwindow.h"
|
||||
#include "misc/mirage_scoped_duration_timer.h"
|
||||
#include "platform_window/platform_window.h"
|
||||
#include "style/mirage_style.h"
|
||||
|
||||
void mirage_log(const char* tag, uint32_t log_level, uint32_t log_item_id, const char* message_or_null,
|
||||
uint32_t line_nr, const char* filename_or_null, void* user_data) {
|
||||
@ -57,6 +58,9 @@ void mirage_app::init() {
|
||||
mirage_scoped_duration_timer timer(duration);
|
||||
|
||||
last_time = get_current_time();
|
||||
if (!mirage_style::get().load_config("default_style.toml")) {
|
||||
fprintf(stderr, "mirage: 无法加载样式配置\n");
|
||||
}
|
||||
render_context = mirage_create_render_context();
|
||||
render_context->init();
|
||||
const sg_desc desc = {
|
||||
@ -70,7 +74,7 @@ void mirage_app::init() {
|
||||
render_context->end_init();
|
||||
}
|
||||
// 初始化用时
|
||||
std::cout << "mirage: " << "Initialization took " << std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() << "ms" << std::endl;
|
||||
fprintf(stderr, "mirage: 初始化耗时 %lld ms\n", std::chrono::duration_cast<std::chrono::milliseconds>(duration).count());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* name_t
|
||||
|
@ -3,108 +3,156 @@
|
||||
#include <charconv>
|
||||
#include <vector>
|
||||
|
||||
linear_color linear_color::from_string(const std::string& in_str) {
|
||||
// **定义一个表示无效输入的默认返回值 (C++20 designated initializers)**
|
||||
// Made static constexpr for potential compile-time use if needed elsewhere
|
||||
static linear_color invalid_color = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
|
||||
std::string str = in_str;
|
||||
|
||||
// **1. 去除前后空格 (No major C++23 change here, std::find_if is efficient)**
|
||||
auto trim_func = [](unsigned char ch){ return !std::isspace(ch); };
|
||||
str.erase(str.begin(), std::ranges::find_if(str, trim_func));
|
||||
str.erase(std::find_if(str.rbegin(), str.rend(), trim_func).base(), str.end());
|
||||
|
||||
// **2. 检查格式前缀和后缀 (C++20 starts_with/ends_with)**
|
||||
bool is_rgba = false;
|
||||
std::string_view value_part_sv;
|
||||
|
||||
if (str.starts_with("rgb(") && str.ends_with(')')) {
|
||||
is_rgba = false;
|
||||
value_part_sv = std::string_view(str).substr(4, str.length() - 5); // Skip "rgb(" and ")"
|
||||
} else if (str.starts_with("rgba(") && str.ends_with(')')) {
|
||||
is_rgba = true;
|
||||
value_part_sv = std::string_view(str).substr(5, str.length() - 6); // Skip "rgba(" and ")"
|
||||
} else {
|
||||
return invalid_color; // **无效格式前缀/后缀**
|
||||
}
|
||||
|
||||
if (value_part_sv.empty() && (is_rgba ? 4 : 3) > 0) {
|
||||
// Handle cases like "rgb()" or "rgba()" which are invalid if components are expected
|
||||
return invalid_color; // **括号内为空**
|
||||
}
|
||||
|
||||
// **3. 分割数值字符串 (Using stringstream, C++23 views could be an alternative but more complex here)**
|
||||
std::vector<float> values;
|
||||
std::stringstream ss;
|
||||
ss << value_part_sv;
|
||||
std::string segment;
|
||||
|
||||
while (std::getline(ss, segment, ',')) {
|
||||
// **4. 处理每个分量**
|
||||
// 去除分量前后的空格
|
||||
segment.erase(segment.begin(), std::ranges::find_if(segment, trim_func));
|
||||
segment.erase(std::find_if(segment.rbegin(), segment.rend(), trim_func).base(), segment.end());
|
||||
|
||||
if (segment.empty()) {
|
||||
return invalid_color; // **空分量值**
|
||||
}
|
||||
|
||||
const char* const first = segment.data();
|
||||
const char* const last = first + segment.size();
|
||||
float component_value = 0.0f;
|
||||
|
||||
// **C++23 std::string::contains to check for decimal point**
|
||||
if (segment.contains('.')) {
|
||||
// **处理浮点数 [0, 1]**
|
||||
float val = 0.0f;
|
||||
auto [ptr, ec] = std::from_chars(first, last, val);
|
||||
|
||||
// Check for errors: conversion failed OR not the entire segment was parsed
|
||||
if (ec != std::errc() || ptr != last) {
|
||||
return invalid_color; // **无效浮点数格式**
|
||||
}
|
||||
|
||||
// Check range [0, 1] for floats
|
||||
if (val < 0.0f || val > 1.0f) {
|
||||
return invalid_color; // **浮点数值超出 [0, 1] 范围**
|
||||
}
|
||||
component_value = val;
|
||||
|
||||
} else {
|
||||
// **处理整数 [0, 255]**
|
||||
int int_val = 0;
|
||||
auto [ptr, ec] = std::from_chars(first, last, int_val);
|
||||
|
||||
// Check for errors: conversion failed OR not the entire segment was parsed
|
||||
if (ec != std::errc() || ptr != last) {
|
||||
return invalid_color; // **无效整数格式**
|
||||
}
|
||||
|
||||
// Check range [0, 255] for integers
|
||||
if (int_val < 0 || int_val > 255) {
|
||||
return invalid_color; // **整数值超出 [0, 255] 范围**
|
||||
}
|
||||
|
||||
// **归一化: 将 uint8 范围的值映射到 [0, 1] float**
|
||||
component_value = static_cast<float>(int_val) / 255.0f;
|
||||
}
|
||||
|
||||
values.push_back(component_value);
|
||||
}
|
||||
|
||||
// **5. 检查分量数量是否匹配**
|
||||
if (is_rgba) {
|
||||
if (values.size() != 4) {
|
||||
return invalid_color; // **rgba 分量数量错误**
|
||||
}
|
||||
return { values[0], values[1], values[2], values[3] };
|
||||
}
|
||||
|
||||
// rgb
|
||||
if (values.size() != 3) {
|
||||
return invalid_color; // **rgb 分量数量错误**
|
||||
}
|
||||
// **对于 rgb,alpha 默认为 1.0f**
|
||||
return { values[0], values[1], values[2], 1.f };
|
||||
/**
|
||||
* @brief 将十六进制字符转换为整数值
|
||||
*
|
||||
* @param hex 十六进制字符 (0-9, A-F, a-f)
|
||||
* @return 对应的整数值 (0-15),如果字符无效则返回-1
|
||||
*/
|
||||
int hex_char_to_int(char hex) {
|
||||
if (hex >= '0' && hex <= '9')
|
||||
return hex - '0';
|
||||
if (hex >= 'A' && hex <= 'F')
|
||||
return hex - 'A' + 10;
|
||||
if (hex >= 'a' && hex <= 'f')
|
||||
return hex - 'a' + 10;
|
||||
return -1; // 无效字符
|
||||
}
|
||||
|
||||
std::optional<linear_color> linear_color::from_string(const std::string& in_str) {
|
||||
linear_color result{};
|
||||
|
||||
// 处理十六进制格式
|
||||
if (!in_str.empty() && in_str[0] == '#') {
|
||||
// **支持的十六进制格式:** #RGB, #RGBA, #RRGGBB, #RRGGBBAA
|
||||
size_t length = in_str.length();
|
||||
|
||||
// 检查格式并解析
|
||||
if (length == 4) { // #RGB 格式
|
||||
// 检查所有字符是否都是有效的十六进制数字
|
||||
for (int i = 1; i < 4; i++) {
|
||||
if (!std::isxdigit(in_str[i]))
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// 对于 #RGB 格式,每个字符需要重复:R -> RR, G -> GG, B -> BB
|
||||
int r = hex_char_to_int(in_str[1]);
|
||||
int g = hex_char_to_int(in_str[2]);
|
||||
int b = hex_char_to_int(in_str[3]);
|
||||
|
||||
// 将 0-15 的值扩展到 0-255 的范围
|
||||
result.r = (r * 16 + r) / 255.0f;
|
||||
result.g = (g * 16 + g) / 255.0f;
|
||||
result.b = (b * 16 + b) / 255.0f;
|
||||
result.a = 1.0f; // 默认为完全不透明
|
||||
|
||||
return result;
|
||||
}
|
||||
if (length == 5) { // #RGBA 格式
|
||||
// 检查所有字符是否都是有效的十六进制数字
|
||||
for (int i = 1; i < 5; i++) {
|
||||
if (!std::isxdigit(in_str[i]))
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
int r = hex_char_to_int(in_str[1]);
|
||||
int g = hex_char_to_int(in_str[2]);
|
||||
int b = hex_char_to_int(in_str[3]);
|
||||
int a = hex_char_to_int(in_str[4]);
|
||||
|
||||
// 将 0-15 的值扩展到 0-255 的范围
|
||||
result.r = (r * 16 + r) / 255.0f;
|
||||
result.g = (g * 16 + g) / 255.0f;
|
||||
result.b = (b * 16 + b) / 255.0f;
|
||||
result.a = (a * 16 + a) / 255.0f;
|
||||
|
||||
return result;
|
||||
}
|
||||
if (length == 7) { // #RRGGBB 格式
|
||||
// 检查所有字符是否都是有效的十六进制数字
|
||||
for (int i = 1; i < 7; i++) {
|
||||
if (!std::isxdigit(in_str[i]))
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
int r = (hex_char_to_int(in_str[1]) << 4) + hex_char_to_int(in_str[2]);
|
||||
int g = (hex_char_to_int(in_str[3]) << 4) + hex_char_to_int(in_str[4]);
|
||||
int b = (hex_char_to_int(in_str[5]) << 4) + hex_char_to_int(in_str[6]);
|
||||
|
||||
result.r = r / 255.0f;
|
||||
result.g = g / 255.0f;
|
||||
result.b = b / 255.0f;
|
||||
result.a = 1.0f; // 默认为完全不透明
|
||||
|
||||
return result;
|
||||
}
|
||||
if (length == 9) { // #RRGGBBAA 格式
|
||||
// 检查所有字符是否都是有效的十六进制数字
|
||||
for (int i = 1; i < 9; i++) {
|
||||
if (!std::isxdigit(in_str[i]))
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
int r = (hex_char_to_int(in_str[1]) << 4) + hex_char_to_int(in_str[2]);
|
||||
int g = (hex_char_to_int(in_str[3]) << 4) + hex_char_to_int(in_str[4]);
|
||||
int b = (hex_char_to_int(in_str[5]) << 4) + hex_char_to_int(in_str[6]);
|
||||
int a = (hex_char_to_int(in_str[7]) << 4) + hex_char_to_int(in_str[8]);
|
||||
|
||||
result.r = r / 255.0f;
|
||||
result.g = g / 255.0f;
|
||||
result.b = b / 255.0f;
|
||||
result.a = a / 255.0f;
|
||||
|
||||
return result;
|
||||
}
|
||||
// 无效的十六进制格式长度
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// 如果不是十六进制格式,继续处理 RGB/RGBA 格式
|
||||
int r_int, g_int, b_int, a_int = 255; // Alpha 默认值为 255 (对应 1.0f)
|
||||
int components_read = 0;
|
||||
char closing_paren = '\0';
|
||||
|
||||
// 尝试匹配 rgba(r,g,b,a) 格式
|
||||
components_read = std::sscanf(in_str.c_str(), "rgba(%d,%d,%d,%d %c",
|
||||
&r_int, &g_int, &b_int, &a_int, &closing_paren);
|
||||
|
||||
if (components_read == 5 && closing_paren == ')') {
|
||||
// 验证数值范围 [0, 255]
|
||||
if (r_int < 0 || r_int > 255 || g_int < 0 || g_int > 255 ||
|
||||
b_int < 0 || b_int > 255 || a_int < 0 || a_int > 255) {
|
||||
return std::nullopt; // 数值超出范围
|
||||
}
|
||||
|
||||
// 归一化到 [0.0, 1.0]
|
||||
result.r = static_cast<float>(r_int) / 255.0f;
|
||||
result.g = static_cast<float>(g_int) / 255.0f;
|
||||
result.b = static_cast<float>(b_int) / 255.0f;
|
||||
result.a = static_cast<float>(a_int) / 255.0f;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 如果 RGBA 格式不匹配,尝试匹配 rgb(r,g,b) 格式
|
||||
closing_paren = '\0'; // 重置
|
||||
components_read = std::sscanf(in_str.c_str(), "rgb(%d,%d,%d %c",
|
||||
&r_int, &g_int, &b_int, &closing_paren);
|
||||
|
||||
if (components_read == 4 && closing_paren == ')') {
|
||||
// 验证数值范围 [0, 255]
|
||||
if (r_int < 0 || r_int > 255 || g_int < 0 || g_int > 255 ||
|
||||
b_int < 0 || b_int > 255) {
|
||||
return std::nullopt; // 数值超出范围
|
||||
}
|
||||
|
||||
// 归一化到 [0.0, 1.0],Alpha 使用默认值 1.0f
|
||||
result.r = static_cast<float>(r_int) / 255.0f;
|
||||
result.g = static_cast<float>(g_int) / 255.0f;
|
||||
result.b = static_cast<float>(b_int) / 255.0f;
|
||||
result.a = 1.0f;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 所有格式都不匹配
|
||||
return std::nullopt;
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ public:
|
||||
* @note **如果字符串格式无效或颜色分量值无效/超出范围,则返回 linear_color{0.0f, 0.0f, 0.0f, 0.0f}。**
|
||||
* 使用 [[nodiscard]] 提示调用者应检查返回值。
|
||||
*/
|
||||
[[nodiscard]] static linear_color from_string(const std::string& in_str);
|
||||
[[nodiscard]] static std::optional<linear_color> from_string(const std::string& in_str);
|
||||
|
||||
//-------------- 成员变量 --------------
|
||||
|
||||
|
@ -8,3 +8,5 @@ add_subdirectory(third_party/tomlplusplus)
|
||||
add_library(${PROJECT_NAME} STATIC ${SRC_FILES})
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC mirage_core mirage_render tomlplusplus::tomlplusplus)
|
||||
|
||||
add_resources(${PROJECT_NAME} src/style/default_style.toml)
|
||||
|
@ -4,6 +4,7 @@ version = "0.0.1"
|
||||
description = "mirage的默认样式"
|
||||
author = "奶酪"
|
||||
|
||||
|
||||
[button]
|
||||
hover_color = "rgb(31, 31, 31)"
|
||||
pressed_color = "rgb(31, 31, 31)"
|
||||
|
@ -6,5 +6,7 @@ bool mirage_style::load_config(const std::filesystem::path& in_filename) {
|
||||
}
|
||||
catch (const toml::parse_error& err) {
|
||||
fprintf(stderr, "%s\n", err.what());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user