96 lines
3.2 KiB
Python
96 lines
3.2 KiB
Python
import os
|
|
from PIL import Image
|
|
from args import args
|
|
import sys
|
|
import datetime
|
|
from assetcache import assetCache, assetGetCache
|
|
|
|
palettes = []
|
|
|
|
def extractPaletteFromImage(image):
|
|
# goes through and finds all unique colors in the image
|
|
if image.mode != 'RGBA':
|
|
image = image.convert('RGBA')
|
|
pixels = list(image.getdata())
|
|
uniqueColors = []
|
|
for color in pixels:
|
|
# We treat all alpha 0 as rgba(0,0,0,0) for palette purposes
|
|
if color[3] == 0:
|
|
color = (0, 0, 0, 0)
|
|
if color not in uniqueColors:
|
|
uniqueColors.append(color)
|
|
return uniqueColors
|
|
|
|
def processPalette(asset):
|
|
print(f"Processing palette: {asset['path']}")
|
|
cache = assetGetCache(asset['path'])
|
|
if cache is not None:
|
|
return cache
|
|
|
|
paletteIndex = len(palettes)
|
|
image = Image.open(asset['path'])
|
|
pixels = extractPaletteFromImage(image)
|
|
|
|
fileNameWithoutExt = os.path.splitext(os.path.basename(asset['path']))[0]
|
|
fileNameWithoutPalette = os.path.splitext(fileNameWithoutExt)[0]
|
|
|
|
# PSP requires that the palette size be a power of two, so we will pad the
|
|
# palette with transparent colors if needed.
|
|
# if args.platform == "psp":
|
|
def mathNextPowTwo(x):
|
|
return 1 << (x - 1).bit_length()
|
|
|
|
nextPowTwo = mathNextPowTwo(len(pixels))
|
|
while len(pixels) < nextPowTwo:
|
|
pixels.append((0, 0, 0, 0))
|
|
|
|
# Header
|
|
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
data = f"// Palette Generated for {asset['path']} at {now}\n"
|
|
data += f"#include \"display/palette/palette.h\"\n\n"
|
|
data += f"#define PALETTE_{paletteIndex}_COLOR_COUNT {len(pixels)}\n\n"
|
|
data += f"#pragma pack(push, 1)\n"
|
|
data += f"static const color_t PALETTE_{paletteIndex}_COLORS[PALETTE_{paletteIndex}_COLOR_COUNT] = {{\n"
|
|
for pixel in pixels:
|
|
data += f" {{ 0x{pixel[0]:02X}, 0x{pixel[1]:02X}, 0x{pixel[2]:02X}, 0x{pixel[3]:02X} }},\n"
|
|
data += f"}};\n\n"
|
|
data += f"#pragma pack(pop)\n\n"
|
|
data += f"static const palette_t PALETTE_{paletteIndex} = {{\n"
|
|
data += f" .colorCount = PALETTE_{paletteIndex}_COLOR_COUNT,\n"
|
|
data += f" .colors = PALETTE_{paletteIndex}_COLORS,\n"
|
|
data += f"}};\n"
|
|
|
|
# Write Header
|
|
outputFile = os.path.join(args.headers_dir, "display", "palette", f"palette_{paletteIndex}.h")
|
|
os.makedirs(os.path.dirname(outputFile), exist_ok=True)
|
|
with open(outputFile, "w") as f:
|
|
f.write(data)
|
|
|
|
palette = {
|
|
"paletteIndex": paletteIndex,
|
|
"paletteName": fileNameWithoutPalette,
|
|
"pixels": pixels,
|
|
"headerFile": os.path.relpath(outputFile, args.headers_dir),
|
|
"asset": asset,
|
|
"files": [ ],# No zippable files.
|
|
}
|
|
|
|
palettes.append(palette)
|
|
return assetCache(asset['path'], palette)
|
|
|
|
def processPaletteList():
|
|
data = f"// Auto-generated palette list\n"
|
|
for palette in palettes:
|
|
data += f"#include \"{palette['headerFile']}\"\n"
|
|
data += f"\n"
|
|
data += f"#define PALETTE_LIST_COUNT {len(palettes)}\n\n"
|
|
data += f"static const palette_t* PALETTE_LIST[PALETTE_LIST_COUNT] = {{\n"
|
|
for palette in palettes:
|
|
data += f" &PALETTE_{palette['paletteIndex']},\n"
|
|
data += f"}};\n"
|
|
|
|
# Write the palette list to a header file
|
|
outputFile = os.path.join(args.headers_dir, "display", "palette", "palettelist.h")
|
|
os.makedirs(os.path.dirname(outputFile), exist_ok=True)
|
|
with open(outputFile, "w") as f:
|
|
f.write(data) |