import argparse import csv import os parser = argparse.ArgumentParser(description="Color CSV to .h defines") parser.add_argument("--csv", required=True, help="Path to color CSV file") parser.add_argument("--output", required=True, help="Path to output .h file") args = parser.parse_args() # Load colors colors = {} with open(args.csv, newline="", encoding="utf-8") as f: reader = csv.DictReader(f) if "name" not in reader.fieldnames: raise ValueError("CSV must have a 'name' column") for row in reader: name = row["name"] r, g, b = row["r"], row["g"], row["b"] a = row["a"] if "a" in row and row["a"] != "" else "1.0" for ch in (r, g, b, a): if not (0.0 <= float(ch) <= 1.0): raise ValueError(f"Color channel {ch!r} for '{name}' out of range [0.0, 1.0]") colors[name] = (r, g, b, a) # Build output out = [ "#pragma once", '#include "dusk.h"', "", "typedef float_t colorchannelf_t;", "typedef uint8_t colorchannel8_t;", "", "typedef struct { colorchannelf_t r, g, b; } color3f_t;", "typedef struct { colorchannelf_t r, g, b, a; } color4f_t;", "typedef struct { colorchannel8_t r, g, b; } color3b_t;", "typedef struct { colorchannel8_t r, g, b, a; } color4b_t;", "typedef color4b_t color_t;", "", "#define color3f(r, g, b) ((color3f_t){ r, g, b })", "#define color4f(r, g, b, a) ((color4f_t){ r, g, b, a })", "#define color3b(r, g, b) ((color3b_t){ r, g, b })", "#define color4b(r, g, b, a) ((color4b_t){ r, g, b, a })", "#define color(r, g, b, a) color4b(r, g, b, a)", "#define colorHex(hex) color4b(((hex >> 24) & 0xFF), ((hex >> 16) & 0xFF), ((hex >> 8) & 0xFF), (hex & 0xFF))", "", ] js = [] for name, (r, g, b, a) in colors.items(): r8, g8, b8, a8 = (int(float(ch) * 255) for ch in (r, g, b, a)) macro = "COLOR_" + name.upper() camel = "".join(p[0].upper() + p[1:].lower() for p in name.split("_")) out += [ f"// {name}", f"#define {macro}_4B color4b({r8}, {g8}, {b8}, {a8})", f"#define {macro}_3B color3b({r8}, {g8}, {b8})", f"#define {macro}_3F color3f({r}f, {g}f, {b}f)", f"#define {macro}_4F color4f({r}f, {g}f, {b}f, {a}f)", f"#define {macro} {macro}_4B", "", ] js += [ f"Color.{name.lower()} = function() {{", f" return new Color({r8}, {g8}, {b8}, {a8});", "};", "", ] out.append("// JS color functions") out.append("#define COLOR_SCRIPT \\") for line in "\n".join(js).rstrip().splitlines(): out.append(f' "{line}\\n" \\') out[-1] = out[-1].rstrip(" \\") out.append("") os.makedirs(os.path.dirname(args.output), exist_ok=True) with open(args.output, "w", encoding="utf-8") as f: f.write("\n".join(out))