Subdirize assets, add TSX support

This commit is contained in:
2025-09-15 09:28:12 -05:00
parent 517b39649c
commit cafeda4368
17 changed files with 124 additions and 37 deletions

View File

@@ -3,8 +3,8 @@
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
add_asset(PALETTE first.palette.png)
add_asset(TILESET font_minogram.png type=ALPHA tileWidth=6 tileHeight=10 columns=16 rows=6)
add_asset(TILESET entities.png type=PALETTIZED tileWidth=16 tileHeight=16)
add_asset(CONFIG init.dcf)
add_asset(CONFIG init_psp.dcf)
add_subdirectory(palette)# Palette asset needs to be added before any images.
add_subdirectory(config)
add_subdirectory(entity)
add_subdirectory(ui)

View File

@@ -0,0 +1,7 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
add_asset(CONFIG init.dcf)
add_asset(CONFIG init_psp.dcf)

View File

@@ -0,0 +1,6 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
add_asset(TILESET entities.tsx)

View File

Before

Width:  |  Height:  |  Size: 336 B

After

Width:  |  Height:  |  Size: 336 B

View File

@@ -0,0 +1,6 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
add_asset(PALETTE pallet0.png)

View File

Before

Width:  |  Height:  |  Size: 268 B

After

Width:  |  Height:  |  Size: 268 B

6
assets/ui/CMakeLists.txt Normal file
View File

@@ -0,0 +1,6 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
add_asset(TILESET minogram.png type=ALPHA tileWidth=6 tileHeight=10 columns=16 rows=6)

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -21,7 +21,7 @@ void uiConsoleRender(void) {
i--;
continue;
}
uiTextDraw(0, i * TILESET_FONT_MINOGRAM.tileHeight, line, COLOR_WHITE);
uiTextDraw(0, i * TILESET_MINOGRAM.tileHeight, line, COLOR_WHITE);
i--;
} while(i > 0);
}

View File

@@ -17,7 +17,7 @@ errorret_t uiTextInit(void) {
memoryZero(&UI_TEXT, sizeof(uitext_t));
errorChain(assetManagerLoadAsset(
TILESET_FONT_MINOGRAM.image, &UI_TEXT.asset, &UI_TEXT.assetRef
TILESET_MINOGRAM.image, &UI_TEXT.asset, &UI_TEXT.assetRef
));
errorOk();
}
@@ -35,23 +35,23 @@ void uiTextDrawChar(
const color_t color
) {
int32_t tileIndex = (int32_t)(c) - UI_TEXT_CHAR_START;
if(tileIndex < 0 || tileIndex >= TILESET_FONT_MINOGRAM.tileCount) {
if(tileIndex < 0 || tileIndex >= TILESET_MINOGRAM.tileCount) {
tileIndex = ((int32_t)'@') - UI_TEXT_CHAR_START;
}
assertTrue(
tileIndex >= 0 && tileIndex <= TILESET_FONT_MINOGRAM.tileCount,
tileIndex >= 0 && tileIndex <= TILESET_MINOGRAM.tileCount,
"Character is out of bounds for font tiles"
);
vec4 uv;
tilesetTileGetUV(&TILESET_FONT_MINOGRAM, tileIndex, uv);
tilesetTileGetUV(&TILESET_MINOGRAM, tileIndex, uv);
spriteBatchPush(
&UI_TEXT.asset->alphaImage.texture,
x, y,
x + TILESET_FONT_MINOGRAM.tileWidth,
y + TILESET_FONT_MINOGRAM.tileHeight,
x + TILESET_MINOGRAM.tileWidth,
y + TILESET_MINOGRAM.tileHeight,
color,
uv[0], uv[1], uv[2], uv[3]
);
@@ -73,17 +73,17 @@ void uiTextDraw(
while((c = text[i++]) != '\0') {
if(c == '\n') {
posX = x;
posY += TILESET_FONT_MINOGRAM.tileHeight;
posY += TILESET_MINOGRAM.tileHeight;
continue;
}
if(c == ' ') {
posX += TILESET_FONT_MINOGRAM.tileWidth;
posX += TILESET_MINOGRAM.tileWidth;
continue;
}
uiTextDrawChar(posX, posY, c, color);
posX += TILESET_FONT_MINOGRAM.tileWidth;
posX += TILESET_MINOGRAM.tileWidth;
}
}
@@ -97,7 +97,7 @@ void uiTextMeasure(
assertNotNull(outHeight, "Output height pointer cannot be NULL");
int32_t width = 0;
int32_t height = TILESET_FONT_MINOGRAM.tileHeight;
int32_t height = TILESET_MINOGRAM.tileHeight;
int32_t lineWidth = 0;
char_t c;
@@ -108,11 +108,11 @@ void uiTextMeasure(
width = lineWidth;
}
lineWidth = 0;
height += TILESET_FONT_MINOGRAM.tileHeight;
height += TILESET_MINOGRAM.tileHeight;
continue;
}
lineWidth += TILESET_FONT_MINOGRAM.tileWidth;
lineWidth += TILESET_MINOGRAM.tileWidth;
}
if(lineWidth > width) {

View File

@@ -7,7 +7,7 @@
#pragma once
#include "asset/assetmanager.h"
#include "display/tileset/tileset_font_minogram.h"
#include "display/tileset/tileset_minogram.h"
#define UI_TEXT_CHAR_START '!'

View File

@@ -33,9 +33,9 @@ errorret_t engineInit(void) {
// Init scripts
#if PSP
consoleExec("exec init_psp.dcf");
consoleExec("exec config/init_psp.dcf");
#else
consoleExec("exec init.dcf");
consoleExec("exec config/init.dcf");
#endif
errorOk();

View File

@@ -8,8 +8,11 @@ from assethelpers import getAssetRelativePath
images = []
def processImage(asset):
type = asset['options'].get('type', 'PALETTIZED').upper()
if type == 'PALETTIZED':
type = None
if 'type' in asset['options']:
type = asset['options'].get('type', 'PALETTIZED').upper()
if type == 'PALETTIZED' or type is None:
return processPalettizedImage(asset)
elif type == 'ALPHA':
return processAlphaImage(asset)

View File

@@ -5,15 +5,55 @@ from assethelpers import getAssetRelativePath
import os
import datetime
from args import args
from xml.etree import ElementTree
def processTileset(asset):
print(f"Processing tileset: {asset['path']}")
def loadTilesetFromTSX(asset):
# Load the TSX file
tree = ElementTree.parse(asset['path'])
root = tree.getroot()
# Expect tileheight, tilewidth, columns and tilecount attributes
if 'tilewidth' not in root.attrib or 'tileheight' not in root.attrib or 'columns' not in root.attrib or 'tilecount' not in root.attrib:
print(f"Error: TSX file {asset['path']} is missing required attributes (tilewidth, tileheight, columns, tilecount)")
sys.exit(1)
tileWidth = int(root.attrib['tilewidth'])
tileHeight = int(root.attrib['tileheight'])
columns = int(root.attrib['columns'])
tileCount = int(root.attrib['tilecount'])
rows = (tileCount + columns - 1) // columns # Calculate rows based on tileCount and columns
# Find the image element
imageElement = root.find('image')
if imageElement is None or 'source' not in imageElement.attrib:
print(f"Error: TSX file {asset['path']} is missing an image element with a source attribute")
sys.exit(1)
imagePath = imageElement.attrib['source']
# Image is relative to the TSX file
imageAssetPath = os.path.join(os.path.dirname(asset['path']), imagePath)
image = processImage({
'path': imageAssetPath,
'options': asset['options'],
})
return {
"image": image,
"tileWidth": tileWidth,
"tileHeight": tileHeight,
"columns": columns,
"rows": rows,
"originalWidth": tileWidth * columns,
"originalHeight": tileHeight * rows,
}
def loadTilesetFromArgs(asset):
# We need to determine how big each tile is. This can either be provided as
# an arg of tileWidth/tileHeight or as a count of rows/columns.
# Additionally, if the image has been factored, then the user can provide both
# tile sizes AND cols/rows to indicate the original size of the image.
image = processImage(asset)
tileWidth, tileHeight = None, None
@@ -48,26 +88,45 @@ def processTileset(asset):
print(f"Error: Tileset {asset['path']} must specify either tileHeight or rows")
sys.exit(1)
return {
"image": image,
"tileWidth": tileWidth,
"tileHeight": tileHeight,
"columns": columns,
"rows": rows,
"originalWidth": originalWidth,
"originalHeight": originalHeight,
}
def processTileset(asset):
print(f"Processing tileset: {asset['path']}")
tilesetData = None
if asset['path'].endswith('.tsx'):
tilesetData = loadTilesetFromTSX(asset)
else:
tilesetData = loadTilesetFromArgs(asset)
fileNameWithoutExtension = os.path.splitext(os.path.basename(asset['path']))[0]
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
tilesetName = fileNameWithoutExtension
tilesetNameUpper = tilesetName.upper()
widthScale = originalWidth / image['width']
heightScale = originalHeight / image['height']
widthScale = tilesetData['originalWidth'] / tilesetData['image']['width']
heightScale = tilesetData['originalHeight'] / tilesetData['image']['height']
# Create header
data = f"// Tileset Generated for {asset['path']} at {now}\n"
data += f"#pragma once\n"
data += f"#include \"display/tileset.h\"\n\n"
data += f"static const tileset_t TILESET_{tilesetNameUpper} = {{\n"
data += f" .tileWidth = {tileWidth},\n"
data += f" .tileHeight = {tileHeight},\n"
data += f" .tileCount = {columns * rows},\n"
data += f" .columns = {columns},\n"
data += f" .rows = {rows},\n"
data += f" .uv = {{ {widthScale / columns}f, {heightScale / rows}f }},\n"
data += f" .image = {json.dumps(image['imagePath'])},\n"
data += f" .tileWidth = {tilesetData['tileWidth']},\n"
data += f" .tileHeight = {tilesetData['tileHeight']},\n"
data += f" .tileCount = {tilesetData['columns'] * tilesetData['rows']},\n"
data += f" .columns = {tilesetData['columns']},\n"
data += f" .rows = {tilesetData['rows']},\n"
data += f" .uv = {{ {widthScale / tilesetData['columns']}f, {heightScale / tilesetData['rows']}f }},\n"
data += f" .image = {json.dumps(tilesetData['image']['imagePath'])},\n"
data += f"}};\n"
# Write Header
@@ -77,8 +136,8 @@ def processTileset(asset):
f.write(data)
outTileset = {
"image": image,
"image": tilesetData['image'],
"headerFile": outputFile,
"files": image['files'],
"files": tilesetData['image']['files'],
}
return outTileset