Files
dusk/archive/asset/asset.c
2025-11-04 10:15:19 -06:00

139 lines
3.8 KiB
C

/**
* 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;
}
}