Moved all files.
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
# 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
|
||||
asset.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(type)
|
||||
@@ -0,0 +1,345 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "asset.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
#include "assert/assert.h"
|
||||
#include "asset/assettype.h"
|
||||
#include "engine/engine.h"
|
||||
#include "debug/debug.h"
|
||||
#include "util/string.h"
|
||||
|
||||
errorret_t assetInit(void) {
|
||||
memoryZero(&ASSET, sizeof(asset_t));
|
||||
|
||||
#if DOLPHIN
|
||||
// Init FAT driver.
|
||||
if(!fatInitDefault()) errorThrow("Failed to initialize FAT filesystem.");
|
||||
|
||||
char_t **dolphinSearchPath = (char_t **)ASSET_DOLPHIN_PATHS;
|
||||
char_t foundPath[FILENAME_MAX];
|
||||
foundPath[0] = '\0';
|
||||
do {
|
||||
// Try open dir
|
||||
DIR *pdir = opendir(*dolphinSearchPath);
|
||||
if(pdir == NULL) continue;
|
||||
|
||||
|
||||
// Scan if file is present
|
||||
while(true) {
|
||||
struct dirent* pent = readdir(pdir);
|
||||
if(pent == NULL) break;
|
||||
|
||||
if(stringCompareInsensitive(pent->d_name, ASSET_FILE) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Copy out filename
|
||||
snprintf(
|
||||
foundPath,
|
||||
FILENAME_MAX,
|
||||
"%s/%s",
|
||||
*dolphinSearchPath,
|
||||
ASSET_FILE
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
// Close dir.
|
||||
closedir(pdir);
|
||||
|
||||
// Did we find the file here?
|
||||
if(foundPath[0] != '\0') break;
|
||||
} while(*(++dolphinSearchPath) != NULL);
|
||||
|
||||
if(foundPath[0] != '\0') {
|
||||
}
|
||||
|
||||
// Did we find the asset file?
|
||||
if(foundPath[0] == '\0') {
|
||||
errorThrow("Failed to find asset file on FAT filesystem.");
|
||||
}
|
||||
|
||||
ASSET.zip = zip_open(foundPath, ZIP_RDONLY, NULL);
|
||||
if(ASSET.zip == NULL) {
|
||||
errorThrow("Failed to open asset file on FAT filesystem.");
|
||||
}
|
||||
errorOk();
|
||||
#endif
|
||||
|
||||
// Engine may have been provided the launch path
|
||||
if(ENGINE.argc > 0) {
|
||||
// Get the directory of the executable
|
||||
char_t buffer[FILENAME_MAX];
|
||||
stringCopy(buffer, ENGINE.argv[0], FILENAME_MAX);
|
||||
size_t len = strlen(buffer);
|
||||
|
||||
// Normalize slashes
|
||||
for(size_t i = 0; i < FILENAME_MAX; i++) {
|
||||
if(buffer[i] == '\0') break;
|
||||
if(buffer[i] == '\\') buffer[i] = '/';
|
||||
}
|
||||
|
||||
// Now find the last slash
|
||||
char_t *end = buffer + len - 1;
|
||||
do {
|
||||
end--;
|
||||
if(*end == '/') {
|
||||
*end = '\0';
|
||||
break;
|
||||
}
|
||||
} while(end != buffer);
|
||||
|
||||
|
||||
// Did we find a slash?
|
||||
if(end != buffer) {
|
||||
// We found the directory, set as system path
|
||||
stringCopy(ASSET.systemPath, buffer, FILENAME_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
// Default system path, intended to be overridden by the platform
|
||||
stringCopy(ASSET.systemPath, ".", FILENAME_MAX);
|
||||
|
||||
// PSP specific asset loading.
|
||||
#if PSP
|
||||
assertTrue(ENGINE.argc >= 1, "PSP requires launch argument.");
|
||||
|
||||
// PSP is given either the prx OR the PBP file.
|
||||
// In the format of "ms0:/PSP/GAME/DUSK/EBOOT.PBP" or "host0:/Dusk.prx"
|
||||
// IF the file is the PBP file, we are loading directly on the PSP itself.
|
||||
// IF the file is the .prx then we are debugging and fopen will return
|
||||
// relative filepaths correctly, e.g. host0:/dusk.dsk will be on host.
|
||||
if(
|
||||
stringEndsWithCaseInsensitive(ENGINE.argv[0], ".pbp") ||
|
||||
ASSET_PBP_READ_PBP_FROM_HOST
|
||||
) {
|
||||
const char_t *pbpPath = (
|
||||
ASSET_PBP_READ_PBP_FROM_HOST ? "./EBOOT.PBP" : ENGINE.argv[0]
|
||||
);
|
||||
ASSET.pbpFile = fopen(pbpPath, "rb");
|
||||
if(ASSET.pbpFile == NULL) {
|
||||
errorThrow("Failed to open PBP file: %s", pbpPath);
|
||||
}
|
||||
|
||||
// Get size of PBP file.
|
||||
if(fseek(ASSET.pbpFile, 0, SEEK_END) != 0) {
|
||||
fclose(ASSET.pbpFile);
|
||||
errorThrow("Failed to seek to end of PBP file : %s", pbpPath);
|
||||
}
|
||||
size_t pbpSize = ftell(ASSET.pbpFile);
|
||||
|
||||
// Rewind to start
|
||||
if(fseek(ASSET.pbpFile, 0, SEEK_SET) != 0) {
|
||||
fclose(ASSET.pbpFile);
|
||||
errorThrow("Failed to seek to start of PBP file : %s", pbpPath);
|
||||
}
|
||||
|
||||
// Read the PBP header
|
||||
size_t read = fread(
|
||||
&ASSET.pbpHeader,
|
||||
1,
|
||||
sizeof(assetpbp_t),
|
||||
ASSET.pbpFile
|
||||
);
|
||||
if(read != sizeof(assetpbp_t)) {
|
||||
fclose(ASSET.pbpFile);
|
||||
errorThrow("Failed to read PBP header", pbpPath);
|
||||
}
|
||||
if(memoryCompare(
|
||||
ASSET.pbpHeader.signature,
|
||||
ASSET_PBP_SIGNATURE,
|
||||
sizeof(ASSET_PBP_SIGNATURE)
|
||||
) != 0) {
|
||||
fclose(ASSET.pbpFile);
|
||||
errorThrow("Invalid PBP signature in file: %s", pbpPath);
|
||||
}
|
||||
|
||||
// If we seek to the PSAR offset, we can read the WAD file from there
|
||||
if(fseek(ASSET.pbpFile, ASSET.pbpHeader.psarOffset, SEEK_SET) != 0) {
|
||||
fclose(ASSET.pbpFile);
|
||||
errorThrow("Failed to seek to PSAR offset in PBP file: %s", pbpPath);
|
||||
}
|
||||
|
||||
zip_uint64_t zipPsarOffset = (zip_uint64_t)ASSET.pbpHeader.psarOffset;
|
||||
zip_int64_t zipPsarSize = (zip_int64_t)(
|
||||
pbpSize - ASSET.pbpHeader.psarOffset
|
||||
);
|
||||
|
||||
zip_source_t *psarSource = zip_source_filep_create(
|
||||
ASSET.pbpFile,
|
||||
zipPsarOffset,
|
||||
zipPsarSize,
|
||||
NULL
|
||||
);
|
||||
if(psarSource == NULL) {
|
||||
fclose(ASSET.pbpFile);
|
||||
errorThrow("Failed to create zip source in PBP file: %s", pbpPath);
|
||||
}
|
||||
|
||||
ASSET.zip = zip_open_from_source(
|
||||
psarSource,
|
||||
ZIP_RDONLY,
|
||||
NULL
|
||||
);
|
||||
if(ASSET.zip == NULL) {
|
||||
zip_source_free(psarSource);
|
||||
fclose(ASSET.pbpFile);
|
||||
errorThrow("Failed to open zip from PBP file: %s", pbpPath);
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Open zip file
|
||||
char_t searchPath[FILENAME_MAX];
|
||||
const char_t **path = ASSET_SEARCH_PATHS;
|
||||
do {
|
||||
sprintf(
|
||||
searchPath,
|
||||
*path,
|
||||
ASSET.systemPath,
|
||||
ASSET_FILE
|
||||
);
|
||||
|
||||
// Try open
|
||||
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.");
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
bool_t assetFileExists(const char_t *filename) {
|
||||
assertStrLenMax(filename, FILENAME_MAX, "Filename too long.");
|
||||
|
||||
zip_int64_t idx = zip_name_locate(ASSET.zip, filename, 0);
|
||||
if(idx < 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t assetLoad(const char_t *filename, void *output) {
|
||||
assertStrLenMax(filename, FILENAME_MAX, "Filename too long.");
|
||||
assertNotNull(output, "Output pointer cannot be NULL.");
|
||||
|
||||
// Determine the asset type by reading the extension
|
||||
const assettypedef_t *def = NULL;
|
||||
for(uint_fast8_t i = 0; i < ASSET_TYPE_COUNT; i++) {
|
||||
const assettypedef_t *cmp = &ASSET_TYPE_DEFINITIONS[i];
|
||||
assertNotNull(cmp, "Asset type definition cannot be NULL.");
|
||||
if(cmp->extension == NULL) continue;
|
||||
if(!stringEndsWithCaseInsensitive(filename, cmp->extension)) continue;
|
||||
def = cmp;
|
||||
break;
|
||||
}
|
||||
if(def == NULL) {
|
||||
errorThrow("Unknown asset type for file: %s", filename);
|
||||
}
|
||||
|
||||
// Get file size of the asset.
|
||||
zip_stat_t st;
|
||||
zip_stat_init(&st);
|
||||
if(!zip_stat(ASSET.zip, filename, 0, &st) == 0) {
|
||||
errorThrow("Failed to stat asset file: %s", filename);
|
||||
}
|
||||
|
||||
// Minimum file size.
|
||||
zip_int64_t fileSize = (zip_int64_t)st.size;
|
||||
if(fileSize <= 0) {
|
||||
errorThrow("Asset file is empty: %s", filename);
|
||||
}
|
||||
|
||||
// Try to open the file
|
||||
zip_file_t *file = zip_fopen(ASSET.zip, filename, 0);
|
||||
if(file == NULL) {
|
||||
errorThrow("Failed to open asset file: %s", filename);
|
||||
}
|
||||
|
||||
// Load the asset data
|
||||
switch(def->loadStrategy) {
|
||||
case ASSET_LOAD_STRAT_ENTIRE:
|
||||
assertNotNull(def->entire, "Asset load function cannot be NULL.");
|
||||
|
||||
// Must have more to read
|
||||
if(fileSize <= 0) {
|
||||
zip_fclose(file);
|
||||
errorThrow("No data remaining to read for asset: %s", filename);
|
||||
}
|
||||
|
||||
if(fileSize > def->dataSize) {
|
||||
zip_fclose(file);
|
||||
errorThrow(
|
||||
"Asset file has too much data remaining after header: %s",
|
||||
filename
|
||||
);
|
||||
}
|
||||
|
||||
// Create space to read the entire asset data
|
||||
void *data = memoryAllocate(fileSize);
|
||||
if(!data) {
|
||||
zip_fclose(file);
|
||||
errorThrow("Failed to allocate memory for asset data of file: %s", filename);
|
||||
}
|
||||
|
||||
// Read in the asset data.
|
||||
zip_int64_t bytesRead = zip_fread(file, data, fileSize);
|
||||
if(bytesRead == 0 || bytesRead > fileSize) {
|
||||
memoryFree(data);
|
||||
zip_fclose(file);
|
||||
errorThrow("Failed to read asset data for file: %s", filename);
|
||||
}
|
||||
fileSize -= bytesRead;
|
||||
|
||||
// Close the file now we have the data
|
||||
zip_fclose(file);
|
||||
|
||||
// Pass to the asset type loader
|
||||
assetentire_t entire = {
|
||||
.data = data,
|
||||
.output = output
|
||||
};
|
||||
errorret_t ret = def->entire(entire);
|
||||
memoryFree(data);
|
||||
|
||||
errorChain(ret);
|
||||
break;
|
||||
|
||||
case ASSET_LOAD_STRAT_CUSTOM:
|
||||
assertNotNull(def->custom, "Asset load function cannot be NULL.");
|
||||
assetcustom_t customData = {
|
||||
.zipFile = file,
|
||||
.output = output
|
||||
};
|
||||
errorChain(def->custom(customData));
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("Unknown asset load strategy.");
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void assetDispose(void) {
|
||||
if(ASSET.zip != NULL) {
|
||||
zip_close(ASSET.zip);
|
||||
ASSET.zip = NULL;
|
||||
}
|
||||
|
||||
#if PSP
|
||||
if(ASSET.pbpFile != NULL) {
|
||||
fclose(ASSET.pbpFile);
|
||||
ASSET.pbpFile = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* 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 "assettype.h"
|
||||
|
||||
#if PSP
|
||||
#define ASSET_PBP_READ_PBP_FROM_HOST 0
|
||||
#define ASSET_PBP_SIGNATURE_SIZE 4
|
||||
#define ASSET_PBP_SIGNATURE "\0PBP"
|
||||
|
||||
typedef struct {
|
||||
char_t signature[ASSET_PBP_SIGNATURE_SIZE];
|
||||
uint32_t version;
|
||||
uint32_t sfoOffset;
|
||||
uint32_t icon0Offset;
|
||||
uint32_t icon1Offset;
|
||||
uint32_t pic0Offset;
|
||||
uint32_t pic1Offset;
|
||||
uint32_t snd0Offset;
|
||||
uint32_t pspOffset;
|
||||
uint32_t psarOffset;
|
||||
} assetpbp_t;
|
||||
|
||||
#elif DOLPHIN
|
||||
#include <fat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const char_t *ASSET_DOLPHIN_PATHS[] = {
|
||||
"/",
|
||||
"/Dusk",
|
||||
"/dusk",
|
||||
"/DUSK",
|
||||
"/apps",
|
||||
"/apps/Dusk",
|
||||
"/apps/dusk",
|
||||
"/apps/DUSK",
|
||||
".",
|
||||
"./",
|
||||
"./Dusk",
|
||||
"./dusk",
|
||||
"./DUSK",
|
||||
"./apps",
|
||||
"./apps/Dusk",
|
||||
"./apps/dusk",
|
||||
"./apps/DUSK",
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
#define ASSET_FILE "dusk.dsk"
|
||||
#define ASSET_HEADER_SIZE 3
|
||||
|
||||
static const char_t *ASSET_SEARCH_PATHS[] = {
|
||||
"%s/%s",
|
||||
"%s",
|
||||
"../%s",
|
||||
"../../%s",
|
||||
"data/%s",
|
||||
"../data/%s",
|
||||
NULL
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
zip_t *zip;
|
||||
char_t systemPath[FILENAME_MAX];
|
||||
uint8_t assetCount;
|
||||
|
||||
// PSP specific information.
|
||||
#if PSP
|
||||
FILE *pbpFile;
|
||||
assetpbp_t pbpHeader;
|
||||
#endif
|
||||
} asset_t;
|
||||
|
||||
static asset_t ASSET;
|
||||
|
||||
/**
|
||||
* Initializes the asset system.
|
||||
*/
|
||||
errorret_t assetInit(void);
|
||||
|
||||
/**
|
||||
* Checks if an asset file exists.
|
||||
*
|
||||
* @param filename The filename of the asset to check.
|
||||
* @return true if the asset file exists, false otherwise.
|
||||
*/
|
||||
bool_t assetFileExists(const char_t *filename);
|
||||
|
||||
/**
|
||||
* Loads an asset by its filename, the output type depends on the asset type.
|
||||
*
|
||||
* @param filename The filename of the asset to retrieve.
|
||||
* @param output The output pointer to store the loaded asset data.
|
||||
* @return An error code if the asset could not be loaded.
|
||||
*/
|
||||
errorret_t assetLoad(const char_t *filename, void *output);
|
||||
|
||||
/**
|
||||
* Disposes/cleans up the asset system.
|
||||
*/
|
||||
void assetDispose(void);
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "type/assettexture.h"
|
||||
#include "type/assetpalette.h"
|
||||
#include "type/assettileset.h"
|
||||
#include "type/assetlanguage.h"
|
||||
#include "type/assetscript.h"
|
||||
#include "type/assetmap.h"
|
||||
#include "type/assetmapchunk.h"
|
||||
#include <zip.h>
|
||||
|
||||
typedef enum {
|
||||
ASSET_TYPE_NULL,
|
||||
|
||||
ASSET_TYPE_TEXTURE,
|
||||
ASSET_TYPE_PALETTE,
|
||||
ASSET_TYPE_TILESET,
|
||||
ASSET_TYPE_LANGUAGE,
|
||||
ASSET_TYPE_SCRIPT,
|
||||
ASSET_TYPE_MAP,
|
||||
ASSET_TYPE_MAP_CHUNK,
|
||||
|
||||
ASSET_TYPE_COUNT,
|
||||
} assettype_t;
|
||||
|
||||
typedef enum {
|
||||
ASSET_LOAD_STRAT_ENTIRE,
|
||||
ASSET_LOAD_STRAT_CUSTOM
|
||||
} assetloadstrat_t;
|
||||
|
||||
typedef struct assetentire_s {
|
||||
void *data;
|
||||
void *output;
|
||||
} assetentire_t;
|
||||
|
||||
typedef struct assetcustom_s {
|
||||
zip_file_t *zipFile;
|
||||
void *output;
|
||||
} assetcustom_t;
|
||||
|
||||
typedef struct {
|
||||
const char_t *extension;
|
||||
const size_t dataSize;
|
||||
const assetloadstrat_t loadStrategy;
|
||||
union {
|
||||
errorret_t (*entire)(assetentire_t entire);
|
||||
errorret_t (*custom)(assetcustom_t custom);
|
||||
};
|
||||
} assettypedef_t;
|
||||
|
||||
static const assettypedef_t ASSET_TYPE_DEFINITIONS[ASSET_TYPE_COUNT] = {
|
||||
[ASSET_TYPE_NULL] = {
|
||||
0
|
||||
},
|
||||
|
||||
[ASSET_TYPE_TEXTURE] = {
|
||||
.extension = "dpt",
|
||||
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
||||
.dataSize = sizeof(assettexture_t),
|
||||
.entire = assetTextureLoad
|
||||
},
|
||||
|
||||
[ASSET_TYPE_PALETTE] = {
|
||||
.extension = "dpf",
|
||||
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
||||
.dataSize = sizeof(palette_t),
|
||||
.entire = assetPaletteLoad
|
||||
},
|
||||
|
||||
[ASSET_TYPE_TILESET] = {
|
||||
.extension = "dtf",
|
||||
.loadStrategy = ASSET_LOAD_STRAT_ENTIRE,
|
||||
.dataSize = sizeof(assettileset_t),
|
||||
.entire = assetTilesetLoad
|
||||
},
|
||||
|
||||
[ASSET_TYPE_LANGUAGE] = {
|
||||
.extension = "DLF",
|
||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||
.custom = assetLanguageHandler
|
||||
},
|
||||
|
||||
[ASSET_TYPE_SCRIPT] = {
|
||||
.extension = "lua",
|
||||
.loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||
.custom = assetScriptHandler
|
||||
},
|
||||
|
||||
// [ASSET_TYPE_MAP] = {
|
||||
// .extension = "DMF",
|
||||
// .loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||
// .custom = assetMapHandler
|
||||
// },
|
||||
|
||||
// [ASSET_TYPE_MAP_CHUNK] = {
|
||||
// .extension = "DMC",
|
||||
// .loadStrategy = ASSET_LOAD_STRAT_CUSTOM,
|
||||
// .custom = assetMapChunkHandler
|
||||
// },
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
# 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
|
||||
assetpalette.c
|
||||
assettileset.c
|
||||
assetlanguage.c
|
||||
assetscript.c
|
||||
assetmap.c
|
||||
assetmapchunk.c
|
||||
)
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 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 <zip.h>
|
||||
|
||||
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);
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 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 "util/memory.h"
|
||||
|
||||
errorret_t assetMapHandler(assetcustom_t custom) {
|
||||
printf("Map Loaded from asset!\n");
|
||||
errorOk();
|
||||
}
|
||||
@@ -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 "error/error.h"
|
||||
|
||||
typedef struct assetcustom_s assetcustom_t;
|
||||
|
||||
/**
|
||||
* Loads a map asset from the given data pointer into the output map structure.
|
||||
*
|
||||
* @param data Pointer to the raw assetmap_t data.
|
||||
* @param output Pointer to the map_t to load the map into.
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t assetMapHandler(assetcustom_t custom);
|
||||
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* 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 "map/mapchunk.h"
|
||||
#include "util/endian.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint32_t tileCount;
|
||||
uint8_t modelCount;
|
||||
uint8_t entityCount;
|
||||
} assetchunkheader_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
maptile_t tile;
|
||||
} assetchunktiledata_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint32_t vertexCount;
|
||||
} assetchunkmodelheader_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint8_t entityType;
|
||||
uint8_t localX;
|
||||
uint8_t localY;
|
||||
uint8_t localZ;
|
||||
} assetchunkentityheader_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
errorret_t assetMapChunkHandler(assetcustom_t custom) {
|
||||
assertNotNull(custom.output, "Output pointer cannot be NULL");
|
||||
assertNotNull(custom.zipFile, "Zip file pointer cannot be NULL");
|
||||
|
||||
mapchunk_t *chunk = (mapchunk_t *)custom.output;
|
||||
assertTrue(chunk->meshCount == 0, "Chunk is not in a good state");
|
||||
|
||||
// Read header
|
||||
assetchunkheader_t header;
|
||||
size_t bytesRead = zip_fread(
|
||||
custom.zipFile, &header, sizeof(assetchunkheader_t)
|
||||
);
|
||||
if(bytesRead != sizeof(assetchunkheader_t)) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow("Failed to read chunk asset header.");
|
||||
}
|
||||
|
||||
// Fix endianess if necessary
|
||||
header.tileCount = endianLittleToHost32(header.tileCount);
|
||||
|
||||
if(header.tileCount != CHUNK_TILE_COUNT) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow(
|
||||
"Chunk asset has invalid tile count: %d (expected %d).",
|
||||
header.tileCount,
|
||||
CHUNK_TILE_COUNT
|
||||
);
|
||||
}
|
||||
|
||||
if(header.modelCount > CHUNK_MESH_COUNT_MAX) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow(
|
||||
"Chunk asset has too many models: %d (max %d).",
|
||||
header.modelCount,
|
||||
CHUNK_MESH_COUNT_MAX
|
||||
);
|
||||
}
|
||||
|
||||
if(header.entityCount > CHUNK_ENTITY_COUNT_MAX) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow(
|
||||
"Chunk asset has too many entities: %d (max %d).",
|
||||
header.entityCount,
|
||||
CHUNK_ENTITY_COUNT_MAX
|
||||
);
|
||||
}
|
||||
|
||||
chunk->meshCount = header.modelCount;
|
||||
|
||||
// Read tile data
|
||||
bytesRead = zip_fread(
|
||||
custom.zipFile,
|
||||
chunk->tiles,
|
||||
sizeof(assetchunktiledata_t) * header.tileCount
|
||||
);
|
||||
if(bytesRead != sizeof(assetchunktiledata_t) * header.tileCount) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow("Failed to read chunk tile data.");
|
||||
}
|
||||
|
||||
// For each model...
|
||||
uint32_t vertexIndex = 0;
|
||||
for(uint8_t i = 0; i < header.modelCount; i++) {
|
||||
assetchunkmodelheader_t modelHeader;
|
||||
bytesRead = zip_fread(
|
||||
custom.zipFile, &modelHeader, sizeof(assetchunkmodelheader_t)
|
||||
);
|
||||
if(bytesRead != sizeof(assetchunkmodelheader_t)) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow("Failed to read chunk model header.");
|
||||
}
|
||||
|
||||
// Fix endianess if necessary
|
||||
modelHeader.vertexCount = endianLittleToHost32(modelHeader.vertexCount);
|
||||
|
||||
if(
|
||||
vertexIndex + modelHeader.vertexCount >
|
||||
CHUNK_VERTEX_COUNT_MAX
|
||||
) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow("Chunk model vertex count exceeds maximum.");
|
||||
}
|
||||
|
||||
// Read vertex data.
|
||||
bytesRead = zip_fread(
|
||||
custom.zipFile,
|
||||
&chunk->vertices[vertexIndex],
|
||||
sizeof(meshvertex_t) * modelHeader.vertexCount
|
||||
);
|
||||
if(bytesRead != sizeof(meshvertex_t) * modelHeader.vertexCount) {
|
||||
zip_fclose(custom.zipFile);
|
||||
errorThrow("Failed to read chunk model vertex data.");
|
||||
}
|
||||
|
||||
// Init the mesh
|
||||
if(modelHeader.vertexCount > 0) {
|
||||
mesh_t *mesh = &chunk->meshes[i];
|
||||
meshInit(
|
||||
mesh,
|
||||
MESH_PRIMITIVE_TRIANGLES,
|
||||
modelHeader.vertexCount,
|
||||
&chunk->vertices[vertexIndex]
|
||||
);
|
||||
|
||||
vertexIndex += modelHeader.vertexCount;
|
||||
} else {
|
||||
chunk->meshes[i].vertexCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Read entity data
|
||||
// for(uint8_t i = 0; i < header.entityCount; i++) {
|
||||
// assetchunkentityheader_t entityHeader;
|
||||
// bytesRead = zip_fread(
|
||||
// custom.zipFile, &entityHeader, sizeof(assetchunkentityheader_t)
|
||||
// );
|
||||
// if(bytesRead != sizeof(assetchunkentityheader_t)) {
|
||||
// zip_fclose(custom.zipFile);
|
||||
// errorThrow("Failed to read chunk entity header.");
|
||||
// }
|
||||
|
||||
// uint8_t entityIndex = entityGetAvailable();
|
||||
// if(entityIndex == 0xFF) {
|
||||
// zip_fclose(custom.zipFile);
|
||||
// errorThrow("No available entity slots.");
|
||||
// }
|
||||
|
||||
// entity_t *entity = &ENTITIES[entityIndex];
|
||||
// entityInit(entity, (entitytype_t)entityHeader.entityType);
|
||||
// entity->position.x = (
|
||||
// (chunk->position.x * CHUNK_WIDTH) + entityHeader.localX
|
||||
// );
|
||||
// entity->position.y = (
|
||||
// (chunk->position.y * CHUNK_HEIGHT) + entityHeader.localY
|
||||
// );
|
||||
// entity->position.z = (
|
||||
// (chunk->position.z * CHUNK_DEPTH) + entityHeader.localZ
|
||||
// );
|
||||
|
||||
// chunk->entities[i] = entityIndex;
|
||||
// }
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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 assetcustom_s assetcustom_t;
|
||||
|
||||
/**
|
||||
* Handles loading of map chunk data from a map chunk asset file.
|
||||
*
|
||||
* @param custom The custom asset loading parameters.
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t assetMapChunkHandler(assetcustom_t custom);
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assetpalette.h"
|
||||
#include "asset/assettype.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
errorret_t assetPaletteLoad(assetentire_t entire) {
|
||||
assertNotNull(entire.data, "Data pointer cannot be NULL.");
|
||||
assertNotNull(entire.output, "Output pointer cannot be NULL.");
|
||||
|
||||
assetpalette_t *assetData = (assetpalette_t *)entire.data;
|
||||
palette_t *palette = (palette_t *)entire.output;
|
||||
|
||||
// Read header and version (first 4 bytes)
|
||||
if(
|
||||
assetData->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();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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);
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* 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 <zip.h>
|
||||
#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);
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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] != 'P' ||
|
||||
assetData->header[2] != 'T'
|
||||
) {
|
||||
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");
|
||||
}
|
||||
|
||||
textureInit(
|
||||
texture,
|
||||
assetData->width,
|
||||
assetData->height,
|
||||
TEXTURE_FORMAT_PALETTE,
|
||||
(texturedata_t){
|
||||
.paletteData = assetData->palette
|
||||
}
|
||||
);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error/error.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;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint8_t palette[ASSET_TEXTURE_SIZE_MAX];
|
||||
} 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);
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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);
|
||||
Reference in New Issue
Block a user