This commit is contained in:
2025-08-24 15:18:01 -05:00
parent 479aad2f06
commit 947f21cac7
12 changed files with 99 additions and 177 deletions

21
tools/assetstool/args.py Normal file
View File

@@ -0,0 +1,21 @@
import os
import argparse
import sys
# Check if the script is run with the correct arguments
parser = argparse.ArgumentParser(description="Generate chunk header files")
parser.add_argument('--assets', required=True, help='Dir to output built assets')
parser.add_argument('--build-type', choices=['wad', 'header'], default='raw', help='Type of build to perform')
parser.add_argument('--output-file', help='Output file for built assets (required for wad build)')
parser.add_argument('--output-headers', help='Output header file for built assets (required for header build)')
parser.add_argument('--output-assets', help='Output directory for built assets (required for raw build)')
parser.add_argument('--input', required=True, help='Input assets to process', nargs='+')
args = parser.parse_args()
inputAssets = []
for inputArg in args.input:
inputAssets.extend(inputArg.split(','))
if not inputAssets:
print("Error: No input assets provided.")
sys.exit(1)

View File

@@ -0,0 +1,6 @@
import os
from args import args
def getAssetRelativePath(fullPath):
# Get the relative path to the asset
return os.path.relpath(fullPath, start=args.assets).replace('\\', '/')

View File

@@ -1,17 +0,0 @@
import os
import sys
from tilesetparser import parseTileset
from imageparser import parseImage
def parseAsset(assetPath):
if not os.path.isfile(assetPath):
print(f"Error: Input asset '{assetPath}' does not exist.")
sys.exit(1)
if assetPath.endswith(".tsx"):
return parseTileset(assetPath)
elif assetPath.endswith(".png"):
return parseImage(assetPath)
else:
print(f"Warning: Unsupported asset type for '{assetPath}'. Skipping.")
return []

View File

@@ -1,31 +1,14 @@
import sys, os
import argparse
from assetparser import parseAsset
from header import setOutputDir
# Check if the script is run with the correct arguments
parser = argparse.ArgumentParser(description="Generate chunk header files")
parser.add_argument('--output', required=True, help='Dir to output headers')
parser.add_argument('--input', required=True, help='Input assets to process', nargs='+')
args = parser.parse_args()
from args import inputAssets
from processasset import processAsset
# Setup headers directory.
setOutputDir(args.output)
outputHeaders = []
# setOutputDir(args.output)
# outputHeaders = []
# Create output directory if it doesn't exist
if not os.path.exists(args.output):
os.makedirs(args.output)
# Split input assets by comma
inputAssets = []
for inputArg in args.input:
inputAssets.extend(inputArg.split(','))
# Begin processing assets
if not inputAssets:
print("Error: No input assets provided.")
sys.exit(1)
# # Create output directory if it doesn't exist
# if not os.path.exists(args.output):
# os.makedirs(args.output)
for asset in inputAssets:
outputHeaders.extend(parseAsset(asset))
processAsset(asset)

View File

@@ -1,15 +0,0 @@
import os
def setOutputDir(outputDir):
global OUTPUT_DIR
OUTPUT_DIR = outputDir
def getOutputDir():
return OUTPUT_DIR
def getHeaderInclude(headerPath):
outputDir = getOutputDir()
relPath = os.path.relpath(headerPath, outputDir)
path = relPath.replace('\\', '/') # Use forward slashes for includes
print(f" Including header: {path}")
return f'#include "{path}"'

View File

@@ -1,34 +0,0 @@
import os
from os import abort
from header import getOutputDir
from PIL import Image
def parseImage(imagePath):
print(f"Parsing image: {imagePath}")
if not os.path.isfile(imagePath):
abort(f"Error: Image file {imagePath} does not exist")
outputFile = os.path.join(getOutputDir(), f"image_{os.path.basename(imagePath)}.h")
dataOut = ""
dataOut += f"// Auto-generated image header for {os.path.basename(imagePath)}\n"
dataOut += f"#pragma once\n"
dataOut += f"#include \"asset/assetimage.h\"\n\n"
name = os.path.splitext(os.path.basename(imagePath))[0]
name = name.upper().replace(' ', '_')
dataOut += f"static const assetimage_t IMAGE_{name} = {{\n"
try:
with Image.open(imagePath) as img:
width, height = img.size
dataOut += f" .width = {width},\n"
dataOut += f" .height = {height},\n"
except Exception as e:
abort(f"Error: Unable to open image {imagePath}: {e}")
dataOut += f"}};\n"
with open(outputFile, 'w') as f:
f.write(dataOut)
return [ outputFile ]

View File

@@ -0,0 +1,14 @@
from processtileset import processTileset
processedAssets = []
def processAsset(assetPath):
if assetPath in processedAssets:
return
processedAssets.append(assetPath)
# Handle tiled tilesets
if assetPath.endswith('.tsx'):
processTileset(assetPath)
return

View File

@@ -0,0 +1,42 @@
import sys, os
import xml.etree.ElementTree as ET
from assethelpers import getAssetRelativePath
def processTileset(assetPath):
# Process the tileset file
print(f"Processing tileset: {assetPath}")
# Load the tileset XML
tree = ET.parse(assetPath)
root = tree.getroot()
# Needs tilewidth, tileheight, tilecount and columns attributes
if not all(attr in root.attrib for attr in ['tilewidth', 'tileheight', 'tilecount', 'columns']):
print(f"Error: Tileset {assetPath} is missing required attributes.")
return
tilewidth = int(root.attrib.get('tilewidth', 0))
tileheight = int(root.attrib.get('tileheight', 0))
tilecount = int(root.attrib.get('tilecount', 0))
columns = int(root.attrib.get('columns', 0))
if tilewidth <= 0 or tileheight <= 0 or tilecount <= 0 or columns <= 0:
print(f"Error: Tileset {assetPath} has invalid attribute values.")
return
# Exactly one image element is required
images = root.findall('image')
if len(images) != 1:
print(f"Error: Tileset {assetPath} must have exactly one image element.")
return
image = images[0]
if 'source' not in image.attrib:
print(f"Error: Tileset {assetPath} is missing image source.")
return
imageSource = image.attrib['source']
# Build
relative = getAssetRelativePath(assetPath)
print(f"Relative path: {relative}")

View File

@@ -1,74 +0,0 @@
from os import abort
import os
import xml.etree.ElementTree as ET
from imageparser import parseImage
from header import getOutputDir, getHeaderInclude
def parseTileset(assetPath):
tree = ET.parse(assetPath)
root = tree.getroot()
# Should have tilewidth, tileheight, tilecount and columns attributes
if not all(attr in root.attrib for attr in ['tilewidth', 'tileheight', 'tilecount', 'columns']):
print(f"Error: Missing required attributes in tileset {assetPath}")
return []
tileWidth = int(root.attrib['tilewidth'])
tileHeight = int(root.attrib['tileheight'])
tileCount = int(root.attrib['tilecount'])
columns = int(root.attrib['columns'])
# Find image elements
images = root.findall('image')
if not images:
abort(f"Error: No image elements found in tileset {assetPath}")
imageSources = []
for image in images:
imageSource = image.attrib.get('source')
if not imageSource:
abort(f"Error: Image element missing 'source' attribute in tileset {assetPath}")
# Get relative dir from this assetPath
assetDir = os.path.dirname(assetPath)
imageSource = os.path.normpath(os.path.join(assetDir, imageSource))
imageSources.extend(parseImage(imageSource))
# Now do our own header.
headers = []
print(f"Generating tileset header for {assetPath}")
name = os.path.splitext(os.path.basename(assetPath))[0]
name = name.upper().replace(' ', '_')
imageNameWithoutExtension = os.path.splitext(os.path.splitext(os.path.basename(imageSources[0]))[0])[0]
imageNameWithoutExtension = imageNameWithoutExtension.upper().replace(' ', '_')
dataOut = ""
dataOut += f"// Auto-generated tileset header for {os.path.basename(assetPath)}\n"
dataOut += f"#pragma once\n"
dataOut += f"#include \"asset/assettileset.h\"\n"
for imgHeader in imageSources:
dataOut += getHeaderInclude(imgHeader) + "\n"
dataOut += f"\n"
dataOut += f"static const assettileset_t TILESET_{name} = {{\n"
dataOut += f" .tileCount = {tileCount},\n"
dataOut += f" .columns = {columns},\n"
dataOut += f" .tileHeight = {tileHeight},\n"
dataOut += f" .tileWidth = {tileWidth},\n"
dataOut += f" .image = &{imageNameWithoutExtension},\n"
dataOut += f"}};\n"
# Write out to output dir
outputDir = getOutputDir()
if not os.path.isdir(outputDir):
os.makedirs(outputDir)
outputFile = os.path.join(outputDir, f"tileset_{os.path.basename(assetPath)}.h")
with open(outputFile, 'w') as f:
f.write(dataOut)
headers.append(outputFile)
headers.extend(imageSources)
return headers