#!/usr/bin/env python3
"""Generate SPIR-V blob arrays as C++ inline file.

Install shaderc from https://github.com/google/shaderc/, and run:

./bin/gen-spirv-shader-arrays.py -d src/libixion/shaders -o src/libixion/vulkan_spirv_blobs.inl
"""

import argparse
import os
import shutil
import sys
import subprocess
import tempfile
from pathlib import Path


def _write_cpp_byte_array(array_name, bytes, file):
    print("// This file has been auto-generated. DO NOT EDIT THIS FILE BY HAND!", file=file)
    print(file=file)
    print(f"uint8_t {array_name}_spirv[] = {{", file=file)

    bytes_per_line = 8

    for i, b in enumerate(bytes):

        if i % bytes_per_line == 0:
            print("    ", end="", file=file)

        print(f"0x{b:02X}, ", end="", file=file)

        if (i + 1) % bytes_per_line == 0:
            print(file=file)

    print(file=file)
    print("};", file=file)
    print(file=file)


def _scan_shader_dir(dirpath, output):
    # Detect glslc command.
    glslc_exec = shutil.which("glslc")

    if not glslc_exec:
        print("glslc command not found in your PATH.", file=sys.stderr)
        sys.exit(1)

    print(f"glslc command: {glslc_exec}")

    temp = tempfile.NamedTemporaryFile(delete=False)
    print(f"temp file name: {temp.name}")

    for f in os.listdir(dirpath):
        filepath = dirpath / f
        if filepath.suffix != ".comp":
            continue

        print(f"parsing {filepath}")
        cmd = [glslc_exec, filepath, "-o", temp.name]
        subprocess.run(cmd)
        spirv_file = Path(temp.name)
        bs = spirv_file.read_bytes()
        _write_cpp_byte_array(filepath.stem, bs, output)

    os.unlink(temp.name)


def main():
    parser = argparse.ArgumentParser(
        description="Generate C++ inline file containing SPIR-V representations of GLSL shaders.")
    parser.add_argument(
        "--shader-dir", "-d", type=Path,
        required=True,
        help="Path to directory where glsl shader files are.")
    parser.add_argument(
        "--output", "-o", type=Path,
        required=True,
        help="Path to output C++ inline file.")
    args = parser.parse_args()

    with args.output.open(mode="w") as output:
        _scan_shader_dir(args.shader_dir, output)


if __name__ == "__main__":
    main()

