# compile_spirv.cmake
# Compila shaders GLSL a SPIR-V i genera headers C++ embedibles.
# Multiplataforma: Windows, macOS, Linux (no requereix bash ni xxd).
#
# Invocat per CMakeLists.txt amb:
#   cmake -D GLSLC=<path> -D SHADERS_DIR=<path> -D HEADERS_DIR=<path> -P compile_spirv.cmake
#
# També es pot executar manualment des de l'arrel del projecte:
#   cmake -D GLSLC=glslc -D SHADERS_DIR=shaders \
#         -D HEADERS_DIR=source/core/rendering/gpu/spv \
#         -P tools/shaders/compile_spirv.cmake

cmake_minimum_required(VERSION 3.10)
cmake_policy(SET CMP0007 NEW)

# Llista de shaders a compilar: font relativa a SHADERS_DIR
set(SHADER_SOURCES
    "line.vert.glsl"
    "line.frag.glsl"
    "postfx.vert.glsl"
    "postfx.frag.glsl"
    "bloom.frag.glsl"
)

# Nom de la variable C++ per a cada shader (mateix ordre).
# UPPER_CASE perquè són constexpr globals (.clang-tidy ho exigeix).
set(SHADER_VARS
    "LINE_VERT_SPV"
    "LINE_FRAG_SPV"
    "POSTFX_VERT_SPV"
    "POSTFX_FRAG_SPV"
    "BLOOM_FRAG_SPV"
)

# Flags extra per a cada shader (necessaris perquè .vert.glsl/.frag.glsl no s'infereixen)
set(SHADER_FLAGS
    "-fshader-stage=vert"
    "-fshader-stage=frag"
    "-fshader-stage=vert"
    "-fshader-stage=frag"
    "-fshader-stage=frag"
)

list(LENGTH SHADER_SOURCES NUM_SHADERS)
math(EXPR LAST_IDX "${NUM_SHADERS} - 1")

foreach(IDX RANGE ${LAST_IDX})
    list(GET SHADER_SOURCES ${IDX} SRC_NAME)
    list(GET SHADER_VARS    ${IDX} VAR)
    list(GET SHADER_FLAGS   ${IDX} EXTRA_FLAG)

    # Derivem el nom del header a partir de la variable: LINE_VERT_SPV → line_vert_spv.h
    string(TOLOWER "${VAR}" HDR_BASE)
    set(SRC "${SHADERS_DIR}/${SRC_NAME}")
    set(SPV "${HEADERS_DIR}/${HDR_BASE}.spv")
    set(HDR "${HEADERS_DIR}/${HDR_BASE}.h")

    message(STATUS "Compilant ${SRC} ...")

    if(EXTRA_FLAG)
        execute_process(
            COMMAND "${GLSLC}" "${EXTRA_FLAG}" -O "${SRC}" -o "${SPV}"
            RESULT_VARIABLE GLSLC_RESULT
            ERROR_VARIABLE  GLSLC_ERROR
        )
    else()
        execute_process(
            COMMAND "${GLSLC}" -O "${SRC}" -o "${SPV}"
            RESULT_VARIABLE GLSLC_RESULT
            ERROR_VARIABLE  GLSLC_ERROR
        )
    endif()

    if(NOT GLSLC_RESULT EQUAL 0)
        message(FATAL_ERROR "glslc ha fallat per a ${SRC}:\n${GLSLC_ERROR}")
    endif()

    # Llegim el binari SPV com a hex (sense separadors) i el dividim en bytes.
    file(READ "${SPV}" HEX_DATA HEX)
    string(REGEX MATCHALL ".." BYTES "${HEX_DATA}")
    list(LENGTH BYTES NUM_BYTES)

    set(ARRAY_BODY "")
    foreach(BYTE ${BYTES})
        string(APPEND ARRAY_BODY "    0x${BYTE},\n")
    endforeach()

    file(WRITE "${HDR}"
        "#pragma once\n"
        "#include <cstddef>\n"
        "#include <cstdint>\n"
        "static const uint8_t ${VAR}[] = {\n"
        "${ARRAY_BODY}"
        "};\n"
        "static const size_t ${VAR}_SIZE = ${NUM_BYTES};\n"
    )

    file(REMOVE "${SPV}")
    message(STATUS "  -> ${HDR} (${NUM_BYTES} bytes)")
endforeach()

message(STATUS "Shaders SPIR-V compilats correctament.")
