include(CMakeParseArguments)

# 查找Python解释器
find_package(Python3 REQUIRED)

# 存储脚本路径
set(SHADER_COMPILE_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/tools/compile_shaders.py")

# 在cache目录下创建着色器目录.txt
set(SHADER_PATH_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cache/shader_paths.txt)
file(REMOVE ${SHADER_PATH_FILE})
file(WRITE ${SHADER_PATH_FILE} "")

# 添加着色器目录的函数
# 参数:
#   path: 要添加的包含 .slang 着色器文件的目录路径
# 功能:
#   1. 将路径转换为适合目标系统的格式 (特别是处理 Cygwin)。
#   2. 将路径追加到 SHADER_PATH_FILE 指定的文件中。
#   3. 查找指定路径下的所有 .slang 文件。
#   4. 将找到的 .slang 文件添加为 CMake 配置的依赖项，
#      以便在这些文件更改时触发重新配置。
# 注意:
#   - 需要在使用此函数前定义 CMAKE_BINARY_DIR 和 SHADER_PATH_FILE 变量。
#     例如: set(SHADER_PATH_FILE ${CMAKE_BINARY_DIR}/shader_paths.txt)
#   - 假定 SHADER_PATH_FILE 的使用者期望接收适合其环境的路径格式
#     (此处在 Cygwin 下转换为 Windows 格式)。
function(add_mirage_shader_directory path)
    # 检查 SHADER_PATH_FILE 变量是否已定义
    if(NOT DEFINED SHADER_PATH_FILE)
        message(FATAL_ERROR "**错误**: SHADER_PATH_FILE 变量未定义。请在使用 add_mirage_shader_directory 前设置此变量。")
    endif()

    # 获取绝对路径以确保一致性
    get_filename_component(abs_path ${path} ABSOLUTE)

    # 保存用于文件操作和写入文件的路径变量
    set(path_to_write ${abs_path})

    # 如果是cygwin环境, 需要转换路径为Windows格式
    if (CYGWIN)
        message(STATUS "检测到 Cygwin 环境，尝试使用 cygpath 转换路径: ${abs_path}")
        # **关键点**: 使用 cygpath -w 将 Cygwin 路径转换为 Windows 路径
        execute_process(
                COMMAND cygpath -w ${abs_path}
                OUTPUT_VARIABLE path_windows
                OUTPUT_STRIP_TRAILING_WHITESPACE # 去除可能的尾随空格
                RESULT_VARIABLE cygpath_result
                ERROR_QUIET # 如果 cygpath 不存在或失败，则不显示错误，但检查 result
        )

        if(cygpath_result EQUAL 0 AND path_windows) # 检查 cygpath 是否成功执行并有输出
            # 更新用于写入文件的路径
            set(path_to_write ${path_windows})
            message(STATUS "路径已成功转换为 Windows 格式: ${path_to_write}")
        else()
            # 如果 cygpath 失败或未找到，发出警告，并回退到原始路径
            message(WARNING "无法使用 cygpath 转换路径 ${abs_path}。将使用原始路径。请确保 cygpath 在系统 PATH 中。")
            # path_to_write 保持为 abs_path
        endif()
    endif()

    # 将（可能已转换的）路径写入shader_paths.txt
    # **关键点**: 追加路径到 ${SHADER_PATH_FILE}
    file(APPEND ${SHADER_PATH_FILE} "${path_to_write}\n")

    # 查找目录下的所有 .slang 文件，包括子目录
    # **关键点**: 递归查找 ${abs_path} 目录下的 *.slang 文件
    file(GLOB_RECURSE SHADER_FILES LIST_DIRECTORIES false "${abs_path}/*.slang")

    # 设置依赖关系，当shader文件变化时重新运行CMake配置
    # **关键点**: 将着色器文件添加为 CMake 配置依赖项
    foreach(SHADER_FILE ${SHADER_FILES})
        get_filename_component(ABS_SHADER_FILE ${SHADER_FILE} ABSOLUTE)
        set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${ABS_SHADER_FILE})
    endforeach()

    # **关键点**: 输出状态消息，告知用户已添加目录
    message(STATUS "添加着色器源文件目录: ${path_to_write}")
endfunction()

set(SHADER_COMPILE_ARGS "")
set(SHADER_SHDC "")
if (WIN32 OR CYGWIN)
    list(APPEND SHADER_COMPILE_ARGS "--hlsl")
    set(SHADER_SHDC ${MIRAGE_ROOT_DIR}/tools/win_mirage_shdc.exe)
elseif (APPLE)
    list(APPEND SHADER_COMPILE_ARGS "--metal")
    set(SHADER_SHDC ${MIRAGE_ROOT_DIR}/tools/mac_mirage_shdc)
else()
    list(APPEND SHADER_COMPILE_ARGS "--glsl")
    set(SHADER_SHDC ${MIRAGE_ROOT_DIR}/tools/linux_mirage_shdc)
endif()

message(STATUS "使用着色器编译器: ${SHADER_SHDC}")

# 如果是Debug模式, 添加--debug选项
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
    list(APPEND SHADER_COMPILE_ARGS "--debug")
endif ()

# 添加编译目标, 调用tools/compile_shaders.py
add_custom_target(compile_shaders ALL
        COMMAND ${Python3_EXECUTABLE} ${SHADER_COMPILE_SCRIPT}
        --shdc ${SHADER_SHDC}
        --shader_list ${SHADER_PATH_FILE}
        ${SHADER_COMPILE_ARGS}
        COMMENT "编译着色器"
        VERBATIM
)

# 定义一个函数，将编译着色器作为其他目标的依赖
function(add_shader_dependencies target)
    add_dependencies(${target} compile_shaders)
endfunction()
