import argparse
import pathlib
from PIL import Image
from os import path
import numpy as np
images_06 = [
"bg_cloud1",
"bg_cloud2",
"bg_cloud3",
"desert_doodads",
"desert_main",
"desert_mountains",
"desert_mountains2",
"desert_sun",
"generic_deathtiles",
"generic_unhookable",
"grass_doodads",
"grass_main",
"jungle_background",
"jungle_deathtiles",
"jungle_doodads",
"jungle_main",
"jungle_midground",
"jungle_unhookables",
"moon",
"mountains",
"snow",
"stars",
"sun",
"winter_doodads",
"winter_main",
"winter_mountains",
"winter_mountains2",
"winter_mountains3"
]
images_07 = [
"bg_cloud1",
"bg_cloud2",
"bg_cloud3",
"desert_doodads",
"desert_main",
"desert_mountains",
"desert_mountains2",
"desert_sun",
"easter",
"generic_deathtiles",
"generic_lamps",
"generic_shadows",
"generic_unhookable",
"grass_doodads",
"grass_main",
"jungle_background",
"jungle_deathtiles",
"jungle_doodads",
"jungle_main",
"jungle_midground",
"jungle_unhookables",
"light",
"moon",
"mountains",
"snow",
"stars",
"sun",
"winter_doodads",
"winter_main",
"winter_mountains",
"winter_mountains2",
"winter_mountains3",
]
if __name__ == "__main__":
arg_parser = argparse.ArgumentParser(description="script to generate the external constants in src/constants/")
arg_parser.add_argument("mapres_version", help="mapres version, '6' for 0.6, '7' for 0.7", choices=["6", "7"])
arg_parser.add_argument("image_directory", help="directory where the external images can be read from", type=pathlib.Path)
arg_parser.add_argument("output_file", type=pathlib.Path)
args = arg_parser.parse_args()
if args.mapres_version == "6":
image_names = images_06
elif args.mapres_version == "7":
image_names = images_07
opaque_tables = []
image_dimensions = []
for name in image_names:
file_path = path.join(args.image_directory, name + ".png")
with Image.open(file_path) as image:
if image.format != "PNG":
print(f"{file_path} is not a png image")
if len(image.getbands()) != 4:
print(f"{file_path} is not a rgba image")
width, height = image.size
image_dimensions.append((width, height))
tile_width, tile_height = width // 16, height // 16
if width % 16 != 0 or height % 16 != 0 or tile_width != tile_height:
opaque_tables.append(None)
continue
pixels = np.frombuffer(image.tobytes()[3::4], dtype=np.uint8)
alpha_values = pixels.reshape((height, width))
opaque_table = [[False for i in range(16)] for j in range(16)]
for y in range(16):
for x in range(16):
opaque_table[y][x] = np.all(alpha_values[y * tile_height:(y + 1) * tile_height, x * tile_width:(x + 1) * tile_width] >= 250)
opaque_tables.append(opaque_table)
const_image_names = [name.upper() for name in image_names]
with open(args.output_file, "w") as file:
file.write("use vek::Extent2;\n\n")
file.write("/// Returns `true` if all clients of that version should have that mapres shipped with their client.\n")
file.write("pub fn is_external_name(name: &str) -> bool {\n")
file.write(" matches!(\n")
file.write(" name,\n")
file.write(" \"")
file.write("\"\n | \"".join(image_names))
file.write("\"\n )\n")
file.write("}\n\n")
file.write("/// Returns the opaque table for external images.\n")
file.write("/// None, if the given name is not a valid external image name, or if the image not square.\n")
file.write("/// The latter restriction is taken from the client source, don't ask me.\n")
file.write("pub fn external_opaque_table(name: &str) -> Option<[[bool; 16]; 16]> {\n")
file.write(" Some(match name {\n")
for name, const_name, table in zip(image_names, const_image_names, opaque_tables):
if table is None:
continue
file.write(f" \"{name}\" => {const_name},\n")
file.write(" _ => return None,\n")
file.write(" })\n")
file.write("}\n\n")
file.write("/// Returns the (width, height) of external images.\n")
file.write("/// None, if the given name is not a valid external image name.\n")
file.write("pub fn external_dimensions(name: &str) -> Option<Extent2<u32>> {\n")
file.write(" Some(match name {\n")
for name, (width, height) in zip(image_names, image_dimensions):
file.write(f" \"{name}\" => Extent2::new({width}, {height}),\n")
file.write(" _ => return None,\n")
file.write(" })\n")
file.write("}\n")
for const_name, opaque_table in zip(const_image_names, opaque_tables):
if opaque_table is None:
continue
file.write("\n#[rustfmt::skip]\n")
file.write(f"const {const_name}: [[bool; 16]; 16] = [\n")
for line in opaque_table:
array = [" true" if boolean else "false" for boolean in line]
array = ", ".join(array)
file.write(f" [{array}],\n")
file.write("];\n")