Asset compartmentalized
This commit is contained in:
@@ -14,208 +14,14 @@
|
|||||||
#include "debug/debug.h"
|
#include "debug/debug.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
|
||||||
|
asset_t ASSET;
|
||||||
|
|
||||||
errorret_t assetInit(void) {
|
errorret_t assetInit(void) {
|
||||||
memoryZero(&ASSET, sizeof(asset_t));
|
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?
|
// assetInitPlatform must either define ASSET.zip or throw an error.
|
||||||
if(ASSET.zip == NULL) errorThrow("Failed to open asset file.");
|
errorChain(assetInitPlatform());
|
||||||
|
assertNotNull(ASSET.zip, "Asset zip null without error.");
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
@@ -330,16 +136,14 @@ errorret_t assetLoad(const char_t *filename, void *output) {
|
|||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
void assetDispose(void) {
|
errorret_t assetDispose(void) {
|
||||||
if(ASSET.zip != NULL) {
|
if(ASSET.zip != NULL) {
|
||||||
zip_close(ASSET.zip);
|
if(zip_close(ASSET.zip) != 0) {
|
||||||
|
errorThrow("Failed to close asset zip archive.");
|
||||||
|
}
|
||||||
ASSET.zip = NULL;
|
ASSET.zip = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PSP
|
errorChain(assetDisposePlatform());
|
||||||
if(ASSET.pbpFile != NULL) {
|
errorOk();
|
||||||
fclose(ASSET.pbpFile);
|
|
||||||
ASSET.pbpFile = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
@@ -8,83 +8,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "error/error.h"
|
#include "error/error.h"
|
||||||
#include "assettype.h"
|
#include "assettype.h"
|
||||||
|
#include "asset/assetplatform.h"
|
||||||
|
|
||||||
#if PSP
|
#ifndef assetInitPlatform
|
||||||
#define ASSET_PBP_READ_PBP_FROM_HOST 0
|
#error "Platform must define assetInitPlatform function."
|
||||||
#define ASSET_PBP_SIGNATURE_SIZE 4
|
#endif
|
||||||
#define ASSET_PBP_SIGNATURE "\0PBP"
|
#ifndef assetDisposePlatform
|
||||||
|
#error "Platform must define assetDisposePlatform function."
|
||||||
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
|
#endif
|
||||||
|
|
||||||
#define ASSET_FILE "dusk.dsk"
|
#define ASSET_FILE_NAME "dusk.dsk"
|
||||||
#define ASSET_HEADER_SIZE 3
|
#define ASSET_HEADER_SIZE 3
|
||||||
|
|
||||||
static const char_t *ASSET_SEARCH_PATHS[] = {
|
|
||||||
"%s/%s",
|
|
||||||
"%s",
|
|
||||||
"../%s",
|
|
||||||
"../../%s",
|
|
||||||
"data/%s",
|
|
||||||
"../data/%s",
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
zip_t *zip;
|
zip_t *zip;
|
||||||
char_t systemPath[FILENAME_MAX];
|
assetplatform_t platform;
|
||||||
uint8_t assetCount;
|
|
||||||
|
|
||||||
// PSP specific information.
|
|
||||||
#if PSP
|
|
||||||
FILE *pbpFile;
|
|
||||||
assetpbp_t pbpHeader;
|
|
||||||
#endif
|
|
||||||
} asset_t;
|
} asset_t;
|
||||||
|
|
||||||
static asset_t ASSET;
|
extern asset_t ASSET;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the asset system.
|
* Initializes the asset system.
|
||||||
@@ -110,5 +51,7 @@ errorret_t assetLoad(const char_t *filename, void *output);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Disposes/cleans up the asset system.
|
* Disposes/cleans up the asset system.
|
||||||
|
*
|
||||||
|
* @return An error code if the asset system could not be disposed properly.
|
||||||
*/
|
*/
|
||||||
void assetDispose(void);
|
errorret_t assetDispose(void);
|
||||||
@@ -77,6 +77,6 @@ errorret_t engineDispose(void) {
|
|||||||
localeManagerDispose();
|
localeManagerDispose();
|
||||||
uiDispose();
|
uiDispose();
|
||||||
errorChain(displayDispose());
|
errorChain(displayDispose());
|
||||||
assetDispose();
|
errorChain(assetDispose());
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
53
src/duskdolphin/asset/assetdolphin.c
Normal file
53
src/duskdolphin/asset/assetdolphin.c
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
// 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();
|
||||||
37
src/duskdolphin/asset/assetdolphin.h
Normal file
37
src/duskdolphin/asset/assetdolphin.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#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
|
||||||
|
};
|
||||||
@@ -10,4 +10,5 @@ target_include_directories(${DUSK_LIBRARY_TARGET_NAME}
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Subdirs
|
# Subdirs
|
||||||
|
add_subdirectory(asset)
|
||||||
add_subdirectory(debug)
|
add_subdirectory(debug)
|
||||||
10
src/dusklinux/asset/CMakeLists.txt
Normal file
10
src/dusklinux/asset/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# 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
|
||||||
|
assetlinux.c
|
||||||
|
)
|
||||||
81
src/dusklinux/asset/assetlinux.c
Normal file
81
src/dusklinux/asset/assetlinux.c
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "asset/asset.h"
|
||||||
|
#include "engine/engine.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
|
||||||
|
errorret_t assetInitLinux(void) {
|
||||||
|
// 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.platform.systemPath, buffer, FILENAME_MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default system path, intended to be overridden by the platform
|
||||||
|
stringCopy(ASSET.platform.systemPath, ".", FILENAME_MAX);
|
||||||
|
|
||||||
|
// Open zip file
|
||||||
|
char_t searchPath[FILENAME_MAX];
|
||||||
|
const char_t **path = ASSET_LINUX_SEARCH_PATHS;
|
||||||
|
int32_t error;
|
||||||
|
do {
|
||||||
|
sprintf(
|
||||||
|
searchPath,
|
||||||
|
*path,
|
||||||
|
ASSET.platform.systemPath,
|
||||||
|
ASSET_FILE_NAME
|
||||||
|
);
|
||||||
|
|
||||||
|
// Try open
|
||||||
|
ASSET.zip = zip_open(searchPath, ZIP_RDONLY, &error);
|
||||||
|
if(ASSET.zip == NULL) continue;
|
||||||
|
if(error != 0) {
|
||||||
|
printf("Warning: Opened asset file with non-zero error code: %d\n", error);
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t assetDisposeLinux(void) {
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
37
src/dusklinux/asset/assetlinux.h
Normal file
37
src/dusklinux/asset/assetlinux.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "error/error.h"
|
||||||
|
|
||||||
|
static const char_t *ASSET_LINUX_SEARCH_PATHS[] = {
|
||||||
|
"%s/%s",
|
||||||
|
"%s",
|
||||||
|
"../%s",
|
||||||
|
"../../%s",
|
||||||
|
"data/%s",
|
||||||
|
"../data/%s",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char_t systemPath[FILENAME_MAX];
|
||||||
|
} assetlinux_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the asset system on Linux.
|
||||||
|
*
|
||||||
|
* @return Error state if failed, otherwise returns success.
|
||||||
|
*/
|
||||||
|
errorret_t assetInitLinux(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the asset system on Linux.
|
||||||
|
*
|
||||||
|
* @return Error state if failed, otherwise returns success.
|
||||||
|
*/
|
||||||
|
errorret_t assetDisposeLinux(void);
|
||||||
13
src/dusklinux/asset/assetplatform.h
Normal file
13
src/dusklinux/asset/assetplatform.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "asset/assetlinux.h"
|
||||||
|
|
||||||
|
typedef assetlinux_t assetplatform_t;
|
||||||
|
#define assetInitPlatform assetInitLinux
|
||||||
|
#define assetDisposePlatform assetDisposeLinux
|
||||||
87
src/duskpsp/asset/assetpbp.c
Normal file
87
src/duskpsp/asset/assetpbp.c
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
31
src/duskpsp/asset/assetpbp.h
Normal file
31
src/duskpsp/asset/assetpbp.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
|
||||||
|
#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;
|
||||||
|
} assetpbpheader_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FILE *pbpFile;
|
||||||
|
assetpbpheader_t pbpHeader;
|
||||||
|
} assetpbp_t;
|
||||||
@@ -48,10 +48,6 @@ errorret_t displaySDL2Init(void) {
|
|||||||
errorChain(errorGLCheck());
|
errorChain(errorGLCheck());
|
||||||
|
|
||||||
errorChain(displayOpenGLInit());
|
errorChain(displayOpenGLInit());
|
||||||
|
|
||||||
// #if DUSK_PSP
|
|
||||||
// errorChain(displayPSPInit());
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
errorChain(errorGLCheck());
|
errorChain(errorGLCheck());
|
||||||
errorOk();
|
errorOk();
|
||||||
|
|||||||
Reference in New Issue
Block a user