Refactor asset loading
This commit is contained in:
@@ -6,9 +6,8 @@
|
||||
# Sources
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
# asset.c
|
||||
# assetmanager.c
|
||||
asset.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
# add_subdirectory(type)
|
||||
add_subdirectory(type)
|
||||
@@ -9,22 +9,23 @@
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
#include "assert/assert.h"
|
||||
#include "asset/assettype.h"
|
||||
|
||||
errorret_t assetInit(void) {
|
||||
memoryZero(&ASSET_MANAGER, sizeof(assetmanager_t));
|
||||
|
||||
// Default system path, intended to be overridden by the paltform
|
||||
stringCopy(ASSET_MANAGER.systemPath, ".", FILENAME_MAX);
|
||||
memoryZero(&ASSET, sizeof(asset_t));
|
||||
|
||||
// Default system path, intended to be overridden by the platform
|
||||
stringCopy(ASSET.systemPath, ".", FILENAME_MAX);
|
||||
|
||||
// Open zip file
|
||||
char_t searchPath[FILENAME_MAX];
|
||||
char_t **path = ASSET_SEARCH_PATHS;
|
||||
const char_t **path = ASSET_SEARCH_PATHS;
|
||||
do {
|
||||
sprintf(
|
||||
searchPath,
|
||||
*path,
|
||||
ASSET_MANAGER.systemPath,
|
||||
ASSET_ASSET_FILE
|
||||
ASSET.systemPath,
|
||||
ASSET_FILE
|
||||
);
|
||||
|
||||
// Try open
|
||||
@@ -39,13 +40,61 @@ errorret_t assetInit(void) {
|
||||
errorOk();
|
||||
}
|
||||
|
||||
erroret_t assetLoad(const char_t *filename, void *output) {
|
||||
errorret_t assetLoad(const char_t *filename, void *output) {
|
||||
assertStrLenMax(filename, FILENAME_MAX, "Filename too long.");
|
||||
assertNotNull(output, "Output pointer cannot be NULL.");
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Read the header.
|
||||
assetheader_t header;
|
||||
memoryZero(&header, sizeof(assetheader_t));
|
||||
zip_int64_t bytesRead = zip_fread(file, &header, sizeof(assetheader_t));
|
||||
if(bytesRead != sizeof(assetheader_t)) {
|
||||
zip_fclose(file);
|
||||
errorThrow("Failed to read asset header for: %s", filename);
|
||||
}
|
||||
|
||||
// Find the asset type based on the header
|
||||
const assettypedef_t *def = NULL;
|
||||
for(uint_fast8_t i = 0; i < ASSET_TYPE_COUNT; i++) {
|
||||
if(ASSET_TYPE_DEFINITIONS[i].header == NULL) continue;
|
||||
if(strcmp(header.header, ASSET_TYPE_DEFINITIONS[i].header) != 0) continue;
|
||||
def = &ASSET_TYPE_DEFINITIONS[i];
|
||||
break;
|
||||
}
|
||||
if(def == NULL) {
|
||||
zip_fclose(file);
|
||||
errorThrow("Unknown asset type for file: %s", filename);
|
||||
}
|
||||
|
||||
// We found the asset type, now load the asset data
|
||||
assertNotNull(def->load, "Asset load function cannot be NULL.");
|
||||
void *data = memoryAllocate(def->dataSize);
|
||||
bytesRead = zip_fread(file, data, def->dataSize);
|
||||
if(bytesRead == 0 || bytesRead > def->dataSize) {
|
||||
memoryFree(data);
|
||||
zip_fclose(file);
|
||||
errorThrow("Failed to read asset data for file: %s", filename);
|
||||
}
|
||||
|
||||
// Close the file now we have the data
|
||||
zip_fclose(file);
|
||||
|
||||
// Pass to the asset type loader
|
||||
errorret_t ret = def->load(data, output);
|
||||
memoryFree(data);
|
||||
errorChain(ret);
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void assetDispose(void) {
|
||||
if(ASSET_MANAGER.zip != NULL) {
|
||||
zip_close(ASSET_MANAGER.zip);
|
||||
ASSET_MANAGER.zip = NULL;
|
||||
if(ASSET.zip != NULL) {
|
||||
zip_close(ASSET.zip);
|
||||
ASSET.zip = NULL;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,12 @@ static const char_t *ASSET_SEARCH_PATHS[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
char_t header[3];
|
||||
} assetheader_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct {
|
||||
zip_t *zip;
|
||||
char_t systemPath[FILENAME_MAX];
|
||||
|
||||
41
src/asset/assettype.h
Normal file
41
src/asset/assettype.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "type/assetpaletteimage.h"
|
||||
#include "type/assetalphaimage.h"
|
||||
|
||||
typedef enum {
|
||||
ASSET_TYPE_NULL,
|
||||
ASSET_TYPE_PALETTE_IMAGE,
|
||||
ASSET_TYPE_ALPHA_IMAGE,
|
||||
ASSET_TYPE_COUNT,
|
||||
} assettype_t;
|
||||
|
||||
typedef struct {
|
||||
const char_t *header;
|
||||
const size_t dataSize;
|
||||
errorret_t (*load)(void *data, void *output);
|
||||
} assettypedef_t;
|
||||
|
||||
static const assettypedef_t ASSET_TYPE_DEFINITIONS[ASSET_TYPE_COUNT] = {
|
||||
[ASSET_TYPE_NULL] = {
|
||||
0
|
||||
},
|
||||
|
||||
[ASSET_TYPE_PALETTE_IMAGE] = {
|
||||
.header = "DPI",
|
||||
.dataSize = sizeof(assetpaletteimage_t),
|
||||
.load = assetPaletteImageLoad
|
||||
},
|
||||
|
||||
[ASSET_TYPE_ALPHA_IMAGE] = {
|
||||
.header = "DAI",
|
||||
.dataSize = sizeof(assetalphaimage_t),
|
||||
.load = assetAlphaImageLoad
|
||||
},
|
||||
};
|
||||
11
src/asset/type/CMakeLists.txt
Normal file
11
src/asset/type/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
# 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
|
||||
assetalphaimage.c
|
||||
assetpaletteimage.c
|
||||
)
|
||||
28
src/asset/type/assetalphaimage.c
Normal file
28
src/asset/type/assetalphaimage.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assetalphaimage.h"
|
||||
#include "assert/assert.h"
|
||||
#include "display/texture.h"
|
||||
|
||||
errorret_t assetAlphaImageLoad(void *data, void *output) {
|
||||
assertNotNull(data, "Data pointer cannot be NULL.");
|
||||
assertNotNull(output, "Output pointer cannot be NULL.");
|
||||
|
||||
assetalphaimage_t *dataPtr = (assetalphaimage_t *)data;
|
||||
texture_t *outputPtr = (texture_t *)output;
|
||||
|
||||
textureInit(
|
||||
outputPtr,
|
||||
dataPtr->width,
|
||||
dataPtr->height,
|
||||
TEXTURE_FORMAT_ALPHA,
|
||||
(texturedata_t){ .alpha = { .data = dataPtr->pixels } }
|
||||
);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
32
src/asset/type/assetalphaimage.h
Normal file
32
src/asset/type/assetalphaimage.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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_ALPHA_IMAGE_WIDTH_MAX 256
|
||||
#define ASSET_ALPHA_IMAGE_HEIGHT_MAX 256
|
||||
#define ASSET_ALPHA_IMAGE_SIZE_MAX ( \
|
||||
ASSET_ALPHA_IMAGE_WIDTH_MAX * ASSET_ALPHA_IMAGE_HEIGHT_MAX \
|
||||
)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint8_t pixels[ASSET_ALPHA_IMAGE_SIZE_MAX];
|
||||
} assetalphaimage_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
/**
|
||||
* Loads an alpha image asset from the given asset structure. The asset must
|
||||
* be of type ASSET_TYPE_ALPHA_IMAGE and must be loaded.
|
||||
*
|
||||
* @param asset The asset to load the alpha image from.
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t assetAlphaImageLoad(void *data, void *output);
|
||||
33
src/asset/type/assetpaletteimage.c
Normal file
33
src/asset/type/assetpaletteimage.c
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "assetpaletteimage.h"
|
||||
#include "assert/assert.h"
|
||||
#include "display/texture.h"
|
||||
|
||||
errorret_t assetPaletteImageLoad(void *data, void *output) {
|
||||
assertNotNull(data, "Data pointer cannot be NULL.");
|
||||
assertNotNull(output, "Output pointer cannot be NULL.");
|
||||
|
||||
assetpaletteimage_t *assetData = (assetpaletteimage_t *)data;
|
||||
texture_t *texture = (texture_t *)output;
|
||||
|
||||
textureInit(
|
||||
texture,
|
||||
assetData->width,
|
||||
assetData->height,
|
||||
TEXTURE_FORMAT_PALETTE,
|
||||
(texturedata_t){
|
||||
.palette = {
|
||||
.palette = assetData->paletteIndex,
|
||||
.data = assetData->palette
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
34
src/asset/type/assetpaletteimage.h
Normal file
34
src/asset/type/assetpaletteimage.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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_PALETTE_IMAGE_WIDTH_MAX 128
|
||||
#define ASSET_PALETTE_IMAGE_HEIGHT_MAX 128
|
||||
#define ASSET_PALETTE_IMAGE_SIZE_MAX ( \
|
||||
ASSET_PALETTE_IMAGE_WIDTH_MAX * ASSET_PALETTE_IMAGE_HEIGHT_MAX \
|
||||
)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint8_t paletteIndex;
|
||||
uint8_t palette[ASSET_PALETTE_IMAGE_SIZE_MAX];
|
||||
} assetpaletteimage_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
/**
|
||||
* Loads a palette image asset from the given data pointer into the output
|
||||
* texture.
|
||||
*
|
||||
* @param data Pointer to the raw assetpaletteimage_t data.
|
||||
* @param output Pointer to the texture_t to load the image into.
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t assetPaletteImageLoad(void *data, void *output);
|
||||
@@ -12,15 +12,12 @@
|
||||
#include "locale/localemanager.h"
|
||||
#include "display/display.h"
|
||||
#include "scene/scenemanager.h"
|
||||
#include "asset/assetmanager.h"
|
||||
#include "asset/asset.h"
|
||||
#include "ui/ui.h"
|
||||
#include "rpg/rpg.h"
|
||||
|
||||
engine_t ENGINE;
|
||||
|
||||
asset_t *outAsset;
|
||||
ref_t outRef;
|
||||
|
||||
errorret_t engineInit(void) {
|
||||
memoryZero(&ENGINE, sizeof(engine_t));
|
||||
ENGINE.running = true;
|
||||
@@ -29,7 +26,7 @@ errorret_t engineInit(void) {
|
||||
timeInit();
|
||||
inputInit();
|
||||
localeManagerInit();
|
||||
errorChain(assetManagerInit());
|
||||
errorChain(assetInit());
|
||||
errorChain(displayInit());
|
||||
errorChain(uiInit());
|
||||
errorChain(rpgInit());
|
||||
@@ -41,7 +38,6 @@ errorret_t engineInit(void) {
|
||||
errorret_t engineUpdate(void) {
|
||||
timeUpdate();
|
||||
inputUpdate();
|
||||
assetManagerUpdate();
|
||||
|
||||
rpgUpdate();
|
||||
uiUpdate();
|
||||
@@ -62,6 +58,6 @@ errorret_t engineDispose(void) {
|
||||
rpgDispose();
|
||||
uiDispose();
|
||||
errorChain(displayDispose());
|
||||
assetManagerDispose();
|
||||
assetDispose();
|
||||
errorOk();
|
||||
}
|
||||
22
src/ui/ui.c
22
src/ui/ui.c
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "ui.h"
|
||||
#include "assert/assert.h"
|
||||
#include "ui/uifps.h"
|
||||
#include "util/memory.h"
|
||||
#include "display/tileset/tileset_minogram.h"
|
||||
@@ -36,26 +37,29 @@ void uiRender(void) {
|
||||
cameraPushMatrix(&UI.camera);
|
||||
|
||||
// Render UI elements here
|
||||
if(UI.font) {
|
||||
uiFPSRender(UI.fontTileset, &UI.font->alphaImage.texture);
|
||||
if(UI.fontTexture.width > 0) {
|
||||
uiFPSRender(UI.fontTileset, &UI.fontTexture);
|
||||
}
|
||||
|
||||
cameraPopMatrix();
|
||||
}
|
||||
|
||||
errorret_t uiSetFont(const tileset_t *fontTileset) {
|
||||
if(UI.font) {
|
||||
assetUnlock(UI.font, UI.fontRef);
|
||||
UI.font = NULL;
|
||||
if(UI.fontTexture.width > 0) {
|
||||
textureDispose(&UI.fontTexture);
|
||||
UI.fontTexture.width = -1;
|
||||
}
|
||||
|
||||
assertNotNull(fontTileset, "Font tileset cannot be NULL.");
|
||||
|
||||
UI.fontTileset = fontTileset;
|
||||
assetManagerLoadAsset(fontTileset->image, &UI.font, &UI.fontRef);
|
||||
errorChain(assetLoad(UI.fontTileset->image, &UI.fontTexture));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void uiDispose(void) {
|
||||
if(UI.font) {
|
||||
assetUnlock(UI.font, UI.fontRef);
|
||||
UI.font = NULL;
|
||||
if(UI.fontTexture.width > 0) {
|
||||
textureDispose(&UI.fontTexture);
|
||||
UI.fontTexture.width = -1;
|
||||
}
|
||||
}
|
||||
@@ -6,16 +6,14 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "asset/asset.h"
|
||||
#include "display/texture.h"
|
||||
#include "display/tileset/tileset.h"
|
||||
#include "display/camera.h"
|
||||
|
||||
typedef struct {
|
||||
camera_t camera;
|
||||
|
||||
ref_t fontRef;
|
||||
asset_t *font;
|
||||
texture_t fontTexture;
|
||||
const tileset_t *fontTileset;
|
||||
} ui_t;
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
// */
|
||||
|
||||
#include "uitext.h"
|
||||
#include "asset/assetmanager.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
#include "display/spritebatch.h"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "asset/asset.h"
|
||||
#include "display/texture.h"
|
||||
#include "display/tileset/tileset_minogram.h"
|
||||
|
||||
#define UI_TEXT_CHAR_START '!'
|
||||
|
||||
@@ -9,5 +9,4 @@ target_sources(${DUSK_TARGET_NAME}
|
||||
memory.c
|
||||
string.c
|
||||
math.c
|
||||
reflist.c
|
||||
)
|
||||
@@ -1,86 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "reflist.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
void refListInit(
|
||||
reflist_t *list,
|
||||
ref_t *array,
|
||||
const uint_fast16_t max
|
||||
) {
|
||||
assertNotNull(list, "Reference list cannot be NULL");
|
||||
assertNotNull(array, "Reference array cannot be NULL");
|
||||
assertTrue(max > 0, "Reference list max must be greater than 0");
|
||||
assertTrue(max <= UINT16_MAX, "Reference list too large");
|
||||
|
||||
memoryZero(list, sizeof(reflist_t));
|
||||
memoryZero(array, sizeof(ref_t) * max);
|
||||
|
||||
list->array = array;
|
||||
list->max = max;
|
||||
}
|
||||
|
||||
ref_t refListLock(reflist_t *list) {
|
||||
assertFalse(refListIsFull(list), "Reference list is full");
|
||||
|
||||
ref_t ref = list->refNext++;
|
||||
assertTrue(ref >= 0, "Reference ID overflow");
|
||||
assertTrue(ref < UINT16_MAX, "Reference ID too large.");
|
||||
|
||||
bool_t empty = list->onNotEmpty && refListIsEmpty(list);
|
||||
|
||||
list->array[list->count++] = ref;
|
||||
|
||||
if(empty) list->onNotEmpty(list);
|
||||
if(list->onAdd) list->onAdd(list, ref);
|
||||
if(list->onFull && refListIsFull(list)) list->onFull(list);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
void refListUnlock(reflist_t *list, const ref_t ref) {
|
||||
assertFalse(refListIsEmpty(list), "Reference list is empty");
|
||||
|
||||
ref_t *slot = list->array;
|
||||
ref_t *end = list->array + list->count;
|
||||
|
||||
do {
|
||||
if(*slot == ref) break;
|
||||
++slot;
|
||||
} while(slot < end);
|
||||
|
||||
assertTrue(slot < end, "Reference not found in list");
|
||||
|
||||
// Can't move if list only has one ref
|
||||
if(list->count > 1) {
|
||||
memoryMove(slot, slot + 1, (end - slot - 1) * sizeof(ref_t));
|
||||
}
|
||||
|
||||
list->count--;
|
||||
if(list->onRemove) list->onRemove(list, ref);
|
||||
if(list->onEmpty && refListIsEmpty(list)) list->onEmpty(list);
|
||||
}
|
||||
|
||||
bool_t refListIsFull(const reflist_t *list) {
|
||||
assertNotNull(list, "Reference list cannot be NULL");
|
||||
assertNotNull(list->array, "Reference list array cannot be NULL");
|
||||
assertTrue(list->max > 0, "Reference list max must be greater than 0");
|
||||
assertTrue(list->max <= UINT16_MAX, "Reference list too large");
|
||||
|
||||
return (list->count >= list->max);
|
||||
}
|
||||
|
||||
bool_t refListIsEmpty(const reflist_t *list) {
|
||||
assertNotNull(list, "Reference list cannot be NULL");
|
||||
assertNotNull(list->array, "Reference list array cannot be NULL");
|
||||
assertTrue(list->max > 0, "Reference list max must be greater than 0");
|
||||
assertTrue(list->max <= UINT16_MAX, "Reference list too large");
|
||||
|
||||
return (list->count == 0);
|
||||
}
|
||||
@@ -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 "dusk.h"
|
||||
|
||||
typedef uint_fast16_t ref_t;
|
||||
|
||||
typedef struct reflist_s reflist_t;
|
||||
|
||||
typedef struct reflist_s {
|
||||
ref_t *array;
|
||||
uint_fast16_t max;
|
||||
uint_fast16_t count;
|
||||
ref_t refNext;
|
||||
|
||||
void *user;
|
||||
|
||||
void (*onNotEmpty)(reflist_t *list);
|
||||
void (*onFull)(reflist_t *list);
|
||||
void (*onAdd)(reflist_t *list, const ref_t ref);
|
||||
void (*onRemove)(reflist_t *list, const ref_t ref);
|
||||
void (*onEmpty)(reflist_t *list);
|
||||
} reflist_t;
|
||||
|
||||
/**
|
||||
* Initialize a reference list. Reference lists just hold a list of references
|
||||
* that are "holding on to" a given object/resource.
|
||||
*
|
||||
* @param list The reference list to initialize.
|
||||
* @param array The array to use as backing storage for the list.
|
||||
* @param max The maximum number of references the list can hold.
|
||||
*/
|
||||
void refListInit(
|
||||
reflist_t *list,
|
||||
ref_t *array,
|
||||
const uint_fast16_t max
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Lock a reference in the list. This will return a new reference ID that can be
|
||||
* used to access the locked reference.
|
||||
*
|
||||
* @param list The reference list to lock a reference in.
|
||||
* @return The locked reference ID, or 0 if the list is full.
|
||||
*/
|
||||
ref_t refListLock(reflist_t *list);
|
||||
|
||||
/**
|
||||
* Unlock a reference in the list. This will free up the reference ID for
|
||||
* reuse.
|
||||
*
|
||||
* @param list The reference list to unlock a reference in.
|
||||
* @param ref The reference ID to unlock.
|
||||
*/
|
||||
void refListUnlock(reflist_t *list, const ref_t ref);
|
||||
|
||||
/**
|
||||
* Checks if the reference list is full.
|
||||
*
|
||||
* @param list The reference list to check.
|
||||
* @return true if the list is full, false otherwise.
|
||||
*/
|
||||
bool_t refListIsFull(const reflist_t *list);
|
||||
|
||||
/**
|
||||
* Checks if the reference list is empty.
|
||||
*
|
||||
* @param list The reference list to check.
|
||||
* @return true if the list is empty, false otherwise.
|
||||
*/
|
||||
bool_t refListIsEmpty(const reflist_t *list);
|
||||
Reference in New Issue
Block a user