Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 45 additions & 13 deletions src/data_win.c
Original file line number Diff line number Diff line change
Expand Up @@ -2328,7 +2328,7 @@ static void parseSTRG(BinaryReader* reader, DataWin* dw) {
free(ptrs);
}

static void parseTXTR(BinaryReader* reader, DataWin* dw, size_t chunkEnd) {
static void parseTXTR(BinaryReader* reader, DataWin* dw, size_t chunkEnd, bool loadTextureDataLazily) {
Txtr* t = &dw->txtr;

uint32_t count;
Expand Down Expand Up @@ -2404,10 +2404,39 @@ static void parseTXTR(BinaryReader* reader, DataWin* dw, size_t chunkEnd) {
}

// Load blob data into owned buffers
repeat(count, i) {
if (t->textures[i].blobOffset == 0 || t->textures[i].blobSize == 0) continue;
t->textures[i].blobData = BinaryReader_readBytesAt(reader, t->textures[i].blobOffset, t->textures[i].blobSize);
if (!loadTextureDataLazily) {
repeat(count, i) {
if (t->textures[i].blobOffset == 0 || t->textures[i].blobSize == 0) continue;
t->textures[i].blobData = BinaryReader_readBytesAt(reader, t->textures[i].blobOffset, t->textures[i].blobSize);
}
}
}

void DataWin_loadTxtrIfNeeded(DataWin* dw, uint32_t textureId) {
Txtr* t = &dw->txtr;
Texture* tex = &t->textures[textureId];

if (tex->blobOffset == 0 || tex->blobSize == 0) return;
if (tex->blobData != nullptr) return;

if (!dw->lazyLoadFile) {
fprintf(stderr, "%s: called without a lazy load file.\n", __func__);
return;
}

tex->blobData = (uint8_t *)safeMalloc(tex->blobSize);

memset(tex->blobData, 0, tex->blobSize);
long old_seek = ftell(dw->lazyLoadFile);
fseek(dw->lazyLoadFile, tex->blobOffset, SEEK_SET);
size_t read = fread(tex->blobData, 1, tex->blobSize, dw->lazyLoadFile);
fseek(dw->lazyLoadFile, old_seek, SEEK_SET);

if (read != tex->blobSize) {
fprintf(stderr, "%s: couldn't read %u bytes to load a texture.\n", __func__, tex->blobSize);
}

fprintf(stderr, "%s: loaded texture data for page %u\n", __func__, textureId);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont bother logging success

}

static void parseAUDO(BinaryReader* reader, DataWin* dw) {
Expand Down Expand Up @@ -2590,13 +2619,15 @@ DataWin* DataWin_parse(const char* filePath, DataWinParserOptions options) {
// Bulk-read the chunk data into memory for fast parsing
uint8_t* chunkBuffer = nullptr;
if (shouldParse && chunkLength > 0 && options.loadType != DATAWINLOADTYPE_LOAD_IN_MEMORY_AHEAD_OF_TIME) {
chunkBuffer = (uint8_t *)safeMalloc(chunkLength);
size_t read = fread(chunkBuffer, 1, chunkLength, reader.file);
if (read != chunkLength) {
fprintf(stderr, "DataWin: short read on chunk %.4s (expected %u, got %zu)\n", chunkName, chunkLength, read);
exit(1);
chunkBuffer = (uint8_t *)malloc(chunkLength);
if (chunkBuffer) {
size_t read = fread(chunkBuffer, 1, chunkLength, reader.file);
if (read != chunkLength) {
fprintf(stderr, "DataWin: short read on chunk %.4s (expected %u, got %zu)\n", chunkName, chunkLength, read);
exit(1);
}
BinaryReader_setBuffer(&reader, chunkBuffer, chunkDataStart, chunkLength);
}
BinaryReader_setBuffer(&reader, chunkBuffer, chunkDataStart, chunkLength);
}

if (options.parseGen8 && memcmp(chunkName, "GEN8", 4) == 0) {
Expand Down Expand Up @@ -2661,7 +2692,7 @@ DataWin* DataWin_parse(const char* filePath, DataWinParserOptions options) {
} else if (options.parseStrg && memcmp(chunkName, "STRG", 4) == 0) {
parseSTRG(&reader, dw);
} else if (options.parseTxtr && memcmp(chunkName, "TXTR", 4) == 0) {
parseTXTR(&reader, dw, chunkEnd);
parseTXTR(&reader, dw, chunkEnd, options.lazyLoadTextures);
} else if (options.parseAudo && memcmp(chunkName, "AUDO", 4) == 0) {
parseAUDO(&reader, dw);
} else {
Expand Down Expand Up @@ -2694,7 +2725,8 @@ DataWin* DataWin_parse(const char* filePath, DataWinParserOptions options) {

// If lazy-loading rooms, keep the file handle open for DataWin_loadRoomPayload, otherwise close it now
dw->lazyLoadRooms = options.lazyLoadRooms;
if (options.lazyLoadRooms) {
dw->lazyLoadTextures = options.lazyLoadTextures;
if (options.lazyLoadRooms || options.lazyLoadTextures) {
dw->lazyLoadFile = file;
dw->lazyLoadFilePath = safeStrdup(filePath);
dw->fileSize = (size_t) fileSize;
Expand Down Expand Up @@ -2916,7 +2948,7 @@ void DataWin_free(DataWin* dw) {
free(dw->strgBuffer);
free(dw->bytecodeBuffer);

// Close the lazy-load file handle (only open when lazyLoadRooms was enabled)
// Close the lazy-load file handle (only open when lazyLoadRooms/lazyLoadTextures was enabled)
if (dw->lazyLoadFile != nullptr) {
fclose(dw->lazyLoadFile);
dw->lazyLoadFile = nullptr;
Expand Down
4 changes: 4 additions & 0 deletions src/data_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ typedef struct {

// If true, Room payloads (backgrounds, views, gameObjects, tiles, layers) are parsed on demand via DataWin_loadRoomPayload during gameplay.
bool lazyLoadRooms;
// If true, TXTR objects will be loaded on demand via DataWin_loadTxtrIfNeeded, and unloaded if memory is tight.
bool lazyLoadTextures;

// When lazyLoadRooms is true, this list indicates which rooms should be loaded during load time instead of demand. They will also not be freed.
StringBooleanEntry* eagerlyLoadedRooms;
Expand Down Expand Up @@ -930,6 +932,7 @@ struct DataWin {
char* lazyLoadFilePath; // owned strdup of the original file path, for diagnostics
size_t fileSize; // cached size of the DataWin, captured at parse time. Used for platforms where fseek(SEEK_END)+ftell is unreliable due to buffering (like the PlayStation 2).
bool lazyLoadRooms; // mirrors the parser option so Runner can branch without re-reading options
bool lazyLoadTextures; // ditto, but with TXTR pages
};

DataWin* DataWin_parse(const char* filePath, DataWinParserOptions options);
Expand All @@ -949,5 +952,6 @@ bool DataWin_isVersionAtLeast(const DataWin* dw, uint32_t major, uint32_t minor,
void DataWin_bumpVersionTo(DataWin* dw, uint32_t major, uint32_t minor, uint32_t release, uint32_t build);
void GamePath_computeInternal(GamePath* path);
PathPositionResult GamePath_getPosition(GamePath* path, float t);
void DataWin_loadTxtrIfNeeded(DataWin* dw, uint32_t textureId);

#endif /* _BS_DATA_WIN_H_ */
1 change: 1 addition & 0 deletions src/desktop/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,7 @@ int main(int argc, char* argv[]) {
options.skipLoadingPreciseMasksForNonPreciseSprites = true;
options.loadType = args.loadType;
options.lazyLoadRooms = args.lazyRooms;
options.lazyLoadTextures = args.lazyTextures;
options.eagerlyLoadedRooms = args.eagerRooms;
DataWin* dataWin = DataWin_parse(currentDataWinPath, options);

Expand Down
2 changes: 2 additions & 0 deletions src/gl/gl_renderer.c
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,8 @@ bool GLRenderer_ensureTextureLoaded(GLRenderer* gl, uint32_t pageId) {
DataWin* dw = gl->base.dataWin;
Texture* txtr = &dw->txtr.textures[pageId];

DataWin_loadTxtrIfNeeded(dw, pageId);

int w, h;
bool gm2022_5 = DataWin_isVersionAtLeast(dw, 2022, 5, 0, 0);
uint8_t* pixels = ImageDecoder_decodeToRgba(txtr->blobData, (size_t) txtr->blobSize, gm2022_5, &w, &h);
Expand Down
2 changes: 2 additions & 0 deletions src/gl_legacy/gl_legacy_renderer.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ bool GLLegacyRenderer_ensureTextureLoaded(GLLegacyRenderer* gl, uint32_t pageId)
DataWin* dw = gl->base.dataWin;
Texture* txtr = &dw->txtr.textures[pageId];

DataWin_loadTxtrIfNeeded(dw, pageId);

bool gm2022_5 = DataWin_isVersionAtLeast(dw, 2022, 5, 0, 0);
uint8_t* pixels = ImageDecoder_decodeToRgba(txtr->blobData, (size_t) txtr->blobSize, gm2022_5, &w, &h);
if (pixels == nullptr) {
Expand Down
Loading