diff --git a/archive/asset/args.py b/archive/asset/args.py deleted file mode 100644 index d086b957..00000000 --- a/archive/asset/args.py +++ /dev/null @@ -1,12 +0,0 @@ -import sys, os -import argparse - -# 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('--headers-dir', required=True, help='Directory to output individual asset headers (required for header build)') -parser.add_argument('--output-headers', help='Output header file for built assets (required for header build)') -parser.add_argument('--output-assets', required=True, help='Output directory for built assets') -parser.add_argument('--output-file', required=True, help='Output file for built assets (required for wad build)') -parser.add_argument('--input', required=True, help='Input assets to process', nargs='+') -args = parser.parse_args() \ No newline at end of file diff --git a/archive/asset/bundle/__main__.py b/archive/asset/bundle/__main__.py deleted file mode 100644 index ebfdc722..00000000 --- a/archive/asset/bundle/__main__.py +++ /dev/null @@ -1,66 +0,0 @@ -import sys, os -from tools.asset.args import args -from tools.asset.process.asset import processAsset -from tools.asset.process.palette import processPaletteList -from tools.asset.process.tileset import processTilesetList -from tools.asset.process.language import processLanguageList -from tools.asset.path import getBuiltAssetsRelativePath -import zipfile - -# Parse input file args. -inputAssets = [] -for inputArg in args.input: - files = inputArg.split('$') - for file in files: - if str(file).strip() == '': - continue - - pieces = file.split('#') - - if len(pieces) < 2: - print(f"Error: Invalid input asset format '{file}'. Expected format: type#path[#option1%option2...]") - sys.exit(1) - - options = {} - if len(pieces) > 2: - optionParts = pieces[2].split('%') - for part in optionParts: - partSplit = part.split('=') - - if len(partSplit) < 1: - continue - if len(partSplit) == 2: - options[partSplit[0]] = partSplit[1] - else: - options[partSplit[0]] = True - - inputAssets.append({ - 'type': pieces[0], - 'path': pieces[1], - 'options': options - }) - -if not inputAssets: - print("Error: No input assets provided.") - sys.exit(1) - -# Process each asset. -files = [] -for asset in inputAssets: - asset = processAsset(asset) - files.extend(asset['files']) - -# Generate additional files -files.extend(processLanguageList()['files']) - -# Take assets and add to a zip archive. -outputFileName = args.output_file -print(f"Creating output file: {outputFileName}") -with zipfile.ZipFile(outputFileName, 'w') as zipf: - for file in files: - relativeOutputPath = getBuiltAssetsRelativePath(file) - zipf.write(file, arcname=relativeOutputPath) - -# Generate additional headers. -processPaletteList() -processTilesetList() \ No newline at end of file diff --git a/archive/asset/cache.py b/archive/asset/cache.py deleted file mode 100644 index 9c1d028e..00000000 --- a/archive/asset/cache.py +++ /dev/null @@ -1,12 +0,0 @@ -processedAssets = {} - -def assetGetCache(assetPath): - if assetPath in processedAssets: - return processedAssets[assetPath] - return None - -def assetCache(assetPath, processedData): - if assetPath in processedAssets: - return processedAssets[assetPath] - processedAssets[assetPath] = processedData - return processedData \ No newline at end of file diff --git a/archive/asset/path.py b/archive/asset/path.py deleted file mode 100644 index d15b8bfe..00000000 --- a/archive/asset/path.py +++ /dev/null @@ -1,10 +0,0 @@ -import os -from tools.asset.args import args - -def getAssetRelativePath(fullPath): - # Get the relative path to the asset - return os.path.relpath(fullPath, start=args.assets).replace('\\', '/') - -def getBuiltAssetsRelativePath(fullPath): - # Get the relative path to the built asset - return os.path.relpath(fullPath, start=args.output_assets).replace('\\', '/') \ No newline at end of file diff --git a/archive/asset/process/asset.py b/archive/asset/process/asset.py deleted file mode 100644 index fcce3023..00000000 --- a/archive/asset/process/asset.py +++ /dev/null @@ -1,33 +0,0 @@ -import sys -# from processtileset import processTileset -from tools.asset.process.image import processImage -from tools.asset.process.palette import processPalette -from tools.asset.process.tileset import processTileset -from tools.asset.process.map import processMap -from tools.asset.process.language import processLanguage -from tools.asset.process.script import processScript - -processedAssets = [] - -def processAsset(asset): - if asset['path'] in processedAssets: - return - processedAssets.append(asset['path']) - - # Handle tiled tilesets - t = asset['type'].lower() - if t == 'palette': - return processPalette(asset) - elif t == 'image': - return processImage(asset) - elif t == 'tileset': - return processTileset(asset) - elif t == 'map': - return processMap(asset) - elif t == 'language': - return processLanguage(asset) - elif t == 'script': - return processScript(asset) - else: - print(f"Error: Unknown asset type '{asset['type']}' for path '{asset['path']}'") - sys.exit(1) \ No newline at end of file diff --git a/archive/asset/process/image.py b/archive/asset/process/image.py deleted file mode 100644 index 0daa9177..00000000 --- a/archive/asset/process/image.py +++ /dev/null @@ -1,134 +0,0 @@ -import os -import sys -from PIL import Image -from tools.asset.process.palette import extractPaletteFromImage, palettes -from tools.asset.args import args -from tools.asset.path import getAssetRelativePath -from tools.asset.cache import assetGetCache, assetCache - -images = [] - -def processImage(asset): - cache = assetGetCache(asset['path']) - if cache is not None: - return cache - - type = None - if 'type' in asset['options']: - type = asset['options'].get('type', 'PALETTIZED').upper() - - if type == 'PALETTIZED' or type is None: - return assetCache(asset['path'], processPalettizedImage(asset)) - elif type == 'ALPHA': - return assetCache(asset['path'], processAlphaImage(asset)) - else: - print(f"Error: Unknown image type {type} for asset {asset['path']}") - sys.exit(1) - -def processPalettizedImage(asset): - assetPath = asset['path'] - cache = assetGetCache(assetPath) - if cache is not None: - return cache - - image = Image.open(assetPath) - imagePalette = extractPaletteFromImage(image) - - # Find palette that contains every color - palette = None - for p in palettes: - hasAllColors = True - for color in imagePalette: - for palColor in p['pixels']: - if color[0] == palColor[0] and color[1] == palColor[1] and color[2] == palColor[2] and color[3] == palColor[3]: - break - elif color[3] == 0 and palColor[3] == 0: - break - else: - print('Pallete {} does not contain color #{}'.format(p['paletteName'], '{:02x}{:02x}{:02x}{:02x}'.format(color[0], color[1], color[2], color[3]))) - hasAllColors = False - break - if hasAllColors: - palette = p - break - - if palette is None: - palette = palettes[0] # Just to avoid reference error - print(f"No matching palette found for {assetPath}!") - # Find which pixel is missing - for color in imagePalette: - if color in palette['pixels']: - continue - # Convert to hex (with alpha) - hexColor = '#{:02x}{:02x}{:02x}{:02x}'.format(color[0], color[1], color[2], color[3]) - print(f"Missing color: {hexColor} in palette {palette['paletteName']}") - sys.exit(1) - - print(f"Converting image {assetPath} to use palette") - - paletteIndexes = [] - for pixel in list(image.getdata()): - if pixel[3] == 0: - pixel = (0, 0, 0, 0) - paletteIndex = palette['pixels'].index(pixel) - paletteIndexes.append(paletteIndex) - - data = bytearray() - data.extend(b"DPI") # Dusk Palettized Image - data.extend(image.width.to_bytes(4, 'little')) # Width - data.extend(image.height.to_bytes(4, 'little')) # Height - data.append(palette['paletteIndex']) # Palette index - for paletteIndex in paletteIndexes: - if paletteIndex > 255 or paletteIndex < 0: - print(f"Error: Palette index {paletteIndex} exceeds 255!") - sys.exit(1) - data.append(paletteIndex.to_bytes(1, 'little')[0]) # Pixel index - - relative = getAssetRelativePath(assetPath) - fileNameWithoutExt = os.path.splitext(os.path.basename(assetPath))[0] - outputFileRelative = os.path.join(os.path.dirname(relative), f"{fileNameWithoutExt}.dpi") - outputFilePath = os.path.join(args.output_assets, outputFileRelative) - os.makedirs(os.path.dirname(outputFilePath), exist_ok=True) - with open(outputFilePath, "wb") as f: - f.write(data) - - outImage = { - "imagePath": outputFileRelative, - "files": [ outputFilePath ], - 'width': image.width, - 'height': image.height, - } - return assetCache(assetPath, outImage) - -def processAlphaImage(asset): - assetPath = asset['path'] - cache = assetGetCache(assetPath) - if cache is not None: - return cache - - print(f"Processing alpha image: {assetPath}") - - data = bytearray() - data.extend(b"DAI") # Dusk Alpha Image - image = Image.open(assetPath).convert("RGBA") - data.extend(image.width.to_bytes(4, 'little')) # Width - data.extend(image.height.to_bytes(4, 'little')) # Height - for pixel in list(image.getdata()): - # Only write alpha channel - data.append(pixel[3].to_bytes(1, 'little')[0]) # Pixel alpha - - relative = getAssetRelativePath(assetPath) - fileNameWithoutExt = os.path.splitext(os.path.basename(assetPath))[0] - outputFileRelative = os.path.join(os.path.dirname(relative), f"{fileNameWithoutExt}.dai") - outputFilePath = os.path.join(args.output_assets, outputFileRelative) - os.makedirs(os.path.dirname(outputFilePath), exist_ok=True) - with open(outputFilePath, "wb") as f: - f.write(data) - - outImage = { - "imagePath": outputFileRelative, - "files": [ outputFilePath ], - 'width': image.width, - 'height': image.height, - } - return assetCache(assetPath, outImage) \ No newline at end of file diff --git a/archive/asset/process/language.py b/archive/asset/process/language.py deleted file mode 100644 index 63222fef..00000000 --- a/archive/asset/process/language.py +++ /dev/null @@ -1,228 +0,0 @@ -import sys -import os -from tools.asset.args import args -from tools.asset.cache import assetCache, assetGetCache -from tools.asset.path import getAssetRelativePath -from tools.dusk.defs import defs -import polib -import re - -LANGUAGE_CHUNK_CHAR_COUNT = int(defs.get('ASSET_LANG_CHUNK_CHAR_COUNT')) - -LANGUAGE_DATA = {} -LANGUAGE_KEYS = [] - -def processLanguageList(): - # Language keys header data - headerKeys = "// Auto-generated language keys header file.\n" - headerKeys += "#pragma once\n" - headerKeys += "#include \"dusk.h\"\n\n" - - # This is the desired chunk groups list.. if a language key STARTS with any - # of the keys in this list we would "like to" put it in that chunk group. - # If there is no match, or the list is full then we will add it to the next - # available chunk group (that isn't a 'desired' one). If the chunk becomes - # full, then we attempt to make another chunk with the same prefix so that - # a second batching can occur. - desiredChunkGroups = { - 'ui': 0 - } - - # Now, for each language key, create the header reference and index. - keyIndex = 0 - languageKeyIndexes = {} - languageKeyChunk = {} - languageKeyChunkIndexes = {} - languageKeyChunkOffsets = {} - for key in LANGUAGE_KEYS: - headerKeys += f"#define {getLanguageVariableName(key)} {keyIndex}\n" - languageKeyIndexes[key] = keyIndex - keyIndex += 1 - - # Find desired chunk group - assignedChunk = None - for desiredKey in desiredChunkGroups: - if key.lower().startswith(desiredKey): - assignedChunk = desiredChunkGroups[desiredKey] - break - # If no desired chunk group matched, assign to -1 - if assignedChunk is None: - assignedChunk = -1 - languageKeyChunk[key] = assignedChunk - - # Setup header. - for lang in LANGUAGE_DATA: - if key not in LANGUAGE_DATA[lang]: - print(f"Warning: Missing translation for key '{key}' in language '{lang}'") - sys.exit(1) - - # Seal the header. - headerKeys += f"\n#define LANG_KEY_COUNT {len(LANGUAGE_KEYS)}\n" - - # Now we can generate the language string chunks. - nextChunkIndex = max(desiredChunkGroups.values()) + 1 - files = [] - - for lang in LANGUAGE_DATA: - langData = LANGUAGE_DATA[lang] - - # Key = chunkIndex, value = chunkInfo - languageChunks = {} - for key in LANGUAGE_KEYS: - keyIndex = languageKeyIndexes[key] - chunkIndex = languageKeyChunk[key] - wasSetChunk = chunkIndex != -1 - - # This will keep looping until we find a chunk - while True: - # Determine the next chunkIndex IF chunkIndex is -1 - if chunkIndex == -1: - chunkIndex = nextChunkIndex - - # Is the chunk full? - curLen = languageChunks.get(chunkIndex, {'len': 0})['len'] - newLen = curLen + len(langData[key]) - if newLen > LANGUAGE_CHUNK_CHAR_COUNT: - # Chunk is full, need to create a new chunk. - chunkIndex = -1 - if wasSetChunk: - wasSetChunk = False - else: - nextChunkIndex += 1 - continue - - # Chunk is not full, we can use it. - if chunkIndex not in languageChunks: - languageChunks[chunkIndex] = { - 'len': 0, - 'keys': [] - } - languageChunks[chunkIndex]['len'] = newLen - languageChunks[chunkIndex]['keys'].append(key) - languageKeyChunkIndexes[key] = chunkIndex - languageKeyChunkOffsets[key] = curLen - break - - # We have now chunked all the keys for this language! - langBuffer = b"" - - # Write header info - langBuffer += b'DLF' # Dusk Language File - - for key in LANGUAGE_KEYS: - # Write the chunk that this key belongs to as uint32_t - chunkIndex = languageKeyChunkIndexes[key] - langBuffer += chunkIndex.to_bytes(4, byteorder='little') - - # Write the offset for this key as uint32_t - offset = languageKeyChunkOffsets[key] - langBuffer += offset.to_bytes(4, byteorder='little') - - # Write the length of the string as uint32_t - strData = langData[key].encode('utf-8') - langBuffer += len(strData).to_bytes(4, byteorder='little') - - # Now write out each chunk's string data, packed tight and no null term. - for chunkIndex in sorted(languageChunks.keys()): - chunkInfo = languageChunks[chunkIndex] - for key in chunkInfo['keys']: - strData = langData[key].encode('utf-8') - langBuffer += strData - - # Now pad the chunk to full size - curLen = chunkInfo['len'] - if curLen < LANGUAGE_CHUNK_CHAR_COUNT: - padSize = LANGUAGE_CHUNK_CHAR_COUNT - curLen - langBuffer += b'\0' * padSize - - # Write out the language data file - outputFile = os.path.join(args.output_assets, "language", f"{lang}.dlf") - files.append(outputFile) - os.makedirs(os.path.dirname(outputFile), exist_ok=True) - with open(outputFile, "wb") as f: - f.write(langBuffer) - - # Write out the language keys header file - outputFile = os.path.join(args.headers_dir, "locale", "language", "keys.h") - os.makedirs(os.path.dirname(outputFile), exist_ok=True) - with open(outputFile, "w") as f: - f.write(headerKeys) - - # Generate language list. - langValues = {} - headerLocale = "#pragma once\n#include \"locale/localeinfo.h\"\n\n" - headerLocale += "typedef enum {\n" - count = 0 - headerLocale += f" DUSK_LOCALE_NULL = {count},\n" - count += 1 - for lang in LANGUAGE_DATA: - langKey = lang.replace('-', '_').replace(' ', '_').upper() - langValues[lang] = count - headerLocale += f" DUSK_LOCALE_{langKey} = {count},\n" - count += 1 - headerLocale += f" DUSK_LOCALE_COUNT = {count}\n" - headerLocale += "} dusklocale_t;\n\n" - - headerLocale += f"static const localeinfo_t LOCALE_INFOS[DUSK_LOCALE_COUNT] = {{\n" - for lang in LANGUAGE_DATA: - langKey = lang.replace('-', '_').replace(' ', '_').upper() - headerLocale += f" [DUSK_LOCALE_{langKey}] = {{\n" - headerLocale += f" .file = \"{lang}\"\n" - headerLocale += f" }},\n" - headerLocale += "};\n" - - headerLocale += f"static const char_t *LOCALE_SCRIPT = \n" - for lang in LANGUAGE_DATA: - langKey = lang.replace('-', '_').replace(' ', '_').upper() - langValue = langValues[lang] - headerLocale += f" \"DUSK_LOCALE_{langKey} = {langValue}\\n\"\n" - headerLocale += ";\n" - - # Write out the locale enum header file - outputFile = os.path.join(args.headers_dir, "locale", "locale.h") - os.makedirs(os.path.dirname(outputFile), exist_ok=True) - with open(outputFile, "w") as f: - f.write(headerLocale) - - return { - 'files': files - } - -def getLanguageVariableName(languageKey): - # Take the language key, prepend LANG_, uppercase, replace any non symbols - # with _ - key = languageKey.strip().upper() - key = re.sub(r'[^A-Z0-9]', '_', key) - return f"LANG_{key}" - -def processLanguage(asset): - cache = assetGetCache(asset['path']) - if cache is not None: - return cache - - # Load PO File - po = polib.pofile(asset['path']) - - langName = po.metadata.get('Language') - if langName not in LANGUAGE_DATA: - LANGUAGE_DATA[langName] = {} - - for entry in po: - key = entry.msgid - val = entry.msgstr - - if key not in LANGUAGE_KEYS: - LANGUAGE_KEYS.append(key) - - if key not in LANGUAGE_DATA[langName]: - LANGUAGE_DATA[langName][key] = val - else: - print(f"Error: Duplicate translation key '{key}' in language '{langName}'") - sys.exit(1) - - outLanguageData = { - 'data': po, - 'path': asset['path'], - 'files': [] - } - return assetCache(asset['path'], outLanguageData) \ No newline at end of file diff --git a/archive/asset/process/map.py b/archive/asset/process/map.py deleted file mode 100644 index f4384e96..00000000 --- a/archive/asset/process/map.py +++ /dev/null @@ -1,154 +0,0 @@ -import struct -import sys -import os -import json -from tools.asset.args import args -from tools.asset.cache import assetCache, assetGetCache -from tools.asset.path import getAssetRelativePath -from tools.dusk.defs import TILE_WIDTH, TILE_HEIGHT, TILE_DEPTH, CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_DEPTH, CHUNK_TILE_COUNT -from tools.dusk.map import Map -from tools.dusk.chunk import Chunk - -def convertModelData(modelData): - # TLDR; Model data stores things efficiently with indices, but we buffer it - # out to 6 vertex quads for simplicity. - outVertices = [] - outUVs = [] - outColors = [] - for indice in modelData['indices']: - vertex = modelData['vertices'][indice] - uv = modelData['uvs'][indice] - color = modelData['colors'][indice] - outVertices.append(vertex) - outUVs.append(uv) - outColors.append(color) - - return { - 'vertices': outVertices, - 'uvs': outUVs, - 'colors': outColors - } - -def processChunk(chunk): - cache = assetGetCache(chunk.getFilename()) - if cache: - return cache - - baseModel = { - 'vertices': [], - 'colors': [], - 'uvs': [] - } - models = [ baseModel ] - - for tileIndex, tile in chunk.tiles.items(): - tileBase = tile.getBaseTileModel() - - convertedBase = convertModelData(tileBase) - baseModel['vertices'].extend(convertedBase['vertices']) - baseModel['colors'].extend(convertedBase['colors']) - baseModel['uvs'].extend(convertedBase['uvs']) - - # Generate binary buffer for efficient output - buffer = bytearray() - buffer.extend(b'DMC')# Header - buffer.extend(len(chunk.tiles).to_bytes(4, 'little')) # Number of tiles - buffer.extend(len(models).to_bytes(1, 'little')) # Number of models - buffer.extend(len(chunk.entities).to_bytes(1, 'little')) # Number of entities - - # Buffer tile data as array of uint8_t - for tileIndex, tile in chunk.tiles.items(): - buffer.extend(tile.shape.to_bytes(1, 'little')) - - # # For each model - for model in models: - vertexCount = len(model['vertices']) - buffer.extend(vertexCount.to_bytes(4, 'little')) - for i in range(vertexCount): - vertex = model['vertices'][i] - uv = model['uvs'][i] - color = model['colors'][i] - - buffer.extend(color[0].to_bytes(1, 'little')) - buffer.extend(color[1].to_bytes(1, 'little')) - buffer.extend(color[2].to_bytes(1, 'little')) - buffer.extend(color[3].to_bytes(1, 'little')) - - buffer.extend(bytearray(struct.pack('header[0] != 'D' || - assetData->header[1] != 'P' || - assetData->header[2] != 'F' - ) { - errorThrow("Invalid palette header"); - } - - // Version (can only be 1 atm) - if(assetData->version != 0x01) { - errorThrow("Unsupported palette version"); - } - - // Check color count. - if( - assetData->colorCount == 0 || - assetData->colorCount > PALETTE_COLOR_COUNT_MAX - ) { - errorThrow("Invalid palette color count"); - } - - paletteInit( - palette, - assetData->colorCount, - assetData->colors - ); - errorOk(); -} \ No newline at end of file diff --git a/archive/assetpalette.h b/archive/assetpalette.h deleted file mode 100644 index cc328f2a..00000000 --- a/archive/assetpalette.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "error/error.h" -#include "display/texture/palette.h" - -typedef struct assetentire_s assetentire_t; - -#pragma pack(push, 1) -typedef struct { - char_t header[3]; - uint8_t version; - - uint8_t colorCount; - color_t colors[PALETTE_COLOR_COUNT_MAX]; -} assetpalette_t; -#pragma pack(pop) - -/** - * Loads a palette from the given data pointer into the output palette. - * - * @param entire Data received from the asset loader system. - * @return An error code. - */ -errorret_t assetPaletteLoad(assetentire_t entire); \ No newline at end of file diff --git a/archive/camera/CMakeLists.txt b/archive/camera/CMakeLists.txt deleted file mode 100644 index d8c90ab1..00000000 --- a/archive/camera/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2026 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - camera.c -) \ No newline at end of file diff --git a/archive/camera/camera.c b/archive/camera/camera.c deleted file mode 100644 index 94379fa1..00000000 --- a/archive/camera/camera.c +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "camera.h" -#include "display/display.h" -#include "assert/assert.h" -#include "display/framebuffer/framebuffer.h" -#include "display/screen/screen.h" - -void cameraInit(camera_t *camera) { - cameraInitPerspective(camera); -} - -void cameraInitPerspective(camera_t *camera) { - assertNotNull(camera, "Not a camera component"); - - camera->projType = CAMERA_PROJECTION_TYPE_PERSPECTIVE; - camera->perspective.fov = glm_rad(45.0f); - camera->nearClip = 0.1f; - camera->farClip = 10000.0f; - - camera->viewType = CAMERA_VIEW_TYPE_LOOKAT; - glm_vec3_copy((vec3){ 5.0f, 5.0f, 5.0f }, camera->lookat.position); - glm_vec3_copy((vec3){ 0.0f, 1.0f, 0.0f }, camera->lookat.up); - glm_vec3_copy((vec3){ 0.0f, 0.0f, 0.0f }, camera->lookat.target); -} - -void cameraInitOrthographic(camera_t *camera) { - assertNotNull(camera, "Not a camera component"); - - camera->projType = CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC; - camera->orthographic.left = 0.0f; - camera->orthographic.right = SCREEN.width; - camera->orthographic.top = SCREEN.height; - camera->orthographic.bottom = 0.0f; - camera->nearClip = 0.1f; - camera->farClip = 1.0f; - - camera->viewType = CAMERA_VIEW_TYPE_2D; - glm_vec2_copy((vec2){ 0.0f, 0.0f }, camera->_2d.position); - camera->_2d.zoom = 1.0f; -} - -void cameraGetProjectionMatrix(camera_t *camera, mat4 dest) { - assertNotNull(camera, "Not a camera component"); - assertNotNull(dest, "Destination matrix must not be null"); - - if( - camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE || - camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED - ) { - glm_mat4_identity(dest); - glm_perspective( - camera->perspective.fov, - SCREEN.aspect, - camera->nearClip, - camera->farClip, - dest - ); - - if(camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED) { - dest[1][1] *= -1.0f; - } - } else if(camera->projType == CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) { - glm_mat4_identity(dest); - glm_ortho( - camera->orthographic.left, - camera->orthographic.right, - camera->orthographic.top, - camera->orthographic.bottom, - camera->nearClip, - camera->farClip, - dest - ); - } -} - -void cameraGetViewMatrix(camera_t *camera, mat4 dest) { - assertNotNull(camera, "Not a camera component"); - assertNotNull(dest, "Destination matrix must not be null"); - - if(camera->viewType == CAMERA_VIEW_TYPE_MATRIX) { - glm_mat4_ucopy(camera->view, dest); - } else if(camera->viewType == CAMERA_VIEW_TYPE_LOOKAT) { - glm_mat4_identity(dest); - glm_lookat( - camera->lookat.position, - camera->lookat.target, - camera->lookat.up, - dest - ); - } else if(camera->viewType == CAMERA_VIEW_TYPE_2D) { - glm_mat4_identity(dest); - glm_lookat( - (vec3){ camera->_2d.position[0], camera->_2d.position[1], 0.5f }, - (vec3){ camera->_2d.position[0], camera->_2d.position[1], 0.0f }, - (vec3){ 0.0f, 1.0f, 0.0f }, - dest - ); - } else if(camera->viewType == CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT) { - assertUnreachable("LOOKAT_PIXEL_PERFECT view type is not implemented yet"); - } -} \ No newline at end of file diff --git a/archive/camera/camera.h b/archive/camera/camera.h deleted file mode 100644 index a5ff7c23..00000000 --- a/archive/camera/camera.h +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "dusk.h" -#include "display/color.h" -#include "display/camera/cameraplatform.h" - -#ifndef cameraPushMatrixPlatform - #error "cameraPushMatrixPlatform must be defined" -#endif - - -typedef enum { - CAMERA_VIEW_TYPE_MATRIX, - CAMERA_VIEW_TYPE_LOOKAT, - CAMERA_VIEW_TYPE_2D, - CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT -} cameraviewtype_t; - -typedef struct camera_s { - union { - mat4 view; - - struct { - vec3 position; - vec3 target; - vec3 up; - } lookat; - - struct { - vec3 offset; - vec3 target; - vec3 up; - float_t pixelsPerUnit; - } lookatPixelPerfect; - - struct { - vec2 position; - float_t zoom; - } _2d; - }; - - union { - struct { - float_t fov; - } perspective; - - struct { - float_t left; - float_t right; - float_t top; - float_t bottom; - } orthographic; - }; - - float_t nearClip; - float_t farClip; - - cameraprojectiontype_t projType; - cameraviewtype_t viewType; -} camera_t; - -/** - * Initializes a camera to default values. This calls cameraInitPerspective. - */ -void cameraInit(camera_t *camera); - -/** - * Initializes a camera for perspective projection. - */ -void cameraInitPerspective(camera_t *camera); - -/** - * Initializes a camera for orthographic projection. - */ -void cameraInitOrthographic(camera_t *camera); - -/** - * Gets the projection matrix for a camera. - * - * @param camera Camera to get the projection matrix for - * @param dest Matrix to store the projection matrix in - */ -void cameraGetProjectionMatrix(camera_t *camera, mat4 dest); - -/** - * Gets the view matrix for a camera. - * - * @param camera Camera to get the view matrix for - * @param dest Matrix to store the view matrix in - */ -void cameraGetViewMatrix(camera_t *camera, mat4 dest); \ No newline at end of file diff --git a/archive/dusk/chunk.py b/archive/dusk/chunk.py deleted file mode 100644 index b15b917a..00000000 --- a/archive/dusk/chunk.py +++ /dev/null @@ -1,158 +0,0 @@ -import json -import os -from tools.dusk.event import Event -from tools.dusk.defs import CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_DEPTH, CHUNK_VERTEX_COUNT_MAX, TILE_SHAPE_NULL -from tools.dusk.tile import Tile -from tools.dusk.entity import Entity -from tools.dusk.region import Region -from tools.editor.map.vertexbuffer import VertexBuffer -from OpenGL.GL import * - -class Chunk: - def __init__(self, map, x, y, z): - self.map = map - self.x = x - self.y = y - self.z = z - self.current = {} - self.original = {} - self.entities = {} - self.regions = {} - self.onChunkData = Event() - self.dirty = False - - self.tiles = {} - self.vertexBuffer = VertexBuffer() - - # Test Region - region = self.regions[0] = Region(self) - region.minX = 0 - region.minY = 0 - region.minZ = 0 - region.maxX = 32 - region.maxY = 32 - region.maxZ = 32 - region.updateVertexs() - - # Gen tiles. - tileIndex = 0 - for tz in range(CHUNK_DEPTH): - for ty in range(CHUNK_HEIGHT): - for tx in range(CHUNK_WIDTH): - self.tiles[tileIndex] = Tile(self, tx, ty, tz, tileIndex) - tileIndex += 1 - - # Update vertices - self.tileUpdateVertices() - - def reload(self, newX, newY, newZ): - self.x = newX - self.y = newY - self.z = newZ - self.entities = {} - for tile in self.tiles.values(): - tile.chunkReload(newX, newY, newZ) - self.load() - - def tileUpdateVertices(self): - self.vertexBuffer.clear() - for tile in self.tiles.values(): - tile.buffer(self.vertexBuffer) - self.vertexBuffer.buildData() - - def load(self): - fname = self.getFilename() - if not fname or not os.path.exists(fname): - self.new() - return - try: - with open(fname, 'r') as f: - data = json.load(f) - - if not 'shapes' in data: - data['shapes'] = [] - - # For each tile. - for tile in self.tiles.values(): - tile.load(data) - - # For each entity. - self.entities = {} - if 'entities' in data: - for id, entData in enumerate(data['entities']): - ent = Entity(self) - ent.load(entData) - self.entities[id] = ent - - self.tileUpdateVertices() - self.dirty = False - self.onChunkData.invoke(self) - self.map.onEntityData.invoke() - except Exception as e: - raise RuntimeError(f"Failed to load chunk file: {e}") - - def save(self): - if not self.isDirty(): - return - - dataOut = { - 'shapes': [], - 'entities': [] - } - - for tile in self.tiles.values(): - dataOut['shapes'].append(tile.shape) - - for ent in self.entities.values(): - entData = {} - ent.save(entData) - dataOut['entities'].append(entData) - - fname = self.getFilename() - if not fname: - raise ValueError("No filename specified for saving chunk.") - try: - with open(fname, 'w') as f: - json.dump(dataOut, f) - self.dirty = False - self.onChunkData.invoke(self) - except Exception as e: - raise RuntimeError(f"Failed to save chunk file: {e}") - - def new(self): - for tile in self.tiles.values(): - tile.shape = TILE_SHAPE_NULL - - self.tileUpdateVertices() - self.dirty = False - self.onChunkData.invoke(self) - - def isDirty(self): - return self.dirty - - def getFilename(self): - if not self.map or not hasattr(self.map, 'getChunkDirectory'): - return None - dirPath = self.map.getChunkDirectory() - if dirPath is None: - return None - return f"{dirPath}/{self.x}_{self.y}_{self.z}.json" - - def draw(self): - self.vertexBuffer.draw() - - def addEntity(self, localX=0, localY=0, localZ=0): - ent = Entity(self, localX, localY, localZ) - self.entities[len(self.entities)] = ent - self.map.onEntityData.invoke() - self.dirty = True - return ent - - def removeEntity(self, entity): - for key, val in list(self.entities.items()): - if val == entity: - del self.entities[key] - self.map.onEntityData.invoke() - self.dirty = True - return True - return False \ No newline at end of file diff --git a/archive/dusk/defs.py b/archive/dusk/defs.py deleted file mode 100644 index 5f5c7952..00000000 --- a/archive/dusk/defs.py +++ /dev/null @@ -1,49 +0,0 @@ -from dotenv import load_dotenv, dotenv_values -import os -import sys - -current_file_path = os.path.abspath(__file__) -duskDefsPath = os.path.join(os.path.dirname(current_file_path), "..", "..", "src", "duskdefs.env") - -# Ensure the .env file exists -if not os.path.isfile(duskDefsPath): - print(f"Error: .env file not found at {duskDefsPath}") - sys.exit(1) - -load_dotenv(dotenv_path=duskDefsPath) -defs = {key: os.getenv(key) for key in os.environ.keys()} - -fileDefs = dotenv_values(dotenv_path=duskDefsPath) - -# Parsed out definitions -CHUNK_WIDTH = int(defs.get('CHUNK_WIDTH')) -CHUNK_HEIGHT = int(defs.get('CHUNK_HEIGHT')) -CHUNK_DEPTH = int(defs.get('CHUNK_DEPTH')) -CHUNK_TILE_COUNT = CHUNK_WIDTH * CHUNK_HEIGHT * CHUNK_DEPTH -CHUNK_VERTEX_COUNT_MAX = int(defs.get('CHUNK_VERTEX_COUNT_MAX')) - -TILE_WIDTH = float(defs.get('TILE_WIDTH')) -TILE_HEIGHT = float(defs.get('TILE_HEIGHT')) -TILE_DEPTH = float(defs.get('TILE_DEPTH')) - -RPG_CAMERA_PIXELS_PER_UNIT = float(defs.get('RPG_CAMERA_PIXELS_PER_UNIT')) -RPG_CAMERA_Z_OFFSET = float(defs.get('RPG_CAMERA_Z_OFFSET')) -RPG_CAMERA_FOV = float(defs.get('RPG_CAMERA_FOV')) - -MAP_WIDTH = 5 -MAP_HEIGHT = 5 -MAP_DEPTH = 3 -MAP_CHUNK_COUNT = MAP_WIDTH * MAP_HEIGHT * MAP_DEPTH - -TILE_SHAPES = {} -for key in defs.keys(): - if key.startswith('TILE_SHAPE_'): - globals()[key] = int(defs.get(key)) - TILE_SHAPES[key] = int(defs.get(key)) - -ENTITY_TYPES = {} -for key in defs.keys(): - if key.startswith('ENTITY_TYPE_'): - globals()[key] = int(defs.get(key)) - if key != 'ENTITY_TYPE_COUNT': - ENTITY_TYPES[key] = int(defs.get(key)) \ No newline at end of file diff --git a/archive/dusk/entity.py b/archive/dusk/entity.py deleted file mode 100644 index 221b28fc..00000000 --- a/archive/dusk/entity.py +++ /dev/null @@ -1,90 +0,0 @@ -from tools.dusk.defs import ENTITY_TYPE_NULL, ENTITY_TYPE_NPC, CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_DEPTH, TILE_WIDTH, TILE_HEIGHT, TILE_DEPTH -from tools.editor.map.vertexbuffer import VertexBuffer - -class Entity: - def __init__(self, chunk, localX=0, localY=0, localZ=0): - self.type = ENTITY_TYPE_NPC - self.name = "Unititled" - self.localX = localX % CHUNK_WIDTH - self.localY = localY % CHUNK_HEIGHT - self.localZ = localZ % CHUNK_DEPTH - - self.chunk = chunk - self.vertexBuffer = VertexBuffer() - pass - - def load(self, obj): - self.type = obj.get('type', ENTITY_TYPE_NULL) - self.localX = obj.get('x', 0) - self.localY = obj.get('y', 0) - self.localZ = obj.get('z', 0) - self.name = obj.get('name', "Untitled") - pass - - def save(self, obj): - obj['type'] = self.type - obj['name'] = self.name - obj['x'] = self.localX - obj['y'] = self.localY - obj['z'] = self.localZ - pass - - def setType(self, entityType): - if self.type == entityType: - return - self.type = entityType - self.chunk.dirty = True - self.chunk.map.onEntityData.invoke() - - def setName(self, name): - if self.name == name: - return - self.name = name - self.chunk.dirty = True - self.chunk.map.onEntityData.invoke() - - def draw(self): - self.vertexBuffer.clear() - - startX = (self.chunk.x * CHUNK_WIDTH + self.localX) * TILE_WIDTH - startY = (self.chunk.y * CHUNK_HEIGHT + self.localY) * TILE_HEIGHT - startZ = (self.chunk.z * CHUNK_DEPTH + self.localZ) * TILE_DEPTH - w = TILE_WIDTH - h = TILE_HEIGHT - d = TILE_DEPTH - - # Center - startX -= w / 2 - startY -= h / 2 - startZ -= d / 2 - - # Offset upwards a little - startZ += 1 - - # Buffer simple quad at current position (need 6 positions) - self.vertexBuffer.vertices = [ - startX, startY, startZ, - startX + w, startY, startZ, - startX + w, startY + h, startZ, - startX, startY, startZ, - startX + w, startY + h, startZ, - startX, startY + h, startZ, - ] - self.vertexBuffer.colors = [ - 1.0, 0.0, 1.0, 1.0, - 1.0, 0.0, 1.0, 1.0, - 1.0, 0.0, 1.0, 1.0, - 1.0, 0.0, 1.0, 1.0, - 1.0, 0.0, 1.0, 1.0, - 1.0, 0.0, 1.0, 1.0, - ] - self.vertexBuffer.uvs = [ - 0.0, 0.0, - 1.0, 0.0, - 1.0, 1.0, - 0.0, 0.0, - 1.0, 1.0, - 0.0, 1.0, - ] - self.vertexBuffer.buildData() - self.vertexBuffer.draw() \ No newline at end of file diff --git a/archive/dusk/event.py b/archive/dusk/event.py deleted file mode 100644 index d98eed80..00000000 --- a/archive/dusk/event.py +++ /dev/null @@ -1,18 +0,0 @@ -class Event: - def __init__(self): - self._subscribers = [] - - def sub(self, callback): - """Subscribe a callback to the event.""" - if callback not in self._subscribers: - self._subscribers.append(callback) - - def unsub(self, callback): - """Unsubscribe a callback from the event.""" - if callback in self._subscribers: - self._subscribers.remove(callback) - - def invoke(self, *args, **kwargs): - """Invoke all subscribers with the given arguments.""" - for callback in self._subscribers: - callback(*args, **kwargs) diff --git a/archive/dusk/map.py b/archive/dusk/map.py deleted file mode 100644 index 4b2ebbf0..00000000 --- a/archive/dusk/map.py +++ /dev/null @@ -1,259 +0,0 @@ -import json -import sys -from tools.dusk.event import Event -from PyQt5.QtWidgets import QFileDialog, QMessageBox -from PyQt5.QtCore import QTimer -import os -from tools.dusk.chunk import Chunk -from tools.dusk.defs import MAP_WIDTH, MAP_HEIGHT, MAP_DEPTH, CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_DEPTH -import traceback - -MAP_DEFAULT_PATH = os.path.join(os.path.dirname(__file__), '../../assets/map/') -EDITOR_CONFIG_PATH = os.path.join(os.path.dirname(__file__), '.editor') - -class Map: - def __init__(self, parent): - self.parent = parent - self.data = {} - self.dataOriginal = {} - self.position = [None, None, None] # x, y, z - self.topLeftX = None - self.topLeftY = None - self.topLeftZ = None - self.chunks = {} - self.onMapData = Event() - self.onPositionChange = Event() - self.onEntityData = Event() - self.mapFileName = None - self.lastFile = None - self.firstLoad = True - - index = 0 - for x in range(MAP_WIDTH): - for y in range(MAP_HEIGHT): - for z in range(MAP_DEPTH): - self.chunks[index] = Chunk(self, x, y, z) - index += 1 - - # Only in editor instances: - self.moveTo(0, 0, 0) - if parent is not None: - QTimer.singleShot(16, self.loadLastFile) - - def loadLastFile(self): - if not os.path.exists(EDITOR_CONFIG_PATH): - return - try: - with open(EDITOR_CONFIG_PATH, 'r') as f: - config = json.load(f) - lastFile = config.get('lastFile') - lastPosition = config.get('lastPosition') - leftPanelIndex = config.get('leftPanelIndex') - if lastFile and os.path.exists(lastFile): - self.load(lastFile) - if lastPosition and isinstance(lastPosition, list) and len(lastPosition) == 3: - self.moveTo(*lastPosition) - if leftPanelIndex is not None: - self.parent.leftPanel.tabs.setCurrentIndex(leftPanelIndex) - except Exception: - traceback.print_exc() - - def updateEditorConfig(self): - if self.parent is None: - return - try: - mapFileName = self.getMapFilename() - config = { - 'lastFile': mapFileName if mapFileName else "", - 'lastPosition': self.position, - 'leftPanelIndex': self.parent.leftPanel.tabs.currentIndex() - } - config_dir = os.path.dirname(EDITOR_CONFIG_PATH) - if not os.path.exists(config_dir): - os.makedirs(config_dir, exist_ok=True) - with open(EDITOR_CONFIG_PATH, 'w') as f: - json.dump(config, f, indent=2) - except Exception: - traceback.print_exc() - - def newFile(self): - self.data = {} - self.dataOriginal = {} - self.mapFileName = None - self.lastFile = None - for chunk in self.chunks.values(): - chunk.new() - self.moveTo(0, 0, 0) - self.onMapData.invoke(self.data) - self.updateEditorConfig() - - def save(self, fname=None): - if not self.getMapFilename() and fname is None: - filePath, _ = QFileDialog.getSaveFileName(None, "Save Map File", MAP_DEFAULT_PATH, "Map Files (*.json)") - if not filePath: - return - self.mapFileName = filePath - if fname: - self.mapFileName = fname - try: - with open(self.getMapFilename(), 'w') as f: - json.dump(self.data, f, indent=2) - self.dataOriginal = json.loads(json.dumps(self.data)) # Deep copy - for chunk in self.chunks.values(): - chunk.save() - self.updateEditorConfig() - except Exception as e: - traceback.print_exc() - QMessageBox.critical(None, "Save Error", f"Failed to save map file:\n{e}") - - def load(self, fileName): - try: - with open(fileName, 'r') as f: - self.data = json.load(f) - self.mapFileName = fileName - self.dataOriginal = json.loads(json.dumps(self.data)) # Deep copy - for chunk in self.chunks.values(): - chunk.load() - self.onMapData.invoke(self.data) - self.updateEditorConfig() - except Exception as e: - traceback.print_exc() - QMessageBox.critical(None, "Load Error", f"Failed to load map file:\n{e}") - - def isMapFileDirty(self): - return json.dumps(self.data, sort_keys=True) != json.dumps(self.dataOriginal, sort_keys=True) - - def isDirty(self): - return self.isMapFileDirty() or self.anyChunksDirty() - - def getMapFilename(self): - return self.mapFileName if self.mapFileName and os.path.exists(self.mapFileName) else None - - def getMapDirectory(self): - if self.mapFileName is None: - return None - dirname = os.path.dirname(self.mapFileName) - return dirname - - def getChunkDirectory(self): - dirName = self.getMapDirectory() - if dirName is None: - return None - return os.path.join(dirName, 'chunks') - - def anyChunksDirty(self): - for chunk in self.chunks.values(): - if chunk.isDirty(): - return True - return False - - def moveTo(self, x, y, z): - if self.position == [x, y, z]: - return - - # We need to decide if the chunks should be unloaded here or not. - newTopLeftChunkX = x // CHUNK_WIDTH - (MAP_WIDTH // 2) - newTopLeftChunkY = y // CHUNK_HEIGHT - (MAP_HEIGHT // 2) - newTopLeftChunkZ = z // CHUNK_DEPTH - (MAP_DEPTH // 2) - - if(newTopLeftChunkX != self.topLeftX or - newTopLeftChunkY != self.topLeftY or - newTopLeftChunkZ != self.topLeftZ): - - chunksToUnload = [] - chunksToKeep = [] - for chunk in self.chunks.values(): - chunkWorldX = chunk.x - chunkWorldY = chunk.y - chunkWorldZ = chunk.z - if(chunkWorldX < newTopLeftChunkX or - chunkWorldX >= newTopLeftChunkX + MAP_WIDTH or - chunkWorldY < newTopLeftChunkY or - chunkWorldY >= newTopLeftChunkY + MAP_HEIGHT or - chunkWorldZ < newTopLeftChunkZ or - chunkWorldZ >= newTopLeftChunkZ + MAP_DEPTH): - chunksToUnload.append(chunk) - else: - chunksToKeep.append(chunk) - - # Unload chunks that are out of the new bounds. - for chunk in chunksToUnload: - if chunk.isDirty(): - print(f"Can't move map, some chunks are dirty: ({chunk.x}, {chunk.y}, {chunk.z})") - return - - # Now we can safely unload the chunks. - chunkIndex = 0 - newChunks = {} - for chunk in chunksToKeep: - newChunks[chunkIndex] = chunk - chunkIndex += 1 - - for xPos in range(newTopLeftChunkX, newTopLeftChunkX + MAP_WIDTH): - for yPos in range(newTopLeftChunkY, newTopLeftChunkY + MAP_HEIGHT): - for zPos in range(newTopLeftChunkZ, newTopLeftChunkZ + MAP_DEPTH): - # Check if we already have this chunk. - found = False - for chunk in chunksToKeep: - if chunk.x == xPos and chunk.y == yPos and chunk.z == zPos: - found = True - break - if not found: - # Create a new chunk. - newChunk = chunksToUnload.pop() - newChunk.reload(xPos, yPos, zPos) - newChunks[chunkIndex] = newChunk - chunkIndex += 1 - - self.chunks = newChunks - self.topLeftX = newTopLeftChunkX - self.topLeftY = newTopLeftChunkY - self.topLeftZ = newTopLeftChunkZ - - self.position = [x, y, z] - self.onPositionChange.invoke(self.position) - if not self.firstLoad: - self.updateEditorConfig() - self.firstLoad = False - - def moveRelative(self, x, y, z): - self.moveTo( - self.position[0] + x, - self.position[1] + y, - self.position[2] + z - ) - - def draw(self): - for chunk in self.chunks.values(): - chunk.draw() - - for chunk in self.chunks.values(): - for entity in chunk.entities.values(): - entity.draw() - - # Only render on Region tab - if self.parent.leftPanel.tabs.currentWidget() == self.parent.leftPanel.regionPanel: - for chunk in self.chunks.values(): - for region in chunk.regions.values(): - region.draw() - - def getChunkAtWorldPos(self, x, y, z): - chunkX = x // CHUNK_WIDTH - chunkY = y // CHUNK_HEIGHT - chunkZ = z // CHUNK_DEPTH - for chunk in self.chunks.values(): - if chunk.x == chunkX and chunk.y == chunkY and chunk.z == chunkZ: - return chunk - return None - - def getTileAtWorldPos(self, x, y, z): - chunk = self.getChunkAtWorldPos(x, y, z) - if not chunk: - print("No chunk found at position:", (x, y, z)) - return None - - tileX = x % CHUNK_WIDTH - tileY = y % CHUNK_HEIGHT - tileZ = z % CHUNK_DEPTH - tileIndex = tileX + tileY * CHUNK_WIDTH + tileZ * CHUNK_WIDTH * CHUNK_HEIGHT - return chunk.tiles.get(tileIndex) \ No newline at end of file diff --git a/archive/dusk/region.py b/archive/dusk/region.py deleted file mode 100644 index 4737afcf..00000000 --- a/archive/dusk/region.py +++ /dev/null @@ -1,141 +0,0 @@ -from tools.dusk.defs import CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_DEPTH, TILE_WIDTH, TILE_HEIGHT, TILE_DEPTH -from tools.editor.map.vertexbuffer import VertexBuffer -from OpenGL.GL import * -from OpenGL.GLU import * - -class Region: - def __init__(self, chunk): - self.minX = 0 - self.minY = 0 - self.minZ = 0 - self.maxX = 0 - self.maxY = 0 - self.maxZ = 0 - self.chunk = chunk - self.vertexBuffer = VertexBuffer() - self.color = (1.0, 0.0, 0.0) - self.updateVertexs() - pass - - def updateVertexs(self): - # Draw a quad, semi transparent with solid outlines - vminX = (self.minX * CHUNK_WIDTH) * TILE_WIDTH - vminY = (self.minY * CHUNK_HEIGHT) * TILE_HEIGHT - vminZ = (self.minZ * CHUNK_DEPTH) * TILE_DEPTH - vmaxX = (self.maxX * CHUNK_WIDTH) * TILE_WIDTH - vmaxY = (self.maxY * CHUNK_HEIGHT) * TILE_HEIGHT - vmaxZ = (self.maxZ * CHUNK_DEPTH) * TILE_DEPTH - alpha = 0.25 - - # Move back half a tile width - vminX -= TILE_WIDTH / 2 - vmaxX -= TILE_WIDTH / 2 - vminY -= TILE_HEIGHT / 2 - vmaxY -= TILE_HEIGHT / 2 - vminZ -= TILE_DEPTH / 2 - vmaxZ -= TILE_DEPTH / 2 - - # Cube (6 verts per face) - self.vertexBuffer.vertices = [ - # Front face - vminX, vminY, vmaxZ, - vmaxX, vminY, vmaxZ, - vmaxX, vmaxY, vmaxZ, - vminX, vminY, vmaxZ, - vmaxX, vmaxY, vmaxZ, - vminX, vmaxY, vmaxZ, - - # Back face - vmaxX, vminY, vminZ, - vminX, vminY, vminZ, - vminX, vmaxY, vminZ, - vmaxX, vminY, vminZ, - vminX, vmaxY, vminZ, - vmaxX, vmaxY, vminZ, - - # Left face - vminX, vminY, vminZ, - vminX, vminY, vmaxZ, - vminX, vmaxY, vmaxZ, - vminX, vminY, vminZ, - vminX, vmaxY, vmaxZ, - vminX, vmaxY, vminZ, - - # Right face - vmaxX, vminY, vmaxZ, - vmaxX, vminY, vminZ, - vmaxX, vmaxY, vminZ, - vmaxX, vminY, vmaxZ, - vmaxX, vmaxY, vminZ, - vmaxX, vmaxY, vmaxZ, - - # Top face - vminX, vmaxY, vmaxZ, - vmaxX, vmaxY, vmaxZ, - vmaxX, vmaxY, vminZ, - vminX, vmaxY, vmaxZ, - vmaxX, vmaxY, vminZ, - vminX, vmaxY, vminZ, - - # Bottom face - vminX, vminY, vminZ, - vmaxX, vminY, vminZ, - vmaxX, vminY, vmaxZ, - vminX, vminY, vminZ, - vmaxX, vminY, vmaxZ, - vminX, vminY, vmaxZ, - ] - - self.vertexBuffer.colors = [ - # Front face - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - - # Back face - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - - # Left face - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - - # Right face - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - - # Top face - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - - # Bottom face - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - self.color[0], self.color[1], self.color[2], alpha, - ] - self.vertexBuffer.buildData() - - def draw(self): - self.vertexBuffer.draw() \ No newline at end of file diff --git a/archive/dusk/tile.py b/archive/dusk/tile.py deleted file mode 100644 index 8f91a335..00000000 --- a/archive/dusk/tile.py +++ /dev/null @@ -1,206 +0,0 @@ -from OpenGL.GL import * -from tools.dusk.defs import ( - TILE_WIDTH, TILE_HEIGHT, TILE_DEPTH, - CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_DEPTH, - TILE_SHAPE_NULL, TILE_SHAPE_FLOOR, - TILE_SHAPE_RAMP_NORTH, TILE_SHAPE_RAMP_SOUTH, - TILE_SHAPE_RAMP_EAST, TILE_SHAPE_RAMP_WEST, - TILE_SHAPE_RAMP_SOUTHWEST, TILE_SHAPE_RAMP_SOUTHEAST, - TILE_SHAPE_RAMP_NORTHWEST, TILE_SHAPE_RAMP_NORTHEAST -) - -def getItem(arr, index, default): - if index < len(arr): - return arr[index] - return default - -class Tile: - def __init__(self, chunk, x, y, z, tileIndex): - self.shape = TILE_SHAPE_NULL - - self.chunk = chunk - self.x = x - self.y = y - self.z = z - self.index = tileIndex - - self.posX = x * TILE_WIDTH + chunk.x * CHUNK_WIDTH * TILE_WIDTH - self.posY = y * TILE_HEIGHT + chunk.y * CHUNK_HEIGHT * TILE_HEIGHT - self.posZ = z * TILE_DEPTH + chunk.z * CHUNK_DEPTH * TILE_DEPTH - - def chunkReload(self, newX, newY, newZ): - self.posX = self.x * TILE_WIDTH + newX * CHUNK_WIDTH * TILE_WIDTH - self.posY = self.y * TILE_HEIGHT + newY * CHUNK_HEIGHT * TILE_HEIGHT - self.posZ = self.z * TILE_DEPTH + newZ * CHUNK_DEPTH * TILE_DEPTH - - def load(self, chunkData): - self.shape = getItem(chunkData['shapes'], self.index, TILE_SHAPE_NULL) - - def setShape(self, shape): - if shape == self.shape: - return - - self.shape = shape - self.chunk.dirty = True - self.chunk.tileUpdateVertices() - self.chunk.onChunkData.invoke(self.chunk) - - def getBaseTileModel(self): - vertices = [] - indices = [] - uvs = [] - colors = [] - - if self.shape == TILE_SHAPE_NULL: - pass - - elif self.shape == TILE_SHAPE_FLOOR: - vertices = [ - (self.posX, self.posY, self.posZ), - (self.posX + TILE_WIDTH, self.posY, self.posZ), - (self.posX + TILE_WIDTH, self.posY + TILE_HEIGHT, self.posZ), - (self.posX, self.posY + TILE_HEIGHT, self.posZ) - ] - indices = [0, 1, 2, 0, 2, 3] - uvs = [ (0, 0), (1, 0), (1, 1), (0, 1) ] - colors = [ (255, 255, 255, 255) ] * 4 - - elif self.shape == TILE_SHAPE_RAMP_NORTH: - vertices = [ - (self.posX, self.posY, self.posZ + TILE_DEPTH), - (self.posX + TILE_WIDTH, self.posY, self.posZ + TILE_DEPTH), - (self.posX + TILE_WIDTH, self.posY + TILE_HEIGHT, self.posZ), - (self.posX, self.posY + TILE_HEIGHT, self.posZ) - ] - indices = [0, 1, 2, 0, 2, 3] - uvs = [ (0, 0), (1, 0), (1, 1), (0, 1) ] - colors = [ (255, 0, 0, 255) ] * 4 - - elif self.shape == TILE_SHAPE_RAMP_SOUTH: - vertices = [ - (self.posX, self.posY, self.posZ), - (self.posX + TILE_WIDTH, self.posY, self.posZ), - (self.posX + TILE_WIDTH, self.posY + TILE_HEIGHT, self.posZ + TILE_DEPTH), - (self.posX, self.posY + TILE_HEIGHT, self.posZ + TILE_DEPTH) - ] - indices = [0, 1, 2, 0, 2, 3] - uvs = [ (0, 0), (1, 0), (1, 1), (0, 1) ] - colors = [ (0, 255, 0, 255) ] * 4 - - elif self.shape == TILE_SHAPE_RAMP_EAST: - vertices = [ - (self.posX, self.posY, self.posZ), - (self.posX + TILE_WIDTH, self.posY, self.posZ + TILE_DEPTH), - (self.posX + TILE_WIDTH, self.posY + TILE_HEIGHT, self.posZ + TILE_DEPTH), - (self.posX, self.posY + TILE_HEIGHT, self.posZ) - ] - indices = [0, 1, 2, 0, 2, 3] - uvs = [ (0, 0), (1, 0), (1, 1), (0, 1) ] - colors = [ (0, 0, 255, 255) ] * 4 - - elif self.shape == TILE_SHAPE_RAMP_WEST: - vertices = [ - (self.posX, self.posY, self.posZ + TILE_DEPTH), - (self.posX + TILE_WIDTH, self.posY, self.posZ), - (self.posX + TILE_WIDTH, self.posY + TILE_HEIGHT, self.posZ), - (self.posX, self.posY + TILE_HEIGHT, self.posZ + TILE_DEPTH) - ] - indices = [0, 1, 2, 0, 2, 3] - uvs = [ (0, 0), (1, 0), (1, 1), (0, 1) ] - colors = [ (255, 255, 0, 255) ] * 4 - - elif self.shape == TILE_SHAPE_RAMP_SOUTHWEST: - vertices = [ - (self.posX, self.posY, self.posZ + TILE_DEPTH), - (self.posX + TILE_WIDTH, self.posY, self.posZ), - (self.posX + TILE_WIDTH, self.posY + TILE_HEIGHT, self.posZ + TILE_DEPTH), - (self.posX, self.posY + TILE_HEIGHT, self.posZ + TILE_DEPTH) - ] - indices = [0, 1, 2, 0, 2, 3] - uvs = [ (0, 0), (1, 0), (1, 1), (0, 1) ] - colors = [ (255, 128, 0, 255) ] * 4 - - elif self.shape == TILE_SHAPE_RAMP_NORTHWEST: - vertices = [ - (self.posX, self.posY, self.posZ + TILE_DEPTH), - (self.posX + TILE_WIDTH, self.posY, self.posZ + TILE_DEPTH), - (self.posX + TILE_WIDTH, self.posY + TILE_HEIGHT, self.posZ), - (self.posX, self.posY + TILE_HEIGHT, self.posZ + TILE_DEPTH) - ] - indices = [0, 1, 2, 0, 2, 3] - uvs = [ (0, 0), (1, 0), (1, 1), (0, 1) ] - colors = [ (128, 255, 0, 255) ] * 4 - - elif self.shape == TILE_SHAPE_RAMP_NORTHEAST: - vertices = [ - (self.posX, self.posY, self.posZ + TILE_DEPTH), - (self.posX + TILE_WIDTH, self.posY, self.posZ + TILE_DEPTH), - (self.posX + TILE_WIDTH, self.posY + TILE_HEIGHT, self.posZ + TILE_DEPTH), - (self.posX, self.posY + TILE_HEIGHT, self.posZ) - ] - indices = [0, 1, 2, 0, 2, 3] - uvs = [ (0, 0), (1, 0), (1, 1), (0, 1) ] - colors = [ (0, 255, 128, 255) ] * 4 - - elif self.shape == TILE_SHAPE_RAMP_SOUTHEAST: - vertices = [ - (self.posX, self.posY, self.posZ), - (self.posX + TILE_WIDTH, self.posY, self.posZ + TILE_DEPTH), - (self.posX + TILE_WIDTH, self.posY + TILE_HEIGHT, self.posZ + TILE_DEPTH), - (self.posX, self.posY + TILE_HEIGHT, self.posZ + TILE_DEPTH) - ] - indices = [0, 1, 2, 0, 2, 3] - uvs = [ (0, 0), (1, 0), (1, 1), (0, 1) ] - colors = [ (255, 128, 255, 255) ] * 4 - - else: - # Solid black cube for unknown shape - x0, y0, z0 = self.posX, self.posY, self.posZ - x1, y1, z1 = self.posX + TILE_WIDTH, self.posY + TILE_HEIGHT, self.posZ + TILE_DEPTH - vertices = [ - (x0, y0, z0), (x1, y0, z0), (x1, y1, z0), (x0, y1, z0), # bottom - (x0, y0, z1), (x1, y0, z1), (x1, y1, z1), (x0, y1, z1) # top - ] - indices = [ - 0,1,2, 0,2,3, # bottom - 4,5,6, 4,6,7, # top - 0,1,5, 0,5,4, # front - 2,3,7, 2,7,6, # back - 1,2,6, 1,6,5, # right - 3,0,4, 3,4,7 # left - ] - uvs = [ (0,0) ] * 8 - colors = [ (0,0,0,255) ] * 8 - - return { - 'vertices': vertices, - 'indices': indices, - 'uvs': uvs, - 'colors': colors - } - - def buffer(self, vertexBuffer): - if self.shape == TILE_SHAPE_NULL: - return - - # New code: - baseData = self.getBaseTileModel() - - # Base data is indiced but we need to buffer unindiced data - for index in baseData['indices']: - verts = baseData['vertices'][index] - uv = baseData['uvs'][index] - color = baseData['colors'][index] - - vertexBuffer.vertices.extend([ - verts[0] - (TILE_WIDTH / 2.0), - verts[1] - (TILE_HEIGHT / 2.0), - verts[2] - (TILE_DEPTH / 2.0) - ]) - - vertexBuffer.colors.extend([ - color[0] / 255.0, - color[1] / 255.0, - color[2] / 255.0, - color[3] / 255.0 - ]) \ No newline at end of file diff --git a/archive/editor/__main__.py b/archive/editor/__main__.py deleted file mode 100755 index 90974893..00000000 --- a/archive/editor/__main__.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 -import sys -from PyQt5.QtWidgets import ( - QApplication, QVBoxLayout, QPushButton, - QDialog -) -from OpenGL.GL import * -from OpenGL.GLU import * -from tools.editor.maptool import MapWindow -from tools.editor.langtool import LangToolWindow -from tools.editor.cutscenetool import CutsceneToolWindow - -DEFAULT_TOOL = None -DEFAULT_TOOL = "map" -# DEFAULT_TOOL = "cutscene" - -TOOLS = [ - ("Map Editor", "map", MapWindow), - ("Language Editor", "language", LangToolWindow), - ("Cutscene Editor", "cutscene", CutsceneToolWindow), -] - -class EditorChoiceDialog(QDialog): - def __init__(self): - super().__init__() - self.setWindowTitle("Choose Tool") - layout = QVBoxLayout(self) - self.selected = None - for label, key, win_cls in TOOLS: - btn = QPushButton(label) - btn.clicked.connect(lambda checked, w=win_cls: self.choose_tool(w)) - layout.addWidget(btn) - - def choose_tool(self, win_cls): - self.selected = win_cls - self.accept() - - def get_choice(self): - return self.selected - -def main(): - app = QApplication(sys.argv) - tool_map = { key: win_cls for _, key, win_cls in TOOLS } - if DEFAULT_TOOL in tool_map: - win_cls = tool_map[DEFAULT_TOOL] - else: - choice_dialog = EditorChoiceDialog() - if choice_dialog.exec_() == QDialog.Accepted: - win_cls = choice_dialog.get_choice() - else: - sys.exit(0) - win = win_cls() - win.show() - sys.exit(app.exec_()) - -if __name__ == "__main__": - main() diff --git a/archive/editor/cutscene/cutsceneitemeditor.py b/archive/editor/cutscene/cutsceneitemeditor.py deleted file mode 100644 index 0241ccdc..00000000 --- a/archive/editor/cutscene/cutsceneitemeditor.py +++ /dev/null @@ -1,58 +0,0 @@ -from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLineEdit, QLabel, QSizePolicy, QComboBox, QHBoxLayout, QSpacerItem -from PyQt5.QtCore import Qt, pyqtSignal -from .cutscenewait import CutsceneWaitEditor -from .cutscenetext import CutsceneTextEditor - -EDITOR_MAP = ( - ( "wait", "Wait", CutsceneWaitEditor ), - ( "text", "Text", CutsceneTextEditor ) -) - -class CutsceneItemEditor(QWidget): - def __init__(self, parent=None): - super().__init__(parent) - self.layout = QVBoxLayout(self) - self.layout.setAlignment(Qt.AlignTop | Qt.AlignLeft) - self.layout.addWidget(QLabel("Item Properties:")) - - rowLayout = QHBoxLayout() - rowLayout.setSpacing(8) - - rowLayout.addWidget(QLabel("Name:")) - self.nameInput = QLineEdit() - rowLayout.addWidget(self.nameInput) - - rowLayout.addWidget(QLabel("Type:")) - self.typeDropdown = QComboBox() - self.typeDropdown.addItems([typeName for typeKey, typeName, editorClass in EDITOR_MAP]) - rowLayout.addWidget(self.typeDropdown) - self.layout.addLayout(rowLayout) - - self.activeEditor = None - - # Events - self.nameInput.textChanged.connect(self.onNameChanged) - self.typeDropdown.currentTextChanged.connect(self.onTypeChanged) - - # First load - self.onNameChanged(self.nameInput.text()) - self.onTypeChanged(self.typeDropdown.currentText()) - - def onNameChanged(self, nameText): - pass - - def onTypeChanged(self, typeText): - typeKey = typeText.lower() - - # Remove existing editor - if self.activeEditor: - self.layout.removeWidget(self.activeEditor) - self.activeEditor.deleteLater() - self.activeEditor = None - - # Create new editor - for key, name, editorClass in EDITOR_MAP: - if key == typeKey: - self.activeEditor = editorClass() - self.layout.addWidget(self.activeEditor) - break \ No newline at end of file diff --git a/archive/editor/cutscene/cutscenemenubar.py b/archive/editor/cutscene/cutscenemenubar.py deleted file mode 100644 index 991ad017..00000000 --- a/archive/editor/cutscene/cutscenemenubar.py +++ /dev/null @@ -1,54 +0,0 @@ -from PyQt5.QtWidgets import QMenuBar, QAction, QFileDialog, QMessageBox -from PyQt5.QtGui import QKeySequence - -class CutsceneMenuBar(QMenuBar): - def __init__(self, parent): - super().__init__(parent) - self.parent = parent - fileMenu = self.addMenu("File") - - self.newAction = QAction("New", self) - self.newAction.setShortcut(QKeySequence.New) - self.newAction.triggered.connect(self.newFile) - fileMenu.addAction(self.newAction) - - self.openAction = QAction("Open", self) - self.openAction.setShortcut(QKeySequence.Open) - self.openAction.triggered.connect(self.openFile) - fileMenu.addAction(self.openAction) - - self.saveAction = QAction("Save", self) - self.saveAction.setShortcut(QKeySequence.Save) - self.saveAction.triggered.connect(self.saveFile) - fileMenu.addAction(self.saveAction) - - self.saveAsAction = QAction("Save As", self) - self.saveAsAction.setShortcut(QKeySequence.SaveAs) - self.saveAsAction.triggered.connect(self.saveFileAs) - fileMenu.addAction(self.saveAsAction) - - def newFile(self): - self.parent.clearCutscene() - - def openFile(self): - path, _ = QFileDialog.getOpenFileName(self.parent, "Open Cutscene File", "", "JSON Files (*.json);;All Files (*)") - if not path: - return - - # TODO: Load file contents into timeline - self.parent.currentFile = path - pass - - def saveFile(self): - if not self.parent.currentFile: - self.saveFileAs() - return - - # TODO: Save timeline to self.parent.currentFile - pass - - def saveFileAs(self): - path, _ = QFileDialog.getSaveFileName(self.parent, "Save Cutscene File As", "", "JSON Files (*.json);;All Files (*)") - if path: - self.parent.currentFile = path - self.saveFile() diff --git a/archive/editor/cutscene/cutscenetext.py b/archive/editor/cutscene/cutscenetext.py deleted file mode 100644 index bf963dde..00000000 --- a/archive/editor/cutscene/cutscenetext.py +++ /dev/null @@ -1,21 +0,0 @@ -from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QTextEdit -from PyQt5.QtCore import Qt - -class CutsceneTextEditor(QWidget): - def __init__(self, parent=None): - super().__init__(parent) - layout = QVBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(0) - label = QLabel("Text:") - label.setSizePolicy(label.sizePolicy().Expanding, label.sizePolicy().Fixed) - layout.addWidget(label) - self.textInput = QTextEdit() - self.textInput.setSizePolicy(self.textInput.sizePolicy().Expanding, self.textInput.sizePolicy().Expanding) - layout.addWidget(self.textInput, stretch=1) - - def setText(self, text): - self.textInput.setPlainText(text) - - def getText(self): - return self.textInput.toPlainText() diff --git a/archive/editor/cutscene/cutscenewait.py b/archive/editor/cutscene/cutscenewait.py deleted file mode 100644 index 3dffb9cc..00000000 --- a/archive/editor/cutscene/cutscenewait.py +++ /dev/null @@ -1,20 +0,0 @@ -from PyQt5.QtWidgets import QWidget, QFormLayout, QDoubleSpinBox, QLabel - -class CutsceneWaitEditor(QWidget): - def __init__(self, parent=None): - super().__init__(parent) - layout = QFormLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.setSpacing(0) - self.waitTimeInput = QDoubleSpinBox() - self.waitTimeInput.setMinimum(0.0) - self.waitTimeInput.setMaximum(9999.0) - self.waitTimeInput.setDecimals(2) - self.waitTimeInput.setSingleStep(0.1) - layout.addRow(QLabel("Wait Time (seconds):"), self.waitTimeInput) - - def setWaitTime(self, value): - self.waitTimeInput.setValue(value) - - def getWaitTime(self): - return self.waitTimeInput.value() diff --git a/archive/editor/cutscenetool.py b/archive/editor/cutscenetool.py deleted file mode 100644 index 3612a6ac..00000000 --- a/archive/editor/cutscenetool.py +++ /dev/null @@ -1,101 +0,0 @@ -from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QListWidget, QListWidgetItem, QMenuBar, QAction, QFileDialog, QMessageBox -from PyQt5.QtGui import QKeySequence -from tools.editor.cutscene.cutsceneitemeditor import CutsceneItemEditor -from tools.editor.cutscene.cutscenemenubar import CutsceneMenuBar -import sys - -class CutsceneToolWindow(QMainWindow): - def __init__(self): - super().__init__() - self.setWindowTitle("Dusk Cutscene Editor") - self.setGeometry(100, 100, 800, 600) - self.nextItemNumber = 1 # Track next available number - self.currentFile = None - self.dirty = False # Track unsaved changes - - # File menu (handled by CutsceneMenuBar) - menubar = CutsceneMenuBar(self) - self.setMenuBar(menubar) - - # Main layout: horizontal split - central = QWidget() - mainLayout = QHBoxLayout(central) - self.setCentralWidget(central) - - # Timeline - leftPanel = QWidget() - leftLayout = QVBoxLayout(leftPanel) - - self.timelineList = QListWidget() - self.timelineList.setSelectionMode(QListWidget.SingleSelection) - leftLayout.addWidget(QLabel("Cutscene Timeline")) - leftLayout.addWidget(self.timelineList) - - btnLayout = QHBoxLayout() - self.addBtn = QPushButton("Add") - self.removeBtn = QPushButton("Remove") - btnLayout.addWidget(self.addBtn) - btnLayout.addWidget(self.removeBtn) - leftLayout.addLayout(btnLayout) - mainLayout.addWidget(leftPanel, 2) - - # Property editor - self.editorPanel = QWidget() - self.editorLayout = QVBoxLayout(self.editorPanel) - self.itemEditor = None # Only create when needed - mainLayout.addWidget(self.editorPanel, 3) - - # Events - self.timelineList.currentItemChanged.connect(self.onItemSelected) - self.addBtn.clicked.connect(self.addCutsceneItem) - self.removeBtn.clicked.connect(self.removeCutsceneItem) - - def addCutsceneItem(self): - name = f"Cutscene item {self.nextItemNumber}" - timelineItem = QListWidgetItem(name) - self.timelineList.addItem(timelineItem) - self.timelineList.setCurrentItem(timelineItem) - self.nextItemNumber += 1 - self.dirty = True - - def removeCutsceneItem(self): - row = self.timelineList.currentRow() - if row < 0: - return - self.timelineList.takeItem(row) - self.dirty = True - - # Remove editor if nothing selected - if self.timelineList.currentItem() is None or self.itemEditor is None: - return - - self.editorLayout.removeWidget(self.itemEditor) - self.itemEditor.deleteLater() - self.itemEditor = None - - def clearCutscene(self): - self.timelineList.clear() - self.nextItemNumber = 1 - self.currentFile = None - self.dirty = False - if self.itemEditor: - self.editorLayout.removeWidget(self.itemEditor) - - def onItemSelected(self, current, previous): - if current: - if not self.itemEditor: - self.itemEditor = CutsceneItemEditor() - self.editorLayout.addWidget(self.itemEditor) - return - - if not self.itemEditor: - return - self.editorLayout.removeWidget(self.itemEditor) - self.itemEditor.deleteLater() - self.itemEditor = None - -if __name__ == "__main__": - app = QApplication(sys.argv) - window = CutsceneToolWindow() - window.show() - sys.exit(app.exec_()) diff --git a/archive/editor/langtool.py b/archive/editor/langtool.py deleted file mode 100644 index ea6e108d..00000000 --- a/archive/editor/langtool.py +++ /dev/null @@ -1,202 +0,0 @@ -#!/usr/bin/env python3 -from PyQt5.QtWidgets import QMainWindow, QApplication, QAction, QMenuBar, QMessageBox, QFileDialog, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QTableWidget, QTableWidgetItem, QHeaderView, QPushButton, QTabWidget, QFormLayout -from PyQt5.QtCore import Qt -import sys -import os -import polib - -class LangToolWindow(QMainWindow): - def __init__(self): - super().__init__() - self.setWindowTitle("Dusk Language Editor") - self.setGeometry(100, 100, 800, 600) - self.current_file = None - self.dirty = False - self.init_menu() - self.init_ui() - - def init_ui(self): - central = QWidget() - layout = QVBoxLayout(central) - - tabs = QTabWidget() - # Header Tab - header_tab = QWidget() - header_layout = QFormLayout(header_tab) - self.language_edit = QLineEdit() - self.language_edit.setMaximumWidth(220) - header_layout.addRow(QLabel("Language:"), self.language_edit) - self.plural_edit = QLineEdit() - self.plural_edit.setMaximumWidth(320) - header_layout.addRow(QLabel("Plural-Forms:"), self.plural_edit) - self.content_type_edit = QLineEdit("text/plain; charset=UTF-8") - self.content_type_edit.setMaximumWidth(320) - header_layout.addRow(QLabel("Content-Type:"), self.content_type_edit) - tabs.addTab(header_tab, "Header") - - # Strings Tab - strings_tab = QWidget() - strings_layout = QVBoxLayout(strings_tab) - self.po_table = QTableWidget() - self.po_table.setColumnCount(2) - self.po_table.setHorizontalHeaderLabels(["msgid", "msgstr"]) - self.po_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - self.po_table.verticalHeader().setMinimumWidth(22) - self.po_table.verticalHeader().setDefaultAlignment(Qt.AlignRight | Qt.AlignVCenter) - strings_layout.addWidget(self.po_table) - row_btn_layout = QHBoxLayout() - add_row_btn = QPushButton("Add Row") - remove_row_btn = QPushButton("Remove Row") - row_btn_layout.addWidget(add_row_btn) - row_btn_layout.addWidget(remove_row_btn) - strings_layout.addLayout(row_btn_layout) - tabs.addTab(strings_tab, "Strings") - - layout.addWidget(tabs) - - add_row_btn.clicked.connect(self.add_row) - remove_row_btn.clicked.connect(self.remove_row) - self.add_row_btn = add_row_btn - self.remove_row_btn = remove_row_btn - - self.setCentralWidget(central) - - # Connect edits to dirty flag - self.language_edit.textChanged.connect(self.set_dirty) - self.plural_edit.textChanged.connect(self.set_dirty) - self.content_type_edit.textChanged.connect(self.set_dirty) - self.po_table.itemChanged.connect(self.set_dirty) - - def set_dirty(self): - self.dirty = True - self.update_save_action() - - def init_menu(self): - menubar = self.menuBar() - file_menu = menubar.addMenu("File") - - new_action = QAction("New", self) - open_action = QAction("Open", self) - save_action = QAction("Save", self) - save_as_action = QAction("Save As", self) - - new_action.triggered.connect(lambda: self.handle_file_action("new")) - open_action.triggered.connect(lambda: self.handle_file_action("open")) - save_action.triggered.connect(self.handle_save) - save_as_action.triggered.connect(self.handle_save_as) - - file_menu.addAction(new_action) - file_menu.addAction(open_action) - file_menu.addAction(save_action) - file_menu.addAction(save_as_action) - - self.save_action = save_action # Store reference for enabling/disabling - self.update_save_action() - - def update_save_action(self): - self.save_action.setEnabled(self.current_file is not None) - - def handle_file_action(self, action): - if self.dirty: - reply = QMessageBox.question(self, "Save Changes?", "Do you want to save changes before proceeding?", QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) - if reply == QMessageBox.Cancel: - return - elif reply == QMessageBox.Yes: - self.handle_save() - if action == "new": - self.new_file() - elif action == "open": - default_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../assets/locale")) - file_path, _ = QFileDialog.getOpenFileName(self, "Open Language File", default_dir, "PO Files (*.po)") - if file_path: - self.open_file(file_path) - - def new_file(self): - self.current_file = None - self.dirty = False - self.language_edit.setText("") - self.plural_edit.setText("") - self.po_table.setRowCount(0) - self.update_save_action() - - def open_file(self, file_path): - self.current_file = file_path - self.dirty = False - self.update_save_action() - self.load_po_file(file_path) - - def load_po_file(self, file_path): - po = polib.pofile(file_path) - language = po.metadata.get('Language', '') - plural = po.metadata.get('Plural-Forms', '') - content_type = po.metadata.get('Content-Type', 'text/plain; charset=UTF-8') - self.language_edit.setText(language) - self.plural_edit.setText(plural) - self.content_type_edit.setText(content_type) - self.po_table.setRowCount(len(po)) - for row, entry in enumerate(po): - self.po_table.setItem(row, 0, QTableWidgetItem(entry.msgid)) - self.po_table.setItem(row, 1, QTableWidgetItem(entry.msgstr)) - - def save_file(self, file_path): - po = polib.POFile() - po.metadata = { - 'Language': self.language_edit.text(), - 'Content-Type': self.content_type_edit.text(), - 'Plural-Forms': self.plural_edit.text(), - } - for row in range(self.po_table.rowCount()): - msgid_item = self.po_table.item(row, 0) - msgstr_item = self.po_table.item(row, 1) - msgid = msgid_item.text() if msgid_item else '' - msgstr = msgstr_item.text() if msgstr_item else '' - if msgid or msgstr: - entry = polib.POEntry(msgid=msgid, msgstr=msgstr) - po.append(entry) - po.save(file_path) - self.dirty = False - self.update_save_action() - - def handle_save(self): - if self.current_file: - self.save_file(self.current_file) - else: - self.handle_save_as() - - def handle_save_as(self): - default_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../assets/locale")) - file_path, _ = QFileDialog.getSaveFileName(self, "Save Language File As", default_dir, "PO Files (*.po)") - if file_path: - self.current_file = file_path - self.update_save_action() - self.save_file(file_path) - - def add_row(self): - row = self.po_table.rowCount() - self.po_table.insertRow(row) - self.po_table.setItem(row, 0, QTableWidgetItem("")) - self.po_table.setItem(row, 1, QTableWidgetItem("")) - self.po_table.setCurrentCell(row, 0) - self.set_dirty() - - def remove_row(self): - row = self.po_table.currentRow() - if row >= 0: - self.po_table.removeRow(row) - self.set_dirty() - - def closeEvent(self, event): - if self.dirty: - reply = QMessageBox.question(self, "Save Changes?", "Do you want to save changes before exiting?", QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) - if reply == QMessageBox.Cancel: - event.ignore() - return - elif reply == QMessageBox.Yes: - self.handle_save() - event.accept() - -if __name__ == "__main__": - app = QApplication(sys.argv) - window = LangToolWindow() - window.show() - sys.exit(app.exec_()) diff --git a/archive/editor/map/camera.py b/archive/editor/map/camera.py deleted file mode 100644 index e7854fa6..00000000 --- a/archive/editor/map/camera.py +++ /dev/null @@ -1,55 +0,0 @@ -import math -import time -from OpenGL.GL import * -from OpenGL.GLU import * -from tools.dusk.defs import TILE_WIDTH, TILE_HEIGHT, TILE_DEPTH, RPG_CAMERA_PIXELS_PER_UNIT, RPG_CAMERA_Z_OFFSET, RPG_CAMERA_FOV - -class Camera: - def __init__(self, parent): - self.parent = parent - self.pixelsPerUnit = RPG_CAMERA_PIXELS_PER_UNIT - self.yOffset = RPG_CAMERA_Z_OFFSET - self.fov = RPG_CAMERA_FOV - self.scale = 8.0 - self.lastTime = time.time() - self.lookAtTarget = [0.0, 0.0, 0.0] - - def setup(self, vw, vh, duration=0.1): - now = time.time() - delta = now - self.lastTime - self.lastTime = now - # Calculate ease factor for exponential smoothing over 'duration' seconds - ease = 1 - math.exp(-delta / duration) - - z = (vh / 2.0) / ( - (self.pixelsPerUnit * self.scale) * math.tan(math.radians(self.fov / 2.0)) - ) - lookAt = [ - self.parent.map.position[0] * TILE_WIDTH, - self.parent.map.position[1] * TILE_HEIGHT, - self.parent.map.position[2] * TILE_DEPTH, - ] - aspectRatio = vw / vh - - # Ease the lookAt target - for i in range(3): - self.lookAtTarget[i] += (lookAt[i] - self.lookAtTarget[i]) * ease - - # Camera position is now based on the eased lookAtTarget - cameraPosition = ( - self.lookAtTarget[0], - self.lookAtTarget[1] + self.yOffset, - self.lookAtTarget[2] + z - ) - - glMatrixMode(GL_PROJECTION) - glLoadIdentity() - gluPerspective(self.fov, aspectRatio, 0.1, 1000.0) - glScalef(1.0, -1.0, 1.0) # Flip the projection matrix upside down - glMatrixMode(GL_MODELVIEW) - glLoadIdentity() - gluLookAt( - cameraPosition[0], cameraPosition[1], cameraPosition[2], - self.lookAtTarget[0], self.lookAtTarget[1], self.lookAtTarget[2], - 0.0, 1.0, 0.0 - ) \ No newline at end of file diff --git a/archive/editor/map/chunkpanel.py b/archive/editor/map/chunkpanel.py deleted file mode 100644 index 0ad87e47..00000000 --- a/archive/editor/map/chunkpanel.py +++ /dev/null @@ -1,80 +0,0 @@ -from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QGridLayout, QTreeWidget, QTreeWidgetItem, QComboBox -from tools.dusk.defs import CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_DEPTH, TILE_SHAPES - -class ChunkPanel(QWidget): - def __init__(self, parent): - super().__init__(parent) - self.parent = parent - layout = QVBoxLayout(self) - - # Tile shape dropdown - self.tileShapeDropdown = QComboBox() - self.tileShapeDropdown.addItems(TILE_SHAPES.keys()) - self.tileShapeDropdown.setToolTip("Tile Shape") - layout.addWidget(self.tileShapeDropdown) - - # Add expandable tree list - self.tree = QTreeWidget() - self.tree.setHeaderLabel("Chunks") - self.tree.expandAll() # Expand by default, remove if you want collapsed - layout.addWidget(self.tree) # Removed invalid stretch factor - - # Add stretch so tree expands - layout.setStretchFactor(self.tree, 1) - - # Event subscriptions - self.parent.map.onMapData.sub(self.onMapData) - self.parent.map.onPositionChange.sub(self.onPositionChange) - self.tileShapeDropdown.currentTextChanged.connect(self.onTileShapeChanged) - - # For each chunk - for chunk in self.parent.map.chunks.values(): - # Create tree element - item = QTreeWidgetItem(self.tree, ["Chunk ({}, {}, {})".format(chunk.x, chunk.y, chunk.z)]) - chunk.chunkPanelTree = item - chunk.chunkPanelTree.setExpanded(True) - item.setData(0, 0, chunk) # Store chunk reference - - chunk.onChunkData.sub(self.onChunkData) - - def onMapData(self, data): - pass - - def onPositionChange(self, pos): - self.updateChunkList() - - tile = self.parent.map.getTileAtWorldPos(*self.parent.map.position) - if tile is None: - return - - key = "TILE_SHAPE_NULL" - for k, v in TILE_SHAPES.items(): - if v != tile.shape: - continue - key = k - break - self.tileShapeDropdown.setCurrentText(key) - - def onTileShapeChanged(self, shape_key): - tile = self.parent.map.getTileAtWorldPos(*self.parent.map.position) - - if tile is None or shape_key not in TILE_SHAPES: - return - tile.setShape(TILE_SHAPES[shape_key]) - - def updateChunkList(self): - # Clear existing items - currentChunk = self.parent.map.getChunkAtWorldPos(*self.parent.map.position) - - # Example tree items - for chunk in self.parent.map.chunks.values(): - title = "Chunk ({}, {}, {})".format(chunk.x, chunk.y, chunk.z) - if chunk == currentChunk: - title += " [C]" - if chunk.isDirty(): - title += " *" - item = chunk.chunkPanelTree - item.setText(0, title) - - def onChunkData(self, chunk): - self.updateChunkList() \ No newline at end of file diff --git a/archive/editor/map/entitypanel.py b/archive/editor/map/entitypanel.py deleted file mode 100644 index 5ca2fd86..00000000 --- a/archive/editor/map/entitypanel.py +++ /dev/null @@ -1,154 +0,0 @@ -from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QComboBox, QHBoxLayout, QPushButton, QLineEdit, QListWidget, QListWidgetItem -from PyQt5.QtCore import Qt -from tools.dusk.entity import Entity -from tools.dusk.defs import CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_DEPTH, ENTITY_TYPES, ENTITY_TYPE_NULL - -class EntityPanel(QWidget): - def __init__(self, parent): - super().__init__(parent) - self.parent = parent - layout = QVBoxLayout(self) - self.setLayout(layout) - - # Top panel placeholder - topWidget = QLabel("Entity Editor") - layout.addWidget(topWidget) - - # Name input - nameLayout = QHBoxLayout() - nameLabel = QLabel("Name:") - self.nameInput = QLineEdit() - nameLayout.addWidget(nameLabel) - nameLayout.addWidget(self.nameInput) - layout.addLayout(nameLayout) - - # Entity Type dropdown (single selection) - typeLayout = QHBoxLayout() - typeLabel = QLabel("Type:") - self.typeDropdown = QComboBox() - self.typeDropdown.addItems(ENTITY_TYPES) - typeLayout.addWidget(typeLabel) - typeLayout.addWidget(self.typeDropdown) - layout.addLayout(typeLayout) - - # Entity list and buttons - self.entityList = QListWidget() - self.entityList.addItems([]) - layout.addWidget(self.entityList, stretch=1) - - btnLayout = QHBoxLayout() - self.btnAdd = QPushButton("Add") - self.btnRemove = QPushButton("Remove") - btnLayout.addWidget(self.btnAdd) - btnLayout.addWidget(self.btnRemove) - layout.addLayout(btnLayout) - - # Events - self.btnAdd.clicked.connect(self.onAddEntity) - self.btnRemove.clicked.connect(self.onRemoveEntity) - self.parent.map.onEntityData.sub(self.onEntityData) - self.parent.map.onPositionChange.sub(self.onPositionChange) - self.entityList.itemClicked.connect(self.onEntityClicked) - self.entityList.itemDoubleClicked.connect(self.onEntityDoubleClicked) - self.typeDropdown.currentIndexChanged.connect(self.onTypeSelected) - self.nameInput.textChanged.connect(self.onNameChanged) - - # Call once to populate - self.onEntityData() - self.onEntityUnselect() - - def onEntityUnselect(self): - self.entityList.setCurrentItem(None) - self.nameInput.setText("") - self.typeDropdown.setCurrentIndex(ENTITY_TYPE_NULL) - - def onEntitySelect(self, entity): - self.entityList.setCurrentItem(entity.item) - self.nameInput.setText(entity.name) - self.typeDropdown.setCurrentIndex(entity.type) - - def onEntityDoubleClicked(self, item): - entity = item.data(Qt.UserRole) - chunk = entity.chunk - worldX = (chunk.x * CHUNK_WIDTH) + entity.localX - worldY = (chunk.y * CHUNK_HEIGHT) + entity.localY - worldZ = (chunk.z * CHUNK_DEPTH) + entity.localZ - self.parent.map.moveTo(worldX, worldY, worldZ) - - def onEntityClicked(self, item): - pass - - def onAddEntity(self): - chunk = self.parent.map.getChunkAtWorldPos(*self.parent.map.position) - if chunk is None: - return - - localX = (self.parent.map.position[0] - (chunk.x * CHUNK_WIDTH)) % CHUNK_WIDTH - localY = (self.parent.map.position[1] - (chunk.y * CHUNK_HEIGHT)) % CHUNK_HEIGHT - localZ = (self.parent.map.position[2] - (chunk.z * CHUNK_DEPTH)) % CHUNK_DEPTH - - # Make sure there's not already an entity here - for ent in chunk.entities.values(): - if ent.localX == localX and ent.localY == localY and ent.localZ == localZ: - print("Entity already exists at this location") - return - - ent = chunk.addEntity(localX, localY, localZ) - - def onRemoveEntity(self): - item = self.entityList.currentItem() - if item is None: - return - entity = item.data(Qt.UserRole) - if entity: - chunk = entity.chunk - chunk.removeEntity(entity) - pass - - def onEntityData(self): - self.onEntityUnselect() - self.entityList.clear() - for chunk in self.parent.map.chunks.values(): - for id, entity in chunk.entities.items(): - item = QListWidgetItem(entity.name) - item.setData(Qt.UserRole, entity) # Store the entity object - entity.item = item - self.entityList.addItem(item) - - # Select if there is something at current position - self.onPositionChange(self.parent.map.position) - - def onPositionChange(self, position): - self.onEntityUnselect() - - # Get Entity at.. - chunk = self.parent.map.getChunkAtWorldPos(*position) - if chunk is None: - return - - localX = (position[0] - (chunk.x * CHUNK_WIDTH)) % CHUNK_WIDTH - localY = (position[1] - (chunk.y * CHUNK_HEIGHT)) % CHUNK_HEIGHT - localZ = (position[2] - (chunk.z * CHUNK_DEPTH)) % CHUNK_DEPTH - - for ent in chunk.entities.values(): - if ent.localX != localX or ent.localY != localY or ent.localZ != localZ: - continue - self.onEntitySelect(ent) - self.entityList.setCurrentItem(ent.item) - break - - def onTypeSelected(self, index): - item = self.entityList.currentItem() - if item is None: - return - entity = item.data(Qt.UserRole) - if entity: - entity.setType(index) - - def onNameChanged(self, text): - item = self.entityList.currentItem() - if item is None: - return - entity = item.data(Qt.UserRole) - if entity: - entity.setName(text) \ No newline at end of file diff --git a/archive/editor/map/glwidget.py b/archive/editor/map/glwidget.py deleted file mode 100644 index 3f18d318..00000000 --- a/archive/editor/map/glwidget.py +++ /dev/null @@ -1,41 +0,0 @@ -from PyQt5.QtCore import QTimer -from PyQt5.QtWidgets import QOpenGLWidget -from OpenGL.GL import * -from OpenGL.GLU import * - -class GLWidget(QOpenGLWidget): - def __init__(self, parent): - super().__init__(parent) - self.parent = parent - self.timer = QTimer(self) - self.timer.timeout.connect(self.update) - self.timer.start(16) # ~60 FPS - - def initializeGL(self): - glClearColor(0.392, 0.584, 0.929, 1.0) - glEnable(GL_DEPTH_TEST) - glEnable(GL_BLEND) - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) - glEnable(GL_POLYGON_OFFSET_FILL) - glPolygonOffset(1.0, 1.0) - glDisable(GL_POLYGON_OFFSET_FILL) - - def resizeGL(self, w, h): - pass - - def paintGL(self): - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) - glLoadIdentity() - - w = self.width() - h = self.height() - if h <= 0: - h = 1 - if w <= 0: - w = 1 - - glViewport(0, 0, w, h) - self.parent.camera.setup(w, h) - self.parent.grid.draw() - self.parent.map.draw() - self.parent.selectBox.draw() \ No newline at end of file diff --git a/archive/editor/map/grid.py b/archive/editor/map/grid.py deleted file mode 100644 index 5697c500..00000000 --- a/archive/editor/map/grid.py +++ /dev/null @@ -1,46 +0,0 @@ -from OpenGL.GL import * -from tools.dusk.defs import TILE_WIDTH, TILE_HEIGHT, TILE_DEPTH - -class Grid: - def __init__(self, lines=1000): - self.cellWidth = TILE_WIDTH - self.cellHeight = TILE_HEIGHT - self.lines = lines - self.enabled = True - - def draw(self): - if not self.enabled: - return - center = [0.01,0.01,0.01] - halfWidth = self.cellWidth * self.lines // 2 - halfHeight = self.cellHeight * self.lines // 2 - # Draw origin axes - glBegin(GL_LINES) - - # X axis - RED - glColor3f(1.0, 0.0, 0.0) - glVertex3f(center[0] - halfWidth, center[1], center[2]) - glVertex3f(center[0] + halfWidth, center[1], center[2]) - - # Y axis - GREEN - glColor3f(0.0, 1.0, 0.0) - glVertex3f(center[0], center[1] - halfHeight, center[2]) - glVertex3f(center[0], center[1] + halfHeight, center[2]) - - # Z axis - BLUE - glColor3f(0.0, 0.0, 1.0) - glVertex3f(center[0], center[1], center[2] - halfWidth) - glVertex3f(center[0], center[1], center[2] + halfWidth) - glEnd() - - # Draw grid - glColor3f(0.8, 0.8, 0.8) - glBegin(GL_LINES) - for i in range(-self.lines // 2, self.lines // 2 + 1): - # Vertical lines - glVertex3f(center[0] + i * self.cellWidth, center[1] - halfHeight, center[2]) - glVertex3f(center[0] + i * self.cellWidth, center[1] + halfHeight, center[2]) - # Horizontal lines - glVertex3f(center[0] - halfWidth, center[1] + i * self.cellHeight, center[2]) - glVertex3f(center[0] + halfWidth, center[1] + i * self.cellHeight, center[2]) - glEnd() \ No newline at end of file diff --git a/archive/editor/map/mapinfopanel.py b/archive/editor/map/mapinfopanel.py deleted file mode 100644 index 2d0f6127..00000000 --- a/archive/editor/map/mapinfopanel.py +++ /dev/null @@ -1,83 +0,0 @@ -from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QLineEdit, QPushButton, QHBoxLayout, QMessageBox -from tools.dusk.defs import CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_DEPTH - -class MapInfoPanel(QWidget): - def __init__(self, parent): - super().__init__(parent) - self.parent = parent - - # Components - layout = QVBoxLayout() - - mapTitleLabel = QLabel("Map Title") - self.mapTitleInput = QLineEdit() - layout.addWidget(mapTitleLabel) - layout.addWidget(self.mapTitleInput) - - tilePositionLabel = QLabel("Tile Position") - layout.addWidget(tilePositionLabel) - tilePositionRow = QHBoxLayout() - self.tileXInput = QLineEdit() - self.tileXInput.setPlaceholderText("X") - tilePositionRow.addWidget(self.tileXInput) - self.tileYInput = QLineEdit() - self.tileYInput.setPlaceholderText("Y") - tilePositionRow.addWidget(self.tileYInput) - self.tileZInput = QLineEdit() - self.tileZInput.setPlaceholderText("Z") - tilePositionRow.addWidget(self.tileZInput) - self.tileGo = QPushButton("Go") - tilePositionRow.addWidget(self.tileGo) - layout.addLayout(tilePositionRow) - - self.chunkPosLabel = QLabel() - layout.addWidget(self.chunkPosLabel) - self.chunkLabel = QLabel() - layout.addWidget(self.chunkLabel) - - layout.addStretch() - self.setLayout(layout) - - # Events - self.tileGo.clicked.connect(self.goToPosition) - self.tileXInput.returnPressed.connect(self.goToPosition) - self.tileYInput.returnPressed.connect(self.goToPosition) - self.tileZInput.returnPressed.connect(self.goToPosition) - self.parent.map.onPositionChange.sub(self.updatePositionLabels) - self.parent.map.onMapData.sub(self.onMapData) - self.mapTitleInput.textChanged.connect(self.onMapNameChange) - - # Initial label setting - self.updatePositionLabels(self.parent.map.position) - - def goToPosition(self): - try: - x = int(self.tileXInput.text()) - y = int(self.tileYInput.text()) - z = int(self.tileZInput.text()) - self.parent.map.moveTo(x, y, z) - except ValueError: - QMessageBox.warning(self, "Invalid Input", "Please enter valid integer coordinates.") - - def updatePositionLabels(self, pos): - self.tileXInput.setText(str(pos[0])) - self.tileYInput.setText(str(pos[1])) - self.tileZInput.setText(str(pos[2])) - - chunkTileX = pos[0] % CHUNK_WIDTH - chunkTileY = pos[1] % CHUNK_HEIGHT - chunkTileZ = pos[2] % CHUNK_DEPTH - chunkTileIndex = chunkTileX + chunkTileY * CHUNK_WIDTH + chunkTileZ * CHUNK_WIDTH * CHUNK_HEIGHT - self.chunkPosLabel.setText(f"Chunk Position: {chunkTileX}, {chunkTileY}, {chunkTileZ} ({chunkTileIndex})") - - chunkX = pos[0] // CHUNK_WIDTH - chunkY = pos[1] // CHUNK_HEIGHT - chunkZ = pos[2] // CHUNK_DEPTH - self.chunkLabel.setText(f"Chunk: {chunkX}, {chunkY}, {chunkZ}") - - def onMapData(self, data): - self.updatePositionLabels(self.parent.map.position) - self.mapTitleInput.setText(data.get("mapName", "")) - - def onMapNameChange(self, text): - self.parent.map.data['mapName'] = text \ No newline at end of file diff --git a/archive/editor/map/mapleftpanel.py b/archive/editor/map/mapleftpanel.py deleted file mode 100644 index b25e5e6c..00000000 --- a/archive/editor/map/mapleftpanel.py +++ /dev/null @@ -1,51 +0,0 @@ -from PyQt5.QtWidgets import QWidget, QVBoxLayout, QGridLayout, QPushButton, QTabWidget, QLabel -from tools.editor.map.chunkpanel import ChunkPanel -from tools.editor.map.entitypanel import EntityPanel -from tools.editor.map.regionpanel import RegionPanel - -class MapLeftPanel(QWidget): - def __init__(self, parent): - super().__init__(parent) - self.parent = parent - layout = QVBoxLayout(self) - self.setLayout(layout) - - # Nav buttons - self.chunkInfoLabel = QLabel("Tile Information") - layout.addWidget(self.chunkInfoLabel) - grid = QGridLayout() - self.btnUp = QPushButton("U") - self.btnN = QPushButton("N") - self.btnDown = QPushButton("D") - self.btnW = QPushButton("W") - self.btnS = QPushButton("S") - self.btnE = QPushButton("E") - - grid.addWidget(self.btnUp, 0, 0) - grid.addWidget(self.btnN, 0, 1) - grid.addWidget(self.btnDown, 0, 2) - grid.addWidget(self.btnW, 1, 0) - grid.addWidget(self.btnS, 1, 1) - grid.addWidget(self.btnE, 1, 2) - layout.addLayout(grid) - - # Panels - self.chunkPanel = ChunkPanel(self.parent) - self.entityPanel = EntityPanel(self.parent) - self.regionPanel = RegionPanel(self.parent) - - # Tabs - self.tabs = QTabWidget() - self.tabs.addTab(self.chunkPanel, "Tiles") - self.tabs.addTab(self.entityPanel, "Entities") - self.tabs.addTab(self.regionPanel, "Regions") - self.tabs.addTab(None, "Triggers") - layout.addWidget(self.tabs) - - # Event subscriptions - self.btnN.clicked.connect(lambda: self.parent.map.moveRelative(0, -1, 0)) - self.btnS.clicked.connect(lambda: self.parent.map.moveRelative(0, 1, 0)) - self.btnE.clicked.connect(lambda: self.parent.map.moveRelative(1, 0, 0)) - self.btnW.clicked.connect(lambda: self.parent.map.moveRelative(-1, 0, 0)) - self.btnUp.clicked.connect(lambda: self.parent.map.moveRelative(0, 0, 1)) - self.btnDown.clicked.connect(lambda: self.parent.map.moveRelative(0, 0, -1)) diff --git a/archive/editor/map/menubar.py b/archive/editor/map/menubar.py deleted file mode 100644 index 5084ed1c..00000000 --- a/archive/editor/map/menubar.py +++ /dev/null @@ -1,46 +0,0 @@ -import os -from PyQt5.QtWidgets import QAction, QMenuBar, QFileDialog -from PyQt5.QtGui import QKeySequence -from tools.dusk.map import MAP_DEFAULT_PATH - -class MapMenubar: - def __init__(self, parent): - self.parent = parent - self.menubar = QMenuBar(parent) - parent.setMenuBar(self.menubar) - - self.fileMenu = self.menubar.addMenu("File") - self.actionNew = QAction("New", parent) - self.actionOpen = QAction("Open", parent) - self.actionSave = QAction("Save", parent) - self.actionSaveAs = QAction("Save As", parent) - - self.actionNew.setShortcut(QKeySequence("Ctrl+N")) - self.actionOpen.setShortcut(QKeySequence("Ctrl+O")) - self.actionSave.setShortcut(QKeySequence("Ctrl+S")) - self.actionSaveAs.setShortcut(QKeySequence("Ctrl+Shift+S")) - - self.actionNew.triggered.connect(self.newFile) - self.actionOpen.triggered.connect(self.openFile) - self.actionSave.triggered.connect(self.saveFile) - self.actionSaveAs.triggered.connect(self.saveAsFile) - self.fileMenu.addAction(self.actionNew) - self.fileMenu.addAction(self.actionOpen) - self.fileMenu.addAction(self.actionSave) - self.fileMenu.addAction(self.actionSaveAs) - - def newFile(self): - self.parent.map.newFile() - - def openFile(self): - filePath, _ = QFileDialog.getOpenFileName(self.menubar, "Open Map File", MAP_DEFAULT_PATH, "Map Files (*.json)") - if filePath: - self.parent.map.load(filePath) - - def saveFile(self): - self.parent.map.save() - - def saveAsFile(self): - filePath, _ = QFileDialog.getSaveFileName(self.menubar, "Save Map File As", MAP_DEFAULT_PATH, "Map Files (*.json)") - if filePath: - self.parent.map.save(filePath) \ No newline at end of file diff --git a/archive/editor/map/regionpanel.py b/archive/editor/map/regionpanel.py deleted file mode 100644 index c2f1ee49..00000000 --- a/archive/editor/map/regionpanel.py +++ /dev/null @@ -1,15 +0,0 @@ -from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QComboBox, QHBoxLayout, QPushButton, QLineEdit, QListWidget, QListWidgetItem -from PyQt5.QtCore import Qt -from tools.dusk.entity import Entity -from tools.dusk.defs import CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_DEPTH, ENTITY_TYPES, ENTITY_TYPE_NULL - -class RegionPanel(QWidget): - def __init__(self, parent): - super().__init__(parent) - self.parent = parent - layout = QVBoxLayout(self) - self.setLayout(layout) - - # Top panel placeholder - topWidget = QLabel("Region Editor") - layout.addWidget(topWidget) \ No newline at end of file diff --git a/archive/editor/map/selectbox.py b/archive/editor/map/selectbox.py deleted file mode 100644 index 9af53ca9..00000000 --- a/archive/editor/map/selectbox.py +++ /dev/null @@ -1,44 +0,0 @@ -import OpenGL.GL as gl -from tools.dusk.defs import defs -import colorsys -from tools.dusk.defs import TILE_WIDTH, TILE_HEIGHT, TILE_DEPTH - -class SelectBox: - def __init__(self, parent): - self.parent = parent - self.hue = 0.0 - - def draw(self): - position = [ - self.parent.map.position[0] * TILE_WIDTH - (TILE_WIDTH / 2.0), - self.parent.map.position[1] * TILE_HEIGHT - (TILE_HEIGHT / 2.0), - self.parent.map.position[2] * TILE_DEPTH - (TILE_DEPTH / 2.0) - ] - - vertices = [ - (position[0], position[1], position[2]), - (position[0]+TILE_WIDTH, position[1], position[2]), - (position[0]+TILE_WIDTH, position[1]+TILE_HEIGHT, position[2]), - (position[0], position[1]+TILE_HEIGHT, position[2]), - (position[0], position[1], position[2]+TILE_DEPTH), - (position[0]+TILE_WIDTH, position[1], position[2]+TILE_DEPTH), - (position[0]+TILE_WIDTH, position[1]+TILE_HEIGHT, position[2]+TILE_DEPTH), - (position[0], position[1]+TILE_HEIGHT, position[2]+TILE_DEPTH) - ] - edges = [ - (0, 1), (1, 2), (2, 3), (3, 0), # bottom face - (4, 5), (5, 6), (6, 7), (7, 4), # top face - (4, 5), (5, 6), (6, 7), (7, 4), # top face - (0, 4), (1, 5), (2, 6), (3, 7) # vertical edges - ] - - # Cycle hue - self.hue = (self.hue + 0.01) % 1.0 - r, g, b = colorsys.hsv_to_rgb(self.hue, 1.0, 1.0) - gl.glColor3f(r, g, b) - gl.glLineWidth(2.0) - gl.glBegin(gl.GL_LINES) - for edge in edges: - for vertex in edge: - gl.glVertex3f(*vertices[vertex]) - gl.glEnd() \ No newline at end of file diff --git a/archive/editor/map/statusbar.py b/archive/editor/map/statusbar.py deleted file mode 100644 index ccb167ac..00000000 --- a/archive/editor/map/statusbar.py +++ /dev/null @@ -1,18 +0,0 @@ -from PyQt5.QtWidgets import QStatusBar, QLabel - -class StatusBar(QStatusBar): - def __init__(self, parent=None): - super().__init__(parent) - self.parent = parent - self.leftLabel = QLabel("") - self.rightLabel = QLabel("") - self.addWidget(self.leftLabel, 1) - self.addPermanentWidget(self.rightLabel) - - parent.map.onMapData.sub(self.onMapData) - - def setStatus(self, message): - self.leftLabel.setText(message) - - def onMapData(self, data): - self.rightLabel.setText(self.parent.map.mapFileName if self.parent.map.mapFileName else "Untitled.json") \ No newline at end of file diff --git a/archive/editor/map/vertexbuffer.py b/archive/editor/map/vertexbuffer.py deleted file mode 100644 index fc804fe3..00000000 --- a/archive/editor/map/vertexbuffer.py +++ /dev/null @@ -1,80 +0,0 @@ -from OpenGL.GL import * -import array - -class VertexBuffer: - def __init__(self, componentsPerVertex=3): - self.componentsPerVertex = componentsPerVertex - self.vertices = [] - self.colors = [] - self.uvs = [] - self.data = None - self.colorData = None - self.uvData = None - - def buildData(self): - hasColors = len(self.colors) > 0 - hasUvs = len(self.uvs) > 0 - - vertexCount = len(self.vertices) // self.componentsPerVertex - - dataList = [] - colorList = [] - uvList = [] - - for i in range(vertexCount): - vStart = i * self.componentsPerVertex - dataList.extend(self.vertices[vStart:vStart+self.componentsPerVertex]) - - if hasColors: - cStart = i * 4 # Assuming RGBA - colorList.extend(self.colors[cStart:cStart+4]) - - if hasUvs: - uStart = i * 2 # Assuming UV - uvList.extend(self.uvs[uStart:uStart+2]) - - self.data = array.array('f', dataList) - - if hasColors: - self.colorData = array.array('f', colorList) - else: - self.colorData = None - - if hasUvs: - self.uvData = array.array('f', uvList) - else: - self.uvData = None - - def draw(self, mode=GL_TRIANGLES, count=-1): - if count == -1: - count = len(self.data) // self.componentsPerVertex - - if count == 0: - return - - glEnableClientState(GL_VERTEX_ARRAY) - glVertexPointer(self.componentsPerVertex, GL_FLOAT, 0, self.data.tobytes()) - - if self.colorData: - glEnableClientState(GL_COLOR_ARRAY) - glColorPointer(4, GL_FLOAT, 0, self.colorData.tobytes()) - - if self.uvData: - glEnableClientState(GL_TEXTURE_COORD_ARRAY) - glTexCoordPointer(2, GL_FLOAT, 0, self.uvData.tobytes()) - - glDrawArrays(mode, 0, count) - - glDisableClientState(GL_VERTEX_ARRAY) - if self.colorData: - glDisableClientState(GL_COLOR_ARRAY) - if self.uvData: - glDisableClientState(GL_TEXTURE_COORD_ARRAY) - - def clear(self): - self.vertices = [] - self.colors = [] - self.uvs = [] - self.data = array.array('f') - self.colorData = None - self.uvData = None \ No newline at end of file diff --git a/archive/editor/maptool.py b/archive/editor/maptool.py deleted file mode 100644 index 4b9a1fe8..00000000 --- a/archive/editor/maptool.py +++ /dev/null @@ -1,143 +0,0 @@ -import os -from PyQt5.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QMessageBox -from PyQt5.QtCore import Qt -from tools.editor.map.glwidget import GLWidget -from tools.editor.map.mapleftpanel import MapLeftPanel -from tools.editor.map.mapinfopanel import MapInfoPanel -from tools.editor.map.menubar import MapMenubar -from tools.editor.map.statusbar import StatusBar -from tools.dusk.map import Map -from tools.dusk.defs import CHUNK_WIDTH, CHUNK_HEIGHT, CHUNK_DEPTH, TILE_SHAPE_NULL, TILE_SHAPE_FLOOR -from tools.editor.map.selectbox import SelectBox -from tools.editor.map.camera import Camera -from tools.editor.map.grid import Grid - -class MapWindow(QMainWindow): - def __init__(self): - super().__init__() - - self.insertPressed = False - self.deletePressed = False - - # Subclasses - self.map = Map(self) - self.camera = Camera(self) - self.grid = Grid() - self.selectBox = SelectBox(self) - - # Window setup - self.setWindowTitle("Dusk Map Editor") - self.resize(1600, 900) - - # Menubar (TESTING) - self.menubar = MapMenubar(self) - - central = QWidget() - self.setCentralWidget(central) - mainLayout = QHBoxLayout(central) - - # Left panel (tabs + nav buttons) - self.leftPanel = MapLeftPanel(self) - self.leftPanel.setFixedWidth(350) - mainLayout.addWidget(self.leftPanel) - - # Center panel (GLWidget + controls) - self.glWidget = GLWidget(self) - mainLayout.addWidget(self.glWidget, stretch=3) - - # Right panel (MapInfoPanel) - self.mapInfoPanel = MapInfoPanel(self) - rightWidget = self.mapInfoPanel - rightWidget.setFixedWidth(250) - mainLayout.addWidget(rightWidget) - - # Status bar - self.statusBar = StatusBar(self) - self.setStatusBar(self.statusBar) - - self.installEventFilter(self) - self.installEventFilterRecursively(self) - - def installEventFilterRecursively(self, widget): - for child in widget.findChildren(QWidget): - child.installEventFilter(self) - self.installEventFilterRecursively(child) - - def closeEvent(self, event): - if not self.map.isDirty(): - event.accept() - return - - reply = QMessageBox.question( - self, - "Unsaved Changes", - "You have unsaved changes. Do you want to save before closing?", - QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel, - QMessageBox.Save - ) - if reply == QMessageBox.Save: - self.map.save() - elif reply == QMessageBox.Cancel: - event.ignore() - return - event.accept() - - def eventFilter(self, obj, event): - if event.type() == event.KeyPress: - amtX, amtY, amtZ = 0, 0, 0 - - key = event.key() - if key == Qt.Key_Left: - amtX = -1 - elif key == Qt.Key_Right: - amtX = 1 - elif key == Qt.Key_Up: - amtY = -1 - elif key == Qt.Key_Down: - amtY = 1 - elif key == Qt.Key_PageUp: - amtZ = 1 - elif key == Qt.Key_PageDown: - amtZ = -1 - - if event.modifiers() & Qt.ShiftModifier: - amtX *= CHUNK_WIDTH - amtY *= CHUNK_HEIGHT - amtZ *= CHUNK_DEPTH - - if amtX != 0 or amtY != 0 or amtZ != 0: - self.map.moveRelative(amtX, amtY, amtZ) - if self.insertPressed: - tile = self.map.getTileAtWorldPos(*self.map.position) - if tile is not None and tile.shape == TILE_SHAPE_NULL: - tile.setShape(TILE_SHAPE_FLOOR) - if self.deletePressed: - tile = self.map.getTileAtWorldPos(*self.map.position) - if tile is not None: - tile.setShape(TILE_SHAPE_NULL) - event.accept() - return True - - if key == Qt.Key_Delete: - tile = self.map.getTileAtWorldPos(*self.map.position) - self.deletePressed = True - if tile is not None: - tile.setShape(TILE_SHAPE_NULL) - event.accept() - return True - if key == Qt.Key_Insert: - tile = self.map.getTileAtWorldPos(*self.map.position) - self.insertPressed = True - if tile is not None and tile.shape == TILE_SHAPE_NULL: - tile.setShape(TILE_SHAPE_FLOOR) - event.accept() - elif event.type() == event.KeyRelease: - key = event.key() - if key == Qt.Key_Delete: - self.deletePressed = False - event.accept() - return True - if key == Qt.Key_Insert: - self.insertPressed = False - event.accept() - return super().eventFilter(obj, event) \ No newline at end of file diff --git a/archive/loader/CMakeLists.txt b/archive/loader/CMakeLists.txt deleted file mode 100644 index 638a677d..00000000 --- a/archive/loader/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - assettexture.c - assettileset.c - assetlanguage.c - assetscript.c -) \ No newline at end of file diff --git a/archive/loader/assetlanguage.c b/archive/loader/assetlanguage.c deleted file mode 100644 index b895a004..00000000 --- a/archive/loader/assetlanguage.c +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "asset/asset.h" -#include "assert/assert.h" -#include "locale/localemanager.h" - -errorret_t assetLanguageHandler(assetcustom_t custom) { - assertNotNull(custom.zipFile, "Custom asset zip file cannot be NULL"); - assertNotNull(custom.output, "Custom asset output cannot be NULL"); - - assetlanguage_t *lang = (assetlanguage_t *)custom.output; - errorChain(assetLanguageInit(lang, custom.zipFile)); - - errorOk(); -} - -errorret_t assetLanguageInit( - assetlanguage_t *lang, - zip_file_t *zipFile -) { - errorThrow("Language asset initialization is not yet implemented."); -} - -errorret_t assetLanguageRead( - assetlanguage_t *lang, - const uint32_t key, - char_t *buffer, - const uint32_t bufferSize, - uint32_t *outLength -) { - errorThrow("Language string reading is not yet implemented."); -} - -void assetLanguageDispose(assetlanguage_t *lang) { - assertNotNull(lang, "Language asset cannot be NULL"); - - if(lang->zip) { - zip_fclose(lang->zip); - } -} \ No newline at end of file diff --git a/archive/loader/assetlanguage.h b/archive/loader/assetlanguage.h deleted file mode 100644 index b6a099ec..00000000 --- a/archive/loader/assetlanguage.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "error/error.h" -#include "duskdefs.h" -#include - -typedef struct { - zip_file_t *zip; - zip_int64_t chunksOffset; -} assetlanguage_t; - -typedef struct assetcustom_s assetcustom_t; - -/** - * Receiving function from the asset manager to handle language assets. - * - * @param custom Custom asset loading data. - * @return Error code. - */ -errorret_t assetLanguageHandler(assetcustom_t custom); - -/** - * Initializes a language asset and loads the header data into memory. - * - * @param lang Language asset to initialize. - * @param zipFile Zip file handle for the language asset. - * @return Error code. - */ -errorret_t assetLanguageInit(assetlanguage_t *lang, zip_file_t *zipFile); - -/** - * Reads a string from the language asset into the provided buffer. - * - * @param lang Language asset to read from. - * @param key Language key to read. - * @param buffer Buffer to read the string into. - * @param bufferSize Size of the provided buffer. - * @param outLength Pointer to store the length of the string read. - * @return Error code. - */ -errorret_t assetLanguageRead( - assetlanguage_t *lang, - const uint32_t key, - char_t *buffer, - const uint32_t bufferSize, - uint32_t *outLength -); - -/** - * Disposes of language asset resources. - * - * @param custom Custom asset loading data. - * @return Error code. - */ -void assetLanguageDispose(assetlanguage_t *lang); \ No newline at end of file diff --git a/archive/loader/assetscript.c b/archive/loader/assetscript.c deleted file mode 100644 index 90772257..00000000 --- a/archive/loader/assetscript.c +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "asset/asset.h" -#include "assert/assert.h" - -errorret_t assetScriptHandler(assetcustom_t custom) { - assertNotNull(custom.zipFile, "Custom asset zip file cannot be NULL"); - assertNotNull(custom.output, "Custom asset output cannot be NULL"); - - assetscript_t *script = (assetscript_t *)custom.output; - errorChain(assetScriptInit(script, custom.zipFile)); - - errorOk(); -} - -errorret_t assetScriptInit( - assetscript_t *script, - zip_file_t *zipFile -) { - assertNotNull(script, "Script asset cannot be NULL"); - assertNotNull(zipFile, "Zip file cannot be NULL"); - - // We now own the zip file handle. - script->zip = zipFile; - - errorOk(); -} - -const char_t * assetScriptReader(lua_State* lState, void* data, size_t* size) { - assetscript_t *script = (assetscript_t *)data; - zip_int64_t bytesRead = zip_fread( - script->zip, script->buffer, sizeof(script->buffer) - ); - - if(bytesRead < 0) { - *size = 0; - return NULL; - } - - *size = (size_t)bytesRead; - return script->buffer; -} - -errorret_t assetScriptDispose(assetscript_t *script) { - assertNotNull(script, "Script asset cannot be NULL"); - - if(script->zip != NULL) { - zip_fclose(script->zip); - script->zip = NULL; - } - - errorOk(); -} \ No newline at end of file diff --git a/archive/loader/assetscript.h b/archive/loader/assetscript.h deleted file mode 100644 index 38b762a9..00000000 --- a/archive/loader/assetscript.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "error/error.h" -#include "duskdefs.h" -#include -#include "script/scriptcontext.h" - -#define ASSET_SCRIPT_BUFFER_SIZE 1024 - -typedef struct assetscript_s { - zip_file_t *zip; - char_t buffer[ASSET_SCRIPT_BUFFER_SIZE]; -} assetscript_t; - -typedef struct assetcustom_s assetcustom_t; - -/** - * Receiving function from the asset manager to handle script assets. - * - * @param custom Custom asset loading data. - * @return Error code. - */ -errorret_t assetScriptHandler(assetcustom_t custom); - -/** - * Initializes a script asset. - * - * @param script Script asset to initialize. - * @param zipFile Zip file handle for the script asset. - * @return Error code. - */ -errorret_t assetScriptInit(assetscript_t *script, zip_file_t *zipFile); - -/** - * Reader function for Lua to read script data from the asset. - * - * @param L Lua state. - * @param data Pointer to the assetscript_t structure. - * @param size Pointer to store the size of the read data. - * @return Pointer to the read data buffer. - */ -const char_t * assetScriptReader(lua_State* L, void* data, size_t* size); - -/** - * Disposes of a script asset, freeing any allocated resources. - * - * @param script Script asset to dispose of. - * @return Error code. - */ -errorret_t assetScriptDispose(assetscript_t *script); - diff --git a/archive/loader/assettexture.c b/archive/loader/assettexture.c deleted file mode 100644 index 07bd9d9b..00000000 --- a/archive/loader/assettexture.c +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "assettexture.h" -#include "asset/assettype.h" -#include "assert/assert.h" -#include "display/texture/texture.h" -#include "util/endian.h" - -errorret_t assetTextureLoad(assetentire_t entire) { - assertNotNull(entire.data, "Data pointer cannot be NULL."); - assertNotNull(entire.output, "Output pointer cannot be NULL."); - - assettexture_t *assetData = (assettexture_t *)entire.data; - texture_t *texture = (texture_t *)entire.output; - - // Read header and version (first 4 bytes) - if( - assetData->header[0] != 'D' || - assetData->header[1] != 'T' || - assetData->header[2] != 'X' - ) { - errorThrow("Invalid texture header"); - } - - // Version (can only be 1 atm) - if(assetData->version != 0x01) { - errorThrow("Unsupported texture version"); - } - - // Fix endian - assetData->width = endianLittleToHost32(assetData->width); - assetData->height = endianLittleToHost32(assetData->height); - - // Check dimensions. - if( - assetData->width == 0 || assetData->width > ASSET_TEXTURE_WIDTH_MAX || - assetData->height == 0 || assetData->height > ASSET_TEXTURE_HEIGHT_MAX - ) { - errorThrow("Invalid texture dimensions"); - } - - // Validate format - textureformat_t format; - texturedata_t data; - - switch(assetData->type) { - case 0x00: // RGBA8888 - format = TEXTURE_FORMAT_RGBA; - data.rgbaColors = (color_t *)assetData->data; - break; - - // case 0x01: - // format = TEXTURE_FORMAT_RGB; - // break; - - // case 0x02: - // format = TEXTURE_FORMAT_RGB565; - // break; - - // case 0x03: - // format = TEXTURE_FORMAT_RGB5A3; - // break; - - default: - errorThrow("Unsupported texture format"); - } - - errorChain(textureInit( - texture, assetData->width, assetData->height, format, data - )); - - errorOk(); -} \ No newline at end of file diff --git a/archive/loader/assettexture.h b/archive/loader/assettexture.h deleted file mode 100644 index 1dbdde4a..00000000 --- a/archive/loader/assettexture.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "error/error.h" -#include "display/color.h" - -#define ASSET_TEXTURE_WIDTH_MAX 2048 -#define ASSET_TEXTURE_HEIGHT_MAX 2048 -#define ASSET_TEXTURE_SIZE_MAX ( \ - ASSET_TEXTURE_WIDTH_MAX * ASSET_TEXTURE_HEIGHT_MAX \ -) - -typedef struct assetentire_s assetentire_t; - -#pragma pack(push, 1) -typedef struct { - char_t header[3]; - uint8_t version; - uint8_t type; - uint32_t width; - uint32_t height; - uint8_t data[ASSET_TEXTURE_SIZE_MAX * sizeof(color4b_t)]; -} assettexture_t; -#pragma pack(pop) - -/** - * Loads a palettized texture from the given data pointer into the output - * texture. - * - * @param data Pointer to the raw assettexture_t data. - * @param output Pointer to the texture_t to load the image into. - * @return An error code. - */ -errorret_t assetTextureLoad(assetentire_t entire); \ No newline at end of file diff --git a/archive/loader/assettileset.c b/archive/loader/assettileset.c deleted file mode 100644 index ea485e07..00000000 --- a/archive/loader/assettileset.c +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "asset/asset.h" -#include "assert/assert.h" -#include "display/texture/tileset.h" -#include "util/memory.h" -#include "util/endian.h" - -errorret_t assetTilesetLoad(assetentire_t entire) { - assertNotNull(entire.data, "Asset data cannot be null"); - assertNotNull(entire.output, "Asset output cannot be null"); - - assettileset_t *tilesetData = (assettileset_t *)entire.data; - tileset_t *tileset = (tileset_t *)entire.output; - - if( - tilesetData->header[0] != 'D' || - tilesetData->header[1] != 'T' || - tilesetData->header[2] != 'F' - ) { - errorThrow("Invalid tileset header"); - } - - if(tilesetData->version != 0x00) { - errorThrow("Unsupported tileset version"); - } - - // Fix endianness - tilesetData->tileWidth = endianLittleToHost16(tilesetData->tileWidth); - tilesetData->tileHeight = endianLittleToHost16(tilesetData->tileHeight); - tilesetData->columnCount = endianLittleToHost16(tilesetData->columnCount); - tilesetData->rowCount = endianLittleToHost16(tilesetData->rowCount); - tilesetData->right = endianLittleToHost16(tilesetData->right); - tilesetData->bottom = endianLittleToHost16(tilesetData->bottom); - - if(tilesetData->tileWidth == 0) { - errorThrow("Tile width cannot be 0"); - } - if(tilesetData->tileHeight == 0) { - errorThrow("Tile height cannot be 0"); - } - if(tilesetData->columnCount == 0) { - errorThrow("Column count cannot be 0"); - } - if(tilesetData->rowCount == 0) { - errorThrow("Row count cannot be 0"); - } - - tilesetData->u0 = endianLittleToHostFloat(tilesetData->u0); - tilesetData->v0 = endianLittleToHostFloat(tilesetData->v0); - - if(tilesetData->v0 < 0.0f || tilesetData->v0 > 1.0f) { - errorThrow("Invalid v0 value in tileset"); - } - - // Setup tileset - tileset->tileWidth = tilesetData->tileWidth; - tileset->tileHeight = tilesetData->tileHeight; - tileset->tileCount = tilesetData->columnCount * tilesetData->rowCount; - tileset->columns = tilesetData->columnCount; - tileset->rows = tilesetData->rowCount; - tileset->uv[0] = tilesetData->u0; - tileset->uv[1] = tilesetData->v0; - errorOk(); -} \ No newline at end of file diff --git a/archive/loader/assettileset.h b/archive/loader/assettileset.h deleted file mode 100644 index a659feaf..00000000 --- a/archive/loader/assettileset.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "error/error.h" - -#pragma pack(push, 1) -typedef struct { - char_t header[3]; - uint8_t version; - uint16_t tileWidth; - uint16_t tileHeight; - uint16_t columnCount; - uint16_t rowCount; - uint16_t right; - uint16_t bottom; - float_t u0; - float_t v0; -} assettileset_t; -#pragma pack(pop) - -/** - * Loads a tileset from the given data pointer into the output tileset. - * - * @param entire Data received from the asset loader system. - * @return An error code. - */ -errorret_t assetTilesetLoad(assetentire_t entire); \ No newline at end of file diff --git a/archive/map/CMakeLists.txt b/archive/map/CMakeLists.txt deleted file mode 100644 index 2665d3f0..00000000 --- a/archive/map/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -add_subdirectory(testmap) \ No newline at end of file diff --git a/archive/map/testmap/CMakeLists.txt b/archive/map/testmap/CMakeLists.txt deleted file mode 100644 index 98749424..00000000 --- a/archive/map/testmap/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -add_asset(MAP testmap.json) \ No newline at end of file diff --git a/archive/map/testmap/chunks/-1_-1_0.json b/archive/map/testmap/chunks/-1_-1_0.json deleted file mode 100644 index 7f5f47e9..00000000 --- a/archive/map/testmap/chunks/-1_-1_0.json +++ /dev/null @@ -1 +0,0 @@ -{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []} \ No newline at end of file diff --git a/archive/map/testmap/chunks/-1_-1_1.json b/archive/map/testmap/chunks/-1_-1_1.json deleted file mode 100644 index cc2dc76a..00000000 --- a/archive/map/testmap/chunks/-1_-1_1.json +++ /dev/null @@ -1 +0,0 @@ -{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []} \ No newline at end of file diff --git a/archive/map/testmap/chunks/-1_0_0.json b/archive/map/testmap/chunks/-1_0_0.json deleted file mode 100644 index e0416962..00000000 --- a/archive/map/testmap/chunks/-1_0_0.json +++ /dev/null @@ -1 +0,0 @@ -{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []} \ No newline at end of file diff --git a/archive/map/testmap/chunks/-2_1_0.json b/archive/map/testmap/chunks/-2_1_0.json deleted file mode 100644 index 144f2ae8..00000000 --- a/archive/map/testmap/chunks/-2_1_0.json +++ /dev/null @@ -1 +0,0 @@ -{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []} \ No newline at end of file diff --git a/archive/map/testmap/chunks/0_-1_0.json b/archive/map/testmap/chunks/0_-1_0.json deleted file mode 100644 index 470f90ef..00000000 --- a/archive/map/testmap/chunks/0_-1_0.json +++ /dev/null @@ -1 +0,0 @@ -{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []} \ No newline at end of file diff --git a/archive/map/testmap/chunks/0_-1_1.json b/archive/map/testmap/chunks/0_-1_1.json deleted file mode 100644 index c567855b..00000000 --- a/archive/map/testmap/chunks/0_-1_1.json +++ /dev/null @@ -1 +0,0 @@ -{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []} \ No newline at end of file diff --git a/archive/map/testmap/chunks/0_0_0.json b/archive/map/testmap/chunks/0_0_0.json deleted file mode 100644 index 3bb86dd8..00000000 --- a/archive/map/testmap/chunks/0_0_0.json +++ /dev/null @@ -1 +0,0 @@ -{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []} \ No newline at end of file diff --git a/archive/map/testmap/chunks/1_0_0.json b/archive/map/testmap/chunks/1_0_0.json deleted file mode 100644 index 144f2ae8..00000000 --- a/archive/map/testmap/chunks/1_0_0.json +++ /dev/null @@ -1 +0,0 @@ -{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []} \ No newline at end of file diff --git a/archive/map/testmap/chunks/2_0_0.json b/archive/map/testmap/chunks/2_0_0.json deleted file mode 100644 index 144f2ae8..00000000 --- a/archive/map/testmap/chunks/2_0_0.json +++ /dev/null @@ -1 +0,0 @@ -{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []} \ No newline at end of file diff --git a/archive/map/testmap/chunks/3_0_0.json b/archive/map/testmap/chunks/3_0_0.json deleted file mode 100644 index 144f2ae8..00000000 --- a/archive/map/testmap/chunks/3_0_0.json +++ /dev/null @@ -1 +0,0 @@ -{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []} \ No newline at end of file diff --git a/archive/map/testmap/chunks/4_0_0.json b/archive/map/testmap/chunks/4_0_0.json deleted file mode 100644 index 144f2ae8..00000000 --- a/archive/map/testmap/chunks/4_0_0.json +++ /dev/null @@ -1 +0,0 @@ -{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "entities": []} \ No newline at end of file diff --git a/archive/map/testmap/chunks/5_0_0.json b/archive/map/testmap/chunks/5_0_0.json deleted file mode 100644 index bf6e0560..00000000 --- a/archive/map/testmap/chunks/5_0_0.json +++ /dev/null @@ -1 +0,0 @@ -{"shapes": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} \ No newline at end of file diff --git a/archive/map/testmap/testmap.json b/archive/map/testmap/testmap.json deleted file mode 100644 index d9e4030d..00000000 --- a/archive/map/testmap/testmap.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name": "Test" -} \ No newline at end of file diff --git a/archive/modulemap.h b/archive/modulemap.h deleted file mode 100644 index 759af4d4..00000000 --- a/archive/modulemap.h +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "script/scriptcontext.h" -#include "debug/debug.h" -#include "assert/assert.h" -#include "rpg/overworld/map.h" - -int moduleMapLoad(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - if(!lua_isstring(L, 1)) { - luaL_error(L, "Expected string map filename"); - return 0; - } - - // Potentially provide up to 3 params - chunkpos_t initial = { .x = 0, .y = 0, .z = 0 }; - if(lua_isnumber(L, 2)) { - initial.x = (chunkunit_t)lua_tonumber(L, 2); - } - if(lua_isnumber(L, 3)) { - initial.y = (chunkunit_t)lua_tonumber(L, 3); - } - if(lua_isnumber(L, 4)) { - initial.z = (chunkunit_t)lua_tonumber(L, 4); - } - - // Load the map. - errorret_t ret = mapLoad(luaL_checkstring(L, 1), initial); - if(ret.code != ERROR_OK) { - luaL_error(L, "Failed to load map"); - errorCatch(errorPrint(ret)); - return 0; - } - - return 0; -} - -void moduleMapSystem(scriptcontext_t *context) { - assertNotNull(context, "Script context cannot be NULL"); - - lua_register(context->luaState, "mapLoad", moduleMapLoad); -} \ No newline at end of file diff --git a/archive/platform/CMakeLists.txt b/archive/platform/CMakeLists.txt deleted file mode 100644 index b1563553..00000000 --- a/archive/platform/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - sdl2.c - psp.c - dolphin.c -) \ No newline at end of file diff --git a/archive/platform/dolphin.c b/archive/platform/dolphin.c deleted file mode 100644 index b21593b9..00000000 --- a/archive/platform/dolphin.c +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "dolphin.h" - -void displayInitDolphin(void) { - VIDEO_Init(); - DISPLAY.screenMode = VIDEO_GetPreferredMode(NULL); - DISPLAY.frameBuffer[0] = MEM_K0_TO_K1( - SYS_AllocateFramebuffer(DISPLAY.screenMode) - ); - DISPLAY.frameBuffer[1] = MEM_K0_TO_K1( - SYS_AllocateFramebuffer(DISPLAY.screenMode) - ); - VIDEO_Configure(DISPLAY.screenMode); - - VIDEO_SetNextFramebuffer(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer]); - // VIDEO_SetPostRetraceCallback(copy_buffers); - VIDEO_SetBlack(FALSE); - VIDEO_Flush(); - VIDEO_WaitVSync(); - if(DISPLAY.screenMode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync(); - - DISPLAY.fifoBuffer = memalign(32, DISPLAY_FIFO_SIZE); - memoryZero(DISPLAY.fifoBuffer, DISPLAY_FIFO_SIZE); - - GX_Init(DISPLAY.fifoBuffer, DISPLAY_FIFO_SIZE); - - // This seems to be mostly related to interlacing vs progressive - GX_SetViewport( - 0, 0, - DISPLAY.screenMode->fbWidth, DISPLAY.screenMode->efbHeight, - 0, 1 - ); - float_t yscale = GX_GetYScaleFactor( - DISPLAY.screenMode->efbHeight, DISPLAY.screenMode->xfbHeight - ); - uint32_t xfbHeight = GX_SetDispCopyYScale(yscale); - GX_SetScissor( - 0, 0, - DISPLAY.screenMode->fbWidth, DISPLAY.screenMode->efbHeight - ); - GX_SetDispCopySrc( - 0, 0, - DISPLAY.screenMode->fbWidth, DISPLAY.screenMode->efbHeight - ); - GX_SetDispCopyDst(DISPLAY.screenMode->fbWidth, xfbHeight); - GX_SetCopyFilter( - DISPLAY.screenMode->aa, - DISPLAY.screenMode->sample_pattern, - GX_TRUE, - DISPLAY.screenMode->vfilter - ); - GX_SetFieldMode( - DISPLAY.screenMode->field_rendering, - ( - (DISPLAY.screenMode->viHeight == 2 * DISPLAY.screenMode->xfbHeight) ? - GX_ENABLE : - GX_DISABLE - ) - ); - - // Setup cull modes - GX_SetCullMode(GX_CULL_NONE); - GX_SetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE); - GX_CopyDisp(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer], GX_TRUE); - GX_SetDispCopyGamma(GX_GM_1_0); - - GX_ClearVtxDesc(); - GX_SetVtxDesc(GX_VA_POS, GX_INDEX16); - GX_SetVtxDesc(GX_VA_CLR0, GX_INDEX16); - GX_SetVtxDesc(GX_VA_TEX0, GX_INDEX16); - GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); - GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_U8, 0); - GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); -} - -void displayDolphinSwap(void) { - GX_DrawDone(); - - DISPLAY.whichFrameBuffer ^= 1; - GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); - GX_SetColorUpdate(GX_TRUE); - GX_CopyDisp(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer], GX_TRUE); - VIDEO_SetNextFramebuffer(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer]); - VIDEO_Flush(); - VIDEO_WaitVSync(); -} \ No newline at end of file diff --git a/archive/platform/dolphin.h b/archive/platform/dolphin.h deleted file mode 100644 index c62fa287..00000000 --- a/archive/platform/dolphin.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "dusk.h" -#include "display/displaydefs.h" - -typedef struct { - void *frameBuffer[2];// Double-Bufferred - int whichFrameBuffer; - GXRModeObj *screenMode; - void *fifoBuffer; -} displaydolphin_t; - -/** - * Initializes the display for Dolphin. - */ -void displayDolphinInit(void); - -/** - * Swaps the back buffer to the front for Dolphin. - */ -void displayDolphinSwap(void); \ No newline at end of file diff --git a/archive/platform/psp.c b/archive/platform/psp.c deleted file mode 100644 index 8fe9e216..00000000 --- a/archive/platform/psp.c +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "psp.h" - -void displayInitPSP(void) { - DISPLAY.usingShaderedPalettes = false; -} \ No newline at end of file diff --git a/archive/platform/psp.h b/archive/platform/psp.h deleted file mode 100644 index d822b2fa..00000000 --- a/archive/platform/psp.h +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once - -/** - * Initializes the display for PSP. - */ -void displayInitPSP(void); \ No newline at end of file diff --git a/archive/platform/sdl2.c b/archive/platform/sdl2.c deleted file mode 100644 index f1e09630..00000000 --- a/archive/platform/sdl2.c +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "sdl2.h" - -void displaySDL2Update(void) { -} - -void displaySDL2Swap(void) { - SDL_GL_SwapWindow(DISPLAY.window); - - GLenum err; - while((err = glGetError()) != GL_NO_ERROR) { - debugPrint("GL Error: %d\n", err); - } -} - -void displaySDL2Dispose(void) { - if(DISPLAY.glContext) { - SDL_GL_DeleteContext(DISPLAY.glContext); - DISPLAY.glContext = NULL; - } - if(DISPLAY.window) { - SDL_DestroyWindow(DISPLAY.window); - DISPLAY.window = NULL; - } - SDL_Quit(); -} \ No newline at end of file diff --git a/archive/platform/sdl2.h b/archive/platform/sdl2.h deleted file mode 100644 index 83ec5715..00000000 --- a/archive/platform/sdl2.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "dusk.h" - -typedef struct { - SDL_Window *window; - SDL_GLContext glContext; - bool_t usingShaderedPalettes; -} displaysdl2_t; - -/** - * Initializes the display for SDL2. - */ -void displaySDL2Init(void); - -/** - * Updates the display for SDL2. - */ -void displaySDL2Update(void); - -/** - * Swaps the display buffers for SDL2. - */ -void displaySDL2Swap(void); - -/** - * Disposes of the display for SDL2. - */ -void displaySDL2Dispose(void); \ No newline at end of file diff --git a/archive/rpg/CMakeLists.txt b/archive/rpg/CMakeLists.txt deleted file mode 100644 index cb964fdb..00000000 --- a/archive/rpg/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - rpg.c - rpgcamera.c - rpgtextbox.c -) - -# Subdirs -add_subdirectory(cutscene) -add_subdirectory(entity) -add_subdirectory(overworld) \ No newline at end of file diff --git a/archive/rpg/cutscene/CMakeLists.txt b/archive/rpg/cutscene/CMakeLists.txt deleted file mode 100644 index 9c927691..00000000 --- a/archive/rpg/cutscene/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - cutscenesystem.c - cutscenemode.c -) - -# Subdirs -add_subdirectory(item) \ No newline at end of file diff --git a/archive/rpg/cutscene/cutscene.h b/archive/rpg/cutscene/cutscene.h deleted file mode 100644 index 7df18ad6..00000000 --- a/archive/rpg/cutscene/cutscene.h +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "rpg/cutscene/item/cutsceneitem.h" - -typedef struct cutscene_s { - const cutsceneitem_t *items; - uint8_t itemCount; -} cutscene_t; \ No newline at end of file diff --git a/archive/rpg/cutscene/cutscenemode.c b/archive/rpg/cutscene/cutscenemode.c deleted file mode 100644 index 39c10b3e..00000000 --- a/archive/rpg/cutscene/cutscenemode.c +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "rpg/cutscene/cutscenesystem.h" - -bool_t cutsceneModeIsInputAllowed() { - switch(CUTSCENE_SYSTEM.mode) { - case CUTSCENE_MODE_FULL_FREEZE: - case CUTSCENE_MODE_INPUT_FREEZE: - return false; - - default: - return true; - } -} \ No newline at end of file diff --git a/archive/rpg/cutscene/cutscenemode.h b/archive/rpg/cutscene/cutscenemode.h deleted file mode 100644 index cf20a3d3..00000000 --- a/archive/rpg/cutscene/cutscenemode.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "dusk.h" - -typedef enum { - CUTSCENE_MODE_NONE, - CUTSCENE_MODE_FULL_FREEZE, - CUTSCENE_MODE_INPUT_FREEZE, - CUTSCENE_MODE_GAMEPLAY -} cutscenemode_t; - -// Default mode for all cutscenes. -#define CUTSCENE_MODE_INITIAL CUTSCENE_MODE_INPUT_FREEZE - -/** - * Check if input is allowed in the current cutscene mode. - * - * @return true if input is allowed, false otherwise. - */ -bool_t cutsceneModeIsInputAllowed(); \ No newline at end of file diff --git a/archive/rpg/cutscene/cutscenesystem.c b/archive/rpg/cutscene/cutscenesystem.c deleted file mode 100644 index d803e05d..00000000 --- a/archive/rpg/cutscene/cutscenesystem.c +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "cutscenesystem.h" -#include "util/memory.h" - -cutscenesystem_t CUTSCENE_SYSTEM; - -void cutsceneSystemInit() { - memoryZero(&CUTSCENE_SYSTEM, sizeof(cutscenesystem_t)); -} - -void cutsceneSystemStartCutscene(const cutscene_t *cutscene) { - CUTSCENE_SYSTEM.scene = cutscene; - CUTSCENE_SYSTEM.mode = CUTSCENE_MODE_INITIAL; - CUTSCENE_SYSTEM.currentItem = 0xFF;// Set to 0xFF so start wraps. - cutsceneSystemNext(); -} - -void cutsceneSystemUpdate() { - if(CUTSCENE_SYSTEM.scene == NULL) return; - - const cutsceneitem_t *item = cutsceneSystemGetCurrentItem(); - cutsceneItemUpdate(item, &CUTSCENE_SYSTEM.data); -} - -void cutsceneSystemNext() { - if(CUTSCENE_SYSTEM.scene == NULL) return; - - CUTSCENE_SYSTEM.currentItem++; - - // End of the cutscene? - if( - CUTSCENE_SYSTEM.currentItem >= CUTSCENE_SYSTEM.scene->itemCount - ) { - CUTSCENE_SYSTEM.scene = NULL; - CUTSCENE_SYSTEM.currentItem = 0xFF; - CUTSCENE_SYSTEM.mode = CUTSCENE_MODE_NONE; - return; - } - - // Start item. - const cutsceneitem_t *item = cutsceneSystemGetCurrentItem(); - memset(&CUTSCENE_SYSTEM.data, 0, sizeof(CUTSCENE_SYSTEM.data)); - cutsceneItemStart(item, &CUTSCENE_SYSTEM.data); -} - -const cutsceneitem_t * cutsceneSystemGetCurrentItem() { - if(CUTSCENE_SYSTEM.scene == NULL) return NULL; - - return &CUTSCENE_SYSTEM.scene->items[CUTSCENE_SYSTEM.currentItem]; -} \ No newline at end of file diff --git a/archive/rpg/cutscene/cutscenesystem.h b/archive/rpg/cutscene/cutscenesystem.h deleted file mode 100644 index 7c3242a9..00000000 --- a/archive/rpg/cutscene/cutscenesystem.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "cutscene.h" -#include "cutscenemode.h" - -typedef struct { - const cutscene_t *scene; - uint8_t currentItem; - - // Data (used by the current item). - cutsceneitemdata_t data; - cutscenemode_t mode; -} cutscenesystem_t; - -extern cutscenesystem_t CUTSCENE_SYSTEM; - -/** - * Initialize the cutscene system. - */ -void cutsceneSystemInit(); - -/** - * Start a cutscene. - * - * @param cutscene Pointer to the cutscene to start. - */ -void cutsceneSystemStartCutscene(const cutscene_t *cutscene); - -/** - * Advance to the next item in the cutscene. - */ -void cutsceneSystemNext(); - -/** - * Update the cutscene system for one frame. - */ -void cutsceneSystemUpdate(); - -/** - * Get the current cutscene item. - * - * @return Pointer to the current cutscene item. - */ -const cutsceneitem_t * cutsceneSystemGetCurrentItem(); \ No newline at end of file diff --git a/archive/rpg/cutscene/item/CMakeLists.txt b/archive/rpg/cutscene/item/CMakeLists.txt deleted file mode 100755 index 6b3e271a..00000000 --- a/archive/rpg/cutscene/item/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - cutsceneitem.c -) \ No newline at end of file diff --git a/archive/rpg/cutscene/item/cutscenecallback.h b/archive/rpg/cutscene/item/cutscenecallback.h deleted file mode 100644 index 494f877d..00000000 --- a/archive/rpg/cutscene/item/cutscenecallback.h +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "dusk.h" - -typedef void (*cutscenecallback_t)(void); \ No newline at end of file diff --git a/archive/rpg/cutscene/item/cutsceneitem.c b/archive/rpg/cutscene/item/cutsceneitem.c deleted file mode 100644 index 18a8b582..00000000 --- a/archive/rpg/cutscene/item/cutsceneitem.c +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "rpg/cutscene/cutscenesystem.h" -#include "input/input.h" -#include "time/time.h" - -void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data) { - switch(item->type) { - case CUTSCENE_ITEM_TYPE_TEXT: { - rpgTextboxShow( - item->text.position, - item->text.text - ); - break; - } - - case CUTSCENE_ITEM_TYPE_WAIT: - data->wait = item->wait; - break; - - case CUTSCENE_ITEM_TYPE_CALLBACK: - if(item->callback != NULL) item->callback(); - break; - - case CUTSCENE_ITEM_TYPE_CUTSCENE: - if(item->cutscene != NULL) cutsceneSystemStartCutscene(item->cutscene); - break; - - default: - break; - } -} - -void cutsceneItemUpdate(const cutsceneitem_t *item, cutsceneitemdata_t *data) { - switch(item->type) { - case CUTSCENE_ITEM_TYPE_TEXT: - if(rpgTextboxIsVisible()) return; - cutsceneSystemNext(); - break; - - case CUTSCENE_ITEM_TYPE_WAIT: - data->wait -= TIME.delta; - if(data->wait <= 0) cutsceneSystemNext(); - break; - - default: - break; - } -} \ No newline at end of file diff --git a/archive/rpg/cutscene/item/cutsceneitem.h b/archive/rpg/cutscene/item/cutsceneitem.h deleted file mode 100644 index f632518d..00000000 --- a/archive/rpg/cutscene/item/cutsceneitem.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "cutscenewait.h" -#include "cutscenecallback.h" -#include "cutscenetext.h" - -typedef struct cutscene_s cutscene_t; - -typedef enum { - CUTSCENE_ITEM_TYPE_NULL, - CUTSCENE_ITEM_TYPE_TEXT, - CUTSCENE_ITEM_TYPE_CALLBACK, - CUTSCENE_ITEM_TYPE_WAIT, - CUTSCENE_ITEM_TYPE_CUTSCENE -} cutsceneitemtype_t; - -typedef struct cutsceneitem_s { - cutsceneitemtype_t type; - - // Arguments/Data that will be used when this item is invoked. - union { - cutscenetext_t text; - cutscenecallback_t callback; - cutscenewait_t wait; - const cutscene_t *cutscene; - }; -} cutsceneitem_t; - -typedef union { - cutscenewaitdata_t wait; -} cutsceneitemdata_t; - -/** - * Start the given cutscene item. - * - * @param item The cutscene item to start. - * @param data The cutscene item data storage. - */ -void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data); - -/** - * Tick the given cutscene item (one frame). - * - * @param item The cutscene item to tick. - * @param data The cutscene item data storage. - */ -void cutsceneItemUpdate(const cutsceneitem_t *item, cutsceneitemdata_t *data); \ No newline at end of file diff --git a/archive/rpg/cutscene/item/cutscenetext.h b/archive/rpg/cutscene/item/cutscenetext.h deleted file mode 100644 index 3ad07f29..00000000 --- a/archive/rpg/cutscene/item/cutscenetext.h +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "rpg/rpgtextbox.h" - -typedef struct { - char_t text[RPG_TEXTBOX_MAX_CHARS]; - rpgtextboxpos_t position; -} cutscenetext_t; \ No newline at end of file diff --git a/archive/rpg/cutscene/item/cutscenewait.h b/archive/rpg/cutscene/item/cutscenewait.h deleted file mode 100644 index 9d590df2..00000000 --- a/archive/rpg/cutscene/item/cutscenewait.h +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "dusk.h" - -typedef float_t cutscenewait_t; -typedef float_t cutscenewaitdata_t; \ No newline at end of file diff --git a/archive/rpg/cutscene/scene/testcutscene.h b/archive/rpg/cutscene/scene/testcutscene.h deleted file mode 100755 index bcdffb21..00000000 --- a/archive/rpg/cutscene/scene/testcutscene.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "rpg/cutscene/cutscenesystem.h" - -static const cutsceneitem_t TEST_CUTSCENE_ONE_ITEMS[] = { - { .type = CUTSCENE_ITEM_TYPE_TEXT, .text = { .text = "This is a test cutscene.", .position = RPG_TEXTBOX_POS_BOTTOM } }, - { .type = CUTSCENE_ITEM_TYPE_WAIT, .wait = 2.0f }, - { .type = CUTSCENE_ITEM_TYPE_TEXT, .text = { .text = "It has multiple lines of text.\nAnd waits in between.", .position = RPG_TEXTBOX_POS_TOP } }, -}; - -static const cutscene_t TEST_CUTSCENE_ONE = { - .items = TEST_CUTSCENE_ONE_ITEMS, - .itemCount = sizeof(TEST_CUTSCENE_ONE_ITEMS) / sizeof(cutsceneitem_t) -}; - -static const cutsceneitem_t TEST_CUTSCENE_TWO_ITEMS[] = { - { .type = CUTSCENE_ITEM_TYPE_WAIT, .wait = 1.0f }, - { .type = CUTSCENE_ITEM_TYPE_CUTSCENE, .cutscene = &TEST_CUTSCENE_ONE }, -}; - -static const cutscene_t TEST_CUTSCENE = { - .items = TEST_CUTSCENE_TWO_ITEMS, - .itemCount = sizeof(TEST_CUTSCENE_TWO_ITEMS) / sizeof(cutsceneitem_t) -}; \ No newline at end of file diff --git a/archive/rpg/entity/CMakeLists.txt b/archive/rpg/entity/CMakeLists.txt deleted file mode 100644 index f6e4cda5..00000000 --- a/archive/rpg/entity/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - entity.c - entityanim.c - npc.c - player.c - entitydir.c -) \ No newline at end of file diff --git a/archive/rpg/entity/entity.c b/archive/rpg/entity/entity.c deleted file mode 100644 index 194c4135..00000000 --- a/archive/rpg/entity/entity.c +++ /dev/null @@ -1,200 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "entity.h" -#include "assert/assert.h" -#include "util/memory.h" -#include "time/time.h" -#include "util/math.h" -#include "rpg/cutscene/cutscenemode.h" -#include "rpg/overworld/map.h" - -entity_t ENTITIES[ENTITY_COUNT]; - -void entityInit(entity_t *entity, const entitytype_t type) { - assertNotNull(entity, "Entity pointer cannot be NULL"); - assertTrue(type < ENTITY_TYPE_COUNT, "Invalid entity type"); - assertTrue(type != ENTITY_TYPE_NULL, "Cannot have NULL entity type"); - assertTrue( - entity >= ENTITIES && entity < ENTITIES + ENTITY_COUNT, - "Entity pointer is out of bounds" - ); - - memoryZero(entity, sizeof(entity_t)); - entity->id = (uint8_t)(entity - ENTITIES); - entity->type = type; - - if(ENTITY_CALLBACKS[type].init != NULL) ENTITY_CALLBACKS[type].init(entity); -} - -void entityUpdate(entity_t *entity) { - assertNotNull(entity, "Entity pointer cannot be NULL"); - assertTrue(entity->type < ENTITY_TYPE_COUNT, "Invalid entity type"); - assertTrue(entity->type != ENTITY_TYPE_NULL, "Cannot have NULL entity type"); - - // What state is the entity in? - if(entity->animation != ENTITY_ANIM_IDLE) { - // Entity is mid animation, tick it (down). - entity->animTime -= TIME.delta; - if(entity->animTime <= 0) { - entity->animation = ENTITY_ANIM_IDLE; - entity->animTime = 0; - } - return; - } - - // Movement code. - if( - cutsceneModeIsInputAllowed() && - ENTITY_CALLBACKS[entity->type].movement != NULL - ) { - ENTITY_CALLBACKS[entity->type].movement(entity); - } -} - -void entityTurn(entity_t *entity, const entitydir_t direction) { - entity->direction = direction; - entity->animation = ENTITY_ANIM_TURN; - entity->animTime = ENTITY_ANIM_TURN_DURATION; -} - -void entityWalk(entity_t *entity, const entitydir_t direction) { - // TODO: Animation, delay, etc. - entity->direction = direction; - - // Where are we moving? - worldpos_t newPos = entity->position; - { - worldunits_t relX, relY; - entityDirGetRelative(direction, &relX, &relY); - newPos.x += relX; - newPos.y += relY; - } - - // Get tile under foot - tile_t tileCurrent = mapGetTile(entity->position); - tile_t tileNew = mapGetTile(newPos); - bool_t fall = false; - bool_t raise = false; - - // Are we walking up a ramp? - if( - tileIsRamp(tileCurrent) && - ( - // Can only walk UP the direction the ramp faces. - (direction+TILE_SHAPE_RAMP_SOUTH) == tileCurrent || - // If diagonal ramp, can go up one of two ways only. - ( - ( - tileCurrent == TILE_SHAPE_RAMP_SOUTHEAST && - (direction == ENTITY_DIR_SOUTH || direction == ENTITY_DIR_EAST) - ) || - ( - tileCurrent == TILE_SHAPE_RAMP_SOUTHWEST && - (direction == ENTITY_DIR_SOUTH || direction == ENTITY_DIR_WEST) - ) || - ( - tileCurrent == TILE_SHAPE_RAMP_NORTHEAST && - (direction == ENTITY_DIR_NORTH || direction == ENTITY_DIR_EAST) - ) || - ( - tileCurrent == TILE_SHAPE_RAMP_NORTHWEST && - (direction == ENTITY_DIR_NORTH || direction == ENTITY_DIR_WEST) - ) - ) - // Must be able to walk up. - ) - ) { - tileNew = TILE_SHAPE_NULL;// Force check for ramp above. - worldpos_t abovePos = newPos; - abovePos.z += 1; - tile_t tileAbove = mapGetTile(abovePos); - - if(tileAbove != TILE_SHAPE_NULL && tileIsWalkable(tileAbove)) { - // We can go up the ramp. - raise = true; - } - } else if(tileNew == TILE_SHAPE_NULL && newPos.z > 0) { - // Falling down? - worldpos_t belowPos = newPos; - belowPos.z -= 1; - tile_t tileBelow = mapGetTile(belowPos); - if( - tileBelow != TILE_SHAPE_NULL && - tileIsRamp(tileBelow) && - ( - // This handles regular cardinal ramps - (entityDirGetOpposite(direction)+TILE_SHAPE_RAMP_SOUTH) == tileBelow || - // This handles diagonal ramps - ( - ( - tileBelow == TILE_SHAPE_RAMP_SOUTHEAST && - (direction == ENTITY_DIR_NORTH || direction == ENTITY_DIR_WEST) - ) || - ( - tileBelow == TILE_SHAPE_RAMP_SOUTHWEST && - (direction == ENTITY_DIR_NORTH || direction == ENTITY_DIR_EAST) - ) || - ( - tileBelow == TILE_SHAPE_RAMP_NORTHEAST && - (direction == ENTITY_DIR_SOUTH || direction == ENTITY_DIR_WEST) - ) || - ( - tileBelow == TILE_SHAPE_RAMP_NORTHWEST && - (direction == ENTITY_DIR_SOUTH || direction == ENTITY_DIR_EAST) - ) - ) - ) - ) { - // We will fall to this tile. - fall = true; - } - } - - // Can we walk here? - if(!raise && !fall && !tileIsWalkable(tileNew)) return;// Blocked - - // Entity in way? - entity_t *other = ENTITIES; - do { - if(other == entity) continue; - if(other->type == ENTITY_TYPE_NULL) continue; - if(!worldPosIsEqual(other->position, newPos)) continue; - return;// Blocked - } while(++other, other < &ENTITIES[ENTITY_COUNT]); - - entity->lastPosition = entity->position; - entity->position = newPos; - entity->animation = ENTITY_ANIM_WALK; - entity->animTime = ENTITY_ANIM_WALK_DURATION;// TODO: Running vs walking - - if(raise) { - entity->position.z += 1; - } else if(fall) { - entity->position.z -= 1; - } -} - -entity_t * entityGetAt(const worldpos_t position) { - entity_t *ent = ENTITIES; - do { - if(ent->type == ENTITY_TYPE_NULL) continue; - if(!worldPosIsEqual(ent->position, position)) continue; - return ent; - } while(++ent, ent < &ENTITIES[ENTITY_COUNT]); - - return NULL; -} - -uint8_t entityGetAvailable() { - entity_t *ent = ENTITIES; - do { - if(ent->type == ENTITY_TYPE_NULL) return ent - ENTITIES; - } while(++ent, ent < &ENTITIES[ENTITY_COUNT]); - - return 0xFF; -} \ No newline at end of file diff --git a/archive/rpg/entity/entity.h b/archive/rpg/entity/entity.h deleted file mode 100644 index 258b54f2..00000000 --- a/archive/rpg/entity/entity.h +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "entitydir.h" -#include "entityanim.h" -#include "entitytype.h" -#include "npc.h" - -typedef struct map_s map_t; - -typedef struct entity_s { - uint8_t id; - entitytype_t type; - entitytypedata_t data; - - // Movement - entitydir_t direction; - worldpos_t position; - worldpos_t lastPosition; - - entityanim_t animation; - float_t animTime; -} entity_t; - -extern entity_t ENTITIES[ENTITY_COUNT]; - -/** - * Initializes an entity structure. - * - * @param entity Pointer to the entity structure to initialize. - * @param type The type of the entity. - */ -void entityInit(entity_t *entity, const entitytype_t type); - -/** - * Updates an entity. - * - * @param entity Pointer to the entity structure to update. - */ -void entityUpdate(entity_t *entity); - -/** - * Turn an entity to face a new direction. - * - * @param entity Pointer to the entity to turn. - * @param direction The direction to face. - */ -void entityTurn(entity_t *entity, const entitydir_t direction); - -/** - * Make an entity walk in a direction. - * - * @param entity Pointer to the entity to make walk. - * @param direction The direction to walk in. - */ -void entityWalk(entity_t *entity, const entitydir_t direction); - -/** - * Gets the entity at a specific world position. - * - * @param map Pointer to the map to check. - * @param pos The world position to check. - * @return Pointer to the entity at the position, or NULL if none. - */ -entity_t *entityGetAt(const worldpos_t pos); - -/** - * Gets an available entity index. - * - * @return The index of an available entity, or 0xFF if none are available. - */ -uint8_t entityGetAvailable(); \ No newline at end of file diff --git a/archive/rpg/entity/entityanim.c b/archive/rpg/entity/entityanim.c deleted file mode 100644 index d5730f3f..00000000 --- a/archive/rpg/entity/entityanim.c +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "entityanim.h" - diff --git a/archive/rpg/entity/entityanim.h b/archive/rpg/entity/entityanim.h deleted file mode 100644 index 42f7d40a..00000000 --- a/archive/rpg/entity/entityanim.h +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "dusk.h" - -#define ENTITY_ANIM_TURN_DURATION 0.06f -#define ENTITY_ANIM_WALK_DURATION 0.1f - -typedef enum { - ENTITY_ANIM_IDLE, - ENTITY_ANIM_TURN, - ENTITY_ANIM_WALK, -} entityanim_t; \ No newline at end of file diff --git a/archive/rpg/entity/entitydir.c b/archive/rpg/entity/entitydir.c deleted file mode 100644 index e272877a..00000000 --- a/archive/rpg/entity/entitydir.c +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "entitydir.h" -#include "assert/assert.h" - -entitydir_t entityDirGetOpposite(const entitydir_t dir) { - switch(dir) { - case ENTITY_DIR_NORTH: return ENTITY_DIR_SOUTH; - case ENTITY_DIR_SOUTH: return ENTITY_DIR_NORTH; - case ENTITY_DIR_EAST: return ENTITY_DIR_WEST; - case ENTITY_DIR_WEST: return ENTITY_DIR_EAST; - default: return dir; - } -} - -void entityDirGetRelative( - const entitydir_t from, - worldunits_t *outX, - worldunits_t *outY -) { - assertValidEntityDir(from, "Invalid direction provided"); - assertNotNull(outX, "Output X pointer cannot be NULL"); - assertNotNull(outY, "Output Y pointer cannot be NULL"); - - switch(from) { - case ENTITY_DIR_NORTH: - *outX = 0; - *outY = -1; - break; - - case ENTITY_DIR_EAST: - *outX = 1; - *outY = 0; - break; - - case ENTITY_DIR_SOUTH: - *outX = 0; - *outY = 1; - break; - - case ENTITY_DIR_WEST: - *outX = -1; - *outY = 0; - break; - } -} \ No newline at end of file diff --git a/archive/rpg/entity/entitydir.h b/archive/rpg/entity/entitydir.h deleted file mode 100644 index b132efb9..00000000 --- a/archive/rpg/entity/entitydir.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "rpg/overworld/worldpos.h" - -typedef enum { - ENTITY_DIR_UP = ENTITY_DIR_NORTH, - ENTITY_DIR_DOWN = ENTITY_DIR_SOUTH, - ENTITY_DIR_LEFT = ENTITY_DIR_WEST, - ENTITY_DIR_RIGHT = ENTITY_DIR_EAST, -} entitydir_t; - -/** - * Gets the opposite direction of a given direction. - * - * @param dir The direction to get the opposite of. - * @return entitydir_t The opposite direction. - */ -entitydir_t entityDirGetOpposite(const entitydir_t dir); - -/** - * Asserts a given direction is valid. - * - * @param dir The direction to validate. - * @param msg The message to display if the assertion fails. - */ -#define assertValidEntityDir(dir, msg) \ - assertTrue( \ - (dir) == ENTITY_DIR_NORTH || \ - (dir) == ENTITY_DIR_EAST || \ - (dir) == ENTITY_DIR_SOUTH || \ - (dir) == ENTITY_DIR_WEST, \ - msg \ - ) - -/** - * Gets the relative x and y offsets for a given direction. - * - * @param dir The direction to get offsets for. - * @param relX Pointer to store the relative x offset. - * @param relY Pointer to store the relative y offset. - */ -void entityDirGetRelative( - const entitydir_t dir, worldunits_t *relX, worldunits_t *relY -); \ No newline at end of file diff --git a/archive/rpg/entity/entitytype.h b/archive/rpg/entity/entitytype.h deleted file mode 100644 index 0e3e4baa..00000000 --- a/archive/rpg/entity/entitytype.h +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "duskdefs.h" -#include "rpg/entity/player.h" -#include "npc.h" - -typedef uint8_t entitytype_t; - -typedef union { - player_t player; - npc_t npc; -} entitytypedata_t; - -typedef struct { - /** - * Initialization callback for the entity type. - * @param entity Pointer to the entity to initialize. - */ - void (*init)(entity_t *entity); - - /** - * Movement callback for the entity type. - * @param entity Pointer to the entity to move. - */ - void (*movement)(entity_t *entity); - - /** - * Interaction callback for the entity type. - * @param player Pointer to the player entity. - * @param entity Pointer to the entity to interact with. - * @return True if the entity handled the interaction, false otherwise. - */ - bool_t (*interact)(entity_t *player, entity_t *entity); -} entitycallback_t; - -static const entitycallback_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT] = { - [ENTITY_TYPE_NULL] = { NULL }, - - [ENTITY_TYPE_PLAYER] = { - .init = playerInit, - .movement = playerInput - }, - - [ENTITY_TYPE_NPC] = { - .init = npcInit, - .movement = npcMovement, - .interact = npcInteract - } -}; \ No newline at end of file diff --git a/archive/rpg/entity/npc.c b/archive/rpg/entity/npc.c deleted file mode 100644 index ec6548bd..00000000 --- a/archive/rpg/entity/npc.c +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "entity.h" -#include "assert/assert.h" - -#include "rpg/cutscene/scene/testcutscene.h" -#include "rpg/rpgtextbox.h" - -void npcInit(entity_t *entity) { - assertNotNull(entity, "Entity pointer cannot be NULL"); -} - -void npcMovement(entity_t *entity) { - assertNotNull(entity, "Entity pointer cannot be NULL"); -} - -bool_t npcInteract(entity_t *player, entity_t *npc) { - assertNotNull(player, "Player entity pointer cannot be NULL"); - assertNotNull(npc, "NPC entity pointer cannot be NULL"); - - cutsceneSystemStartCutscene(&TEST_CUTSCENE); - - // rpgTextboxShow(RPG_TEXTBOX_POS_BOTTOM, "Hello World!"); - - return false; -}; \ No newline at end of file diff --git a/archive/rpg/entity/npc.h b/archive/rpg/entity/npc.h deleted file mode 100644 index df36f15e..00000000 --- a/archive/rpg/entity/npc.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "dusk.h" - -typedef struct entity_s entity_t; - -typedef struct { - void *nothing; -} npc_t; - -/** - * Initializes an NPC entity. - * - * @param entity Pointer to the entity structure to initialize. - */ -void npcInit(entity_t *entity); - -/** - * Updates an NPC entity. - * - * @param entity Pointer to the entity structure to update. - */ -void npcMovement(entity_t *entity); - -/** - * Handles interaction with an NPC entity. - * - * @param player Pointer to the player entity. - * @param npc Pointer to the NPC entity. - */ -bool_t npcInteract(entity_t *player, entity_t *npc); \ No newline at end of file diff --git a/archive/rpg/entity/player.c b/archive/rpg/entity/player.c deleted file mode 100644 index cf33d562..00000000 --- a/archive/rpg/entity/player.c +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "entity.h" -#include "assert/assert.h" -#include "rpg/rpgcamera.h" -#include "util/memory.h" -#include "time/time.h" - -void playerInit(entity_t *entity) { - assertNotNull(entity, "Entity pointer cannot be NULL"); -} - -void playerInput(entity_t *entity) { - assertNotNull(entity, "Entity pointer cannot be NULL"); - - // Turn - const playerinputdirmap_t *dirMap = PLAYER_INPUT_DIR_MAP; - do { - if(!inputIsDown(dirMap->action)) continue; - if(entity->direction == dirMap->direction) continue; - return entityTurn(entity, dirMap->direction); - } while((++dirMap)->action != 0xFF); - - // Walk - dirMap = PLAYER_INPUT_DIR_MAP; - do { - if(!inputIsDown(dirMap->action)) continue; - if(entity->direction != dirMap->direction) continue; - return entityWalk(entity, dirMap->direction); - } while((++dirMap)->action != 0xFF); - - // Interaction - if(inputPressed(INPUT_ACTION_ACCEPT)) { - worldunit_t x, y, z; - { - worldunits_t relX, relY; - entityDirGetRelative(entity->direction, &relX, &relY); - x = entity->position.x + relX; - y = entity->position.y + relY; - z = entity->position.z; - } - - entity_t *interact = entityGetAt((worldpos_t){ x, y, z }); - if(interact != NULL && ENTITY_CALLBACKS[interact->type].interact != NULL) { - if(ENTITY_CALLBACKS[interact->type].interact(entity, interact)) return; - } - } - -} \ No newline at end of file diff --git a/archive/rpg/entity/player.h b/archive/rpg/entity/player.h deleted file mode 100644 index 8c10f31c..00000000 --- a/archive/rpg/entity/player.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "input/input.h" - -typedef struct entity_s entity_t; - -typedef struct { - void *nothing; -} player_t; - -typedef struct { - inputaction_t action; - entitydir_t direction; -} playerinputdirmap_t; - -static const playerinputdirmap_t PLAYER_INPUT_DIR_MAP[] = { - { INPUT_ACTION_UP, ENTITY_DIR_NORTH }, - { INPUT_ACTION_DOWN, ENTITY_DIR_SOUTH }, - { INPUT_ACTION_LEFT, ENTITY_DIR_WEST }, - { INPUT_ACTION_RIGHT, ENTITY_DIR_EAST }, - - { 0xFF, 0xFF } -}; - -/** - * Initializes a player entity. - * - * @param entity Pointer to the entity structure to initialize. - */ -void playerInit(entity_t *entity); - -/** - * Handles movement logic for the player entity. - * - * @param entity Pointer to the player entity structure. - */ -void playerInput(entity_t *entity); \ No newline at end of file diff --git a/archive/rpg/overworld/CMakeLists.txt b/archive/rpg/overworld/CMakeLists.txt deleted file mode 100644 index b697bf8a..00000000 --- a/archive/rpg/overworld/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - chunk.c - map.c - worldpos.c - tile.c -) \ No newline at end of file diff --git a/archive/rpg/overworld/chunk.c b/archive/rpg/overworld/chunk.c deleted file mode 100644 index 19a9999e..00000000 --- a/archive/rpg/overworld/chunk.c +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "chunk.h" - -uint32_t chunkGetTileIndex(const chunkpos_t position) { - return ( - (position.z * CHUNK_WIDTH * CHUNK_HEIGHT) + - (position.y * CHUNK_WIDTH) + - position.x - ); -} - -bool_t chunkPositionIsEqual(const chunkpos_t a, const chunkpos_t b) { - return (a.x == b.x) && (a.y == b.y) && (a.z == b.z); -} \ No newline at end of file diff --git a/archive/rpg/overworld/chunk.h b/archive/rpg/overworld/chunk.h deleted file mode 100644 index 508b15f9..00000000 --- a/archive/rpg/overworld/chunk.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "rpg/overworld/tile.h" -#include "worldpos.h" -#include "display/mesh/quad.h" - -typedef struct chunk_s { - chunkpos_t position; - tile_t tiles[CHUNK_TILE_COUNT]; - - uint8_t meshCount; - meshvertex_t vertices[CHUNK_VERTEX_COUNT_MAX]; - mesh_t meshes[CHUNK_MESH_COUNT_MAX]; - uint8_t entities[CHUNK_ENTITY_COUNT_MAX]; -} chunk_t; - -/** - * Gets the tile index for a tile position within a chunk. - * - * @param position The position within the chunk. - * @return The tile index within the chunk. - */ -uint32_t chunkGetTileIndex(const chunkpos_t position); - -/** - * Checks if two chunk positions are equal. - * - * @param a The first chunk position. - * @param b The second chunk position. - * @return true if equal, false otherwise. - */ -bool_t chunkPositionIsEqual(const chunkpos_t a, const chunkpos_t b); \ No newline at end of file diff --git a/archive/rpg/overworld/map.c b/archive/rpg/overworld/map.c deleted file mode 100644 index 32ff403a..00000000 --- a/archive/rpg/overworld/map.c +++ /dev/null @@ -1,269 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "map.h" -#include "util/memory.h" -#include "assert/assert.h" -#include "asset/asset.h" -#include "rpg/entity/entity.h" -#include "util/string.h" -#include "script/scriptcontext.h" - -map_t MAP; - -errorret_t mapInit() { - memoryZero(&MAP, sizeof(map_t)); - errorOk(); -} - -bool_t mapIsLoaded() { - return MAP.filePath[0] != '\0'; -} - -errorret_t mapLoad(const char_t *path, const chunkpos_t position) { - assertStrLenMin(path, 1, "Map file path cannot be empty"); - assertStrLenMax(path, MAP_FILE_PATH_MAX - 1, "Map file path too long"); - - if(stringCompare(MAP.filePath, path) == 0) { - // Same map, no need to reload - errorOk(); - } - - chunkindex_t i; - - // Unload all loaded chunks - if(mapIsLoaded()) { - for(i = 0; i < MAP_CHUNK_COUNT; i++) { - mapChunkUnload(&MAP.chunks[i]); - } - } - - // Store the map file path - stringCopy(MAP.filePath, path, MAP_FILE_PATH_MAX); - - // Determine directory path (it is dirname) - stringCopy(MAP.dirPath, path, MAP_FILE_PATH_MAX); - char_t *last = stringFindLastChar(MAP.dirPath, '/'); - if(last == NULL) errorThrow("Invalid map file path"); - - // Store filename, sans extension - stringCopy(MAP.fileName, last + 1, MAP_FILE_PATH_MAX); - *last = '\0'; // Terminate to get directory path - - last = stringFindLastChar(MAP.fileName, '.'); - if(last == NULL) errorThrow("Map file name has no extension"); - *last = '\0'; // Terminate to remove extension - - // Reset map position - MAP.chunkPosition = position; - - // Perform "initial load" - i = 0; - for(chunkunit_t z = 0; z < MAP_CHUNK_DEPTH; z++) { - for(chunkunit_t y = 0; y < MAP_CHUNK_HEIGHT; y++) { - for(chunkunit_t x = 0; x < MAP_CHUNK_WIDTH; x++) { - chunk_t *chunk = &MAP.chunks[i]; - chunk->position.x = x + position.x; - chunk->position.y = y + position.y; - chunk->position.z = z + position.z; - MAP.chunkOrder[i] = chunk; - errorChain(mapChunkLoad(chunk)); - i++; - } - } - } - - // Execute map script. - char_t scriptPath[MAP_FILE_PATH_MAX + 16]; - stringFormat( - scriptPath, sizeof(scriptPath), "%s/%s.dsf", - MAP.dirPath, MAP.fileName - ); - if(assetFileExists(scriptPath)) { - scriptcontext_t ctx; - errorChain(scriptContextInit(&ctx)); - errorChain(scriptContextExecFile(&ctx, scriptPath)); - scriptContextDispose(&ctx); - } - - errorOk(); -} - -errorret_t mapPositionSet(const chunkpos_t newPos) { - if(!mapIsLoaded()) errorThrow("No map loaded"); - - const chunkpos_t curPos = MAP.chunkPosition; - if(chunkPositionIsEqual(curPos, newPos)) { - errorOk(); - } - - // Determine which chunks remain loaded - chunkindex_t chunksRemaining[MAP_CHUNK_COUNT] = {0}; - chunkindex_t chunksFreed[MAP_CHUNK_COUNT] = {0}; - - uint32_t remainingCount = 0; - uint32_t freedCount = 0; - - for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) { - // Will this chunk remain loaded? - chunk_t *chunk = &MAP.chunks[i]; - if( - chunk->position.x >= newPos.x && - chunk->position.x < newPos.x + MAP_CHUNK_WIDTH && - - chunk->position.y >= newPos.y && - chunk->position.y < newPos.y + MAP_CHUNK_HEIGHT && - - chunk->position.z >= newPos.z && - chunk->position.z < newPos.z + MAP_CHUNK_DEPTH - ) { - // Stays loaded - chunksRemaining[remainingCount++] = i; - continue; - } - - // Not remaining loaded - chunksFreed[freedCount++] = i; - } - - // Unload the freed chunks - for(chunkindex_t i = 0; i < freedCount; i++) { - chunk_t *chunk = &MAP.chunks[chunksFreed[i]]; - mapChunkUnload(chunk); - } - - // This can probably be optimized later, for now we check each chunk and see - // if it needs loading or not, and update the chunk order - chunkindex_t orderIndex = 0; - for(chunkunit_t zOff = 0; zOff < MAP_CHUNK_DEPTH; zOff++) { - for(chunkunit_t yOff = 0; yOff < MAP_CHUNK_HEIGHT; yOff++) { - for(chunkunit_t xOff = 0; xOff < MAP_CHUNK_WIDTH; xOff++) { - const chunkpos_t newChunkPos = { - newPos.x + xOff, newPos.y + yOff, newPos.z + zOff - }; - - // Is this chunk already loaded (was not unloaded earlier)? - chunkindex_t chunkIndex = -1; - for(chunkindex_t i = 0; i < remainingCount; i++) { - chunk_t *chunk = &MAP.chunks[chunksRemaining[i]]; - if(!chunkPositionIsEqual(chunk->position, newChunkPos)) continue; - chunkIndex = chunksRemaining[i]; - break; - } - - // Need to load this chunk - if(chunkIndex == -1) { - // Find a freed chunk to reuse - chunkIndex = chunksFreed[--freedCount]; - chunk_t *chunk = &MAP.chunks[chunkIndex]; - chunk->position = newChunkPos; - errorChain(mapChunkLoad(chunk)); - } - - MAP.chunkOrder[orderIndex++] = &MAP.chunks[chunkIndex]; - } - } - } - - // Update map position - MAP.chunkPosition = newPos; - - errorOk(); -} - -void mapUpdate() { - -} - -void mapDispose() { - for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) { - mapChunkUnload(&MAP.chunks[i]); - } -} - -void mapChunkUnload(chunk_t* chunk) { - for(uint8_t i = 0; i < CHUNK_ENTITY_COUNT_MAX; i++) { - if(chunk->entities[i] == 0xFF) break; - entity_t *entity = &ENTITIES[chunk->entities[i]]; - entity->type = ENTITY_TYPE_NULL; - } - - for(uint8_t i = 0; i < chunk->meshCount; i++) { - if(chunk->meshes[i].vertexCount == 0) continue; - meshDispose(&chunk->meshes[i]); - } -} - -errorret_t mapChunkLoad(chunk_t* chunk) { - if(!mapIsLoaded()) errorThrow("No map loaded"); - - char_t buffer[64]; - - // TODO: Can probably move this to asset load logic? - chunk->meshCount = 0; - memoryZero(chunk->meshes, sizeof(chunk->meshes)); - memorySet(chunk->entities, 0xFF, sizeof(chunk->entities)); - - // Get chunk filepath. - snprintf(buffer, sizeof(buffer), "%s/chunks/%d_%d_%d.dmc", - MAP.dirPath, - chunk->position.x, - chunk->position.y, - chunk->position.z - ); - - // Chunk available? - if(!assetFileExists(buffer)) { - memoryZero(chunk->tiles, sizeof(chunk->tiles)); - errorOk(); - } - - // Load. - errorChain(assetLoad(buffer, chunk)); - errorOk(); -} - -chunkindex_t mapGetChunkIndexAt(const chunkpos_t position) { - if(!mapIsLoaded()) return -1; - - chunkpos_t relPos = { - position.x - MAP.chunkPosition.x, - position.y - MAP.chunkPosition.y, - position.z - MAP.chunkPosition.z - }; - - if( - relPos.x < 0 || relPos.y < 0 || relPos.z < 0 || - relPos.x >= MAP_CHUNK_WIDTH || - relPos.y >= MAP_CHUNK_HEIGHT || - relPos.z >= MAP_CHUNK_DEPTH - ) { - return -1; - } - - return chunkPosToIndex(&relPos); -} - -chunk_t* mapGetChunk(const uint8_t index) { - if(index >= MAP_CHUNK_COUNT) return NULL; - if(!mapIsLoaded()) return NULL; - return MAP.chunkOrder[index]; -} - -tile_t mapGetTile(const worldpos_t position) { - if(!mapIsLoaded()) return TILE_SHAPE_NULL; - - chunkpos_t chunkPos; - worldPosToChunkPos(&position, &chunkPos); - chunkindex_t chunkIndex = mapGetChunkIndexAt(chunkPos); - if(chunkIndex == -1) return TILE_SHAPE_NULL; - - chunk_t *chunk = mapGetChunk(chunkIndex); - assertNotNull(chunk, "Chunk pointer cannot be NULL"); - chunktileindex_t tileIndex = worldPosToChunkTileIndex(&position); - return chunk->tiles[tileIndex]; -} \ No newline at end of file diff --git a/archive/rpg/overworld/map.h b/archive/rpg/overworld/map.h deleted file mode 100644 index 8373fca0..00000000 --- a/archive/rpg/overworld/map.h +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "rpg/overworld/chunk.h" - -#define MAP_FILE_PATH_MAX 128 - -typedef struct map_s { - char_t filePath[MAP_FILE_PATH_MAX]; - char_t dirPath[MAP_FILE_PATH_MAX]; - char_t fileName[MAP_FILE_PATH_MAX]; - - chunk_t chunks[MAP_CHUNK_COUNT]; - chunk_t *chunkOrder[MAP_CHUNK_COUNT]; - chunkpos_t chunkPosition; -} map_t; - -extern map_t MAP; - -/** - * Initializes the map. - * - * @return An error code. - */ -errorret_t mapInit(); - -/** - * Checks if a map is loaded. - * - * @return true if a map is loaded, false otherwise. - */ -bool_t mapIsLoaded(); - -/** - * Loads a map from the given file path. - * - * @param path The file path. - * @param position The initial chunk position. - * @return An error code. - */ -errorret_t mapLoad( - const char_t *path, - const chunkpos_t position -); - -/** - * Updates the map. - */ -void mapUpdate(); - -/** - * Disposes of the map. - */ -void mapDispose(); - -/** - * Sets the map position and updates chunks accordingly. - * - * @param newPos The new chunk position. - * @return An error code. - */ -errorret_t mapPositionSet(const chunkpos_t newPos); - -/** - * Unloads a chunk. - * - * @param chunk The chunk to unload. - */ -void mapChunkUnload(chunk_t* chunk); - -/** - * Loads a chunk. - * - * @param chunk The chunk to load. - * @return An error code. - */ -errorret_t mapChunkLoad(chunk_t* chunk); - -/** - * Gets the index of a chunk, within the world, at the given position. - * - * @param position The chunk position. - * @return The index of the chunk, or -1 if out of bounds. - */ -chunkindex_t mapGetChunkIndexAt(const chunkpos_t position); - -/** - * Gets a chunk by its index. - * - * @param chunkIndex The index of the chunk. - * @return A pointer to the chunk. - */ -chunk_t * mapGetChunk(const uint8_t chunkIndex); - -/** - * Gets the tile at the given world position. - * - * @param position The world position. - * @return The tile at that position, or TILE_NULL if the chunk is unloaded. - */ -tile_t mapGetTile(const worldpos_t position); \ No newline at end of file diff --git a/archive/rpg/overworld/tile.c b/archive/rpg/overworld/tile.c deleted file mode 100644 index cc25881b..00000000 --- a/archive/rpg/overworld/tile.c +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "tile.h" - -bool_t tileIsWalkable(const tile_t tile) { - switch(tile) { - case TILE_SHAPE_NULL: - return false; - - default: - return true; - } -} - -bool_t tileIsRamp(const tile_t tile) { - switch(tile) { - case TILE_SHAPE_RAMP_NORTH: - case TILE_SHAPE_RAMP_SOUTH: - case TILE_SHAPE_RAMP_EAST: - case TILE_SHAPE_RAMP_WEST: - case TILE_SHAPE_RAMP_NORTHEAST: - case TILE_SHAPE_RAMP_NORTHWEST: - case TILE_SHAPE_RAMP_SOUTHEAST: - case TILE_SHAPE_RAMP_SOUTHWEST: - return true; - - default: - return false; - } -} \ No newline at end of file diff --git a/archive/rpg/overworld/tile.h b/archive/rpg/overworld/tile.h deleted file mode 100644 index 6b1d11bc..00000000 --- a/archive/rpg/overworld/tile.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "rpg/entity/entitydir.h" - -typedef uint8_t tile_t; - -/** - * Returns whether or not the given tile is walkable. - * - * @param tile The tile to check. - * @return bool_t True if walkable, false if not. - */ -bool_t tileIsWalkable(const tile_t tile); - -/** - * Returns whether or not the given tile is a ramp tile. - * - * @param tile The tile to check. - * @return bool_t True if ramp, false if not. - */ -bool_t tileIsRamp(const tile_t tile); \ No newline at end of file diff --git a/archive/rpg/overworld/worldpos.c b/archive/rpg/overworld/worldpos.c deleted file mode 100644 index 3cdd7100..00000000 --- a/archive/rpg/overworld/worldpos.c +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "worldpos.h" -#include "assert/assert.h" - -bool_t worldPosIsEqual(const worldpos_t a, const worldpos_t b) { - return a.x == b.x && a.y == b.y && a.z == b.z; -} - -void chunkPosToWorldPos(const chunkpos_t* chunkPos, worldpos_t* out) { - assertNotNull(chunkPos, "Chunk position pointer cannot be NULL"); - assertNotNull(out, "Output world position pointer cannot be NULL"); - - out->x = (worldunit_t)(chunkPos->x * CHUNK_WIDTH); - out->y = (worldunit_t)(chunkPos->y * CHUNK_HEIGHT); - out->z = (worldunit_t)(chunkPos->z * CHUNK_DEPTH); -} - -void worldPosToChunkPos(const worldpos_t* worldPos, chunkpos_t* out) { - assertNotNull(worldPos, "World position pointer cannot be NULL"); - assertNotNull(out, "Output chunk position pointer cannot be NULL"); - - if(worldPos->x < 0) { - out->x = (chunkunit_t)((worldPos->x - (CHUNK_WIDTH - 1)) / CHUNK_WIDTH); - } else { - out->x = (chunkunit_t)(worldPos->x / CHUNK_WIDTH); - } - - if(worldPos->y < 0) { - out->y = (chunkunit_t)((worldPos->y - (CHUNK_HEIGHT - 1)) / CHUNK_HEIGHT); - } else { - out->y = (chunkunit_t)(worldPos->y / CHUNK_HEIGHT); - } - - if(worldPos->z < 0) { - out->z = (chunkunit_t)((worldPos->z - (CHUNK_DEPTH - 1)) / CHUNK_DEPTH); - } else { - out->z = (chunkunit_t)(worldPos->z / CHUNK_DEPTH); - } -} - -chunktileindex_t worldPosToChunkTileIndex(const worldpos_t* worldPos) { - assertNotNull(worldPos, "World position pointer cannot be NULL"); - - uint8_t localX, localY, localZ; - if(worldPos->x < 0) { - localX = (uint8_t)( - (CHUNK_WIDTH - 1) - ((-worldPos->x - 1) % CHUNK_WIDTH) - ); - } else { - localX = (uint8_t)(worldPos->x % CHUNK_WIDTH); - } - - if(worldPos->y < 0) { - localY = (uint8_t)( - (CHUNK_HEIGHT - 1) - ((-worldPos->y - 1) % CHUNK_HEIGHT) - ); - } else { - localY = (uint8_t)(worldPos->y % CHUNK_HEIGHT); - } - - if(worldPos->z < 0) { - localZ = (uint8_t)( - (CHUNK_DEPTH - 1) - ((-worldPos->z - 1) % CHUNK_DEPTH) - ); - } else { - localZ = (uint8_t)(worldPos->z % CHUNK_DEPTH); - } - - chunktileindex_t chunkTileIndex = (chunktileindex_t)( - (localZ * CHUNK_WIDTH * CHUNK_HEIGHT) + - (localY * CHUNK_WIDTH) + - localX - ); - assertTrue( - chunkTileIndex < CHUNK_TILE_COUNT, - "Calculated chunk tile index is out of bounds" - ); - return chunkTileIndex; -} - -chunkindex_t chunkPosToIndex(const chunkpos_t* pos) { - assertNotNull(pos, "Chunk position pointer cannot be NULL"); - - chunkindex_t chunkIndex = (chunkindex_t)( - (pos->z * MAP_CHUNK_WIDTH * MAP_CHUNK_HEIGHT) + - (pos->y * MAP_CHUNK_WIDTH) + - pos->x - ); - - return chunkIndex; -} \ No newline at end of file diff --git a/archive/rpg/overworld/worldpos.h b/archive/rpg/overworld/worldpos.h deleted file mode 100644 index a9432e4e..00000000 --- a/archive/rpg/overworld/worldpos.h +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "dusk.h" -#include "duskdefs.h" - -#define CHUNK_TILE_COUNT (CHUNK_WIDTH * CHUNK_HEIGHT * CHUNK_DEPTH) - -#define MAP_CHUNK_WIDTH 3 -#define MAP_CHUNK_HEIGHT 3 -#define MAP_CHUNK_DEPTH 3 -#define MAP_CHUNK_COUNT (MAP_CHUNK_WIDTH * MAP_CHUNK_HEIGHT * MAP_CHUNK_DEPTH) - -typedef int16_t worldunit_t; -typedef int16_t chunkunit_t; -typedef int16_t chunkindex_t; -typedef uint32_t chunktileindex_t; - -typedef int32_t worldunits_t; -typedef int32_t chunkunits_t; - -typedef struct worldpos_s { - worldunit_t x, y, z; -} worldpos_t; - -typedef struct chunkpos_t { - chunkunit_t x, y, z; -} chunkpos_t; - -/** - * Compares two world positions for equality. - * - * @param a The first world position. - * @param b The second world position. - * @return true if equal, false otherwise. - */ -bool_t worldPosIsEqual(const worldpos_t a, const worldpos_t b); - -/** - * Converts a world position to a chunk position. - * - * @param worldPos The world position. - * @param out The output chunk position. - */ -void chunkPosToWorldPos(const chunkpos_t* chunkPos, worldpos_t* out); - -/** - * Converts a chunk position to a world position. - * - * @param worldPos The world position. - * @param out The output chunk position. - */ -void worldPosToChunkPos(const worldpos_t* worldPos, chunkpos_t* out); - -/** - * Converts a position in world-space to an index inside a chunk that the tile - * resides in. - * - * @param worldPos The world position. - * @return The tile index within the chunk. - */ -chunktileindex_t worldPosToChunkTileIndex(const worldpos_t* worldPos); - -/** - * Converts a chunk position to a world position. - * - * @param worldPos The world position. - * @param out The output chunk position. - */ -chunkindex_t chunkPosToIndex(const chunkpos_t* pos); \ No newline at end of file diff --git a/archive/rpg/rpg.c b/archive/rpg/rpg.c deleted file mode 100644 index 653b36fe..00000000 --- a/archive/rpg/rpg.c +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "rpg.h" -#include "entity/entity.h" -#include "rpg/overworld/map.h" -#include "rpg/cutscene/cutscenesystem.h" -#include "time/time.h" -#include "rpgcamera.h" -#include "rpgtextbox.h" -#include "util/memory.h" -#include "assert/assert.h" - -errorret_t rpgInit(void) { - memoryZero(ENTITIES, sizeof(ENTITIES)); - - // Init cutscene subsystem - cutsceneSystemInit(); - - errorChain(mapInit()); - - rpgCameraInit(); - rpgTextboxInit(); - - // TEST: Create some entities. - // uint8_t entIndex = entityGetAvailable(); - // assertTrue(entIndex != 0xFF, "No available entity slots!."); - // entity_t *ent = &ENTITIES[entIndex]; - // entityInit(ent, ENTITY_TYPE_PLAYER); - // RPG_CAMERA.mode = RPG_CAMERA_MODE_FOLLOW_ENTITY; - // RPG_CAMERA.followEntity.followEntityId = ent->id; - // ent->position.x = 2, ent->position.y = 2; - - // All Good! - errorOk(); -} - -errorret_t rpgUpdate(void) { - #if TIME_FIXED == 0 - if(TIME.dynamicUpdate) errorOk(); - #endif - - // TODO: Do not update if the scene is not the map scene? - mapUpdate(); - - // Update overworld ents. - entity_t *ent = &ENTITIES[0]; - do { - if(ent->type == ENTITY_TYPE_NULL) continue; - entityUpdate(ent); - } while(++ent < &ENTITIES[ENTITY_COUNT]); - - cutsceneSystemUpdate(); - errorChain(rpgCameraUpdate()); - errorOk(); -} - -void rpgDispose(void) { - mapDispose(); -} \ No newline at end of file diff --git a/archive/rpg/rpg.h b/archive/rpg/rpg.h deleted file mode 100644 index 7460dfb5..00000000 --- a/archive/rpg/rpg.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "error/error.h" - -typedef struct { - int32_t nothing; -} rpg_t; - -/** - * Initialize the RPG subsystem. - * - * @return An error code and state. - */ -errorret_t rpgInit(void); - -/** - * Update the RPG subsystem. - * - * @return An error code. - */ -errorret_t rpgUpdate(void); - -/** - * Dispose of the RPG subsystem. - */ -void rpgDispose(void); \ No newline at end of file diff --git a/archive/rpg/rpgcamera.c b/archive/rpg/rpgcamera.c deleted file mode 100644 index b32c0179..00000000 --- a/archive/rpg/rpgcamera.c +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "rpgcamera.h" -#include "util/memory.h" -#include "rpg/entity/entity.h" -#include "rpg/overworld/map.h" -#include "assert/assert.h" - -rpgcamera_t RPG_CAMERA; - -void rpgCameraInit(void) { - memoryZero(&RPG_CAMERA, sizeof(rpgcamera_t)); -} - -errorret_t rpgCameraUpdate(void) { - if(!mapIsLoaded()) errorOk(); - - chunkpos_t chunkPos; - - switch(RPG_CAMERA.mode) { - case RPG_CAMERA_MODE_FREE: - worldPosToChunkPos(&RPG_CAMERA.free, &chunkPos); - break; - - case RPG_CAMERA_MODE_FOLLOW_ENTITY: { - entity_t *entity = &ENTITIES[RPG_CAMERA.followEntity.followEntityId]; - if(entity->type == ENTITY_TYPE_NULL) { - errorOk(); - } - - // Update map position to match camera. By default map wants to know the - // top left but we want to set the center, so we need to sub half map size - worldPosToChunkPos(&entity->position, &chunkPos); - break; - } - - default: - assertUnreachable("Invalid RPG camera mode"); - } - - errorChain(mapPositionSet((chunkpos_t){ - .x = chunkPos.x - (MAP_CHUNK_WIDTH / 2), - .y = chunkPos.y - (MAP_CHUNK_HEIGHT / 2), - .z = chunkPos.z - (MAP_CHUNK_DEPTH / 2) - })); - errorOk(); -} \ No newline at end of file diff --git a/archive/rpg/rpgcamera.h b/archive/rpg/rpgcamera.h deleted file mode 100644 index d3e49663..00000000 --- a/archive/rpg/rpgcamera.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "rpg/overworld/worldpos.h" -#include "error/error.h" - -typedef enum { - RPG_CAMERA_MODE_FREE, - RPG_CAMERA_MODE_FOLLOW_ENTITY, -} rpgcameramode_t; - -typedef struct { - rpgcameramode_t mode; - union { - worldpos_t free; - struct { - uint8_t followEntityId; - } followEntity; - }; -} rpgcamera_t; - -extern rpgcamera_t RPG_CAMERA; - -/** - * Initializes the RPG camera. - */ -void rpgCameraInit(void); - -/** - * Updates the RPG camera. - * - * @return An error code. - */ -errorret_t rpgCameraUpdate(void); \ No newline at end of file diff --git a/archive/rpg/rpgtextbox.c b/archive/rpg/rpgtextbox.c deleted file mode 100644 index 6fba985c..00000000 --- a/archive/rpg/rpgtextbox.c +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "rpgtextbox.h" -#include "util/memory.h" -#include "util/string.h" -#include "assert/assert.h" - -rpgtextbox_t RPG_TEXTBOX; - -void rpgTextboxInit() { - memoryZero(&RPG_TEXTBOX, sizeof(rpgtextbox_t)); -} - -void rpgTextboxShow( - const rpgtextboxpos_t position, - const char_t *text -) { - RPG_TEXTBOX.position = position; - RPG_TEXTBOX.visible = true; - - stringCopy( - RPG_TEXTBOX.text, - text, - RPG_TEXTBOX_MAX_CHARS - ); -} - -void rpgTextboxHide() { - RPG_TEXTBOX.visible = false; -} - -bool_t rpgTextboxIsVisible() { - return RPG_TEXTBOX.visible; -} \ No newline at end of file diff --git a/archive/rpg/rpgtextbox.h b/archive/rpg/rpgtextbox.h deleted file mode 100644 index 02e8cd98..00000000 --- a/archive/rpg/rpgtextbox.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "dusk.h" - -#define RPG_TEXTBOX_MAX_CHARS 256 - -typedef enum { - RPG_TEXTBOX_POS_TOP, - RPG_TEXTBOX_POS_BOTTOM, -} rpgtextboxpos_t; - -typedef struct { - rpgtextboxpos_t position; - bool_t visible; - char_t text[RPG_TEXTBOX_MAX_CHARS]; -} rpgtextbox_t; - -extern rpgtextbox_t RPG_TEXTBOX; - -/** - * Initializes the RPG textbox. - */ -void rpgTextboxInit(); - -/** - * Shows the RPG textbox at a specified position. - * - * @param position The position to show the textbox at. - * @param text The text to display in the textbox (copied). - */ -void rpgTextboxShow( - const rpgtextboxpos_t position, - const char_t *text -); - -/** - * Hides the RPG textbox. - */ -void rpgTextboxHide(); - -/** - * Checks if the RPG textbox is currently visible. - * - * @return true if the textbox is visible, false otherwise. - */ -bool_t rpgTextboxIsVisible(); \ No newline at end of file diff --git a/archive/scene/CMakeLists.txt b/archive/scene/CMakeLists.txt deleted file mode 100644 index 94aaa08b..00000000 --- a/archive/scene/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - scenemanager.c -) - -# Subdirs -add_subdirectory(scene) \ No newline at end of file diff --git a/archive/scene/scene.h b/archive/scene/scene.h deleted file mode 100644 index 39c89a4f..00000000 --- a/archive/scene/scene.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "dusk.h" -#include "error/error.h" -#include "display/color.h" - -#define SCENE_FLAG_INITIALIZED (1 << 0) - -typedef struct scenedata_s scenedata_t; - -typedef struct { - const char_t *name; - errorret_t (*init)(scenedata_t *data); - void (*update)(scenedata_t *data); - void (*render)(scenedata_t *data); - void (*dispose)(scenedata_t *data); - uint8_t flags; -} scene_t; \ No newline at end of file diff --git a/archive/scene/scene/CMakeLists.txt b/archive/scene/scene/CMakeLists.txt deleted file mode 100644 index e5e83ab0..00000000 --- a/archive/scene/scene/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - scenetest.c - scenemap.c -) - -# Subdirs \ No newline at end of file diff --git a/archive/scene/scene/scenemap.c b/archive/scene/scene/scenemap.c deleted file mode 100644 index 76991160..00000000 --- a/archive/scene/scene/scenemap.c +++ /dev/null @@ -1,212 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "scenemap.h" -#include "scene/scenedata.h" -#include "display/spritebatch.h" -#include "assert/assert.h" -#include "asset/asset.h" -#include "rpg/entity/entity.h" -#include "rpg/overworld/map.h" -#include "display/screen.h" -#include "rpg/rpgcamera.h" -#include "util/memory.h" -#include "duskdefs.h" - -errorret_t sceneMapInit(scenedata_t *data) { - // Init the camera. - cameraInitPerspective(&data->sceneMap.camera); - data->sceneMap.camera.projType = CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED; - data->sceneMap.camera.viewType = CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT; - glm_vec3_zero(data->sceneMap.camera.lookatPixelPerfect.offset); - data->sceneMap.camera.lookatPixelPerfect.offset[1] = RPG_CAMERA_Z_OFFSET; - glm_vec3_copy( - (vec3){ 0.0f, 0.0f, 0.0f }, - data->sceneMap.camera.lookatPixelPerfect.target - ); - glm_vec3_copy( - (vec3){ 0.0f, 1.0f, 0.0f }, - data->sceneMap.camera.lookatPixelPerfect.up - ); - data->sceneMap.camera.lookatPixelPerfect.pixelsPerUnit = ( - RPG_CAMERA_PIXELS_PER_UNIT - ); - data->sceneMap.camera.perspective.fov = glm_rad(RPG_CAMERA_FOV); - - errorOk(); -} - -void sceneMapUpdate(scenedata_t *data) { - -} - -void sceneMapGetWorldPosition(const worldpos_t pos, vec3 outPosition) { - assertNotNull(outPosition, "Output position cannot be NULL"); - - outPosition[0] = pos.x * TILE_WIDTH; - outPosition[1] = pos.y * TILE_HEIGHT; - outPosition[2] = pos.z * TILE_DEPTH; - - // Handle stair tiles. - tile_t tile = mapGetTile(pos); - if(tileIsRamp(tile)) { - outPosition[2] += TILE_DEPTH / 2.0f; - } -} - -void sceneMapEntityGetPosition(const entity_t *entity, vec3 outPosition) { - assertNotNull(entity, "Entity cannot be NULL"); - assertNotNull(outPosition, "Output position cannot be NULL"); - - // Get position - sceneMapGetWorldPosition(entity->position, outPosition); - - // Add a small offset so we render above the tile - outPosition[2] += 0.1f; - - // Add animation offset(s) - switch(entity->animation) { - case ENTITY_ANIM_WALK: { - float_t animPercentage = entity->animTime / ENTITY_ANIM_WALK_DURATION; - - vec3 lastPosition; - sceneMapGetWorldPosition(entity->lastPosition, lastPosition); - - vec3 offset; - glm_vec3_sub(outPosition, lastPosition, offset); - glm_vec3_scale(offset, -animPercentage, offset); - glm_vec3_add(outPosition, offset, outPosition); - break; - } - - default: - break; - } -} - -void sceneMapRender(scenedata_t *data) { - if(!mapIsLoaded()) return; - - // Look at target. - vec3 cameraTarget; - switch(RPG_CAMERA.mode) { - case RPG_CAMERA_MODE_FREE: - sceneMapGetWorldPosition(RPG_CAMERA.free, cameraTarget); - break; - - case RPG_CAMERA_MODE_FOLLOW_ENTITY: { - const entity_t *ent = &ENTITIES[RPG_CAMERA.followEntity.followEntityId]; - sceneMapEntityGetPosition(ent, cameraTarget); - break; - } - - default: - glm_vec3_zero(cameraTarget); - break; - } - - glm_vec3_copy( - cameraTarget, - data->sceneMap.camera.lookatPixelPerfect.target - ); - - // Push camera - cameraPushMatrix(&data->sceneMap.camera); - - // Render map probably. - sceneMapRenderMap(); - - // Render ents - entity_t *ent = ENTITIES; - do { - sceneMapRenderEntity(ent); - } while(++ent, ent < &ENTITIES[ENTITY_COUNT]); - spriteBatchFlush(); - - // Finished, pop back camera. - cameraPopMatrix(); -} - -void sceneMapRenderEntity(entity_t *entity) { - assertNotNull(entity, "Entity cannot be NULL"); - - if(entity->type == ENTITY_TYPE_NULL) return; - - vec3 posMin, posMax; - vec3 size = { TILE_WIDTH, TILE_HEIGHT, TILE_DEPTH }; - sceneMapEntityGetPosition(entity, posMin); - glm_vec3_add(posMin, size, posMax); - - // TEST: Change color depending on dir. - color_t testColor; - switch(entity->direction) { - case ENTITY_DIR_NORTH: - testColor = COLOR_BLUE; - break; - case ENTITY_DIR_EAST: - testColor = COLOR_GREEN; - break; - case ENTITY_DIR_SOUTH: - testColor = COLOR_CYAN; - break; - case ENTITY_DIR_WEST: - testColor = COLOR_YELLOW; - break; - default: - testColor = COLOR_WHITE; - break; - } - - vec2 uv0 = { 0.0f, 0.0f }; - vec2 uv1 = { 1.0f, 1.0f }; - - spriteBatchPush3D(NULL, posMin, posMax, testColor, uv0, uv1); -} - -void sceneMapRenderMap() { - assertTrue(mapIsLoaded(), "No map loaded to render"); - - // For each chunk. - for(uint32_t i = 0; i < MAP_CHUNK_COUNT; i++) { - chunk_t *chunk = MAP.chunkOrder[i]; - - for(uint8_t j = 0; j < chunk->meshCount; j++) { - mesh_t *mesh = &chunk->meshes[j]; - if(mesh->vertexCount == 0) continue; - textureBind(NULL); - meshDraw(mesh, -1, -1); - } - - // vec3 min, max; - // min[0] = chunk->position.x * CHUNK_WIDTH * TILE_WIDTH; - // min[1] = chunk->position.y * CHUNK_HEIGHT * TILE_HEIGHT; - // min[2] = chunk->position.z * CHUNK_DEPTH * TILE_DEPTH; - - // max[0] = min[0] + (CHUNK_WIDTH * TILE_WIDTH); - // max[1] = min[1] + (CHUNK_HEIGHT * TILE_HEIGHT); - // max[2] = min[2]; - - // color_t color = COLOR_WHITE; - // if(chunk->position.x % 2 == 0) { - // color = (chunk->position.y % 2 == 0) ? COLOR_BLACK : COLOR_WHITE; - // } else { - // color = (chunk->position.y % 2 == 0) ? COLOR_WHITE : COLOR_BLACK; - // } - - // spriteBatchPush3D( - // NULL, - // min, - // max, - // color, - // (vec2){ 0.0f, 0.0f }, - // (vec2){ 1.0f, 1.0f } - // ); - } -} - -void sceneMapDispose(scenedata_t *data) { -} diff --git a/archive/scene/scene/scenemap.h b/archive/scene/scene/scenemap.h deleted file mode 100644 index 8e28b7c4..00000000 --- a/archive/scene/scene/scenemap.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "scene/scene.h" -#include "rpg/entity/entity.h" -#include "display/camera/camera.h" -#include "asset/asset.h" - -typedef struct { - camera_t camera; -} scenemap_t; - -errorret_t sceneMapInit(scenedata_t *data); -void sceneMapUpdate(scenedata_t *data); -void sceneMapRender(scenedata_t *data); -void sceneMapRenderEntity(entity_t *entity); -void sceneMapRenderMap(); -void sceneMapDispose(scenedata_t *data); - -static scene_t SCENE_MAP = { - .name = "map", - .init = sceneMapInit, - .update = sceneMapUpdate, - .render = sceneMapRender, - .dispose = sceneMapDispose, - .flags = 0 -}; \ No newline at end of file diff --git a/archive/scene/scene/scenetest.c b/archive/scene/scene/scenetest.c deleted file mode 100644 index 1fba8990..00000000 --- a/archive/scene/scene/scenetest.c +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "scenetest.h" -#include "scene/scenedata.h" - -errorret_t sceneTestInit(scenedata_t *data) { - data->sceneTest.nothing = 0; - errorOk(); -} - -void sceneTestUpdate(scenedata_t *data) { - -} - -void sceneTestRender(scenedata_t *data) { - -} - -void sceneTestDispose(scenedata_t *data) { - -} \ No newline at end of file diff --git a/archive/scene/scene/scenetest.h b/archive/scene/scene/scenetest.h deleted file mode 100644 index de8051d0..00000000 --- a/archive/scene/scene/scenetest.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "scene/scene.h" - -typedef struct { - int32_t nothing; -} scenetest_t; - -errorret_t sceneTestInit(scenedata_t *data); -void sceneTestUpdate(scenedata_t *data); -void sceneTestRender(scenedata_t *data); -void sceneTestDispose(scenedata_t *data); - -static scene_t SCENE_TEST = { - .name = "test", - .init = sceneTestInit, - .update = sceneTestUpdate, - .render = sceneTestRender, - .dispose = sceneTestDispose, - .flags = 0 -}; \ No newline at end of file diff --git a/archive/scene/scenedata.h b/archive/scene/scenedata.h deleted file mode 100644 index 948bed61..00000000 --- a/archive/scene/scenedata.h +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "scene/scene.h" - -#include "scene/scene/scenetest.h" -#include "scene/scene/scenemap.h" \ No newline at end of file diff --git a/archive/scene/scenemanager.c b/archive/scene/scenemanager.c deleted file mode 100644 index aff10b3c..00000000 --- a/archive/scene/scenemanager.c +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "scenemanager.h" -#include "util/memory.h" -#include "assert/assert.h" -#include "display/framebuffer.h" -#include "util/string.h" -#include "asset/asset.h" -#include "script/scriptmanager.h" - -scenemanager_t SCENE_MANAGER; - -errorret_t sceneManagerInit(void) { - memoryZero(&SCENE_MANAGER, sizeof(scenemanager_t)); - - sceneManagerRegisterScene(&SCENE_TEST); - sceneManagerRegisterScene(&SCENE_MAP); - - errorOk(); -} - -scene_t * sceneManagerGetSceneByName(const char_t *name) { - assertNotNull(name, "Name is null"); - - for(uint8_t i = 0; i < SCENE_MANAGER.sceneCount; i++) { - if(strcmp(SCENE_MANAGER.scenes[i]->name, name) != 0) continue; - return SCENE_MANAGER.scenes[i]; - } - - return NULL; -} - -void sceneManagerRegisterScene(scene_t *scene) { - assertNotNull(scene, "Scene is null"); - assertTrue( - SCENE_MANAGER.sceneCount < SCENE_MANAGER_SCENE_COUNT_MAX, - "Scene count exceeded max" - ); - assertNotNull(scene->name, "Scene name is null"); - assertNull( - sceneManagerGetSceneByName(scene->name), "Scene name already registered" - ); - - SCENE_MANAGER.scenes[SCENE_MANAGER.sceneCount++] = scene; -} - -errorret_t sceneManagerSetScene(scene_t *scene) { - if( - SCENE_MANAGER.current && - (SCENE_MANAGER.current->flags & SCENE_FLAG_INITIALIZED) != 0 - ) { - SCENE_MANAGER.current->flags &= ~SCENE_FLAG_INITIALIZED; - if(SCENE_MANAGER.current->dispose) { - SCENE_MANAGER.current->dispose(&SCENE_MANAGER.sceneData); - } - } - - SCENE_MANAGER.current = scene; - - if(scene && (scene->flags & SCENE_FLAG_INITIALIZED) == 0) { - scene->flags |= SCENE_FLAG_INITIALIZED; - - if(scene->init) errorChain(scene->init(&SCENE_MANAGER.sceneData)); - - // Execute scene script if it exists - char_t buffer[256]; - snprintf(buffer, sizeof(buffer), "scene/%s.dsf", scene->name); - if(assetFileExists(buffer)) { - scriptcontext_t ctx; - scriptContextInit(&ctx); - errorChain(scriptContextExecFile(&ctx, buffer)); - scriptContextDispose(&ctx); - } - } - - errorOk(); -} - -void sceneManagerUpdate(void) { - if(!SCENE_MANAGER.current) return; - - assertTrue( - SCENE_MANAGER.current->flags & SCENE_FLAG_INITIALIZED, - "Current scene not initialized" - ); - - if(SCENE_MANAGER.current->update) { - SCENE_MANAGER.current->update(&SCENE_MANAGER.sceneData); - } -} - -void sceneManagerRender(void) { - if(!SCENE_MANAGER.current) return; - - assertTrue( - SCENE_MANAGER.current->flags & SCENE_FLAG_INITIALIZED, - "Current scene not initialized" - ); - - if(SCENE_MANAGER.current->render) { - SCENE_MANAGER.current->render(&SCENE_MANAGER.sceneData); - } -} - -void sceneManagerDispose(void) { - for(uint8_t i = 0; i < SCENE_MANAGER.sceneCount; i++) { - scene_t *scene = SCENE_MANAGER.scenes[i]; - if(scene->flags & SCENE_FLAG_INITIALIZED) { - scene->dispose(&SCENE_MANAGER.sceneData); - } - } - - SCENE_MANAGER.sceneCount = 0; -} diff --git a/archive/scene/scenemanager.h b/archive/scene/scenemanager.h deleted file mode 100644 index d31a96ff..00000000 --- a/archive/scene/scenemanager.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "scene.h" -#include "scenedata.h" - -#define SCENE_MANAGER_SCENE_COUNT_MAX 16 - -typedef struct { - scene_t *current; - scene_t *scenes[SCENE_MANAGER_SCENE_COUNT_MAX]; - uint8_t sceneCount; -} scenemanager_t; - -extern scenemanager_t SCENE_MANAGER; - -/** - * Initializes the scene manager and the initial scene. - */ -errorret_t sceneManagerInit(void); - -/** - * Retrieves a registered scene by its name. - * - * @param name The name of the scene to retrieve. - * @return The scene with the specified name, or NULL if not found. - */ -scene_t * sceneManagerGetSceneByName(const char_t *name); - -/** - * Registers a scene with the scene manager. - * - * @param scene The scene to register. - */ -void sceneManagerRegisterScene(scene_t *scene); - -/** - * Sets the current active scene. - * - * @param scene The scene to set as current. - * @return An error code indicating success or failure. - */ -errorret_t sceneManagerSetScene(scene_t *scene); - -/** - * Updates all active scenes. - */ -void sceneManagerUpdate(void); - -/** - * Renders all visible scenes. - */ -void sceneManagerRender(void); - -/** - * Disposes of all scenes. - */ -void sceneManagerDispose(void); \ No newline at end of file diff --git a/archive/scriptfuncentity.h b/archive/scriptfuncentity.h deleted file mode 100644 index 40d44227..00000000 --- a/archive/scriptfuncentity.h +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "script/scriptcontext.h" -#include "rpg/entity/entity.h" -#include "assert/assert.h" - -int scriptFuncEntityAdd(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - assertTrue(lua_isnumber(L, 1), "Expected integer entity type"); - - entitytype_t entityType = (entitytype_t)luaL_checknumber(L, 1); - assertTrue( - entityType >= ENTITY_TYPE_NULL && entityType < ENTITY_TYPE_COUNT, - "Invalid entity type passed to scriptFuncEntityAdd" - ); - - // Pop entity - uint8_t available = entityGetAvailable(); - if(available == 0xFF) { - lua_pushnil(L); - return 1; - } - - entity_t *ent = &ENTITIES[available]; - entityInit(ent, (entitytype_t)entityType); - - // May include X, Y and/or Z - if(lua_isinteger(L, 2)) { - lua_Integer xPos = luaL_checkinteger(L, 2); - ent->position.x = (int32_t)xPos; - } - if(lua_isinteger(L, 3)) { - lua_Integer yPos = luaL_checkinteger(L, 3); - ent->position.y = (int32_t)yPos; - } - if(lua_isinteger(L, 4)) { - lua_Integer zPos = luaL_checkinteger(L, 4); - ent->position.z = (int32_t)zPos; - } - - // Send entity id. - lua_pushinteger(L, ent->id); - return 1; -} - -int scriptFuncEntitySetX(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - assertTrue(lua_isinteger(L, 1), "Expected integer entity id"); - assertTrue(lua_isinteger(L, 2), "Expected integer x position"); - - lua_Integer entityId = luaL_checkinteger(L, 1); - lua_Integer xPos = luaL_checkinteger(L, 2); - - assertTrue( - entityId >= 0 && entityId < ENTITY_COUNT, - "Invalid entity id passed to scriptFuncEntitySetX" - ); - - entity_t *ent = &ENTITIES[entityId]; - assertTrue( - ent->type != ENTITY_TYPE_NULL, - "Cannot set position of NULL entity in scriptFuncEntitySetX" - ); - - ent->position.x = (int32_t)xPos; - - return 0; -} - -int scriptFuncEntitySetY(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - assertTrue(lua_isinteger(L, 1), "Expected integer entity id"); - assertTrue(lua_isinteger(L, 2), "Expected integer y position"); - - lua_Integer entityId = luaL_checkinteger(L, 1); - lua_Integer yPos = luaL_checkinteger(L, 2); - - assertTrue( - entityId >= 0 && entityId < ENTITY_COUNT, - "Invalid entity id passed to scriptFuncEntitySetY" - ); - - entity_t *ent = &ENTITIES[entityId]; - assertTrue( - ent->type != ENTITY_TYPE_NULL, - "Cannot set position of NULL entity in scriptFuncEntitySetY" - ); - - ent->position.y = (int32_t)yPos; - - return 0; -} - -int scriptFuncEntitySetZ(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - assertTrue(lua_isinteger(L, 1), "Expected integer entity id"); - assertTrue(lua_isinteger(L, 2), "Expected integer z position"); - - lua_Integer entityId = luaL_checkinteger(L, 1); - lua_Integer zPos = luaL_checkinteger(L, 2); - - assertTrue( - entityId >= 0 && entityId < ENTITY_COUNT, - "Invalid entity id passed to scriptFuncEntitySetZ" - ); - - entity_t *ent = &ENTITIES[entityId]; - assertTrue( - ent->type != ENTITY_TYPE_NULL, - "Cannot set position of NULL entity in scriptFuncEntitySetZ" - ); - - ent->position.z = (int32_t)zPos; - - return 0; -} - -void scriptFuncEntity(scriptcontext_t *context) { - assertNotNull(context, "Script context cannot be NULL"); - - lua_register(context->luaState, "entityAdd", scriptFuncEntityAdd); - lua_register(context->luaState, "entitySetX", scriptFuncEntitySetX); - lua_register(context->luaState, "entitySetY", scriptFuncEntitySetY); - lua_register(context->luaState, "entitySetZ", scriptFuncEntitySetZ); -} \ No newline at end of file diff --git a/archive/ui/CMakeLists.txt b/archive/ui/CMakeLists.txt deleted file mode 100644 index 0155c3b3..00000000 --- a/archive/ui/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - ui.c - uitext.c - uidebug.c - uiframe.c - uitextbox.c -) - -# Subdirs -add_subdirectory(element) \ No newline at end of file diff --git a/archive/ui/element/CMakeLists.txt b/archive/ui/element/CMakeLists.txt deleted file mode 100644 index 0b31e39a..00000000 --- a/archive/ui/element/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC -) \ No newline at end of file diff --git a/archive/ui/element/uielementtype.h b/archive/ui/element/uielementtype.h deleted file mode 100644 index 32c2367a..00000000 --- a/archive/ui/element/uielementtype.h +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once - -typedef enum { - UI_ELEMENT_TYPE_NULL, - - UI_ELEMENT_TYPE_TEXT, - - UI_ELEMENT_TYPE_COUNT, -} uielementtype_t; \ No newline at end of file diff --git a/archive/ui/ui.c b/archive/ui/ui.c deleted file mode 100644 index c6bf8834..00000000 --- a/archive/ui/ui.c +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "ui.h" -#include "assert/assert.h" -#include "ui/uidebug.h" -#include "util/memory.h" -#include "display/tileset/tileset_minogram.h" -#include "display/screen.h" -// #include "ui/uitextbox.h" - -ui_t UI; - -errorret_t uiInit(void) { - memoryZero(&UI, sizeof(ui_t)); - - cameraInitOrthographic(&UI.camera); - - // Initialize UI components here - uiSetFont(&TILESET_MINOGRAM); - - errorOk(); -} - -void uiUpdate(void) { - // Update UI state here - UI.camera.orthographic.left = 0; - UI.camera.orthographic.right = SCREEN.width; - UI.camera.orthographic.top = 0; - UI.camera.orthographic.bottom = SCREEN.height; - - // uiTextboxUpdate(); -} - -void uiRender(void) { - cameraPushMatrix(&UI.camera); - - // Render UI elements here - if(UI.fontTexture.width > 0) { - uiDebugRender(UI.fontTileset, &UI.fontTexture); - } - cameraPopMatrix(); -} - -errorret_t uiSetFont(const tileset_t *fontTileset) { - if(UI.fontTexture.width > 0) { - textureDispose(&UI.fontTexture); - UI.fontTexture.width = -1; - } - - assertNotNull(fontTileset, "Font tileset cannot be NULL."); - - UI.fontTileset = fontTileset; - errorChain(assetLoad(UI.fontTileset->image, &UI.fontTexture)); - errorOk(); -} - -void uiDispose(void) { - if(UI.fontTexture.width > 0) { - textureDispose(&UI.fontTexture); - UI.fontTexture.width = -1; - } -} \ No newline at end of file diff --git a/archive/ui/ui.h b/archive/ui/ui.h deleted file mode 100644 index 956fe450..00000000 --- a/archive/ui/ui.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "asset/asset.h" -#include "display/texture.h" -#include "display/tileset/tileset.h" -#include "display/camera/camera.h" - -typedef struct { - camera_t camera; - texture_t fontTexture; - const tileset_t *fontTileset; -} ui_t; - -extern ui_t UI; - -/** - * Initializes the UI system, loading necessary resources. - * - * @return An errorret_t indicating success or failure. - */ -errorret_t uiInit(void); - -/** - * Updates the UI state, handling user interactions and animations. - */ -void uiUpdate(void); - -/** - * Renders the UI elements to the screen. - */ -void uiRender(void); - -/** - * Sets the font tileset for UI text rendering. - * - * @param fontTileset Pointer to the tileset to use for UI fonts. - * - * @return An errorret_t indicating success or failure. - */ -errorret_t uiSetFont(const tileset_t *fontTileset); - -/** - * Cleans up and frees all UI resources. - */ -void uiDispose(void); \ No newline at end of file diff --git a/archive/ui/uidebug.c b/archive/ui/uidebug.c deleted file mode 100644 index 56e7db54..00000000 --- a/archive/ui/uidebug.c +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "uidebug.h" -#include "time/time.h" -#include "util/string.h" -#include "ui/uitext.h" -#include "display/screen.h" -#include "display/spritebatch.h" -// #include "rpg/entity/entity.h" - -bool_t UI_DEBUG_DRAW = true; - -void uiDebugRender(const tileset_t *tileset, texture_t *texture) { - if(!UI_DEBUG_DRAW) return; - - char_t buffer[128]; - color_t color; - int32_t w, h, hOffset = 0; - - // FPS Meter - #if TIME_FIXED == 0 - float_t fpsDynamic = TIME.dynamicDelta > 0.0f ? (1.0f / TIME.dynamicDelta) : 0.0f; - float_t fpsFixed = TIME.delta > 0.0f ? (1.0f / TIME.delta) : 0.0f; - snprintf( - buffer, - sizeof(buffer), - "%.2f/%.2f/%d/%d", - TIME.dynamicDelta * 1000.0f, - TIME.delta * 1000.0f, - TIME.dynamicUpdate, - (int32_t)fpsDynamic - ); - - color = ( - fpsDynamic >= 50.0f ? COLOR_GREEN : - fpsDynamic >= 30.0f ? COLOR_YELLOW : - COLOR_RED - ); - #else - float_t fps = TIME.delta > 0.0f ? (1.0f / TIME.delta) : 0.0f; - snprintf( - buffer, - sizeof(buffer), - "%.2f/%d/FXD", - TIME.delta * 1000.0f, - (int32_t)fps - ); - - color = ( - fps >= 50.0f ? COLOR_GREEN : - fps >= 30.0f ? COLOR_YELLOW : - COLOR_RED - ); - #endif - - uiTextMeasure(buffer, tileset, &w, &h); - uiTextDraw( - SCREEN.width - w, hOffset, - buffer, color, tileset, texture - ); - hOffset += h; - - - // Player position - // entity_t *player = NULL; - // for(uint8_t i = 0; i < ENTITY_COUNT; i++) { - // if(ENTITIES[i].type != ENTITY_TYPE_PLAYER) continue; - // player = &ENTITIES[i]; - // break; - // } - // if(player == NULL) { - // snprintf(buffer, sizeof(buffer), "Player: N/A"); - // } else { - // snprintf( - // buffer, - // sizeof(buffer), - // "%d,%d,%d/%d/%d", - // player->position.x, - // player->position.y, - // player->position.z, - // (int32_t)player->direction, - // (int32_t)player->animation - // ); - // } - // uiTextMeasure(buffer, tileset, &w, &h); - // uiTextDraw( - // SCREEN.width - w, hOffset, - // buffer, COLOR_GREEN, tileset, texture - // ); - // hOffset += h; - - spriteBatchFlush(); -} \ No newline at end of file diff --git a/archive/ui/uidebug.h b/archive/ui/uidebug.h deleted file mode 100644 index 3f106dfe..00000000 --- a/archive/ui/uidebug.h +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "display/tileset/tileset.h" -#include "display/texture.h" - -/** - * Renders the debug information UI element. - * - * @param tileset The tileset to use for rendering text. - * @param texture The texture associated with the tileset. - */ -void uiDebugRender(const tileset_t *tileset, texture_t *texture); \ No newline at end of file diff --git a/archive/ui/uiframe.c b/archive/ui/uiframe.c deleted file mode 100644 index f3e32c65..00000000 --- a/archive/ui/uiframe.c +++ /dev/null @@ -1,390 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "uiframe.h" -#include "display/spritebatch.h" -#include "assert/assert.h" -#include "util/math.h" - -void uiFrameDraw( - const float_t x, - const float_t y, - const float_t width, - const float_t height, - const tileset_t *tileset, - const uint16_t column, - const uint16_t row, - const bool_t drawInner, - texture_t *texture -) { - assertNotNull(tileset, "Tileset cannot be NULL"); - assertNotNull(texture, "Texture cannot be NULL"); - - if(height <= 0 || width <= 0) return; - - // Top-Left - vec4 uv; - - tilesetPositionGetUV( - tileset, - column, - row, - uv - ); - spriteBatchPush( - texture, - x, y, - x + tileset->tileWidth, - y + tileset->tileHeight, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - - // Top-Center - tilesetPositionGetUV( - tileset, - column + 1, - row, - uv - ); - spriteBatchPush( - texture, - x + tileset->tileWidth, y, - x + width - tileset->tileWidth, y + tileset->tileHeight, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - - // Top-Right - tilesetPositionGetUV( - tileset, - column + 2, - row, - uv - ); - spriteBatchPush( - texture, - x + width - tileset->tileWidth, y, - x + width, y + tileset->tileHeight, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - - // Middle-Left - tilesetPositionGetUV( - tileset, - column, - row + 1, - uv - ); - spriteBatchPush( - texture, - x, y + tileset->tileHeight, - x + tileset->tileWidth, y + height - tileset->tileHeight, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - - // Middle-Center - if(drawInner) { - tilesetPositionGetUV( - tileset, - column + 1, - row + 1, - uv - ); - spriteBatchPush( - texture, - x + tileset->tileWidth, y + tileset->tileHeight, - x + width - tileset->tileWidth, y + height - tileset->tileHeight, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - } - - // Middle-Right - tilesetPositionGetUV( - tileset, - column + 2, - row + 1, - uv - ); - spriteBatchPush( - texture, - x + width - tileset->tileWidth, y + tileset->tileHeight, - x + width, y + height - tileset->tileHeight, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - - // Bottom-Left - tilesetPositionGetUV( - tileset, - column, - row + 2, - uv - ); - spriteBatchPush( - texture, - x, y + height - tileset->tileHeight, - x + tileset->tileWidth, y + height, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - - // Bottom-Center - tilesetPositionGetUV( - tileset, - column + 1, - row + 2, - uv - ); - spriteBatchPush( - texture, - x + tileset->tileWidth, y + height - tileset->tileHeight, - x + width - tileset->tileWidth, y + height, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - - // Bottom-Right - tilesetPositionGetUV( - tileset, - column + 2, - row + 2, - uv - ); - spriteBatchPush( - texture, - x + width - tileset->tileWidth, y + height - tileset->tileHeight, - x + width, y + height, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); -} - -void uiFrameDrawTiled( - const float_t x, - const float_t y, - const float_t width, - const float_t height, - const tileset_t *tileset, - const uint16_t column, - const uint16_t row, - const bool_t drawInner, - texture_t *texture -) { - assertNotNull(tileset, "Tileset cannot be NULL"); - assertNotNull(texture, "Texture cannot be NULL"); - - if(height <= 0 || width <= 0) return; - - uint32_t segmentsX, segmentsY; - float_t remainderX, remainderY; - segmentsX = (width - (tileset->tileWidth * 2)) / tileset->tileWidth; - segmentsY = (height - (tileset->tileHeight * 2)) / tileset->tileHeight; - remainderX = fmodf(width - (tileset->tileWidth * 2), tileset->tileWidth); - remainderY = fmodf(height - (tileset->tileHeight * 2), tileset->tileHeight); - - // Corners - vec4 uv; - - // Top-Left - tilesetPositionGetUV( - tileset, - column, - row, - uv - ); - spriteBatchPush( - texture, - x, y, - x + tileset->tileWidth, - y + tileset->tileHeight, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - - // Top-Right - tilesetPositionGetUV( - tileset, - column + 2, - row, - uv - ); - spriteBatchPush( - texture, - x + width - tileset->tileWidth, y, - x + width, y + tileset->tileHeight, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - - // Bottom-Left - tilesetPositionGetUV( - tileset, - column, - row + 2, - uv - ); - spriteBatchPush( - texture, - x, y + height - tileset->tileHeight, - x + tileset->tileWidth, y + height, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - - // Bottom-Right - tilesetPositionGetUV( - tileset, - column + 2, - row + 2, - uv - ); - spriteBatchPush( - texture, - x + width - tileset->tileWidth, y + height - tileset->tileHeight, - x + width, y + height, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - - // Top and Bottom Edges (Tiled) - tilesetPositionGetUV(tileset, column + 1, row, uv); // Top edge - float_t edgeX = x + tileset->tileWidth; - for(uint32_t i = 0; i < segmentsX; ++i, edgeX += tileset->tileWidth) { - spriteBatchPush( - texture, - edgeX, y, - edgeX + tileset->tileWidth, y + tileset->tileHeight, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - } - if(remainderX) { - spriteBatchPush( - texture, - edgeX, y, - edgeX + remainderX, y + tileset->tileHeight, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - } - - tilesetPositionGetUV(tileset, column + 1, row + 2, uv); // Bottom edge - edgeX = x + tileset->tileWidth; - for(uint32_t i = 0; i < segmentsX; ++i, edgeX += tileset->tileWidth) { - spriteBatchPush( - texture, - edgeX, y + height - tileset->tileHeight, - edgeX + tileset->tileWidth, y + height, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - } - if(remainderX) { - spriteBatchPush( - texture, - edgeX, y + height - tileset->tileHeight, - edgeX + remainderX, y + height, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - } - - // Left and Right Edges (Tiled) - tilesetPositionGetUV(tileset, column, row + 1, uv); // Left edge - float_t edgeY = y + tileset->tileHeight; - for(uint32_t i = 0; i < segmentsY; ++i, edgeY += tileset->tileHeight) { - spriteBatchPush( - texture, - x, edgeY, - x + tileset->tileWidth, edgeY + tileset->tileHeight, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - } - if(remainderY) { - spriteBatchPush( - texture, - x, edgeY, - x + tileset->tileWidth, edgeY + remainderY, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - } - - tilesetPositionGetUV(tileset, column + 2, row + 1, uv); // Right edge - edgeY = y + tileset->tileHeight; - for(uint32_t i = 0; i < segmentsY; ++i, edgeY += tileset->tileHeight) { - spriteBatchPush( - texture, - x + width - tileset->tileWidth, edgeY, - x + width, edgeY + tileset->tileHeight, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - } - if(remainderY) { - spriteBatchPush( - texture, - x + width - tileset->tileWidth, edgeY, - x + width, edgeY + remainderY, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - } - - // Center (Tiled) - if(!drawInner) return; - - tilesetPositionGetUV(tileset, column + 1, row + 1, uv); // Center tile - float_t centerY = y + tileset->tileHeight; - for(uint32_t j = 0; j < segmentsY; ++j, centerY += tileset->tileHeight) { - float_t centerX = x + tileset->tileWidth; - for(uint32_t i = 0; i < segmentsX; ++i, centerX += tileset->tileWidth) { - spriteBatchPush( - texture, - centerX, centerY, - centerX + tileset->tileWidth, centerY + tileset->tileHeight, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - } - if(remainderX) { - spriteBatchPush( - texture, - centerX, centerY, - centerX + remainderX, centerY + tileset->tileHeight, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - } - } - if(remainderY) { - float_t centerX = x + tileset->tileWidth; - for(uint32_t i = 0; i < segmentsX; ++i, centerX += tileset->tileWidth) { - spriteBatchPush( - texture, - centerX, centerY, - centerX + tileset->tileWidth, centerY + remainderY, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - } - if(remainderX) { - spriteBatchPush( - texture, - centerX, centerY, - centerX + remainderX, centerY + remainderY, - COLOR_WHITE, - uv[0], uv[1], uv[2], uv[3] - ); - } - } -} \ No newline at end of file diff --git a/archive/ui/uiframe.h b/archive/ui/uiframe.h deleted file mode 100644 index 2a9e9d01..00000000 --- a/archive/ui/uiframe.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "display/tileset/tileset.h" -#include "display/texture.h" - -/** - * Draw a UI Frame (using the 9-slice technique). - * - * @param x The x position to draw the frame at. - * @param y The y position to draw the frame at. - * @param width The width of the frame. - * @param height The height of the frame. - * @param tileset The tileset to use for rendering the frame. - * @param column The column in the tileset to use for the frame. - * @param row The row in the tileset to use for the frame. - * @param drawInner Whether to draw the inner area. - * @param texture The texture associated with the tileset. - */ -void uiFrameDraw( - const float_t x, - const float_t y, - const float_t width, - const float_t height, - const tileset_t *tileset, - const uint16_t column, - const uint16_t row, - const bool_t drawInner, - texture_t *texture -); - -/** - * Draw a tiled UI Frame (using the 9-slice technique). This will tile the - * center components to allow them to repeat without distortion. - * - * @param x The x position to draw the frame at. - * @param y The y position to draw the frame at. - * @param width The width of the frame. - * @param height The height of the frame. - * @param tileset The tileset to use for rendering the frame. - * @param column The column in the tileset to use for the frame. - * @param row The row in the tileset to use for the frame. - * @param drawInner Whether to draw the inner tiled area. - * @param texture The texture associated with the tileset. - */ -void uiFrameDrawTiled( - const float_t x, - const float_t y, - const float_t width, - const float_t height, - const tileset_t *tileset, - const uint16_t column, - const uint16_t row, - const bool_t drawInner, - texture_t *texture -); \ No newline at end of file diff --git a/archive/ui/uitext.c b/archive/ui/uitext.c deleted file mode 100644 index 2b43a2be..00000000 --- a/archive/ui/uitext.c +++ /dev/null @@ -1,111 +0,0 @@ -// /** -// * Copyright (c) 2025 Dominic Masters -// * -// * This software is released under the MIT License. -// * https://opensource.org/licenses/MIT -// */ - -#include "uitext.h" -#include "assert/assert.h" -#include "util/memory.h" -#include "display/spritebatch.h" - -void uiTextDrawChar( - const float_t x, - const float_t y, - const char_t c, - const color_t color, - const tileset_t *tileset, - texture_t *texture -) { - int32_t tileIndex = (int32_t)(c) - UI_TEXT_CHAR_START; - if(tileIndex < 0 || tileIndex >= tileset->tileCount) { - tileIndex = ((int32_t)'@') - UI_TEXT_CHAR_START; - } - - assertTrue( - tileIndex >= 0 && tileIndex <= tileset->tileCount, - "Character is out of bounds for font tiles" - ); - - vec4 uv; - tilesetTileGetUV(tileset, tileIndex, uv); - - spriteBatchPush( - texture, - x, y, - x + tileset->tileWidth, - y + tileset->tileHeight, - color, - uv[0], uv[1], uv[2], uv[3] - ); -} - -void uiTextDraw( - const float_t x, - const float_t y, - const char_t *text, - const color_t color, - const tileset_t *tileset, - texture_t *texture -) { - assertNotNull(text, "Text cannot be NULL"); - - float_t posX = x; - float_t posY = y; - - char_t c; - int32_t i = 0; - while((c = text[i++]) != '\0') { - if(c == '\n') { - posX = x; - posY += tileset->tileHeight; - continue; - } - - if(c == ' ') { - posX += tileset->tileWidth; - continue; - } - - uiTextDrawChar(posX, posY, c, color, tileset, texture); - posX += tileset->tileWidth; - } -} - -void uiTextMeasure( - const char_t *text, - const tileset_t *tileset, - int32_t *outWidth, - int32_t *outHeight -) { - assertNotNull(text, "Text cannot be NULL"); - assertNotNull(outWidth, "Output width pointer cannot be NULL"); - assertNotNull(outHeight, "Output height pointer cannot be NULL"); - - int32_t width = 0; - int32_t height = tileset->tileHeight; - int32_t lineWidth = 0; - - char_t c; - int32_t i = 0; - while((c = text[i++]) != '\0') { - if(c == '\n') { - if(lineWidth > width) { - width = lineWidth; - } - lineWidth = 0; - height += tileset->tileHeight; - continue; - } - - lineWidth += tileset->tileWidth; - } - - if(lineWidth > width) { - width = lineWidth; - } - - *outWidth = width; - *outHeight = height; -} \ No newline at end of file diff --git a/archive/ui/uitext.h b/archive/ui/uitext.h deleted file mode 100644 index 210f051e..00000000 --- a/archive/ui/uitext.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "asset/asset.h" -#include "display/texture.h" -#include "display/tileset/tileset_minogram.h" - -#define UI_TEXT_CHAR_START '!' - -/** - * Draws a single character at the specified position. - * - * @param x The x-coordinate to draw the character at. - * @param y The y-coordinate to draw the character at. - * @param c The character to draw. - * @param color The color to draw the character in. - * @param tileset Font tileset to use for rendering. - * @param texture Texture containing the font tileset image. - */ -void uiTextDrawChar( - const float_t x, - const float_t y, - const char_t c, - const color_t color, - const tileset_t *tileset, - texture_t *texture -); - -/** - * Draws a string of text at the specified position. - * - * @param x The x-coordinate to draw the text at. - * @param y The y-coordinate to draw the text at. - * @param text The null-terminated string of text to draw. - * @param color The color to draw the text in. - * @param tileset Font tileset to use for rendering. - * @param texture Texture containing the font tileset image. - */ -void uiTextDraw( - const float_t x, - const float_t y, - const char_t *text, - const color_t color, - const tileset_t *tileset, - texture_t *texture -); - -/** - * Measures the width and height of the given text string when rendered. - * - * @param text The null-terminated string of text to measure. - * @param tileset Font tileset to use for measurement. - * @param outWidth Pointer to store the measured width in pixels. - * @param outHeight Pointer to store the measured height in pixels. - */ -void uiTextMeasure( - const char_t *text, - const tileset_t *tileset, - int32_t *outWidth, - int32_t *outHeight -); \ No newline at end of file diff --git a/archive/ui/uitextbox.c b/archive/ui/uitextbox.c deleted file mode 100644 index 3aecfa85..00000000 --- a/archive/ui/uitextbox.c +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "uitextbox.h" -#include "ui/ui.h" -#include "ui/uitext.h" -// #include "rpg/rpgtextbox.h" -#include "display/screen.h" -#include "display/spritebatch.h" -#include "input/input.h" - -// void uiTextboxUpdate() { -// if(!rpgTextboxIsVisible()) return; - -// if(inputPressed(INPUT_ACTION_ACCEPT)) { -// rpgTextboxHide(); -// } -// } - -// void uiTextboxRender() { -// if(!rpgTextboxIsVisible()) return; - -// const char_t *text = RPG_TEXTBOX.text; -// int32_t textWidth, textHeight; - -// uiTextMeasure(text, UI.fontTileset, &textWidth, &textHeight); - -// float_t y = 0; -// if(RPG_TEXTBOX.position == RPG_TEXTBOX_POS_BOTTOM) { -// y = SCREEN.height - (float_t)textHeight; -// } - -// spriteBatchPush( -// NULL, -// 0.0f, y, -// (float_t)SCREEN.width, (float_t)(y + textHeight), -// COLOR_BLACK, -// 0.0f, 0.0f, 1.0f, 1.0f -// ); -// uiTextDraw(0, y, text, COLOR_RED, UI.fontTileset, &UI.fontTexture); -// } \ No newline at end of file diff --git a/archive/ui/uitextbox.h b/archive/ui/uitextbox.h deleted file mode 100644 index 09b28232..00000000 --- a/archive/ui/uitextbox.h +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "dusk.h" - -/** - * Updates the RPG textbox state. - */ -void uiTextboxUpdate(); - -/** - * Draws the RPG textbox if it is visible. - */ -void uiTextboxRender(); \ No newline at end of file diff --git a/archive/ui2/CMakeLists.txt b/archive/ui2/CMakeLists.txt deleted file mode 100644 index 9b35b01d..00000000 --- a/archive/ui2/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2026 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC -) \ No newline at end of file diff --git a/archive/ui2/ui2.c b/archive/ui2/ui2.c deleted file mode 100644 index df850eb3..00000000 --- a/archive/ui2/ui2.c +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "ui2.h" \ No newline at end of file diff --git a/archive/ui2/ui2.h b/archive/ui2/ui2.h deleted file mode 100644 index 02339b41..00000000 --- a/archive/ui2/ui2.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2026 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#pragma once -#include "dusk.h" - -// Two kinds of UI elements, those that are scripted (with a state, logic, etc) -// and those that are draw only (rectangle, text, etc). \ No newline at end of file diff --git a/src/dusk/display/spritebatch/CMakeLists.txt b/src/dusk/display/spritebatch/CMakeLists.txt index 5897115a..20ba6f23 100644 --- a/src/dusk/display/spritebatch/CMakeLists.txt +++ b/src/dusk/display/spritebatch/CMakeLists.txt @@ -7,4 +7,5 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC spritebatch.c + spritebatchsprite.c ) \ No newline at end of file diff --git a/src/dusk/display/spritebatch/spritebatch.h b/src/dusk/display/spritebatch/spritebatch.h index 88e7475d..ee816aa5 100644 --- a/src/dusk/display/spritebatch/spritebatch.h +++ b/src/dusk/display/spritebatch/spritebatch.h @@ -6,6 +6,7 @@ */ #pragma once +#include "spritebatchsprite.h" #include "display/mesh/quad.h" #include "display/texture/texture.h" #include "display/shader/shadermaterial.h" @@ -17,13 +18,6 @@ SPRITEBATCH_SPRITES_MAX / SPRITEBATCH_FLUSH_COUNT \ ) -typedef struct { - vec3 min; - vec3 max; - vec2 uvMin; - vec2 uvMax; -} spritebatchsprite_t; - typedef struct { mesh_t mesh; int32_t spriteCount; diff --git a/src/dusk/display/spritebatch/spritebatchsprite.c b/src/dusk/display/spritebatch/spritebatchsprite.c new file mode 100644 index 00000000..bc0437db --- /dev/null +++ b/src/dusk/display/spritebatch/spritebatchsprite.c @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "spritebatchsprite.h" +#include "util/memory.h" + +spritebatchsprite_t spriteBatchSpriteTilesetPosition( + const tileset_t *tileset, + const uint16_t column, + const uint16_t row, + const float_t x, + const float_t y, + const float_t width, + const float_t height +) { + spritebatchsprite_t sprite; + if(width == 0 || height == 0) { + memoryZero(sprite.min, sizeof(vec3)); + memoryZero(sprite.max, sizeof(vec3)); + return sprite; + } + + vec4 uv; + tilesetPositionGetUV(tileset, column, row, uv); + + sprite.min[0] = x; + sprite.min[1] = y; + sprite.min[2] = 0.0f; + sprite.max[0] = x + width; + sprite.max[1] = y + height; + sprite.max[2] = 0.0f; + sprite.uvMin[0] = uv[0]; + sprite.uvMin[1] = uv[1]; + sprite.uvMax[0] = uv[2]; + sprite.uvMax[1] = uv[3]; + return sprite; +} diff --git a/src/dusk/display/spritebatch/spritebatchsprite.h b/src/dusk/display/spritebatch/spritebatchsprite.h new file mode 100644 index 00000000..ef7e2924 --- /dev/null +++ b/src/dusk/display/spritebatch/spritebatchsprite.h @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" +#include "display/texture/tileset.h" + +typedef struct { + vec3 min; + vec3 max; + vec2 uvMin; + vec2 uvMax; +} spritebatchsprite_t; + +/** + * Builds a sprite from a tileset tile at a given column/row, positioned and + * sized in screen space. + * + * @param tileset Tileset to read UV coordinates from. + * @param column Column of the tile within the tileset. + * @param row Row of the tile within the tileset. + * @param x Screen x position of the sprite's top-left corner. + * @param y Screen y position of the sprite's top-left corner. + * @param width Width of the sprite in screen space. + * @param height Height of the sprite in screen space. + * @returns The populated sprite. + */ +spritebatchsprite_t spriteBatchSpriteTilesetPosition( + const tileset_t *tileset, + const uint16_t column, + const uint16_t row, + const float_t x, + const float_t y, + const float_t width, + const float_t height +); diff --git a/src/dusk/display/text/text.c b/src/dusk/display/text/text.c index 2b16229c..dde87683 100644 --- a/src/dusk/display/text/text.c +++ b/src/dusk/display/text/text.c @@ -81,6 +81,8 @@ errorret_t textDraw( font_t *font ) { assertNotNull(text, "Text cannot be NULL"); + + if(font == NULL) font = &FONT_DEFAULT; spritebatchsprite_t sprite; shadermaterial_t material = { diff --git a/src/dusk/input/input.h b/src/dusk/input/input.h index bf3238a8..b1545979 100644 --- a/src/dusk/input/input.h +++ b/src/dusk/input/input.h @@ -233,4 +233,14 @@ void inputBind(const inputbutton_t button, const inputaction_t act); * @param deadzone The deadzone threshold (0.0f to 1.0f). * @return The input value after applying the deadzone. */ -float_t inputDeadzone(const float_t rawValue, const float_t deadzone); \ No newline at end of file +float_t inputDeadzone(const float_t rawValue, const float_t deadzone); + +#ifdef DUSK_TIME_DYNAMIC + #define inputPressedIfDynamic(action) inputPressedDynamic(action) + #define inputReleasedIfDynamic(action) inputReleasedDynamic(action) + #define inputDownIfDynamic(action) inputIsDownDynamic(action) +#else + #define inputPressedIfDynamic(action) inputPressed(action) + #define inputReleasedIfDynamic(action) inputReleased(action) + #define inputDownIfDynamic(action) inputIsDown(action) +#endif \ No newline at end of file diff --git a/src/dusk/rpg/entity/player.c b/src/dusk/rpg/entity/player.c index b8f6bead..01b703e4 100644 --- a/src/dusk/rpg/entity/player.c +++ b/src/dusk/rpg/entity/player.c @@ -10,6 +10,7 @@ #include "rpg/rpgcamera.h" #include "util/memory.h" #include "time/time.h" +#include "ui/focus/uifocus.h" void playerInit(entity_t *entity) { assertNotNull(entity, "Entity pointer cannot be NULL"); @@ -17,6 +18,11 @@ void playerInit(entity_t *entity) { void playerInput(entity_t *entity) { assertNotNull(entity, "Entity pointer cannot be NULL"); + + // Can player act? + if(UI_FOCUS.count > 0) { + return; + } // Turn const playerinputdirmap_t *dirMap = PLAYER_INPUT_DIR_MAP; diff --git a/src/dusk/ui/focus/uifocus.c b/src/dusk/ui/focus/uifocus.c index c28a878b..69e2e8be 100644 --- a/src/dusk/ui/focus/uifocus.c +++ b/src/dusk/ui/focus/uifocus.c @@ -25,7 +25,7 @@ void uiFocusInit(void) { memoryZero(&UI_FOCUS, sizeof(uifocus_t)); } -void uiFocusPush( +uifocusitem_t * uiFocusPush( const uint8_t cols, const uint8_t rows, uifocusitemcallback_t selected, @@ -36,6 +36,8 @@ void uiFocusPush( UI_FOCUS.count < UI_FOCUS_STACK_MAX, "UI focus stack overflow" ); + assertTrue(cols > 0, "Focus item cols must be > 0"); + assertTrue(rows > 0, "Focus item rows must be > 0"); uifocusitem_t *item = &UI_FOCUS.items[UI_FOCUS.count]; memoryZero(item, sizeof(uifocusitem_t)); @@ -45,6 +47,7 @@ void uiFocusPush( item->changed = changed; item->closed = closed; UI_FOCUS.count++; + return item; } void uiFocusPop(void) { @@ -55,17 +58,25 @@ void uiFocusPop(void) { UI_FOCUS.count--; } -void uiFocusPopTo(const int32_t depth) { - assertTrue(depth >= 0, "Focus depth must be >= 0"); - assertTrue(depth <= UI_FOCUS.count, "Focus depth exceeds current depth"); - while(UI_FOCUS.count > depth) uiFocusPop(); +void uiFocusPopItem(uifocusitem_t *item) { + assertTrue(UI_FOCUS.count > 0, "UI focus stack underflow"); + assertTrue(item >= UI_FOCUS.items, "Item is not on the focus stack"); + assertTrue( + item < UI_FOCUS.items + UI_FOCUS.count, + "Item is not on the focus stack" + ); + + while(&UI_FOCUS.items[UI_FOCUS.count - 1] != item) { + uiFocusPop(); + } + uiFocusPop(); } -void uiFocusSelect(const uint8_t x, const uint8_t y) { +void uiFocusSetPosition(uifocusitem_t *item, const uint8_t x, const uint8_t y) { assertTrue(UI_FOCUS.count > 0, "No active focus item"); - uifocusitem_t *item = &UI_FOCUS.items[UI_FOCUS.count - 1]; assertTrue(item->cols > 0, "Focus item cols must be > 0"); assertTrue(item->rows > 0, "Focus item rows must be > 0"); + uint8_t newX = x % item->cols; uint8_t newY = y % item->rows; @@ -89,91 +100,82 @@ void uiFocusMoveDirection( uifocusitem_t *item, const uifocusdirection_t dir ) { - const uifocusdirmap_t *m = UI_FOCUS_DIR_MAP; - while(m->action != INPUT_ACTION_NULL) { - if(m->direction == dir) { - uint8_t x = (uint8_t)( - (item->x + item->cols + m->dx) % item->cols - ); - uint8_t y = (uint8_t)( - (item->y + item->rows + m->dy) % item->rows - ); - uiFocusSelect(x, y); - return; - } - m++; + for( + const uifocusdirmap_t *m = UI_FOCUS_DIR_MAP; + m->action != INPUT_ACTION_NULL; + m++ + ) { + if(m->direction != dir) continue; + + uint8_t x = (uint8_t)(item->x + m->dx); + uint8_t y = (uint8_t)(item->y + m->dy); + uiFocusSetPosition(item, x, y); + break; } } void uiFocusUpdate(void) { if(UI_FOCUS.count == 0) return; + + // Current item uifocusitem_t *item = &UI_FOCUS.items[UI_FOCUS.count - 1]; - #ifdef DUSK_TIME_DYNAMIC - #define PRESSED(a) inputPressedDynamic(a) - #define IS_DOWN(a) inputIsDownDynamic(a) - #else - #define PRESSED(a) inputPressed(a) - #define IS_DOWN(a) inputIsDown(a) - #endif - - if(PRESSED(INPUT_ACTION_ACCEPT)) { + // Accept + if(inputPressedIfDynamic(INPUT_ACTION_ACCEPT)) { if(item->selected != NULL) item->selected(item); - goto done; + return; } - if(PRESSED(INPUT_ACTION_CANCEL)) { - if(item->closed != NULL && item->closed(item)) { - UI_FOCUS.count--; - } - goto done; + // Return + if(inputPressedIfDynamic(INPUT_ACTION_CANCEL)) { + uiFocusPop(); + return; } - { + // Handle pressed directions + for( const uifocusdirmap_t *m = UI_FOCUS_DIR_MAP; - while(m->action != INPUT_ACTION_NULL) { - if(PRESSED(m->action)) { - UI_FOCUS.direction = m->direction; - UI_FOCUS.timeHeld = 0.0f; - uiFocusMoveDirection(item, m->direction); - goto done; - } - m++; - } + m->action != INPUT_ACTION_NULL; + m++ + ) { + if(!inputPressedIfDynamic(m->action)) continue; + + UI_FOCUS.direction = m->direction; + UI_FOCUS.timeHeld = 0.0f; + uiFocusMoveDirection(item, m->direction); + return; } - { - bool_t held = false; + // Handle held directions + bool_t held = false; + for( const uifocusdirmap_t *m = UI_FOCUS_DIR_MAP; - while(m->action != INPUT_ACTION_NULL) { - if(m->direction == UI_FOCUS.direction) { - held = IS_DOWN(m->action); - break; - } - m++; - } + m->action != INPUT_ACTION_NULL; + m++ + ) { + if(m->direction != UI_FOCUS.direction) continue; - if(!held) { - UI_FOCUS.direction = UI_FOCUS_DIRECTION_NONE; - UI_FOCUS.timeHeld = 0.0f; - goto done; - } + held = inputDownIfDynamic(m->action); + break; } + // Are we still holding? + if(!held) { + UI_FOCUS.direction = UI_FOCUS_DIRECTION_NONE; + UI_FOCUS.timeHeld = 0.0f; + return; + } + + #ifdef DUSK_TIME_DYNAMIC UI_FOCUS.timeHeld += TIME.dynamicDelta; #else UI_FOCUS.timeHeld += TIME.delta; #endif - if(UI_FOCUS.timeHeld < UI_FOCUS_HOLD_DELAY) goto done; - - if(UI_FOCUS.timeHeld >= UI_FOCUS_HOLD_DELAY + UI_FOCUS_HOLD_REPEAT) { - UI_FOCUS.timeHeld = UI_FOCUS_HOLD_DELAY; - uiFocusMoveDirection(item, UI_FOCUS.direction); - } - -done: - #undef PRESSED - #undef IS_DOWN + // Can tick? + if(UI_FOCUS.timeHeld < UI_FOCUS_HOLD_DELAY) return; + if(UI_FOCUS.timeHeld < UI_FOCUS_HOLD_DELAY + UI_FOCUS_HOLD_REPEAT) return; + UI_FOCUS.timeHeld = UI_FOCUS_HOLD_DELAY; + uiFocusMoveDirection(item, UI_FOCUS.direction); } diff --git a/src/dusk/ui/focus/uifocus.h b/src/dusk/ui/focus/uifocus.h index 24dc6ed7..1c69edef 100644 --- a/src/dusk/ui/focus/uifocus.h +++ b/src/dusk/ui/focus/uifocus.h @@ -50,7 +50,7 @@ extern const uifocusdirmap_t UI_FOCUS_DIR_MAP[]; */ typedef struct { uifocusitem_t items[UI_FOCUS_STACK_MAX]; - int32_t count; + uint8_t count; uifocusdirection_t direction; float_t timeHeld; } uifocus_t; @@ -71,8 +71,9 @@ void uiFocusInit(void); * @param selected Called when the user selects the focused cell. * @param changed Called when the focused cell position changes. * @param closed Called when this focus item is popped. + * @returns Pointer to the newly pushed focus item. */ -void uiFocusPush( +uifocusitem_t * uiFocusPush( const uint8_t cols, const uint8_t rows, uifocusitemcallback_t selected, @@ -87,28 +88,27 @@ void uiFocusPush( void uiFocusPop(void); /** - * Pops focus items until the stack depth reaches the given value. - * Each popped item has its closed callback invoked as normal. - * - * @param depth Target stack depth to pop back to. + * Pops an item and anything that was pushed after it from the focus stack. + * + * @param item The focus item to pop to. Must be on the stack. */ -void uiFocusPopTo(const int32_t depth); +void uiFocusPopItem(uifocusitem_t *item); /** * Manually sets the cursor position of the topmost focus item and * fires its changed callback. * - * @param x Column to move to. - * @param y Row to move to. + * @param x Column to move to. + * @param y Row to move to. */ -void uiFocusSelect(const uint8_t x, const uint8_t y); +void uiFocusSetPosition(uifocusitem_t *item, const uint8_t x, const uint8_t y); /** * Moves the topmost focus item one step in the given direction, * wrapping at the grid edges, and fires its changed callback. * * @param item The focus item to move. - * @param dir Direction to move. + * @param dir Direction to move. */ void uiFocusMoveDirection( uifocusitem_t *item, diff --git a/src/dusk/ui/frame/uiframe.c b/src/dusk/ui/frame/uiframe.c index 8608e5db..3097fcbe 100644 --- a/src/dusk/ui/frame/uiframe.c +++ b/src/dusk/ui/frame/uiframe.c @@ -19,25 +19,25 @@ errorret_t uiFrameInit(void) { memoryZero(&UI_FRAME, sizeof(uiframe_t)); // Init texture. - color_t border = color4b(0, 100, 220, 200); - color_t center = color4b(0, 100, 220, 50); + color_t border = color4b(0, 100, 220, 255); + color_t center = color4b(0, 100, 220, 200); - for(uint8_t y = 0; y < UIFRAME_DUMMY_HEIGHT; y++) { - for(uint8_t x = 0; x < UIFRAME_DUMMY_WIDTH; x++) { + for(uint8_t y = 0; y < UIFRAME_BORDER_HEIGHT; y++) { + for(uint8_t x = 0; x < UIFRAME_BORDER_WIDTH; x++) { color_t c; - if(x >= 12 || y >= 12) { + if(x >= 12 || y >= 12) {// Because power of two is required. c = COLOR_TRANSPARENT; } else if(y < 4 || y >= 8 || x < 4 || x >= 8) { c = border; } else { c = center; } - UI_FRAME.pixels[y * UIFRAME_DUMMY_WIDTH + x] = c; + UI_FRAME.pixels[y * UIFRAME_BORDER_WIDTH + x] = c; } } errorChain(textureInit( - &UI_FRAME.texture, UIFRAME_DUMMY_WIDTH, UIFRAME_DUMMY_HEIGHT, + &UI_FRAME.texture, UIFRAME_BORDER_WIDTH, UIFRAME_BORDER_HEIGHT, TEXTURE_FORMAT_RGBA, (texturedata_t){ .rgbaColors = UI_FRAME.pixels } )); @@ -47,8 +47,8 @@ errorret_t uiFrameInit(void) { UI_FRAME.tileset.columns = 3; UI_FRAME.tileset.rows = 3; UI_FRAME.tileset.tileCount = 9; - UI_FRAME.tileset.uv[0] = 4.0f / UIFRAME_DUMMY_WIDTH; - UI_FRAME.tileset.uv[1] = 4.0f / UIFRAME_DUMMY_HEIGHT; + UI_FRAME.tileset.uv[0] = 4.0f / UIFRAME_BORDER_WIDTH; + UI_FRAME.tileset.uv[1] = 4.0f / UIFRAME_BORDER_HEIGHT; errorOk(); } @@ -68,115 +68,44 @@ errorret_t uiFrameDraw( spritebatchsprite_t sprites[9]; float_t tileW = (float_t)UI_FRAME.tileset.tileWidth; float_t tileH = (float_t)UI_FRAME.tileset.tileHeight; - vec4 uv; - tilesetPositionGetUV(&UI_FRAME.tileset, 0, 0, uv); - sprites[0].min[0] = x; - sprites[0].min[1] = y; - sprites[0].min[2] = 0.0f; - sprites[0].max[0] = x + tileW; - sprites[0].max[1] = y + tileH; - sprites[0].max[2] = 0.0f; - sprites[0].uvMin[0] = uv[0]; - sprites[0].uvMin[1] = uv[1]; - sprites[0].uvMax[0] = uv[2]; - sprites[0].uvMax[1] = uv[3]; - - tilesetPositionGetUV(&UI_FRAME.tileset, 1, 0, uv); - sprites[1].min[0] = x + tileW; - sprites[1].min[1] = y; - sprites[1].min[2] = 0.0f; - sprites[1].max[0] = x + width - tileW; - sprites[1].max[1] = y + tileH; - sprites[1].max[2] = 0.0f; - sprites[1].uvMin[0] = uv[0]; - sprites[1].uvMin[1] = uv[1]; - sprites[1].uvMax[0] = uv[2]; - sprites[1].uvMax[1] = uv[3]; - - tilesetPositionGetUV(&UI_FRAME.tileset, 2, 0, uv); - sprites[2].min[0] = x + width - tileW; - sprites[2].min[1] = y; - sprites[2].min[2] = 0.0f; - sprites[2].max[0] = x + width; - sprites[2].max[1] = y + tileH; - sprites[2].max[2] = 0.0f; - sprites[2].uvMin[0] = uv[0]; - sprites[2].uvMin[1] = uv[1]; - sprites[2].uvMax[0] = uv[2]; - sprites[2].uvMax[1] = uv[3]; - - tilesetPositionGetUV(&UI_FRAME.tileset, 0, 1, uv); - sprites[3].min[0] = x; - sprites[3].min[1] = y + tileH; - sprites[3].min[2] = 0.0f; - sprites[3].max[0] = x + tileW; - sprites[3].max[1] = y + height - tileH; - sprites[3].max[2] = 0.0f; - sprites[3].uvMin[0] = uv[0]; - sprites[3].uvMin[1] = uv[1]; - sprites[3].uvMax[0] = uv[2]; - sprites[3].uvMax[1] = uv[3]; - - tilesetPositionGetUV(&UI_FRAME.tileset, 1, 1, uv); - sprites[4].min[0] = x + tileW; - sprites[4].min[1] = y + tileH; - sprites[4].min[2] = 0.0f; - sprites[4].max[0] = x + width - tileW; - sprites[4].max[1] = y + height - tileH; - sprites[4].max[2] = 0.0f; - sprites[4].uvMin[0] = uv[0]; - sprites[4].uvMin[1] = uv[1]; - sprites[4].uvMax[0] = uv[2]; - sprites[4].uvMax[1] = uv[3]; - - tilesetPositionGetUV(&UI_FRAME.tileset, 2, 1, uv); - sprites[5].min[0] = x + width - tileW; - sprites[5].min[1] = y + tileH; - sprites[5].min[2] = 0.0f; - sprites[5].max[0] = x + width; - sprites[5].max[1] = y + height - tileH; - sprites[5].max[2] = 0.0f; - sprites[5].uvMin[0] = uv[0]; - sprites[5].uvMin[1] = uv[1]; - sprites[5].uvMax[0] = uv[2]; - sprites[5].uvMax[1] = uv[3]; - - tilesetPositionGetUV(&UI_FRAME.tileset, 0, 2, uv); - sprites[6].min[0] = x; - sprites[6].min[1] = y + height - tileH; - sprites[6].min[2] = 0.0f; - sprites[6].max[0] = x + tileW; - sprites[6].max[1] = y + height; - sprites[6].max[2] = 0.0f; - sprites[6].uvMin[0] = uv[0]; - sprites[6].uvMin[1] = uv[1]; - sprites[6].uvMax[0] = uv[2]; - sprites[6].uvMax[1] = uv[3]; - - tilesetPositionGetUV(&UI_FRAME.tileset, 1, 2, uv); - sprites[7].min[0] = x + tileW; - sprites[7].min[1] = y + height - tileH; - sprites[7].min[2] = 0.0f; - sprites[7].max[0] = x + width - tileW; - sprites[7].max[1] = y + height; - sprites[7].max[2] = 0.0f; - sprites[7].uvMin[0] = uv[0]; - sprites[7].uvMin[1] = uv[1]; - sprites[7].uvMax[0] = uv[2]; - sprites[7].uvMax[1] = uv[3]; - - tilesetPositionGetUV(&UI_FRAME.tileset, 2, 2, uv); - sprites[8].min[0] = x + width - tileW; - sprites[8].min[1] = y + height - tileH; - sprites[8].min[2] = 0.0f; - sprites[8].max[0] = x + width; - sprites[8].max[1] = y + height; - sprites[8].max[2] = 0.0f; - sprites[8].uvMin[0] = uv[0]; - sprites[8].uvMin[1] = uv[1]; - sprites[8].uvMax[0] = uv[2]; - sprites[8].uvMax[1] = uv[3]; + sprites[0] = spriteBatchSpriteTilesetPosition( + &UI_FRAME.tileset, 0, 0, + x, y, tileW, tileH + ); + sprites[1] = spriteBatchSpriteTilesetPosition( + &UI_FRAME.tileset, 1, 0, + x + tileW, y, width - (tileW * 2.0f), tileH + ); + sprites[2] = spriteBatchSpriteTilesetPosition( + &UI_FRAME.tileset, 2, 0, + x + width - tileW, y, tileW, tileH + ); + sprites[3] = spriteBatchSpriteTilesetPosition( + &UI_FRAME.tileset, 0, 1, + x, y + tileH, tileW, height - (tileH * 2.0f) + ); + sprites[4] = spriteBatchSpriteTilesetPosition( + &UI_FRAME.tileset, 1, 1, + x + tileW, y + tileH, + width - (tileW * 2.0f), height - (tileH * 2.0f) + ); + sprites[5] = spriteBatchSpriteTilesetPosition( + &UI_FRAME.tileset, 2, 1, + x + width - tileW, y + tileH, tileW, height - (tileH * 2.0f) + ); + sprites[6] = spriteBatchSpriteTilesetPosition( + &UI_FRAME.tileset, 0, 2, + x, y + height - tileH, tileW, tileH + ); + sprites[7] = spriteBatchSpriteTilesetPosition( + &UI_FRAME.tileset, 1, 2, + x + tileW, y + height - tileH, width - (tileW * 2.0f), tileH + ); + sprites[8] = spriteBatchSpriteTilesetPosition( + &UI_FRAME.tileset, 2, 2, + x + width - tileW, y + height - tileH, tileW, tileH + ); return spriteBatchBuffer(sprites, 9, &SHADER_UNLIT, material); } diff --git a/src/dusk/ui/frame/uiframe.h b/src/dusk/ui/frame/uiframe.h index 64c45274..20511a2e 100644 --- a/src/dusk/ui/frame/uiframe.h +++ b/src/dusk/ui/frame/uiframe.h @@ -10,13 +10,13 @@ #include "display/texture/texture.h" #include "display/texture/tileset.h" -#define UIFRAME_DUMMY_WIDTH 16 -#define UIFRAME_DUMMY_HEIGHT 16 +#define UIFRAME_BORDER_WIDTH 16 +#define UIFRAME_BORDER_HEIGHT 16 typedef struct { tileset_t tileset; texture_t texture; - color_t pixels[UIFRAME_DUMMY_WIDTH * UIFRAME_DUMMY_HEIGHT]; + color_t pixels[UIFRAME_BORDER_WIDTH * UIFRAME_BORDER_HEIGHT]; } uiframe_t; extern uiframe_t UI_FRAME; diff --git a/src/dusk/ui/frame/uisettings.c b/src/dusk/ui/frame/uisettings.c index 7408e79a..a27f4966 100644 --- a/src/dusk/ui/frame/uisettings.c +++ b/src/dusk/ui/frame/uisettings.c @@ -8,6 +8,9 @@ #include "uisettings.h" #include "ui/frame/uiframe.h" #include "util/memory.h" +#include "display/spritebatch/spritebatch.h" +#include "display/text/text.h" +#include "input/input.h" uisettings_t UI_SETTINGS; @@ -17,18 +20,60 @@ errorret_t uiSettingsInit(void) { } errorret_t uiSettingsUpdate(void) { - // if(!UI_SETTINGS.visible) errorOk(); + if(!inputPressedIfDynamic(INPUT_ACTION_PAUSE)) errorOk(); + + if(UI_SETTINGS.item == NULL) { + uiSettingsOpen(); + } else { + uiSettingsClose(); + } + errorOk(); } errorret_t uiSettingsDraw(void) { - // if(!UI_SETTINGS.visible) errorOk(); + if(UI_SETTINGS.item == NULL) errorOk(); + + const char_t *texts[] = { + "Settings", + "Settings two", + "Settings three" + }; + const uint8_t textCount = sizeof(texts) / sizeof(texts[0]); + errorChain(uiFrameDraw( - 100.0f, 100.0f, 1.0f, 1.0f + 0.0f, 0.0f, 100.0f, FONT_DEFAULT.tileset->tileHeight * textCount + (UIFRAME_BORDER_HEIGHT * 2) )); + + for(uint8_t i = 0; i < textCount; i++) { + const char_t *c = texts[i]; + errorChain(textDraw( + UIFRAME_BORDER_WIDTH, + UIFRAME_BORDER_HEIGHT + (i * FONT_DEFAULT.tileset->tileHeight), + c, + UI_SETTINGS.item->y == i ? COLOR_RED : COLOR_WHITE, NULL + )); + } + + errorChain(spriteBatchFlush()); errorOk(); } +void uiSettingsOpen() { + if(UI_SETTINGS.item != NULL) return; + + UI_SETTINGS.item = uiFocusPush( + 1, 3, NULL, NULL, NULL + ); +} + +void uiSettingsClose() { + if(UI_SETTINGS.item == NULL) return; + + uiFocusPopItem(UI_SETTINGS.item); + UI_SETTINGS.item = NULL; +} + errorret_t uiSettingsDispose(void) { errorOk(); } diff --git a/src/dusk/ui/frame/uisettings.h b/src/dusk/ui/frame/uisettings.h index bc7f2d24..6ba12013 100644 --- a/src/dusk/ui/frame/uisettings.h +++ b/src/dusk/ui/frame/uisettings.h @@ -7,9 +7,10 @@ #pragma once #include "error/error.h" +#include "ui/focus/uifocus.h" typedef struct { - bool_t visible; + uifocusitem_t *item; } uisettings_t; extern uisettings_t UI_SETTINGS; @@ -35,6 +36,16 @@ errorret_t uiSettingsUpdate(void); */ errorret_t uiSettingsDraw(void); +/** + * Opens the settings panel. No-op when already open. + */ +void uiSettingsOpen(); + +/** + * Closes the settings panel. No-op when already closed. + */ +void uiSettingsClose(); + /** * Disposes of the settings panel. *