Renders on PSP identically.
This commit is contained in:
11
src/duskpsp/asset/CMakeLists.txt
Normal file
11
src/duskpsp/asset/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
# 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
|
||||
assetpbp.c
|
||||
assetpsp.c
|
||||
)
|
||||
@@ -1,87 +1,113 @@
|
||||
assertTrue(ENGINE.argc >= 1, "PSP requires launch argument.");
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
// 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);
|
||||
}
|
||||
#include "asset/asset.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
// 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);
|
||||
errorret_t assetInitPBP(const char_t *pbpPath) {
|
||||
assertNotNull(pbpPath, "PBP path cannot be null.");
|
||||
assertStrLenMin(pbpPath, 1, "PBP path cannot be empty.");
|
||||
assertStrLenMax(pbpPath, FILENAME_MAX, "PBP path is too long.");
|
||||
|
||||
// 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);
|
||||
}
|
||||
ASSET.platform.pbpFile = fopen(pbpPath, "rb");
|
||||
if(ASSET.platform.pbpFile == NULL) {
|
||||
errorThrow("Failed to open 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);
|
||||
}
|
||||
// Get size of PBP file.
|
||||
if(fseek(ASSET.platform.pbpFile, 0, SEEK_END) != 0) {
|
||||
fclose(ASSET.platform.pbpFile);
|
||||
errorThrow("Failed to seek to end of PBP 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);
|
||||
}
|
||||
size_t pbpSize = ftell(ASSET.platform.pbpFile);
|
||||
if(pbpSize == -1L) {
|
||||
fclose(ASSET.platform.pbpFile);
|
||||
errorThrow("Failed to get size of 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
|
||||
);
|
||||
if(pbpSize < sizeof(assetpbpheader_t)) {
|
||||
fclose(ASSET.platform.pbpFile);
|
||||
errorThrow("PBP file is too small to be valid: %s", pbpPath);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
// Rewind to start
|
||||
if(fseek(ASSET.platform.pbpFile, 0, SEEK_SET) != 0) {
|
||||
fclose(ASSET.platform.pbpFile);
|
||||
errorThrow("Failed to seek to start of PBP file : %s", pbpPath);
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
// Read the PBP header
|
||||
size_t read = fread(
|
||||
&ASSET.platform.pbpHeader,
|
||||
1,
|
||||
sizeof(assetpbpheader_t),
|
||||
ASSET.platform.pbpFile
|
||||
);
|
||||
if(read != sizeof(assetpbpheader_t)) {
|
||||
fclose(ASSET.platform.pbpFile);
|
||||
errorThrow("Failed to read PBP header", pbpPath);
|
||||
}
|
||||
|
||||
if(memoryCompare(
|
||||
ASSET.platform.pbpHeader.signature,
|
||||
ASSET_PBP_SIGNATURE,
|
||||
sizeof(ASSET_PBP_SIGNATURE)
|
||||
) != 0) {
|
||||
fclose(ASSET.platform.pbpFile);
|
||||
errorThrow("Invalid PBP signature in file: %s", pbpPath);
|
||||
}
|
||||
|
||||
// If we seek to the PSAR offset, we can read the WAD file from there.
|
||||
// I'm not sure what PSAR was intended for, but it holds any user data we
|
||||
// want, so I shoved the entire dusk wad there.
|
||||
if(fseek(
|
||||
ASSET.platform.pbpFile, ASSET.platform.pbpHeader.psarOffset, SEEK_SET
|
||||
) != 0) {
|
||||
fclose(ASSET.platform.pbpFile);
|
||||
errorThrow("Failed to seek to PSAR offset in PBP file: %s", pbpPath);
|
||||
}
|
||||
|
||||
zip_uint64_t zipPsarOffset = (zip_uint64_t)ASSET.platform.pbpHeader.psarOffset;
|
||||
zip_int64_t zipPsarSize = (zip_int64_t)(
|
||||
pbpSize - ASSET.platform.pbpHeader.psarOffset
|
||||
);
|
||||
|
||||
zip_source_t *psarSource = zip_source_filep_create(
|
||||
ASSET.platform.pbpFile,
|
||||
zipPsarOffset,
|
||||
zipPsarSize,
|
||||
NULL
|
||||
);
|
||||
if(psarSource == NULL) {
|
||||
fclose(ASSET.platform.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.platform.pbpFile);
|
||||
errorThrow("Failed to open zip from PBP file: %s", pbpPath);
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t assetDisposePBP(void) {
|
||||
if(ASSET.platform.pbpFile != NULL) {
|
||||
fclose(ASSET.platform.pbpFile);
|
||||
ASSET.platform.pbpFile = NULL;
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
@@ -6,9 +6,8 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "error/error.h"
|
||||
|
||||
#define ASSET_PBP_READ_PBP_FROM_HOST 0
|
||||
#define ASSET_PBP_SIGNATURE_SIZE 4
|
||||
#define ASSET_PBP_SIGNATURE "\0PBP"
|
||||
|
||||
@@ -28,4 +27,19 @@ typedef struct {
|
||||
typedef struct {
|
||||
FILE *pbpFile;
|
||||
assetpbpheader_t pbpHeader;
|
||||
} assetpbp_t;
|
||||
} assetpbp_t;
|
||||
|
||||
/**
|
||||
* Initializes the PBP style asset system.
|
||||
*
|
||||
* @param pbpPath The file path to the PBP file to read.
|
||||
* @returns An errorret_t indicating success or failure of the operation.
|
||||
*/
|
||||
errorret_t assetInitPBP(const char_t *pbpPath);
|
||||
|
||||
/**
|
||||
* Disposes the PBP style asset system.
|
||||
*
|
||||
* @returns An errorret_t indicating success or failure of the operation.
|
||||
*/
|
||||
errorret_t assetDisposePBP(void);
|
||||
13
src/duskpsp/asset/assetplatform.h
Normal file
13
src/duskpsp/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 "assetpsp.h"
|
||||
|
||||
typedef assetpsp_t assetplatform_t;
|
||||
#define assetInitPlatform assetInitPSP
|
||||
#define assetDisposePlatform assetDisposePSP
|
||||
40
src/duskpsp/asset/assetpsp.c
Normal file
40
src/duskpsp/asset/assetpsp.c
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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 "assert/assert.h"
|
||||
#include "util/string.h"
|
||||
|
||||
errorret_t assetInitPSP(void) {
|
||||
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.
|
||||
|
||||
// Originally I was going to allow host to read the .dsk directly but then
|
||||
// I'd have to maintain two file implementations.
|
||||
|
||||
const char_t *pbpPath;
|
||||
if(stringEndsWithCaseInsensitive(ENGINE.argv[0], ASSET_PSP_EXTENSION_PBP)) {
|
||||
pbpPath = ENGINE.argv[0];
|
||||
} else {
|
||||
// In Debugging this would be next to host0:/Dusk.prx
|
||||
pbpPath = "./EBOOT.PBP";
|
||||
}
|
||||
|
||||
errorChain(assetInitPBP(pbpPath));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t assetDisposePSP(void) {
|
||||
errorChain(assetDisposePBP());
|
||||
errorOk();
|
||||
}
|
||||
27
src/duskpsp/asset/assetpsp.h
Normal file
27
src/duskpsp/asset/assetpsp.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "assetpbp.h"
|
||||
|
||||
#define ASSET_PSP_EXTENSION_PBP ".pbp"
|
||||
|
||||
typedef assetpbp_t assetpsp_t;
|
||||
|
||||
/**
|
||||
* Initializes the PSP style asset system.
|
||||
*
|
||||
* @returns An errorret_t indicating success or failure of the operation.
|
||||
*/
|
||||
errorret_t assetInitPSP(void);
|
||||
|
||||
/**
|
||||
* Disposes the PSP style asset system.
|
||||
*
|
||||
* @returns An errorret_t indicating success or failure of the operation.
|
||||
*/
|
||||
errorret_t assetDisposePSP(void);
|
||||
Reference in New Issue
Block a user