Subdirize assets, add TSX support
This commit is contained in:
@@ -3,8 +3,8 @@
|
|||||||
# This software is released under the MIT License.
|
# This software is released under the MIT License.
|
||||||
# https://opensource.org/licenses/MIT
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
add_asset(PALETTE first.palette.png)
|
add_subdirectory(palette)# Palette asset needs to be added before any images.
|
||||||
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_subdirectory(config)
|
||||||
add_asset(CONFIG init.dcf)
|
add_subdirectory(entity)
|
||||||
add_asset(CONFIG init_psp.dcf)
|
add_subdirectory(ui)
|
7
assets/config/CMakeLists.txt
Normal file
7
assets/config/CMakeLists.txt
Normal 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)
|
6
assets/entity/CMakeLists.txt
Normal file
6
assets/entity/CMakeLists.txt
Normal 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)
|
Before Width: | Height: | Size: 336 B After Width: | Height: | Size: 336 B |
6
assets/palette/CMakeLists.txt
Normal file
6
assets/palette/CMakeLists.txt
Normal 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)
|
Before Width: | Height: | Size: 268 B After Width: | Height: | Size: 268 B |
6
assets/ui/CMakeLists.txt
Normal file
6
assets/ui/CMakeLists.txt
Normal 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)
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -21,7 +21,7 @@ void uiConsoleRender(void) {
|
|||||||
i--;
|
i--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uiTextDraw(0, i * TILESET_FONT_MINOGRAM.tileHeight, line, COLOR_WHITE);
|
uiTextDraw(0, i * TILESET_MINOGRAM.tileHeight, line, COLOR_WHITE);
|
||||||
i--;
|
i--;
|
||||||
} while(i > 0);
|
} while(i > 0);
|
||||||
}
|
}
|
@@ -17,7 +17,7 @@ errorret_t uiTextInit(void) {
|
|||||||
memoryZero(&UI_TEXT, sizeof(uitext_t));
|
memoryZero(&UI_TEXT, sizeof(uitext_t));
|
||||||
|
|
||||||
errorChain(assetManagerLoadAsset(
|
errorChain(assetManagerLoadAsset(
|
||||||
TILESET_FONT_MINOGRAM.image, &UI_TEXT.asset, &UI_TEXT.assetRef
|
TILESET_MINOGRAM.image, &UI_TEXT.asset, &UI_TEXT.assetRef
|
||||||
));
|
));
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
@@ -35,23 +35,23 @@ void uiTextDrawChar(
|
|||||||
const color_t color
|
const color_t color
|
||||||
) {
|
) {
|
||||||
int32_t tileIndex = (int32_t)(c) - UI_TEXT_CHAR_START;
|
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;
|
tileIndex = ((int32_t)'@') - UI_TEXT_CHAR_START;
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(
|
assertTrue(
|
||||||
tileIndex >= 0 && tileIndex <= TILESET_FONT_MINOGRAM.tileCount,
|
tileIndex >= 0 && tileIndex <= TILESET_MINOGRAM.tileCount,
|
||||||
"Character is out of bounds for font tiles"
|
"Character is out of bounds for font tiles"
|
||||||
);
|
);
|
||||||
|
|
||||||
vec4 uv;
|
vec4 uv;
|
||||||
tilesetTileGetUV(&TILESET_FONT_MINOGRAM, tileIndex, uv);
|
tilesetTileGetUV(&TILESET_MINOGRAM, tileIndex, uv);
|
||||||
|
|
||||||
spriteBatchPush(
|
spriteBatchPush(
|
||||||
&UI_TEXT.asset->alphaImage.texture,
|
&UI_TEXT.asset->alphaImage.texture,
|
||||||
x, y,
|
x, y,
|
||||||
x + TILESET_FONT_MINOGRAM.tileWidth,
|
x + TILESET_MINOGRAM.tileWidth,
|
||||||
y + TILESET_FONT_MINOGRAM.tileHeight,
|
y + TILESET_MINOGRAM.tileHeight,
|
||||||
color,
|
color,
|
||||||
uv[0], uv[1], uv[2], uv[3]
|
uv[0], uv[1], uv[2], uv[3]
|
||||||
);
|
);
|
||||||
@@ -73,17 +73,17 @@ void uiTextDraw(
|
|||||||
while((c = text[i++]) != '\0') {
|
while((c = text[i++]) != '\0') {
|
||||||
if(c == '\n') {
|
if(c == '\n') {
|
||||||
posX = x;
|
posX = x;
|
||||||
posY += TILESET_FONT_MINOGRAM.tileHeight;
|
posY += TILESET_MINOGRAM.tileHeight;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(c == ' ') {
|
if(c == ' ') {
|
||||||
posX += TILESET_FONT_MINOGRAM.tileWidth;
|
posX += TILESET_MINOGRAM.tileWidth;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uiTextDrawChar(posX, posY, c, color);
|
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");
|
assertNotNull(outHeight, "Output height pointer cannot be NULL");
|
||||||
|
|
||||||
int32_t width = 0;
|
int32_t width = 0;
|
||||||
int32_t height = TILESET_FONT_MINOGRAM.tileHeight;
|
int32_t height = TILESET_MINOGRAM.tileHeight;
|
||||||
int32_t lineWidth = 0;
|
int32_t lineWidth = 0;
|
||||||
|
|
||||||
char_t c;
|
char_t c;
|
||||||
@@ -108,11 +108,11 @@ void uiTextMeasure(
|
|||||||
width = lineWidth;
|
width = lineWidth;
|
||||||
}
|
}
|
||||||
lineWidth = 0;
|
lineWidth = 0;
|
||||||
height += TILESET_FONT_MINOGRAM.tileHeight;
|
height += TILESET_MINOGRAM.tileHeight;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
lineWidth += TILESET_FONT_MINOGRAM.tileWidth;
|
lineWidth += TILESET_MINOGRAM.tileWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(lineWidth > width) {
|
if(lineWidth > width) {
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "asset/assetmanager.h"
|
#include "asset/assetmanager.h"
|
||||||
#include "display/tileset/tileset_font_minogram.h"
|
#include "display/tileset/tileset_minogram.h"
|
||||||
|
|
||||||
#define UI_TEXT_CHAR_START '!'
|
#define UI_TEXT_CHAR_START '!'
|
||||||
|
|
||||||
|
@@ -33,9 +33,9 @@ errorret_t engineInit(void) {
|
|||||||
|
|
||||||
// Init scripts
|
// Init scripts
|
||||||
#if PSP
|
#if PSP
|
||||||
consoleExec("exec init_psp.dcf");
|
consoleExec("exec config/init_psp.dcf");
|
||||||
#else
|
#else
|
||||||
consoleExec("exec init.dcf");
|
consoleExec("exec config/init.dcf");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
|
@@ -8,8 +8,11 @@ from assethelpers import getAssetRelativePath
|
|||||||
images = []
|
images = []
|
||||||
|
|
||||||
def processImage(asset):
|
def processImage(asset):
|
||||||
type = asset['options'].get('type', 'PALETTIZED').upper()
|
type = None
|
||||||
if type == 'PALETTIZED':
|
if 'type' in asset['options']:
|
||||||
|
type = asset['options'].get('type', 'PALETTIZED').upper()
|
||||||
|
|
||||||
|
if type == 'PALETTIZED' or type is None:
|
||||||
return processPalettizedImage(asset)
|
return processPalettizedImage(asset)
|
||||||
elif type == 'ALPHA':
|
elif type == 'ALPHA':
|
||||||
return processAlphaImage(asset)
|
return processAlphaImage(asset)
|
||||||
|
@@ -5,15 +5,55 @@ from assethelpers import getAssetRelativePath
|
|||||||
import os
|
import os
|
||||||
import datetime
|
import datetime
|
||||||
from args import args
|
from args import args
|
||||||
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
def processTileset(asset):
|
def loadTilesetFromTSX(asset):
|
||||||
print(f"Processing tileset: {asset['path']}")
|
# 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
|
# 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.
|
# 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
|
# 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.
|
# tile sizes AND cols/rows to indicate the original size of the image.
|
||||||
|
|
||||||
image = processImage(asset)
|
image = processImage(asset)
|
||||||
|
|
||||||
tileWidth, tileHeight = None, None
|
tileWidth, tileHeight = None, None
|
||||||
@@ -47,27 +87,46 @@ def processTileset(asset):
|
|||||||
else:
|
else:
|
||||||
print(f"Error: Tileset {asset['path']} must specify either tileHeight or rows")
|
print(f"Error: Tileset {asset['path']} must specify either tileHeight or rows")
|
||||||
sys.exit(1)
|
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]
|
fileNameWithoutExtension = os.path.splitext(os.path.basename(asset['path']))[0]
|
||||||
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
tilesetName = fileNameWithoutExtension
|
tilesetName = fileNameWithoutExtension
|
||||||
tilesetNameUpper = tilesetName.upper()
|
tilesetNameUpper = tilesetName.upper()
|
||||||
|
|
||||||
widthScale = originalWidth / image['width']
|
widthScale = tilesetData['originalWidth'] / tilesetData['image']['width']
|
||||||
heightScale = originalHeight / image['height']
|
heightScale = tilesetData['originalHeight'] / tilesetData['image']['height']
|
||||||
|
|
||||||
# Create header
|
# Create header
|
||||||
data = f"// Tileset Generated for {asset['path']} at {now}\n"
|
data = f"// Tileset Generated for {asset['path']} at {now}\n"
|
||||||
data += f"#pragma once\n"
|
data += f"#pragma once\n"
|
||||||
data += f"#include \"display/tileset.h\"\n\n"
|
data += f"#include \"display/tileset.h\"\n\n"
|
||||||
data += f"static const tileset_t TILESET_{tilesetNameUpper} = {{\n"
|
data += f"static const tileset_t TILESET_{tilesetNameUpper} = {{\n"
|
||||||
data += f" .tileWidth = {tileWidth},\n"
|
data += f" .tileWidth = {tilesetData['tileWidth']},\n"
|
||||||
data += f" .tileHeight = {tileHeight},\n"
|
data += f" .tileHeight = {tilesetData['tileHeight']},\n"
|
||||||
data += f" .tileCount = {columns * rows},\n"
|
data += f" .tileCount = {tilesetData['columns'] * tilesetData['rows']},\n"
|
||||||
data += f" .columns = {columns},\n"
|
data += f" .columns = {tilesetData['columns']},\n"
|
||||||
data += f" .rows = {rows},\n"
|
data += f" .rows = {tilesetData['rows']},\n"
|
||||||
data += f" .uv = {{ {widthScale / columns}f, {heightScale / rows}f }},\n"
|
data += f" .uv = {{ {widthScale / tilesetData['columns']}f, {heightScale / tilesetData['rows']}f }},\n"
|
||||||
data += f" .image = {json.dumps(image['imagePath'])},\n"
|
data += f" .image = {json.dumps(tilesetData['image']['imagePath'])},\n"
|
||||||
data += f"}};\n"
|
data += f"}};\n"
|
||||||
|
|
||||||
# Write Header
|
# Write Header
|
||||||
@@ -77,8 +136,8 @@ def processTileset(asset):
|
|||||||
f.write(data)
|
f.write(data)
|
||||||
|
|
||||||
outTileset = {
|
outTileset = {
|
||||||
"image": image,
|
"image": tilesetData['image'],
|
||||||
"headerFile": outputFile,
|
"headerFile": outputFile,
|
||||||
"files": image['files'],
|
"files": tilesetData['image']['files'],
|
||||||
}
|
}
|
||||||
return outTileset
|
return outTileset
|
Reference in New Issue
Block a user