Relative
This commit is contained in:
@@ -24,6 +24,8 @@ set(DUSK_SOURCES_DIR "${DUSK_ROOT_DIR}/src")
|
|||||||
set(DUSK_TEMP_DIR "${DUSK_BUILD_DIR}/temp")
|
set(DUSK_TEMP_DIR "${DUSK_BUILD_DIR}/temp")
|
||||||
set(DUSK_TOOLS_DIR "${DUSK_ROOT_DIR}/tools")
|
set(DUSK_TOOLS_DIR "${DUSK_ROOT_DIR}/tools")
|
||||||
set(DUSK_DATA_DIR "${DUSK_ROOT_DIR}/data")
|
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_GENERATED_HEADERS_DIR "${DUSK_BUILD_DIR}/generated")
|
||||||
set(DUSK_TARGET_NAME "Dusk" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
set(DUSK_TARGET_NAME "Dusk" CACHE INTERNAL ${DUSK_CACHE_TARGET})
|
||||||
set(DUSK_BUILD_BINARY ${DUSK_BUILD_DIR}/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
|
add_custom_target(DUSK_ASSETS_BUILT ALL
|
||||||
COMMAND
|
COMMAND
|
||||||
${Python3_EXECUTABLE} ${DUSK_TOOLS_DIR}/assetstool/assets.py
|
${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}
|
--input ${DUSK_ASSETS_ARGUMENTS}
|
||||||
COMMENT
|
COMMENT
|
||||||
"Creating assets build directory ${DUSK_ASSETS}"
|
"Creating assets build directory ${DUSK_ASSETS}"
|
||||||
)
|
)
|
||||||
add_dependencies(${DUSK_TARGET_NAME} DUSK_ASSETS_BUILT)
|
add_dependencies(${DUSK_TARGET_NAME} DUSK_ASSETS_BUILT)
|
||||||
|
|
||||||
# Postbuild, create PBP file for PSP.
|
# Postbuild
|
||||||
if(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
if(DUSK_TARGET_SYSTEM STREQUAL "psp")
|
||||||
create_pbp_file(
|
create_pbp_file(
|
||||||
TARGET "${DUSK_TARGET_NAME}"
|
TARGET "${DUSK_TARGET_NAME}"
|
||||||
|
@@ -7,6 +7,5 @@
|
|||||||
target_sources(${DUSK_TARGET_NAME}
|
target_sources(${DUSK_TARGET_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
asset.c
|
asset.c
|
||||||
assetraw.c
|
|
||||||
assetsystem.c
|
assetsystem.c
|
||||||
)
|
)
|
@@ -7,15 +7,6 @@
|
|||||||
|
|
||||||
#include "asset.h"
|
#include "asset.h"
|
||||||
|
|
||||||
assetcallbacks_t ASSET_CALLBACKS[] = {
|
|
||||||
{
|
|
||||||
.init = assetRawInit,
|
|
||||||
.loadAsync = assetRawLoadAsync,
|
|
||||||
.loadSync = assetRawLoadSync,
|
|
||||||
.dispose = assetRawDispose
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void assetInit() {
|
void assetInit() {
|
||||||
|
|
||||||
}
|
}
|
21
tools/assetstool/args.py
Normal file
21
tools/assetstool/args.py
Normal 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)
|
6
tools/assetstool/assethelpers.py
Normal file
6
tools/assetstool/assethelpers.py
Normal 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('\\', '/')
|
@@ -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 []
|
|
@@ -1,31 +1,14 @@
|
|||||||
import sys, os
|
import sys, os
|
||||||
import argparse
|
from args import inputAssets
|
||||||
from assetparser import parseAsset
|
from processasset import processAsset
|
||||||
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()
|
|
||||||
|
|
||||||
# Setup headers directory.
|
# Setup headers directory.
|
||||||
setOutputDir(args.output)
|
# setOutputDir(args.output)
|
||||||
outputHeaders = []
|
# outputHeaders = []
|
||||||
|
|
||||||
# Create output directory if it doesn't exist
|
# # Create output directory if it doesn't exist
|
||||||
if not os.path.exists(args.output):
|
# if not os.path.exists(args.output):
|
||||||
os.makedirs(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)
|
|
||||||
|
|
||||||
for asset in inputAssets:
|
for asset in inputAssets:
|
||||||
outputHeaders.extend(parseAsset(asset))
|
processAsset(asset)
|
@@ -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}"'
|
|
@@ -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 ]
|
|
14
tools/assetstool/processasset.py
Normal file
14
tools/assetstool/processasset.py
Normal 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
|
42
tools/assetstool/processtileset.py
Normal file
42
tools/assetstool/processtileset.py
Normal 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}")
|
@@ -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
|
|
Reference in New Issue
Block a user