Started asset refact

This commit is contained in:
YourWishes committed 2025-11-04 10:15:19 -06:00
1 parent 7d46b98310
commit 7c11a7e5bc
25 files changed
+362 -208

No files matched your search

+14
View File
@@ -0,0 +1,14 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_TARGET_NAME}
PRIVATE
asset.c
assetmanager.c
)
# Subdirs
add_subdirectory(type)
+139
View File
@@ -0,0 +1,139 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "asset.h"
#include "assetmanager.h"
#include "util/memory.h"
#include "assert/assert.h"
assetdef_t ASSET_DEFINITIONS[ASSET_TYPE_COUNT] = {
[ASSET_TYPE_PALETTE_IMAGE] = {
"DPI", assetPaletteImageLoad, assetPaletteImageDispose
},
[ASSET_TYPE_ALPHA_IMAGE] = {
"DAI", assetAlphaImageLoad, assetAlphaImageDispose
},
};
errorret_t assetInit(asset_t *asset, const char_t *filename) {
assertNotNull(asset, "Asset cannot be NULL.");
assertNotNull(filename, "Filename cannot be NULL.");
assertTrue(strlen(filename) < FILENAME_MAX, "Filename too long.");
assertTrue(strlen(filename) > 0, "Filename cannot be empty.");
memoryZero(asset, sizeof(asset_t));
memoryCopy(asset->filename, filename, strlen(filename) + 1);
// Initialze the reference list.
refListInit(
&asset->refList,
asset->refListArray,
ASSET_REFERENCE_COUNT_MAX
);
// Test the file can be opened. In future I may make the handle stay open for
// a while to see if it increases performance and stops disk thrashing.
asset->file = zip_fopen(ASSET_MANAGER.zip, filename, 0);
if(asset->file == NULL) errorThrow("Failed to open asset file: %s", filename);
zip_fclose(asset->file);
asset->file = NULL;
errorOk();
}
ref_t assetLock(asset_t *asset) {
assertNotNull(asset, "Asset cannot be NULL.");
return refListLock(&asset->refList);
}
void assetUnlock(asset_t *asset, const ref_t ref) {
assertNotNull(asset, "Asset cannot be NULL.");
// Just unlock the reference in the reference list.
refListUnlock(&asset->refList, ref);
}
errorret_t assetLoad(asset_t *asset) {
assertNotNull(asset, "Asset cannot be NULL.");
assertTrue(
asset->state == ASSET_STATE_NOT_LOADED,
"Asset is already loaded or loading."
);
// Mark as loading.
asset->state = ASSET_STATE_LOADING;
// Open the file.
if(asset->file == NULL) {
asset->file = zip_fopen(ASSET_MANAGER.zip, asset->filename, 0);
if(asset->file == NULL) {
asset->state = ASSET_STATE_ERROR;
errorThrow("Failed to open asset file: %s", asset->filename);
}
}
// Read header.
char_t header[ASSET_HEADER_SIZE + 1];
memoryZero(header, ASSET_HEADER_SIZE + 1);
zip_int64_t bytesRead = zip_fread(asset->file, header, ASSET_HEADER_SIZE);
if(bytesRead != ASSET_HEADER_SIZE) {
asset->state = ASSET_STATE_ERROR;
zip_fclose(asset->file);
asset->file = NULL;
errorThrow("Failed to read asset header for: %s", asset->filename);
}
// Check header.
if(strlen(header) != ASSET_HEADER_SIZE) {
asset->state = ASSET_STATE_ERROR;
zip_fclose(asset->file);
asset->file = NULL;
errorThrow("Invalid asset header for: %s", asset->filename);
}
// Get the asset definition based on the header.
assetdef_t *def;
for(uint_fast8_t i = 0; i < ASSET_TYPE_COUNT; i++) {
if(strcmp(header, ASSET_DEFINITIONS[i].header) == 0) {
def = &ASSET_DEFINITIONS[i];
asset->type = i;
break;
}
}
assertNotNull(def, "Failed to find asset definition for header.");
// Load the asset
errorret_t ret = def->load(asset);
if(ret.code != ERROR_OK) {
asset->state = ASSET_STATE_ERROR;
zip_fclose(asset->file);
asset->file = NULL;
errorChain(ret);
}
// Finished loading.
asset->state = ASSET_STATE_LOADED;
zip_fclose(asset->file);
asset->file = NULL;
errorOk();
}
errorret_t assetDispose(asset_t *asset) {
assertNotNull(asset, "Asset cannot be NULL.");
if(asset->state == ASSET_STATE_LOADED) {
// Dispose of the asset based on its type.
assetdef_t *def = &ASSET_DEFINITIONS[asset->type];
if(def->dispose) errorChain(def->dispose(asset));
asset->state = ASSET_STATE_NOT_LOADED;
}
if(asset->file) {
zip_fclose(asset->file);
asset->file = NULL;
}
}
+104
View File
@@ -0,0 +1,104 @@
/**
* 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 "util/reflist.h"
#include <zip.h>
#include "asset/type/assetpaletteimage.h"
#include "asset/type/assetalphaimage.h"
#define ASSET_HEADER_SIZE 3
#define ASSET_REFERENCE_COUNT_MAX 8
typedef struct {
void (*load)();
} assetcallback_t;
typedef enum {
ASSET_STATE_NOT_LOADED,
ASSET_STATE_LOADING,
ASSET_STATE_LOADED,
ASSET_STATE_ERROR,
} assetstate_t;
typedef enum {
ASSET_TYPE_UNKNOWN,
ASSET_TYPE_PALETTE_IMAGE,
ASSET_TYPE_ALPHA_IMAGE,
ASSET_TYPE_COUNT
} assettype_t;
typedef struct asset_s {
char_t filename[FILENAME_MAX];
ref_t refListArray[ASSET_REFERENCE_COUNT_MAX];
reflist_t refList;
assetstate_t state;
assettype_t type;
zip_file_t *file;
union {
assetpaletteimage_t paletteImage;
assetalphaimage_t alphaImage;
};
} asset_t;
typedef struct {
const char_t header[ASSET_HEADER_SIZE + 1];
errorret_t (*load)(asset_t *asset);
errorret_t (*dispose)(asset_t *asset);
} assetdef_t;
extern assetdef_t ASSET_DEFINITIONS[ASSET_TYPE_COUNT];
/**
* Initializes an asset structure. This should be called by the asset manager
* only.
*
* @param asset The asset structure to initialize.
* @param filename The filename of the asset.
* @return An error code.
*/
errorret_t assetInit(asset_t *asset, const char_t *filename);
/**
* Requests a lock on the given asset. This will increase the reference count
* of the asset, and prevent it from being unloaded until all locks are
* released.
*
* @param asset The asset to lock.
* @return A unique reference ID for the lock.
*/
ref_t assetLock(asset_t *asset);
/**
* Releases a lock on the given asset. This will decrease the reference count
* of the asset, and allow it to be unloaded if there are no more locks.
*
* @param asset The asset to unlock.
* @param ref The reference ID of the lock to release.
*/
void assetUnlock(asset_t *asset, const ref_t ref);
/**
* Permission has been granted to load the asset data from disk. This should
* only be called by the asset manager.
*
* @param asset The asset to load.
* @return An error code.
*/
errorret_t assetLoad(asset_t *asset);
/**
* Disposes of the asset, freeing any allocated memory and closing any open
* file handles. This should only be called by the asset manager.
*
* @param asset The asset to dispose of.
*/
errorret_t assetDispose(asset_t *asset);
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1 -1
View File
@@ -34,7 +34,7 @@ add_subdirectory(display)
add_subdirectory(engine) add_subdirectory(engine)
add_subdirectory(error) add_subdirectory(error)
add_subdirectory(input) add_subdirectory(input)
# add_subdirectory(locale) add_subdirectory(locale)
add_subdirectory(rpg) add_subdirectory(rpg)
add_subdirectory(scene) add_subdirectory(scene)
add_subdirectory(thread) add_subdirectory(thread)
+3 -3
View File
@@ -6,9 +6,9 @@
# Sources # Sources
target_sources(${DUSK_TARGET_NAME} target_sources(${DUSK_TARGET_NAME}
PRIVATE PRIVATE
asset.c # asset.c
assetmanager.c # assetmanager.c
) )
# Subdirs # Subdirs
add_subdirectory(type) # add_subdirectory(type)
+29 -117
View File
@@ -6,134 +6,46 @@
*/ */
#include "asset.h" #include "asset.h"
#include "assetmanager.h"
#include "util/memory.h" #include "util/memory.h"
#include "util/string.h"
#include "assert/assert.h" #include "assert/assert.h"
assetdef_t ASSET_DEFINITIONS[ASSET_TYPE_COUNT] = { errorret_t assetInit(void) {
[ASSET_TYPE_PALETTE_IMAGE] = { memoryZero(&ASSET_MANAGER, sizeof(assetmanager_t));
"DPI", assetPaletteImageLoad, assetPaletteImageDispose
}, // Default system path, intended to be overridden by the paltform
[ASSET_TYPE_ALPHA_IMAGE] = { stringCopy(ASSET_MANAGER.systemPath, ".", FILENAME_MAX);
"DAI", assetAlphaImageLoad, assetAlphaImageDispose
},
};
errorret_t assetInit(asset_t *asset, const char_t *filename) { // Open zip file
assertNotNull(asset, "Asset cannot be NULL."); char_t searchPath[FILENAME_MAX];
assertNotNull(filename, "Filename cannot be NULL."); char_t **path = ASSET_SEARCH_PATHS;
assertTrue(strlen(filename) < FILENAME_MAX, "Filename too long."); do {
assertTrue(strlen(filename) > 0, "Filename cannot be empty."); sprintf(
searchPath,
*path,
ASSET_MANAGER.systemPath,
ASSET_ASSET_FILE
);
memoryZero(asset, sizeof(asset_t)); // Try open
memoryCopy(asset->filename, filename, strlen(filename) + 1); ASSET.zip = zip_open(searchPath, ZIP_RDONLY, NULL);
if(ASSET.zip == NULL) continue;
break;// Found!
} while(*(++path) != NULL);
// Did we open the asset?
if(ASSET.zip == NULL) errorThrow("Failed to open asset file.");
// Initialze the reference list.
refListInit(
&asset->refList,
asset->refListArray,
ASSET_REFERENCE_COUNT_MAX
);
// Test the file can be opened. In future I may make the handle stay open for
// a while to see if it increases performance and stops disk thrashing.
asset->file = zip_fopen(ASSET_MANAGER.zip, filename, 0);
if(asset->file == NULL) errorThrow("Failed to open asset file: %s", filename);
zip_fclose(asset->file);
asset->file = NULL;
errorOk(); errorOk();
} }
ref_t assetLock(asset_t *asset) { erroret_t assetLoad(const char_t *filename, void *output) {
assertNotNull(asset, "Asset cannot be NULL.");
return refListLock(&asset->refList);
}
void assetUnlock(asset_t *asset, const ref_t ref) {
assertNotNull(asset, "Asset cannot be NULL.");
// Just unlock the reference in the reference list.
refListUnlock(&asset->refList, ref);
}
errorret_t assetLoad(asset_t *asset) {
assertNotNull(asset, "Asset cannot be NULL.");
assertTrue(
asset->state == ASSET_STATE_NOT_LOADED,
"Asset is already loaded or loading."
);
// Mark as loading.
asset->state = ASSET_STATE_LOADING;
// Open the file.
if(asset->file == NULL) {
asset->file = zip_fopen(ASSET_MANAGER.zip, asset->filename, 0);
if(asset->file == NULL) {
asset->state = ASSET_STATE_ERROR;
errorThrow("Failed to open asset file: %s", asset->filename);
}
}
// Read header.
char_t header[ASSET_HEADER_SIZE + 1];
memoryZero(header, ASSET_HEADER_SIZE + 1);
zip_int64_t bytesRead = zip_fread(asset->file, header, ASSET_HEADER_SIZE);
if(bytesRead != ASSET_HEADER_SIZE) {
asset->state = ASSET_STATE_ERROR;
zip_fclose(asset->file);
asset->file = NULL;
errorThrow("Failed to read asset header for: %s", asset->filename);
}
// Check header.
if(strlen(header) != ASSET_HEADER_SIZE) {
asset->state = ASSET_STATE_ERROR;
zip_fclose(asset->file);
asset->file = NULL;
errorThrow("Invalid asset header for: %s", asset->filename);
}
// Get the asset definition based on the header.
assetdef_t *def;
for(uint_fast8_t i = 0; i < ASSET_TYPE_COUNT; i++) {
if(strcmp(header, ASSET_DEFINITIONS[i].header) == 0) {
def = &ASSET_DEFINITIONS[i];
asset->type = i;
break;
}
}
assertNotNull(def, "Failed to find asset definition for header.");
// Load the asset
errorret_t ret = def->load(asset);
if(ret.code != ERROR_OK) {
asset->state = ASSET_STATE_ERROR;
zip_fclose(asset->file);
asset->file = NULL;
errorChain(ret);
}
// Finished loading.
asset->state = ASSET_STATE_LOADED;
zip_fclose(asset->file);
asset->file = NULL;
errorOk(); errorOk();
} }
errorret_t assetDispose(asset_t *asset) { void assetDispose(void) {
assertNotNull(asset, "Asset cannot be NULL."); if(ASSET_MANAGER.zip != NULL) {
zip_close(ASSET_MANAGER.zip);
if(asset->state == ASSET_STATE_LOADED) { ASSET_MANAGER.zip = NULL;
// Dispose of the asset based on its type.
assetdef_t *def = &ASSET_DEFINITIONS[asset->type];
if(def->dispose) errorChain(def->dispose(asset));
asset->state = ASSET_STATE_NOT_LOADED;
}
if(asset->file) {
zip_fclose(asset->file);
asset->file = NULL;
} }
} }
+28 -78
View File
@@ -7,98 +7,48 @@
#pragma once #pragma once
#include "error/error.h" #include "error/error.h"
#include "util/reflist.h"
#include <zip.h> #include <zip.h>
#include "asset/type/assetpaletteimage.h" #if ASSET_TYPE == wad
#include "asset/type/assetalphaimage.h" #else
#error "Unsupported ASSET_TYPE"
#endif
#define ASSET_HEADER_SIZE 3 #define ASSET_FILE "dusk.dsk"
#define ASSET_REFERENCE_COUNT_MAX 8
static const char_t *ASSET_SEARCH_PATHS[] = {
"%s/%s",
"%s",
"../%s",
"../../%s",
"data/%s",
"../data/%s",
NULL
};
typedef struct { typedef struct {
void (*load)(); zip_t *zip;
} assetcallback_t; char_t systemPath[FILENAME_MAX];
uint8_t assetCount;
typedef enum {
ASSET_STATE_NOT_LOADED,
ASSET_STATE_LOADING,
ASSET_STATE_LOADED,
ASSET_STATE_ERROR,
} assetstate_t;
typedef enum {
ASSET_TYPE_UNKNOWN,
ASSET_TYPE_PALETTE_IMAGE,
ASSET_TYPE_ALPHA_IMAGE,
ASSET_TYPE_COUNT
} assettype_t;
typedef struct asset_s {
char_t filename[FILENAME_MAX];
ref_t refListArray[ASSET_REFERENCE_COUNT_MAX];
reflist_t refList;
assetstate_t state;
assettype_t type;
zip_file_t *file;
union {
assetpaletteimage_t paletteImage;
assetalphaimage_t alphaImage;
};
} asset_t; } asset_t;
typedef struct { static asset_t ASSET;
const char_t header[ASSET_HEADER_SIZE + 1];
errorret_t (*load)(asset_t *asset);
errorret_t (*dispose)(asset_t *asset);
} assetdef_t;
extern assetdef_t ASSET_DEFINITIONS[ASSET_TYPE_COUNT];
/** /**
* Initializes an asset structure. This should be called by the asset manager * Initializes the asset system.
* only.
*
* @param asset The asset structure to initialize.
* @param filename The filename of the asset.
* @return An error code.
*/ */
errorret_t assetInit(asset_t *asset, const char_t *filename); errorret_t assetInit(void);
/** /**
* Requests a lock on the given asset. This will increase the reference count * Loads an asset by its filename, the output type depends on the asset type.
* of the asset, and prevent it from being unloaded until all locks are
* released.
* *
* @param asset The asset to lock. * @param filename The filename of the asset to retrieve.
* @return A unique reference ID for the lock. * @param output The output pointer to store the loaded asset data.
* @return An error code if the asset could not be loaded.
*/ */
ref_t assetLock(asset_t *asset); errorret_t assetLoad(const char_t *filename, void *output);
/** /**
* Releases a lock on the given asset. This will decrease the reference count * Disposes/cleans up the asset system.
* of the asset, and allow it to be unloaded if there are no more locks.
*
* @param asset The asset to unlock.
* @param ref The reference ID of the lock to release.
*/ */
void assetUnlock(asset_t *asset, const ref_t ref); void assetDispose(void);
/**
* Permission has been granted to load the asset data from disk. This should
* only be called by the asset manager.
*
* @param asset The asset to load.
* @return An error code.
*/
errorret_t assetLoad(asset_t *asset);
/**
* Disposes of the asset, freeing any allocated memory and closing any open
* file handles. This should only be called by the asset manager.
*
* @param asset The asset to dispose of.
*/
errorret_t assetDispose(asset_t *asset);
+2
View File
@@ -9,6 +9,7 @@
#include "util/memory.h" #include "util/memory.h"
#include "time/time.h" #include "time/time.h"
#include "input/input.h" #include "input/input.h"
#include "locale/localemanager.h"
#include "display/display.h" #include "display/display.h"
#include "scene/scenemanager.h" #include "scene/scenemanager.h"
#include "asset/assetmanager.h" #include "asset/assetmanager.h"
@@ -27,6 +28,7 @@ errorret_t engineInit(void) {
// Init systems. Order is important. // Init systems. Order is important.
timeInit(); timeInit();
inputInit(); inputInit();
localeManagerInit();
errorChain(assetManagerInit()); errorChain(assetManagerInit());
errorChain(displayInit()); errorChain(displayInit());
errorChain(uiInit()); errorChain(uiInit());
-1
View File
@@ -21,7 +21,6 @@ typedef struct {
errorstate_t *state; errorstate_t *state;
} errorret_t; } errorret_t;
static const errorcode_t ERROR_OK = 0; static const errorcode_t ERROR_OK = 0;
static const errorcode_t ERROR_NOT_OK = 1; static const errorcode_t ERROR_NOT_OK = 1;
+1 -1
View File
@@ -6,5 +6,5 @@
# Sources # Sources
target_sources(${DUSK_TARGET_NAME} target_sources(${DUSK_TARGET_NAME}
PRIVATE PRIVATE
language.c localemanager.c
) )
+15
View File
@@ -0,0 +1,15 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "localemanager.h"
#include "util/memory.h"
localemanager_t LOCALE;
void localeManagerInit() {
memoryZero(&LOCALE, sizeof(localemanager_t));
}
+20
View File
@@ -0,0 +1,20 @@
/**
* 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 {
void *nothing;
} localemanager_t;
extern localemanager_t LOCALE;
/**
* Initialize the locale system.
*/
void localeManagerInit();
+3 -3
View File
@@ -6,7 +6,7 @@
*/ */
#include "engine/engine.h" #include "engine/engine.h"
#include "asset/assetmanager.h" #include "asset/asset.h"
#include "util/string.h" #include "util/string.h"
#include "input/input.h" #include "input/input.h"
@@ -23,8 +23,8 @@ int main(int argc, char **argv) {
// Setup system path on asset manager // Setup system path on asset manager
if(argc > 0) { if(argc > 0) {
stringCopy( stringCopy(
ASSET_MANAGER.systemPath, argv[0], ASSET.systemPath, argv[0],
sizeof(ASSET_MANAGER.systemPath) / sizeof(char_t) sizeof(ASSET.systemPath) / sizeof(char_t)
); );
} }
+1 -1
View File
@@ -7,7 +7,7 @@
#pragma once #pragma once
#include "dusk.h" #include "dusk.h"
#include "asset/assetmanager.h" #include "asset/asset.h"
#include "display/tileset/tileset.h" #include "display/tileset/tileset.h"
#include "display/camera.h" #include "display/camera.h"
+1 -1
View File
@@ -6,7 +6,7 @@
*/ */
#pragma once #pragma once
#include "asset/assetmanager.h" #include "asset/asset.h"
#include "display/tileset/tileset_minogram.h" #include "display/tileset/tileset_minogram.h"
#define UI_TEXT_CHAR_START '!' #define UI_TEXT_CHAR_START '!'
+1 -2
View File
@@ -36,7 +36,6 @@ def processPalette(asset):
# PSP requires that the palette size be a power of two, so we will pad the # PSP requires that the palette size be a power of two, so we will pad the
# palette with transparent colors if needed. # palette with transparent colors if needed.
# if args.platform == "psp":
def mathNextPowTwo(x): def mathNextPowTwo(x):
return 1 << (x - 1).bit_length() return 1 << (x - 1).bit_length()
@@ -53,7 +52,7 @@ def processPalette(asset):
data += f"static const color_t PALETTE_{paletteIndex}_COLORS[PALETTE_{paletteIndex}_COLOR_COUNT] = {{\n" data += f"static const color_t PALETTE_{paletteIndex}_COLORS[PALETTE_{paletteIndex}_COLOR_COUNT] = {{\n"
for pixel in pixels: for pixel in pixels:
data += f" {{ 0x{pixel[0]:02X}, 0x{pixel[1]:02X}, 0x{pixel[2]:02X}, 0x{pixel[3]:02X} }},\n" data += f" {{ 0x{pixel[0]:02X}, 0x{pixel[1]:02X}, 0x{pixel[2]:02X}, 0x{pixel[3]:02X} }},\n"
data += f"}};\n\n" data += f"}};\n"
data += f"#pragma pack(pop)\n\n" data += f"#pragma pack(pop)\n\n"
data += f"static const palette_t PALETTE_{paletteIndex} = {{\n" data += f"static const palette_t PALETTE_{paletteIndex} = {{\n"
data += f" .colorCount = PALETTE_{paletteIndex}_COLOR_COUNT,\n" data += f" .colorCount = PALETTE_{paletteIndex}_COLOR_COUNT,\n"