diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f872d8..3c48e55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,8 @@ set(DUSK_SOURCES_DIR "${DUSK_ROOT_DIR}/src") set(DUSK_TEMP_DIR "${DUSK_BUILD_DIR}/temp") set(DUSK_TOOLS_DIR "${DUSK_ROOT_DIR}/tools") set(DUSK_DATA_DIR "${DUSK_ROOT_DIR}/data") +set(DUSK_ASSETS_DIR "${DUSK_ROOT_DIR}/assets") +set(DUSK_BUILT_ASSETS_DIR "${DUSK_BUILD_DIR}/assets" CACHE INTERNAL ${DUSK_CACHE_TARGET}) set(DUSK_GENERATED_HEADERS_DIR "${DUSK_BUILD_DIR}/generated") set(DUSK_TARGET_NAME "Dusk" CACHE INTERNAL ${DUSK_CACHE_TARGET}) set(DUSK_BUILD_BINARY ${DUSK_BUILD_DIR}/Dusk CACHE INTERNAL ${DUSK_CACHE_TARGET}) @@ -88,14 +90,18 @@ string(JOIN "," DUSK_ASSETS_ARGUMENTS ${DUSK_ASSETS}) add_custom_target(DUSK_ASSETS_BUILT ALL COMMAND ${Python3_EXECUTABLE} ${DUSK_TOOLS_DIR}/assetstool/assets.py - --output ${DUSK_GENERATED_HEADERS_DIR}/assets + --assets ${DUSK_ASSETS_DIR} + --build-type wad + --output-assets ${DUSK_BUILT_ASSETS_DIR} + --output-file ${DUSK_BUILD_DIR}/dusk.dsk + --output-headers ${DUSK_GENERATED_HEADERS_DIR}/asset/assetbundle.h --input ${DUSK_ASSETS_ARGUMENTS} COMMENT "Creating assets build directory ${DUSK_ASSETS}" ) add_dependencies(${DUSK_TARGET_NAME} DUSK_ASSETS_BUILT) -# Postbuild, create PBP file for PSP. +# Postbuild if(DUSK_TARGET_SYSTEM STREQUAL "psp") create_pbp_file( TARGET "${DUSK_TARGET_NAME}" diff --git a/src/asset/CMakeLists.txt b/src/asset/CMakeLists.txt index d708d97..afa05a7 100644 --- a/src/asset/CMakeLists.txt +++ b/src/asset/CMakeLists.txt @@ -7,6 +7,5 @@ target_sources(${DUSK_TARGET_NAME} PRIVATE asset.c - assetraw.c assetsystem.c ) \ No newline at end of file diff --git a/src/asset/asset.c b/src/asset/asset.c index d02d2d4..e016193 100644 --- a/src/asset/asset.c +++ b/src/asset/asset.c @@ -7,15 +7,6 @@ #include "asset.h" -assetcallbacks_t ASSET_CALLBACKS[] = { - { - .init = assetRawInit, - .loadAsync = assetRawLoadAsync, - .loadSync = assetRawLoadSync, - .dispose = assetRawDispose - } -}; - void assetInit() { } \ No newline at end of file diff --git a/tools/assetstool/args.py b/tools/assetstool/args.py new file mode 100644 index 0000000..4d38222 --- /dev/null +++ b/tools/assetstool/args.py @@ -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) \ No newline at end of file diff --git a/tools/assetstool/assethelpers.py b/tools/assetstool/assethelpers.py new file mode 100644 index 0000000..a9060c3 --- /dev/null +++ b/tools/assetstool/assethelpers.py @@ -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('\\', '/') diff --git a/tools/assetstool/assetparser.py b/tools/assetstool/assetparser.py deleted file mode 100644 index 4cbc98a..0000000 --- a/tools/assetstool/assetparser.py +++ /dev/null @@ -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 [] \ No newline at end of file diff --git a/tools/assetstool/assets.py b/tools/assetstool/assets.py index aea1038..95ba826 100644 --- a/tools/assetstool/assets.py +++ b/tools/assetstool/assets.py @@ -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)) \ No newline at end of file + processAsset(asset) \ No newline at end of file diff --git a/tools/assetstool/header.py b/tools/assetstool/header.py deleted file mode 100644 index 2a6b0de..0000000 --- a/tools/assetstool/header.py +++ /dev/null @@ -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}"' \ No newline at end of file diff --git a/tools/assetstool/imageparser.py b/tools/assetstool/imageparser.py deleted file mode 100644 index 7715e07..0000000 --- a/tools/assetstool/imageparser.py +++ /dev/null @@ -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 ] \ No newline at end of file diff --git a/tools/assetstool/processasset.py b/tools/assetstool/processasset.py new file mode 100644 index 0000000..eb53bc6 --- /dev/null +++ b/tools/assetstool/processasset.py @@ -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 \ No newline at end of file diff --git a/tools/assetstool/processtileset.py b/tools/assetstool/processtileset.py new file mode 100644 index 0000000..baad0ea --- /dev/null +++ b/tools/assetstool/processtileset.py @@ -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}") \ No newline at end of file diff --git a/tools/assetstool/tilesetparser.py b/tools/assetstool/tilesetparser.py deleted file mode 100644 index 273e1e0..0000000 --- a/tools/assetstool/tilesetparser.py +++ /dev/null @@ -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 \ No newline at end of file