diff --git a/assets/CMakeLists.txt b/assets/CMakeLists.txt index 9a17f3d..660e4ad 100644 --- a/assets/CMakeLists.txt +++ b/assets/CMakeLists.txt @@ -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) \ No newline at end of file +add_subdirectory(palette)# Palette asset needs to be added before any images. + +add_subdirectory(config) +add_subdirectory(entity) +add_subdirectory(ui) \ No newline at end of file diff --git a/assets/config/CMakeLists.txt b/assets/config/CMakeLists.txt new file mode 100644 index 0000000..bd115c1 --- /dev/null +++ b/assets/config/CMakeLists.txt @@ -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) \ No newline at end of file diff --git a/assets/init.dcf b/assets/config/init.dcf similarity index 100% rename from assets/init.dcf rename to assets/config/init.dcf diff --git a/assets/init_psp.dcf b/assets/config/init_psp.dcf similarity index 100% rename from assets/init_psp.dcf rename to assets/config/init_psp.dcf diff --git a/assets/entity/CMakeLists.txt b/assets/entity/CMakeLists.txt new file mode 100644 index 0000000..6cee926 --- /dev/null +++ b/assets/entity/CMakeLists.txt @@ -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) \ No newline at end of file diff --git a/assets/entities.png b/assets/entity/entities.png similarity index 100% rename from assets/entities.png rename to assets/entity/entities.png diff --git a/assets/entities.tsx b/assets/entity/entities.tsx similarity index 100% rename from assets/entities.tsx rename to assets/entity/entities.tsx diff --git a/assets/palette/CMakeLists.txt b/assets/palette/CMakeLists.txt new file mode 100644 index 0000000..947af28 --- /dev/null +++ b/assets/palette/CMakeLists.txt @@ -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) \ No newline at end of file diff --git a/assets/first.palette.png b/assets/palette/pallet0.png similarity index 100% rename from assets/first.palette.png rename to assets/palette/pallet0.png diff --git a/assets/ui/CMakeLists.txt b/assets/ui/CMakeLists.txt new file mode 100644 index 0000000..ffe622f --- /dev/null +++ b/assets/ui/CMakeLists.txt @@ -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) \ No newline at end of file diff --git a/assets/font_minogram.png b/assets/ui/minogram.png similarity index 100% rename from assets/font_minogram.png rename to assets/ui/minogram.png diff --git a/src/display/ui/uiconsole.c b/src/display/ui/uiconsole.c index 3164ae2..f3a3d9e 100644 --- a/src/display/ui/uiconsole.c +++ b/src/display/ui/uiconsole.c @@ -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); } \ No newline at end of file diff --git a/src/display/ui/uitext.c b/src/display/ui/uitext.c index c3de09d..197a705 100644 --- a/src/display/ui/uitext.c +++ b/src/display/ui/uitext.c @@ -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) { diff --git a/src/display/ui/uitext.h b/src/display/ui/uitext.h index 973606e..c6581f8 100644 --- a/src/display/ui/uitext.h +++ b/src/display/ui/uitext.h @@ -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 '!' diff --git a/src/engine/engine.c b/src/engine/engine.c index f89312d..0f569e7 100644 --- a/src/engine/engine.c +++ b/src/engine/engine.c @@ -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(); diff --git a/tools/assetstool/processimage.py b/tools/assetstool/processimage.py index 7940c12..85b0ed4 100644 --- a/tools/assetstool/processimage.py +++ b/tools/assetstool/processimage.py @@ -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) diff --git a/tools/assetstool/processtileset.py b/tools/assetstool/processtileset.py index 5f5baca..a10d119 100644 --- a/tools/assetstool/processtileset.py +++ b/tools/assetstool/processtileset.py @@ -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 @@ -47,27 +87,46 @@ def processTileset(asset): else: 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 \ No newline at end of file