From 4b9ab4de5f5c916ab3321a0ec7ff3dea060e78fd Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 2 Apr 2024 23:28:27 +1100 Subject: [PATCH 1/6] Start refactoring resource creation --- src/Audio.c | 3 +- src/Resources.c | 131 ++++++++++++++++++++++++++---------------------- src/Vorbis.c | 4 ++ src/Vorbis.h | 4 +- 4 files changed, 80 insertions(+), 62 deletions(-) diff --git a/src/Audio.c b/src/Audio.c index 3c3a042d8..6cc450b13 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -335,7 +335,7 @@ static cc_result Music_Buffer(cc_int16* data, int maxSamples, struct VorbisState static cc_result Music_PlayOgg(struct Stream* source) { struct OggState ogg; - struct VorbisState vorbis = { 0 }; + struct VorbisState vorbis; int channels, sampleRate, volume; int chunkSize, samplesPerSecond; @@ -344,6 +344,7 @@ static cc_result Music_PlayOgg(struct Stream* source) { cc_result res; Ogg_Init(&ogg, source); + Vorbis_Init(&vorbis); vorbis.source = &ogg; if ((res = Vorbis_DecodeHeaders(&vorbis))) goto cleanup; diff --git a/src/Resources.c b/src/Resources.c index a81710053..137794819 100644 --- a/src/Resources.c +++ b/src/Resources.c @@ -44,6 +44,9 @@ struct ResourceZipEntry { union ResourceValue value; cc_uint32 offset, crc32; }; +#define RESOURCE_TYPE_DATA 1 +#define RESOURCE_TYPE_PNG 2 +#define RESOURCE_TYPE_CONST 3 static CC_NOINLINE cc_bool Fetcher_Get(int reqID, struct HttpRequest* item); CC_NOINLINE static struct ResourceZipEntry* ZipEntries_Find(const cc_string* name); @@ -325,30 +328,36 @@ static void SoundPatcher_WriteWav(struct Stream* s, struct VorbisState* ctx) { /* Converts an OGG sound to a WAV sound for faster decoding later */ static void SoundPatcher_Save(const char* name, struct HttpRequest* req) { cc_string path; char pathBuffer[STRING_SIZE]; - struct OggState ogg; + struct OggState* ogg = NULL; + struct VorbisState* ctx = NULL; struct Stream src, dst; - struct VorbisState* ctx; cc_result res; - ctx = (struct VorbisState*)Mem_TryAllocCleared(1, sizeof(struct VorbisState)); - if (!ctx) { Logger_SysWarn(ERR_OUT_OF_MEMORY, "allocating memory"); return; } + ogg = (struct OggState*)Mem_TryAlloc(1, sizeof(struct OggState)); + if (!ogg) { Logger_SysWarn(ERR_OUT_OF_MEMORY, "allocating memory"); goto cleanup; } + + ctx = (struct VorbisState*)Mem_TryAlloc(1, sizeof(struct VorbisState)); + if (!ctx) { Logger_SysWarn(ERR_OUT_OF_MEMORY, "allocating memory"); goto cleanup; } Stream_ReadonlyMemory(&src, req->data, req->size); String_InitArray(path, pathBuffer); String_Format1(&path, "audio/%c.wav", name); res = Stream_CreateFile(&dst, &path); - if (res) { Logger_SysWarn(res, "creating .wav file"); return; } + if (res) { Logger_SysWarn(res, "creating .wav file"); goto cleanup; } - Ogg_Init(&ogg, &src); - ctx->source = &ogg; + Ogg_Init(ogg, &src); + Vorbis_Init(ctx); + ctx->source = ogg; SoundPatcher_WriteWav(&dst, ctx); res = dst.Close(&dst); if (res) Logger_SysWarn(res, "closing .wav file"); - Vorbis_Free(ctx); +cleanup: + if (ctx) Vorbis_Free(ctx); Mem_Free(ctx); + Mem_Free(ogg); } @@ -463,7 +472,7 @@ static const struct AssetSet ccTexsAssetSet = { /*########################################################################################################################* -*---------------------------------------------------------Zip writer------------------------------------------------------* +*------------------------------------------------------Zip entry writer---------------------------------------------------* *#########################################################################################################################*/ static void GetCurrentZipDate(int* modTime, int* modDate) { struct DateTime now; @@ -598,13 +607,56 @@ static cc_result ZipWriter_WritePng(struct Stream* dst, struct ResourceZipEntry* } +/*########################################################################################################################* +*------------------------------------------------------Zip file writer----------------------------------------------------* +*#########################################################################################################################*/ +static cc_result ZipFile_WriteEntries(struct Stream* s, struct ResourceZipEntry* entries, int numEntries) { + struct ResourceZipEntry* e; + cc_uint32 beg, end; + int i; + cc_result res; + + for (i = 0; i < numEntries; i++) + { + e = &entries[i]; + + if (e->type == RESOURCE_TYPE_PNG) { + if ((res = ZipWriter_WritePng(s, e))) return res; + } else { + if ((res = ZipWriter_WriteData(s, e))) return res; + } + } + + if ((res = s->Position(s, &beg))) return res; + for (i = 0; i < numEntries; i++) + { + if ((res = ZipWriter_CentralDir(s, &entries[i]))) return res; + } + + if ((res = s->Position(s, &end))) return res; + return ZipWriter_EndOfCentralDir(s, numEntries, beg, end); +} + +static void ZipFile_Create(cc_string* path, struct ResourceZipEntry* entries, int numEntries) { + struct Stream s; + cc_result res; + + res = Stream_CreateFile(&s, path); + if (res) { + Logger_SysWarn2(res, "creating", path); return; + } + + res = ZipFile_WriteEntries(&s, entries, numEntries); + if (res) Logger_SysWarn2(res, "making", path); + + res = s.Close(&s); + if (res) Logger_SysWarn2(res, "closing", path); +} + + /*########################################################################################################################* *----------------------------------------------------default.zip resources------------------------------------------------* *#########################################################################################################################*/ -#define RESOURCE_TYPE_DATA 1 -#define RESOURCE_TYPE_PNG 2 -#define RESOURCE_TYPE_CONST 3 - #define ANIMS_TXT \ "# This file defines the animations used in a texture pack for ClassiCube.\r\n" \ "# Each line is in the format : \r\n" \ @@ -883,52 +935,6 @@ static cc_result Classic0023Patcher_OldGold(struct HttpRequest* req) { } -/*########################################################################################################################* -*------------------------------------------------------default.zip writer-------------------------------------------------* -*#########################################################################################################################*/ -static cc_result DefaultZip_WriteEntries(struct Stream* s) { - struct ResourceZipEntry* e; - cc_uint32 beg, end; - int i; - cc_result res; - - for (i = 0; i < Array_Elems(defaultZipEntries); i++) { - e = &defaultZipEntries[i]; - - if (e->type == RESOURCE_TYPE_PNG) { - if ((res = ZipWriter_WritePng(s, e))) return res; - } else { - if ((res = ZipWriter_WriteData(s, e))) return res; - } - } - - if ((res = s->Position(s, &beg))) return res; - for (i = 0; i < Array_Elems(defaultZipEntries); i++) { - if ((res = ZipWriter_CentralDir(s, &defaultZipEntries[i]))) return res; - } - - if ((res = s->Position(s, &end))) return res; - return ZipWriter_EndOfCentralDir(s, Array_Elems(defaultZipEntries), beg, end); -} - -static void DefaultZip_Create(void) { - cc_string path = String_FromReadonly(Game_Version.DefaultTexpack); - struct Stream s; - cc_result res; - - res = Stream_CreateFile(&s, &path); - if (res) { - Logger_SysWarn2(res, "creating", &path); return; - } - - res = DefaultZip_WriteEntries(&s); - if (res) Logger_SysWarn2(res, "making", &path); - - res = s.Close(&s); - if (res) Logger_SysWarn2(res, "closing", &path); -} - - /*########################################################################################################################* *-----------------------------------------------Minecraft Classic texture assets------------------------------------------* *#########################################################################################################################*/ @@ -1008,6 +1014,11 @@ static const char* MCCTextures_GetRequestName(int reqID) { /*########################################################################################################################* *------------------------------------------Minecraft Classic texture assets processing -----------------------------------* *#########################################################################################################################*/ +static void MCCTextures_CreateDefaultZip(void) { + cc_string path = String_FromReadonly(Game_Version.DefaultTexpack); + ZipFile_Create(&path, defaultZipEntries, Array_Elems(defaultZipEntries)); +} + static void MCCTextures_CheckSource(struct ZipfileSource* source) { struct HttpRequest item; cc_result res; @@ -1023,7 +1034,7 @@ static void MCCTextures_CheckSource(struct ZipfileSource* source) { HttpRequest_Free(&item); if (++numDefaultZipProcessed < numDefaultZipSources) return; - DefaultZip_Create(); + MCCTextures_CreateDefaultZip(); } static void MCCTextures_CheckStatus(void) { diff --git a/src/Vorbis.c b/src/Vorbis.c index 2c75d7f72..b0a2e74d5 100644 --- a/src/Vorbis.c +++ b/src/Vorbis.c @@ -1229,6 +1229,10 @@ static void Vorbis_CalcWindow(struct VorbisWindow* window, int blockSize) { } } +void Vorbis_Init(struct VorbisState* ctx) { + Mem_Set(ctx, 0, sizeof(*ctx) - sizeof(ctx->imdct)); +} + void Vorbis_Free(struct VorbisState* ctx) { int i; for (i = 0; i < ctx->numCodebooks; i++) diff --git a/src/Vorbis.h b/src/Vorbis.h index 56353aa90..b37437ad7 100644 --- a/src/Vorbis.h +++ b/src/Vorbis.h @@ -56,7 +56,9 @@ struct VorbisState { struct imdct_state imdct[2]; }; -/* Frees all dynamic memory allocated to decode the given vorbis audio. */ +/* Initialises the given context to defaults */ +void Vorbis_Init(struct VorbisState* ctx); +/* Frees all memory dynamically allocated by the given context */ void Vorbis_Free(struct VorbisState* ctx); /* Reads and decodes the initial vorbis headers and setup data. */ cc_result Vorbis_DecodeHeaders(struct VorbisState* ctx); From f600f84cbf4b84cac75611c526ebde67fb389b3e Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 3 Apr 2024 07:45:04 +1100 Subject: [PATCH 2/6] More WIP towards sound zip creation --- src/Resources.c | 449 +++++++++++++++++++++++++++--------------------- 1 file changed, 249 insertions(+), 200 deletions(-) diff --git a/src/Resources.c b/src/Resources.c index 137794819..52b0be256 100644 --- a/src/Resources.c +++ b/src/Resources.c @@ -28,6 +28,8 @@ struct AssetSet { const char* (*GetRequestName)(int reqID); /* Checks if any assets have been downloaded, and processes them if so */ void (*CheckStatus)(void); + /* Resets state and frees and allocated memory */ + void (*ResetState)(void); }; int Resources_Count, Resources_Size; @@ -47,12 +49,196 @@ struct ResourceZipEntry { #define RESOURCE_TYPE_DATA 1 #define RESOURCE_TYPE_PNG 2 #define RESOURCE_TYPE_CONST 3 +#define RESOURCE_TYPE_SOUND 4 static CC_NOINLINE cc_bool Fetcher_Get(int reqID, struct HttpRequest* item); CC_NOINLINE static struct ResourceZipEntry* ZipEntries_Find(const cc_string* name); static cc_result ZipEntry_ExtractData(struct ResourceZipEntry* e, struct Stream* data, struct ZipEntry* source); +/*########################################################################################################################* +*------------------------------------------------------Zip entry writer---------------------------------------------------* +*#########################################################################################################################*/ +static void GetCurrentZipDate(int* modTime, int* modDate) { + struct DateTime now; + DateTime_CurrentLocal(&now); + + *modTime = (now.second / 2) | (now.minute << 5) | (now.hour << 11); + *modDate = (now.day) | (now.month << 5) | ((now.year - 1980) << 9); +} + +static cc_result ZipWriter_LocalFile(struct Stream* s, struct ResourceZipEntry* e) { + int filenameLen = String_Length(e->filename); + cc_uint8 header[30 + STRING_SIZE]; + cc_result res; + int modTime, modDate; + + GetCurrentZipDate(&modTime, &modDate); + if ((res = s->Position(s, &e->offset))) return res; + + Stream_SetU32_LE(header + 0, 0x04034b50); /* signature */ + Stream_SetU16_LE(header + 4, 20); /* version needed */ + Stream_SetU16_LE(header + 6, 0); /* bitflags */ + Stream_SetU16_LE(header + 8, 0); /* compression method */ + Stream_SetU16_LE(header + 10, modTime); /* last modified */ + Stream_SetU16_LE(header + 12, modDate); /* last modified */ + + Stream_SetU32_LE(header + 14, e->crc32); /* CRC32 */ + Stream_SetU32_LE(header + 18, e->size); /* Compressed size */ + Stream_SetU32_LE(header + 22, e->size); /* Uncompressed size */ + + Stream_SetU16_LE(header + 26, filenameLen); /* name length */ + Stream_SetU16_LE(header + 28, 0); /* extra field length */ + + Mem_Copy(header + 30, e->filename, filenameLen); + return Stream_Write(s, header, 30 + filenameLen); +} + +static cc_result ZipWriter_CentralDir(struct Stream* s, struct ResourceZipEntry* e) { + int filenameLen = String_Length(e->filename); + cc_uint8 header[46 + STRING_SIZE]; + int modTime, modDate; + GetCurrentZipDate(&modTime, &modDate); + + Stream_SetU32_LE(header + 0, 0x02014b50); /* signature */ + Stream_SetU16_LE(header + 4, 20); /* version */ + Stream_SetU16_LE(header + 6, 20); /* version needed */ + Stream_SetU16_LE(header + 8, 0); /* bitflags */ + Stream_SetU16_LE(header + 10, 0); /* compression method */ + Stream_SetU16_LE(header + 12, modTime); /* last modified */ + Stream_SetU16_LE(header + 14, modDate); /* last modified */ + + Stream_SetU32_LE(header + 16, e->crc32); /* CRC32 */ + Stream_SetU32_LE(header + 20, e->size); /* compressed size */ + Stream_SetU32_LE(header + 24, e->size); /* uncompressed size */ + + Stream_SetU16_LE(header + 28, filenameLen); /* name length */ + Stream_SetU16_LE(header + 30, 0); /* extra field length */ + Stream_SetU16_LE(header + 32, 0); /* file comment length */ + Stream_SetU16_LE(header + 34, 0); /* disk number */ + Stream_SetU16_LE(header + 36, 0); /* internal attributes */ + Stream_SetU32_LE(header + 38, 0); /* external attributes */ + Stream_SetU32_LE(header + 42, e->offset); /* local header offset */ + + Mem_Copy(header + 46, e->filename, filenameLen); + return Stream_Write(s, header, 46 + filenameLen); +} + +static cc_result ZipWriter_EndOfCentralDir(struct Stream* s, int numEntries, + cc_uint32 centralDirBeg, cc_uint32 centralDirEnd) { + cc_uint8 header[22]; + + Stream_SetU32_LE(header + 0, 0x06054b50); /* signature */ + Stream_SetU16_LE(header + 4, 0); /* disk number */ + Stream_SetU16_LE(header + 6, 0); /* disk number of start */ + Stream_SetU16_LE(header + 8, numEntries); /* disk entries */ + Stream_SetU16_LE(header + 10, numEntries); /* total entries */ + Stream_SetU32_LE(header + 12, centralDirEnd - centralDirBeg); /* central dir size */ + Stream_SetU32_LE(header + 16, centralDirBeg); /* central dir start */ + Stream_SetU16_LE(header + 20, 0); /* comment length */ + return Stream_Write(s, header, 22); +} + +static cc_result ZipWriter_FixupLocalFile(struct Stream* s, struct ResourceZipEntry* e) { + int filenameLen = String_Length(e->filename); + cc_uint8 tmp[2048]; + cc_uint32 dataBeg, dataEnd; + cc_uint32 i, crc, toRead, read; + cc_result res; + + dataBeg = e->offset + 30 + filenameLen; + if ((res = s->Position(s, &dataEnd))) return res; + e->size = dataEnd - dataBeg; + + /* work out the CRC 32 */ + crc = 0xffffffffUL; + if ((res = s->Seek(s, dataBeg))) return res; + + for (; dataBeg < dataEnd; dataBeg += read) { + toRead = dataEnd - dataBeg; + toRead = min(toRead, sizeof(tmp)); + + if ((res = s->Read(s, tmp, toRead, &read))) return res; + if (!read) return ERR_END_OF_STREAM; + + for (i = 0; i < read; i++) { + crc = Utils_Crc32Table[(crc ^ tmp[i]) & 0xFF] ^ (crc >> 8); + } + } + e->crc32 = crc ^ 0xffffffffUL; + + /* then fixup the header */ + if ((res = s->Seek(s, e->offset))) return res; + if ((res = ZipWriter_LocalFile(s, e))) return res; + return s->Seek(s, dataEnd); +} + +static cc_result ZipWriter_WriteData(struct Stream* dst, struct ResourceZipEntry* e) { + cc_uint8* data = e->value.data; + cc_result res; + e->crc32 = Utils_CRC32(data, e->size); + + if ((res = ZipWriter_LocalFile(dst, e))) return res; + return Stream_Write(dst, data, e->size); +} + +static cc_result ZipWriter_WritePng(struct Stream* dst, struct ResourceZipEntry* e) { + struct Bitmap* src = &e->value.bmp; + cc_result res; + + if ((res = ZipWriter_LocalFile(dst, e))) return res; + if ((res = Png_Encode(src, dst, NULL, true, NULL))) return res; + return ZipWriter_FixupLocalFile(dst, e); +} + + +/*########################################################################################################################* +*------------------------------------------------------Zip file writer----------------------------------------------------* +*#########################################################################################################################*/ +static cc_result ZipFile_WriteEntries(struct Stream* s, struct ResourceZipEntry* entries, int numEntries) { + struct ResourceZipEntry* e; + cc_uint32 beg, end; + int i; + cc_result res; + + for (i = 0; i < numEntries; i++) + { + e = &entries[i]; + + if (e->type == RESOURCE_TYPE_PNG) { + if ((res = ZipWriter_WritePng(s, e))) return res; + } else { + if ((res = ZipWriter_WriteData(s, e))) return res; + } + } + + if ((res = s->Position(s, &beg))) return res; + for (i = 0; i < numEntries; i++) + { + if ((res = ZipWriter_CentralDir(s, &entries[i]))) return res; + } + + if ((res = s->Position(s, &end))) return res; + return ZipWriter_EndOfCentralDir(s, numEntries, beg, end); +} + +static void ZipFile_Create(cc_string* path, struct ResourceZipEntry* entries, int numEntries) { + struct Stream s; + cc_result res; + + res = Stream_CreateFile(&s, path); + if (res) { + Logger_SysWarn2(res, "creating", path); return; + } + + res = ZipFile_WriteEntries(&s, entries, numEntries); + if (res) Logger_SysWarn2(res, "making", path); + + res = s.Close(&s); + if (res) Logger_SysWarn2(res, "closing", path); +} + + /*########################################################################################################################* *---------------------------------------------------------Music assets----------------------------------------------------* *#########################################################################################################################*/ @@ -161,12 +347,16 @@ static void MusicAssets_CheckStatus(void) { } } +static void MusicAssets_ResetState(void) { +} + static const struct AssetSet mccMusicAssetSet = { MusicAssets_CheckExistence, MusicAssets_CountMissing, MusicAssets_DownloadAssets, MusicAssets_GetRequestName, - MusicAssets_CheckStatus + MusicAssets_CheckStatus, + MusicAssets_ResetState }; @@ -176,7 +366,8 @@ static const struct AssetSet mccMusicAssetSet = { static struct SoundAsset { const char* name; const char* hash; - int reqID; + int reqID, size; + void* data; } soundAssets[] = { { "dig_cloth1", "5fd568d724ba7d53911b6cccf5636f859d2662e8" }, { "dig_cloth2", "56c1d0ac0de2265018b2c41cb571cc6631101484" }, { "dig_cloth3", "9c63f2a3681832dc32d206f6830360bfe94b5bfc" }, { "dig_cloth4", "55da1856e77cfd31a7e8c3d358e1f856c5583198" }, @@ -361,11 +552,15 @@ cleanup: } -static void SoundAsset_Check(const struct SoundAsset* sound) { +static void SoundAsset_Check(struct SoundAsset* sound) { struct HttpRequest item; if (!Fetcher_Get(sound->reqID, &item)) return; SoundPatcher_Save(sound->name, &item); + + sound->data = item.data; + sound->size = item.size; + item.data = NULL; HttpRequest_Free(&item); } @@ -377,12 +572,24 @@ static void SoundAssets_CheckStatus(void) { } } +static void SoundAssets_ResetState(void) { + int i; + allSoundsExist = false; + + for (i = 0; i < Array_Elems(soundAssets); i++) + { + Mem_Free(soundAssets[i].data); + soundAssets[i].data = NULL; + } +} + static const struct AssetSet mccSoundAssetSet = { SoundAssets_CheckExistence, SoundAssets_CountMissing, SoundAssets_DownloadAssets, SoundAssets_GetRequestName, - SoundAssets_CheckStatus + SoundAssets_CheckStatus, + SoundAssets_ResetState }; @@ -462,198 +669,21 @@ static void CCTextures_CheckStatus(void) { HttpRequest_Free(&item); } +static void CCTextures_ResetState(void) { + ccTexturesExist = false; + ccTexturesDownloaded = false; +} + static const struct AssetSet ccTexsAssetSet = { CCTextures_CheckExistence, CCTextures_CountMissing, CCTextures_DownloadAssets, CCTextures_GetRequestName, - CCTextures_CheckStatus + CCTextures_CheckStatus, + CCTextures_ResetState }; -/*########################################################################################################################* -*------------------------------------------------------Zip entry writer---------------------------------------------------* -*#########################################################################################################################*/ -static void GetCurrentZipDate(int* modTime, int* modDate) { - struct DateTime now; - DateTime_CurrentLocal(&now); - - *modTime = (now.second / 2) | (now.minute << 5) | (now.hour << 11); - *modDate = (now.day) | (now.month << 5) | ((now.year - 1980) << 9); -} - -static cc_result ZipWriter_LocalFile(struct Stream* s, struct ResourceZipEntry* e) { - int filenameLen = String_Length(e->filename); - cc_uint8 header[30 + STRING_SIZE]; - cc_result res; - int modTime, modDate; - - GetCurrentZipDate(&modTime, &modDate); - if ((res = s->Position(s, &e->offset))) return res; - - Stream_SetU32_LE(header + 0, 0x04034b50); /* signature */ - Stream_SetU16_LE(header + 4, 20); /* version needed */ - Stream_SetU16_LE(header + 6, 0); /* bitflags */ - Stream_SetU16_LE(header + 8, 0); /* compression method */ - Stream_SetU16_LE(header + 10, modTime); /* last modified */ - Stream_SetU16_LE(header + 12, modDate); /* last modified */ - - Stream_SetU32_LE(header + 14, e->crc32); /* CRC32 */ - Stream_SetU32_LE(header + 18, e->size); /* Compressed size */ - Stream_SetU32_LE(header + 22, e->size); /* Uncompressed size */ - - Stream_SetU16_LE(header + 26, filenameLen); /* name length */ - Stream_SetU16_LE(header + 28, 0); /* extra field length */ - - Mem_Copy(header + 30, e->filename, filenameLen); - return Stream_Write(s, header, 30 + filenameLen); -} - -static cc_result ZipWriter_CentralDir(struct Stream* s, struct ResourceZipEntry* e) { - int filenameLen = String_Length(e->filename); - cc_uint8 header[46 + STRING_SIZE]; - int modTime, modDate; - GetCurrentZipDate(&modTime, &modDate); - - Stream_SetU32_LE(header + 0, 0x02014b50); /* signature */ - Stream_SetU16_LE(header + 4, 20); /* version */ - Stream_SetU16_LE(header + 6, 20); /* version needed */ - Stream_SetU16_LE(header + 8, 0); /* bitflags */ - Stream_SetU16_LE(header + 10, 0); /* compression method */ - Stream_SetU16_LE(header + 12, modTime); /* last modified */ - Stream_SetU16_LE(header + 14, modDate); /* last modified */ - - Stream_SetU32_LE(header + 16, e->crc32); /* CRC32 */ - Stream_SetU32_LE(header + 20, e->size); /* compressed size */ - Stream_SetU32_LE(header + 24, e->size); /* uncompressed size */ - - Stream_SetU16_LE(header + 28, filenameLen); /* name length */ - Stream_SetU16_LE(header + 30, 0); /* extra field length */ - Stream_SetU16_LE(header + 32, 0); /* file comment length */ - Stream_SetU16_LE(header + 34, 0); /* disk number */ - Stream_SetU16_LE(header + 36, 0); /* internal attributes */ - Stream_SetU32_LE(header + 38, 0); /* external attributes */ - Stream_SetU32_LE(header + 42, e->offset); /* local header offset */ - - Mem_Copy(header + 46, e->filename, filenameLen); - return Stream_Write(s, header, 46 + filenameLen); -} - -static cc_result ZipWriter_EndOfCentralDir(struct Stream* s, int numEntries, - cc_uint32 centralDirBeg, cc_uint32 centralDirEnd) { - cc_uint8 header[22]; - - Stream_SetU32_LE(header + 0, 0x06054b50); /* signature */ - Stream_SetU16_LE(header + 4, 0); /* disk number */ - Stream_SetU16_LE(header + 6, 0); /* disk number of start */ - Stream_SetU16_LE(header + 8, numEntries); /* disk entries */ - Stream_SetU16_LE(header + 10, numEntries); /* total entries */ - Stream_SetU32_LE(header + 12, centralDirEnd - centralDirBeg); /* central dir size */ - Stream_SetU32_LE(header + 16, centralDirBeg); /* central dir start */ - Stream_SetU16_LE(header + 20, 0); /* comment length */ - return Stream_Write(s, header, 22); -} - -static cc_result ZipWriter_FixupLocalFile(struct Stream* s, struct ResourceZipEntry* e) { - int filenameLen = String_Length(e->filename); - cc_uint8 tmp[2048]; - cc_uint32 dataBeg, dataEnd; - cc_uint32 i, crc, toRead, read; - cc_result res; - - dataBeg = e->offset + 30 + filenameLen; - if ((res = s->Position(s, &dataEnd))) return res; - e->size = dataEnd - dataBeg; - - /* work out the CRC 32 */ - crc = 0xffffffffUL; - if ((res = s->Seek(s, dataBeg))) return res; - - for (; dataBeg < dataEnd; dataBeg += read) { - toRead = dataEnd - dataBeg; - toRead = min(toRead, sizeof(tmp)); - - if ((res = s->Read(s, tmp, toRead, &read))) return res; - if (!read) return ERR_END_OF_STREAM; - - for (i = 0; i < read; i++) { - crc = Utils_Crc32Table[(crc ^ tmp[i]) & 0xFF] ^ (crc >> 8); - } - } - e->crc32 = crc ^ 0xffffffffUL; - - /* then fixup the header */ - if ((res = s->Seek(s, e->offset))) return res; - if ((res = ZipWriter_LocalFile(s, e))) return res; - return s->Seek(s, dataEnd); -} - -static cc_result ZipWriter_WriteData(struct Stream* dst, struct ResourceZipEntry* e) { - cc_uint8* data = e->value.data; - cc_result res; - e->crc32 = Utils_CRC32(data, e->size); - - if ((res = ZipWriter_LocalFile(dst, e))) return res; - return Stream_Write(dst, data, e->size); -} - -static cc_result ZipWriter_WritePng(struct Stream* dst, struct ResourceZipEntry* e) { - struct Bitmap* src = &e->value.bmp; - cc_result res; - - if ((res = ZipWriter_LocalFile(dst, e))) return res; - if ((res = Png_Encode(src, dst, NULL, true, NULL))) return res; - return ZipWriter_FixupLocalFile(dst, e); -} - - -/*########################################################################################################################* -*------------------------------------------------------Zip file writer----------------------------------------------------* -*#########################################################################################################################*/ -static cc_result ZipFile_WriteEntries(struct Stream* s, struct ResourceZipEntry* entries, int numEntries) { - struct ResourceZipEntry* e; - cc_uint32 beg, end; - int i; - cc_result res; - - for (i = 0; i < numEntries; i++) - { - e = &entries[i]; - - if (e->type == RESOURCE_TYPE_PNG) { - if ((res = ZipWriter_WritePng(s, e))) return res; - } else { - if ((res = ZipWriter_WriteData(s, e))) return res; - } - } - - if ((res = s->Position(s, &beg))) return res; - for (i = 0; i < numEntries; i++) - { - if ((res = ZipWriter_CentralDir(s, &entries[i]))) return res; - } - - if ((res = s->Position(s, &end))) return res; - return ZipWriter_EndOfCentralDir(s, numEntries, beg, end); -} - -static void ZipFile_Create(cc_string* path, struct ResourceZipEntry* entries, int numEntries) { - struct Stream s; - cc_result res; - - res = Stream_CreateFile(&s, path); - if (res) { - Logger_SysWarn2(res, "creating", path); return; - } - - res = ZipFile_WriteEntries(&s, entries, numEntries); - if (res) Logger_SysWarn2(res, "making", path); - - res = s.Close(&s); - if (res) Logger_SysWarn2(res, "closing", path); -} - - /*########################################################################################################################* *----------------------------------------------------default.zip resources------------------------------------------------* *#########################################################################################################################*/ @@ -998,6 +1028,7 @@ static void MCCTextures_DownloadAssets(void) { { url = String_FromReadonly(defaultZipSources[i].url); defaultZipSources[i].reqID = Http_AsyncGetData(&url, 0); + defaultZipSources[i].downloaded = false; } } @@ -1046,12 +1077,29 @@ static void MCCTextures_CheckStatus(void) { } } +static void MCCTextures_ResetState(void) { + int i; + allZipEntriesExist = false; + zipEntriesFound = 0; + + for (i = 0; i < Array_Elems(defaultZipEntries); i++) + { + if (defaultZipEntries[i].type == RESOURCE_TYPE_CONST) continue; + + /* can reuse value.data for value.bmp case too */ + Mem_Free(defaultZipEntries[i].value.data); + defaultZipEntries[i].value.data = NULL; + defaultZipEntries[i].size = 0; + } +} + static const struct AssetSet mccTexsAssetSet = { MCCTextures_CheckExistence, MCCTextures_CountMissing, MCCTextures_DownloadAssets, MCCTextures_GetRequestName, - MCCTextures_CheckStatus + MCCTextures_CheckStatus, + MCCTextures_ResetState }; @@ -1069,11 +1117,21 @@ static const struct AssetSet* const asset_sets[] = { &mccSoundAssetSet }; -void Resources_CheckExistence(void) { +static void ResetState() { int i; Resources_Count = 0; Resources_Size = 0; + for (i = 0; i < Array_Elems(asset_sets); i++) + { + asset_sets[i]->ResetState(); + } +} + +void Resources_CheckExistence(void) { + int i; + ResetState(); + for (i = 0; i < Array_Elems(asset_sets); i++) { asset_sets[i]->CheckExistence(); @@ -1111,18 +1169,9 @@ void Fetcher_Run(void) { } static void Fetcher_Finish(void) { - int i; Fetcher_Completed = true; Fetcher_Working = false; - - for (i = 0; i < Array_Elems(defaultZipEntries); i++) { - if (defaultZipEntries[i].type == RESOURCE_TYPE_CONST) continue; - - /* can reuse value.data for value.bmp case too */ - Mem_Free(defaultZipEntries[i].value.data); - defaultZipEntries[i].value.data = NULL; - defaultZipEntries[i].size = 0; - } + ResetState(); } static void Fetcher_Fail(struct HttpRequest* item) { From 4ecffcedb01640e87a6dc05e4c6d2738136c2107 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 3 Apr 2024 18:37:52 +1100 Subject: [PATCH 3/6] More work on audio zip generation --- src/Audio.c | 1 + src/Audio.h | 1 + src/ClassiCube.vcxproj.filters | 6 +- src/Resources.c | 450 ++++++++++++++++++--------------- 4 files changed, 257 insertions(+), 201 deletions(-) diff --git a/src/Audio.c b/src/Audio.c index 6cc450b13..f8ece07b8 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -17,6 +17,7 @@ #include "Window.h" #endif int Audio_SoundsVolume, Audio_MusicVolume; +const cc_string Sounds_DefaultZipPath = String_FromConst("audio/default.zip"); static const cc_string audio_dir = String_FromConst("audio"); struct Sound { diff --git a/src/Audio.h b/src/Audio.h index 416a42b36..c8dd34cf4 100644 --- a/src/Audio.h +++ b/src/Audio.h @@ -34,6 +34,7 @@ extern int Audio_SoundsVolume; /* Volume music is played at, from 0-100. */ /* NOTE: Use Audio_SetMusic, don't change this directly. */ extern int Audio_MusicVolume; +extern const cc_string Sounds_DefaultZipPath; void Audio_SetMusic(int volume); void Audio_SetSounds(int volume); diff --git a/src/ClassiCube.vcxproj.filters b/src/ClassiCube.vcxproj.filters index 86b40ac23..aef0be6f9 100644 --- a/src/ClassiCube.vcxproj.filters +++ b/src/ClassiCube.vcxproj.filters @@ -620,9 +620,6 @@ Source Files\Platform - - Source Files\Window - Source Files\Window @@ -713,6 +710,9 @@ Source Files\Graphics + + Source Files\Audio + diff --git a/src/Resources.c b/src/Resources.c index 52b0be256..a868c2ada 100644 --- a/src/Resources.c +++ b/src/Resources.c @@ -14,6 +14,7 @@ #include "LWeb.h" #include "Http.h" #include "Game.h" +#include "Audio.h" /* Represents a set of assets/resources */ /* E.g. music set, sounds set, textures set */ @@ -56,6 +57,130 @@ CC_NOINLINE static struct ResourceZipEntry* ZipEntries_Find(const cc_string* nam static cc_result ZipEntry_ExtractData(struct ResourceZipEntry* e, struct Stream* data, struct ZipEntry* source); +/*########################################################################################################################* +*------------------------------------------------=-----Utility functions ------------------------=------------------------* +*#########################################################################################################################*/ +static void ZipFile_InspectEntries(const cc_string* path, Zip_SelectEntry selector) { + struct Stream stream; + cc_result res; + + res = Stream_OpenFile(&stream, path); + if (res == ReturnCode_FileNotFound) return; + if (res) { Logger_SysWarn2(res, "opening", path); return; } + + res = Zip_Extract(&stream, selector, NULL); + if (res) Logger_SysWarn2(res, "inspecting", path); + + /* No point logging error for closing readonly file */ + (void)stream.Close(&stream); +} + +static cc_result ZipEntry_ExtractData(struct ResourceZipEntry* e, struct Stream* data, struct ZipEntry* source) { + cc_uint32 size = source->UncompressedSize; + e->value.data = Mem_TryAlloc(size, 1); + e->size = size; + + if (!e->value.data) return ERR_OUT_OF_MEMORY; + return Stream_Read(data, e->value.data, size); +} + + +/*########################################################################################################################* +*-----------------------------------------------------Sound asset writing ------------------------------------------------* +*#########################################################################################################################*/ +#define WAV_FourCC(a, b, c, d) (((cc_uint32)a << 24) | ((cc_uint32)b << 16) | ((cc_uint32)c << 8) | (cc_uint32)d) +#define WAV_HDR_SIZE 44 + +/* Fixes up the .WAV header after having written all samples */ +static cc_result SoundPatcher_FixupHeader(struct Stream* s, struct VorbisState* ctx, cc_uint32 offset, cc_uint32 len) { + cc_uint8 header[WAV_HDR_SIZE]; + cc_result res = s->Seek(s, offset); + if (res) return res; + + Stream_SetU32_BE(header + 0, WAV_FourCC('R','I','F','F')); + Stream_SetU32_LE(header + 4, len - 8); + Stream_SetU32_BE(header + 8, WAV_FourCC('W','A','V','E')); + Stream_SetU32_BE(header + 12, WAV_FourCC('f','m','t',' ')); + Stream_SetU32_LE(header + 16, 16); /* fmt chunk size */ + Stream_SetU16_LE(header + 20, 1); /* PCM audio format */ + Stream_SetU16_LE(header + 22, ctx->channels); + Stream_SetU32_LE(header + 24, ctx->sampleRate); + + Stream_SetU32_LE(header + 28, ctx->sampleRate * ctx->channels * 2); /* byte rate */ + Stream_SetU16_LE(header + 32, ctx->channels * 2); /* block align */ + Stream_SetU16_LE(header + 34, 16); /* bits per sample */ + Stream_SetU32_BE(header + 36, WAV_FourCC('d','a','t','a')); + Stream_SetU32_LE(header + 40, len - WAV_HDR_SIZE); + + return Stream_Write(s, header, WAV_HDR_SIZE); +} + +/* Decodes all samples, then produces a .WAV file from them */ +static cc_result SoundPatcher_WriteWav(struct Stream* s, struct VorbisState* ctx) { + cc_int16* samples; + cc_uint32 begOffset; + cc_uint32 len = WAV_HDR_SIZE; + cc_result res; + int count; + + if ((res = s->Position(s, &begOffset))) return res; + + /* reuse context here for a temp garbage header */ + if ((res = Stream_Write(s, (const cc_uint8*)ctx, WAV_HDR_SIZE))) return res; + if ((res = Vorbis_DecodeHeaders(ctx))) return res; + + samples = (cc_int16*)Mem_TryAlloc(ctx->blockSizes[1] * ctx->channels, 2); + if (!samples) return ERR_OUT_OF_MEMORY; + + for (;;) { + res = Vorbis_DecodeFrame(ctx); + if (res == ERR_END_OF_STREAM) { + /* reached end of samples, so done */ + res = SoundPatcher_FixupHeader(s, ctx, begOffset, len); + break; + } + if (res) break; + + count = Vorbis_OutputFrame(ctx, samples); + len += count * 2; + /* TODO: Do we need to account for big endian */ + res = Stream_Write(s, samples, count * 2); + if (res) break; + } + + Mem_Free(samples); + if (!res) res = s->Seek(s, begOffset + len); + return res; +} + +/* Converts an OGG sound to a WAV sound for faster decoding later */ +static cc_result SoundPatcher_Save(struct Stream* s, struct ResourceZipEntry* e) { + struct OggState* ogg = NULL; + struct VorbisState* ctx = NULL; + struct Stream src; + cc_result res; + + ogg = (struct OggState*)Mem_TryAlloc(1, sizeof(struct OggState)); + if (!ogg) { res = ERR_OUT_OF_MEMORY; goto cleanup; } + + ctx = (struct VorbisState*)Mem_TryAlloc(1, sizeof(struct VorbisState)); + if (!ctx) { res = ERR_OUT_OF_MEMORY; goto cleanup; } + + Stream_ReadonlyMemory(&src, e->value.data, e->size); + + Ogg_Init(ogg, &src); + Vorbis_Init(ctx); + ctx->source = ogg; + res = SoundPatcher_WriteWav(s, ctx); + +cleanup: + if (ctx) Vorbis_Free(ctx); + Mem_Free(ctx); + Mem_Free(ogg); + return res; +} + + /*########################################################################################################################* *------------------------------------------------------Zip entry writer---------------------------------------------------* *#########################################################################################################################*/ @@ -191,6 +316,14 @@ static cc_result ZipWriter_WritePng(struct Stream* dst, struct ResourceZipEntry* return ZipWriter_FixupLocalFile(dst, e); } +static cc_result ZipWriter_WriteWav(struct Stream* dst, struct ResourceZipEntry* e) { + cc_result res; + + if ((res = ZipWriter_LocalFile(dst, e))) return res; + if ((res = SoundPatcher_Save(dst, e))) return res; + return ZipWriter_FixupLocalFile(dst, e); +} + /*########################################################################################################################* *------------------------------------------------------Zip file writer----------------------------------------------------* @@ -207,9 +340,11 @@ static cc_result ZipFile_WriteEntries(struct Stream* s, struct ResourceZipEntry* if (e->type == RESOURCE_TYPE_PNG) { if ((res = ZipWriter_WritePng(s, e))) return res; + } else if (e->type == RESOURCE_TYPE_SOUND) { + if ((res = ZipWriter_WriteWav(s, e))) return res; } else { if ((res = ZipWriter_WriteData(s, e))) return res; - } + } } if ((res = s->Position(s, &beg))) return res; @@ -222,7 +357,7 @@ static cc_result ZipFile_WriteEntries(struct Stream* s, struct ResourceZipEntry* return ZipWriter_EndOfCentralDir(s, numEntries, beg, end); } -static void ZipFile_Create(cc_string* path, struct ResourceZipEntry* entries, int numEntries) { +static void ZipFile_Create(const cc_string* path, struct ResourceZipEntry* entries, int numEntries) { struct Stream s; cc_result res; @@ -364,60 +499,89 @@ static const struct AssetSet mccMusicAssetSet = { *---------------------------------------------------------Sound assets----------------------------------------------------* *#########################################################################################################################*/ static struct SoundAsset { - const char* name; + const char* filename; const char* hash; int reqID, size; void* data; } soundAssets[] = { - { "dig_cloth1", "5fd568d724ba7d53911b6cccf5636f859d2662e8" }, { "dig_cloth2", "56c1d0ac0de2265018b2c41cb571cc6631101484" }, - { "dig_cloth3", "9c63f2a3681832dc32d206f6830360bfe94b5bfc" }, { "dig_cloth4", "55da1856e77cfd31a7e8c3d358e1f856c5583198" }, - { "dig_grass1", "41cbf5dd08e951ad65883854e74d2e034929f572" }, { "dig_grass2", "86cb1bb0c45625b18e00a64098cd425a38f6d3f2" }, - { "dig_grass3", "f7d7e5c7089c9b45fa5d1b31542eb455fad995db" }, { "dig_grass4", "c7b1005d4926f6a2e2387a41ab1fb48a72f18e98" }, - { "dig_gravel1", "e8b89f316f3e9989a87f6e6ff12db9abe0f8b09f" }, { "dig_gravel2", "c3b3797d04cb9640e1d3a72d5e96edb410388fa3" }, - { "dig_gravel3", "48f7e1bb098abd36b9760cca27b9d4391a23de26" }, { "dig_gravel4", "7bf3553a4fe41a0078f4988a13d6e1ed8663ef4c" }, - { "dig_sand1", "9e59c3650c6c3fc0a475f1b753b2fcfef430bf81" }, { "dig_sand2", "0fa4234797f336ada4e3735e013e44d1099afe57" }, - { "dig_sand3", "c75589cc0087069f387de127dd1499580498738e" }, { "dig_sand4", "37afa06f97d58767a1cd1382386db878be1532dd" }, - { "dig_snow1", "e9bab7d3d15541f0aaa93fad31ad37fd07e03a6c" }, { "dig_snow2", "5887d10234c4f244ec5468080412f3e6ef9522f3" }, - { "dig_snow3", "a4bc069321a96236fde04a3820664cc23b2ea619" }, { "dig_snow4", "e26fa3036cdab4c2264ceb19e1cd197a2a510227" }, - { "dig_stone1", "4e094ed8dfa98656d8fec52a7d20c5ee6098b6ad" }, { "dig_stone2", "9c92f697142ae320584bf64c0d54381d59703528" }, - { "dig_stone3", "8f23c02475d388b23e5faa680eafe6b991d7a9d4" }, { "dig_stone4", "363545a76277e5e47538b2dd3a0d6aa4f7a87d34" }, - { "dig_wood1", "9bc2a84d0aa98113fc52609976fae8fc88ea6333" }, { "dig_wood2", "98102533e6085617a2962157b4f3658f59aea018" }, - { "dig_wood3", "45b2aef7b5049e81b39b58f8d631563fadcc778b" }, { "dig_wood4", "dc66978374a46ab2b87db6472804185824868095" }, - { "dig_glass1", "7274a2231ed4544a37e599b7b014e589e5377094" }, { "dig_glass2", "87c47bda3645c68f18a49e83cbf06e5302d087ff" }, - { "dig_glass3", "ad7d770b7fff3b64121f75bd60cecfc4866d1cd6" }, + { "dig_cloth1.wav", "5fd568d724ba7d53911b6cccf5636f859d2662e8" }, { "dig_cloth2.wav", "56c1d0ac0de2265018b2c41cb571cc6631101484" }, + { "dig_cloth3.wav", "9c63f2a3681832dc32d206f6830360bfe94b5bfc" }, { "dig_cloth4.wav", "55da1856e77cfd31a7e8c3d358e1f856c5583198" }, + { "dig_grass1.wav", "41cbf5dd08e951ad65883854e74d2e034929f572" }, { "dig_grass2.wav", "86cb1bb0c45625b18e00a64098cd425a38f6d3f2" }, + { "dig_grass3.wav", "f7d7e5c7089c9b45fa5d1b31542eb455fad995db" }, { "dig_grass4.wav", "c7b1005d4926f6a2e2387a41ab1fb48a72f18e98" }, + { "dig_gravel1.wav", "e8b89f316f3e9989a87f6e6ff12db9abe0f8b09f" }, { "dig_gravel2.wav", "c3b3797d04cb9640e1d3a72d5e96edb410388fa3" }, + { "dig_gravel3.wav", "48f7e1bb098abd36b9760cca27b9d4391a23de26" }, { "dig_gravel4.wav", "7bf3553a4fe41a0078f4988a13d6e1ed8663ef4c" }, + { "dig_sand1.wav", "9e59c3650c6c3fc0a475f1b753b2fcfef430bf81" }, { "dig_sand2.wav", "0fa4234797f336ada4e3735e013e44d1099afe57" }, + { "dig_sand3.wav", "c75589cc0087069f387de127dd1499580498738e" }, { "dig_sand4.wav", "37afa06f97d58767a1cd1382386db878be1532dd" }, + { "dig_snow1.wav", "e9bab7d3d15541f0aaa93fad31ad37fd07e03a6c" }, { "dig_snow2.wav", "5887d10234c4f244ec5468080412f3e6ef9522f3" }, + { "dig_snow3.wav", "a4bc069321a96236fde04a3820664cc23b2ea619" }, { "dig_snow4.wav", "e26fa3036cdab4c2264ceb19e1cd197a2a510227" }, + { "dig_stone1.wav", "4e094ed8dfa98656d8fec52a7d20c5ee6098b6ad" }, { "dig_stone2.wav", "9c92f697142ae320584bf64c0d54381d59703528" }, + { "dig_stone3.wav", "8f23c02475d388b23e5faa680eafe6b991d7a9d4" }, { "dig_stone4.wav", "363545a76277e5e47538b2dd3a0d6aa4f7a87d34" }, + { "dig_wood1.wav", "9bc2a84d0aa98113fc52609976fae8fc88ea6333" }, { "dig_wood2.wav", "98102533e6085617a2962157b4f3658f59aea018" }, + { "dig_wood3.wav", "45b2aef7b5049e81b39b58f8d631563fadcc778b" }, { "dig_wood4.wav", "dc66978374a46ab2b87db6472804185824868095" }, + { "dig_glass1.wav", "7274a2231ed4544a37e599b7b014e589e5377094" }, { "dig_glass2.wav", "87c47bda3645c68f18a49e83cbf06e5302d087ff" }, + { "dig_glass3.wav", "ad7d770b7fff3b64121f75bd60cecfc4866d1cd6" }, - { "step_cloth1", "5fd568d724ba7d53911b6cccf5636f859d2662e8" }, { "step_cloth2", "56c1d0ac0de2265018b2c41cb571cc6631101484" }, - { "step_cloth3", "9c63f2a3681832dc32d206f6830360bfe94b5bfc" }, { "step_cloth4", "55da1856e77cfd31a7e8c3d358e1f856c5583198" }, - { "step_grass1", "41cbf5dd08e951ad65883854e74d2e034929f572" }, { "step_grass2", "86cb1bb0c45625b18e00a64098cd425a38f6d3f2" }, - { "step_grass3", "f7d7e5c7089c9b45fa5d1b31542eb455fad995db" }, { "step_grass4", "c7b1005d4926f6a2e2387a41ab1fb48a72f18e98" }, - { "step_gravel1", "e8b89f316f3e9989a87f6e6ff12db9abe0f8b09f" }, { "step_gravel2", "c3b3797d04cb9640e1d3a72d5e96edb410388fa3" }, - { "step_gravel3", "48f7e1bb098abd36b9760cca27b9d4391a23de26" }, { "step_gravel4", "7bf3553a4fe41a0078f4988a13d6e1ed8663ef4c" }, - { "step_sand1", "9e59c3650c6c3fc0a475f1b753b2fcfef430bf81" }, { "step_sand2", "0fa4234797f336ada4e3735e013e44d1099afe57" }, - { "step_sand3", "c75589cc0087069f387de127dd1499580498738e" }, { "step_sand4", "37afa06f97d58767a1cd1382386db878be1532dd" }, - { "step_snow1", "e9bab7d3d15541f0aaa93fad31ad37fd07e03a6c" }, { "step_snow2", "5887d10234c4f244ec5468080412f3e6ef9522f3" }, - { "step_snow3", "a4bc069321a96236fde04a3820664cc23b2ea619" }, { "step_snow4", "e26fa3036cdab4c2264ceb19e1cd197a2a510227" }, - { "step_stone1", "4e094ed8dfa98656d8fec52a7d20c5ee6098b6ad" }, { "step_stone2", "9c92f697142ae320584bf64c0d54381d59703528" }, - { "step_stone3", "8f23c02475d388b23e5faa680eafe6b991d7a9d4" }, { "step_stone4", "363545a76277e5e47538b2dd3a0d6aa4f7a87d34" }, - { "step_wood1", "9bc2a84d0aa98113fc52609976fae8fc88ea6333" }, { "step_wood2", "98102533e6085617a2962157b4f3658f59aea018" }, - { "step_wood3", "45b2aef7b5049e81b39b58f8d631563fadcc778b" }, { "step_wood4", "dc66978374a46ab2b87db6472804185824868095" } + { "step_cloth1.wav", "5fd568d724ba7d53911b6cccf5636f859d2662e8" }, { "step_cloth2.wav", "56c1d0ac0de2265018b2c41cb571cc6631101484" }, + { "step_cloth3.wav", "9c63f2a3681832dc32d206f6830360bfe94b5bfc" }, { "step_cloth4.wav", "55da1856e77cfd31a7e8c3d358e1f856c5583198" }, + { "step_grass1.wav", "41cbf5dd08e951ad65883854e74d2e034929f572" }, { "step_grass2.wav", "86cb1bb0c45625b18e00a64098cd425a38f6d3f2" }, + { "step_grass3.wav", "f7d7e5c7089c9b45fa5d1b31542eb455fad995db" }, { "step_grass4.wav", "c7b1005d4926f6a2e2387a41ab1fb48a72f18e98" }, + { "step_gravel1.wav", "e8b89f316f3e9989a87f6e6ff12db9abe0f8b09f" }, { "step_gravel2.wav", "c3b3797d04cb9640e1d3a72d5e96edb410388fa3" }, + { "step_gravel3.wav", "48f7e1bb098abd36b9760cca27b9d4391a23de26" }, { "step_gravel4.wav", "7bf3553a4fe41a0078f4988a13d6e1ed8663ef4c" }, + { "step_sand1.wav", "9e59c3650c6c3fc0a475f1b753b2fcfef430bf81" }, { "step_sand2.wav", "0fa4234797f336ada4e3735e013e44d1099afe57" }, + { "step_sand3.wav", "c75589cc0087069f387de127dd1499580498738e" }, { "step_sand4.wav", "37afa06f97d58767a1cd1382386db878be1532dd" }, + { "step_snow1.wav", "e9bab7d3d15541f0aaa93fad31ad37fd07e03a6c" }, { "step_snow2.wav", "5887d10234c4f244ec5468080412f3e6ef9522f3" }, + { "step_snow3.wav", "a4bc069321a96236fde04a3820664cc23b2ea619" }, { "step_snow4.wav", "e26fa3036cdab4c2264ceb19e1cd197a2a510227" }, + { "step_stone1.wav", "4e094ed8dfa98656d8fec52a7d20c5ee6098b6ad" }, { "step_stone2.wav", "9c92f697142ae320584bf64c0d54381d59703528" }, + { "step_stone3.wav", "8f23c02475d388b23e5faa680eafe6b991d7a9d4" }, { "step_stone4.wav", "363545a76277e5e47538b2dd3a0d6aa4f7a87d34" }, + { "step_wood1.wav", "9bc2a84d0aa98113fc52609976fae8fc88ea6333" }, { "step_wood2.wav", "98102533e6085617a2962157b4f3658f59aea018" }, + { "step_wood3.wav", "45b2aef7b5049e81b39b58f8d631563fadcc778b" }, { "step_wood4.wav", "dc66978374a46ab2b87db6472804185824868095" } }; static cc_bool allSoundsExist; -static void SoundAssets_CheckExistence(void) { - cc_string path; char pathBuffer[FILENAME_SIZE]; +static void SoundAssets_ResetState(void) { + int i; + allSoundsExist = false; + + for (i = 0; i < Array_Elems(soundAssets); i++) + { + Mem_Free(soundAssets[i].data); + soundAssets[i].data = NULL; + soundAssets[i].size = 0; + } +} + + +/*########################################################################################################################* +*-----------------------------------------------------Sound asset checking -----------------------------------------------* +*#########################################################################################################################*/ +static int soundEntriesFound; + +static struct SoundAsset* SoundAssest_Find(const cc_string* name) { + struct SoundAsset* a; int i; - String_InitArray(path, pathBuffer); for (i = 0; i < Array_Elems(soundAssets); i++) { - path.length = 0; - String_Format1(&path, "audio/%c.wav", soundAssets[i].name); - - if (File_Exists(&path)) continue; - allSoundsExist = false; - return; + a = &soundAssets[i]; + if (String_CaselessEqualsConst(name, a->filename)) return a; } - allSoundsExist = true; + return NULL; +} + +static cc_bool SoundAssets_CheckEntry(const cc_string* path) { + cc_string name = *path; + Utils_UNSAFE_GetFilename(&name); + + if (SoundAssest_Find(&name)) soundEntriesFound++; + return false; +} + +static void SoundAssets_CheckExistence(void) { + soundEntriesFound = 0; + ZipFile_InspectEntries(&Sounds_DefaultZipPath, SoundAssets_CheckEntry); + + /* >= in case somehow have say "gui.png", "GUI.png" */ + allSoundsExist = soundEntriesFound >= Array_Elems(soundAssets); } static void SoundAssets_CountMissing(void) { @@ -427,6 +591,28 @@ static void SoundAssets_CountMissing(void) { Resources_Size += 417; } + +/*########################################################################################################################* +*----------------------------------------------------Sound asset generation ----------------------------------------------* +*#########################################################################################################################*/ +static void SoundAsset_CreateZip(void) { + struct ResourceZipEntry entries[Array_Elems(soundAssets)]; + int i; + + for (i = 0; i < Array_Elems(soundAssets); i++) + { + entries[i].filename = soundAssets[i].filename; + entries[i].type = RESOURCE_TYPE_SOUND; + + entries[i].value.data = soundAssets[i].data; + entries[i].size = soundAssets[i].size; + } + + ZipFile_Create(&Sounds_DefaultZipPath, entries, Array_Elems(soundAssets)); + SoundAssets_ResetState(); +} + + /*########################################################################################################################* *-----------------------------------------------------Sound asset fetching -----------------------------------------------* *#########################################################################################################################*/ @@ -445,141 +631,29 @@ static const char* SoundAssets_GetRequestName(int reqID) { int i; for (i = 0; i < Array_Elems(soundAssets); i++) { - if (reqID == soundAssets[i].reqID) return soundAssets[i].name; + if (reqID == soundAssets[i].reqID) return soundAssets[i].filename; } return NULL; } - -/*########################################################################################################################* -*----------------------------------------------------Sound asset processing ----------------------------------------------* -*#########################################################################################################################*/ -#define WAV_FourCC(a, b, c, d) (((cc_uint32)a << 24) | ((cc_uint32)b << 16) | ((cc_uint32)c << 8) | (cc_uint32)d) -#define WAV_HDR_SIZE 44 - -/* Fixes up the .WAV header after having written all samples */ -static void SoundPatcher_FixupHeader(struct Stream* s, struct VorbisState* ctx, cc_uint32 len) { - cc_uint8 header[WAV_HDR_SIZE]; - cc_result res = s->Seek(s, 0); - if (res) { Logger_SysWarn(res, "seeking to .wav start"); return; } - - Stream_SetU32_BE(header + 0, WAV_FourCC('R','I','F','F')); - Stream_SetU32_LE(header + 4, len - 8); - Stream_SetU32_BE(header + 8, WAV_FourCC('W','A','V','E')); - Stream_SetU32_BE(header + 12, WAV_FourCC('f','m','t',' ')); - Stream_SetU32_LE(header + 16, 16); /* fmt chunk size */ - Stream_SetU16_LE(header + 20, 1); /* PCM audio format */ - Stream_SetU16_LE(header + 22, ctx->channels); - Stream_SetU32_LE(header + 24, ctx->sampleRate); - - Stream_SetU32_LE(header + 28, ctx->sampleRate * ctx->channels * 2); /* byte rate */ - Stream_SetU16_LE(header + 32, ctx->channels * 2); /* block align */ - Stream_SetU16_LE(header + 34, 16); /* bits per sample */ - Stream_SetU32_BE(header + 36, WAV_FourCC('d','a','t','a')); - Stream_SetU32_LE(header + 40, len - WAV_HDR_SIZE); - - res = Stream_Write(s, header, WAV_HDR_SIZE); - if (res) Logger_SysWarn(res, "fixing .wav header"); -} - -/* Decodes all samples, then produces a .WAV file from them */ -static void SoundPatcher_WriteWav(struct Stream* s, struct VorbisState* ctx) { - cc_int16* samples; - cc_uint32 len = WAV_HDR_SIZE; - cc_result res; - int count; - - /* ctx is all 0, so reuse here for empty header */ - res = Stream_Write(s, (const cc_uint8*)ctx, WAV_HDR_SIZE); - if (res) { Logger_SysWarn(res, "writing .wav header"); return; } - - res = Vorbis_DecodeHeaders(ctx); - if (res) { Logger_SysWarn(res, "decoding .ogg header"); return; } - - samples = (cc_int16*)Mem_TryAlloc(ctx->blockSizes[1] * ctx->channels, 2); - if (!samples) { Logger_SysWarn(ERR_OUT_OF_MEMORY, "allocating .ogg samples"); return; } - - for (;;) { - res = Vorbis_DecodeFrame(ctx); - if (res == ERR_END_OF_STREAM) { - /* reached end of samples, so done */ - SoundPatcher_FixupHeader(s, ctx, len); break; - } - if (res) { Logger_SysWarn(res, "decoding .ogg"); break; } - - count = Vorbis_OutputFrame(ctx, samples); - len += count * 2; - /* TODO: Do we need to account for big endian */ - res = Stream_Write(s, samples, count * 2); - if (res) { Logger_SysWarn(res, "writing samples"); break; } - } - Mem_Free(samples); -} - -/* Converts an OGG sound to a WAV sound for faster decoding later */ -static void SoundPatcher_Save(const char* name, struct HttpRequest* req) { - cc_string path; char pathBuffer[STRING_SIZE]; - struct OggState* ogg = NULL; - struct VorbisState* ctx = NULL; - struct Stream src, dst; - cc_result res; - - ogg = (struct OggState*)Mem_TryAlloc(1, sizeof(struct OggState)); - if (!ogg) { Logger_SysWarn(ERR_OUT_OF_MEMORY, "allocating memory"); goto cleanup; } - - ctx = (struct VorbisState*)Mem_TryAlloc(1, sizeof(struct VorbisState)); - if (!ctx) { Logger_SysWarn(ERR_OUT_OF_MEMORY, "allocating memory"); goto cleanup; } - - Stream_ReadonlyMemory(&src, req->data, req->size); - String_InitArray(path, pathBuffer); - String_Format1(&path, "audio/%c.wav", name); - - res = Stream_CreateFile(&dst, &path); - if (res) { Logger_SysWarn(res, "creating .wav file"); goto cleanup; } - - Ogg_Init(ogg, &src); - Vorbis_Init(ctx); - ctx->source = ogg; - SoundPatcher_WriteWav(&dst, ctx); - - res = dst.Close(&dst); - if (res) Logger_SysWarn(res, "closing .wav file"); - -cleanup: - if (ctx) Vorbis_Free(ctx); - Mem_Free(ctx); - Mem_Free(ogg); -} - - -static void SoundAsset_Check(struct SoundAsset* sound) { +static void SoundAsset_Check(struct SoundAsset* sound, int i) { struct HttpRequest item; if (!Fetcher_Get(sound->reqID, &item)) return; - SoundPatcher_Save(sound->name, &item); - sound->data = item.data; sound->size = item.size; item.data = NULL; HttpRequest_Free(&item); + + if (i == Array_Elems(soundAssets) - 1) + SoundAsset_CreateZip(); } static void SoundAssets_CheckStatus(void) { int i; for (i = 0; i < Array_Elems(soundAssets); i++) { - SoundAsset_Check(&soundAssets[i]); - } -} - -static void SoundAssets_ResetState(void) { - int i; - allSoundsExist = false; - - for (i = 0; i < Array_Elems(soundAssets); i++) - { - Mem_Free(soundAssets[i].data); - soundAssets[i].data = NULL; + SoundAsset_Check(&soundAssets[i], i); } } @@ -738,15 +812,6 @@ CC_NOINLINE static struct ResourceZipEntry* ZipEntries_Find(const cc_string* nam return NULL; } -static cc_result ZipEntry_ExtractData(struct ResourceZipEntry* e, struct Stream* data, struct ZipEntry* source) { - cc_uint32 size = source->UncompressedSize; - e->value.data = Mem_TryAlloc(size, 1); - e->size = size; - - if (!e->value.data) return ERR_OUT_OF_MEMORY; - return Stream_Read(data, e->value.data, size); -} - static cc_result ClassicPatcher_ExtractFiles(struct HttpRequest* req); static cc_result ModernPatcher_ExtractFiles(struct HttpRequest* req); @@ -771,6 +836,19 @@ static struct ZipfileSource { }; static int numDefaultZipSources, numDefaultZipProcessed; +static void MCCTextures_ResetState(void) { + int i; + for (i = 0; i < Array_Elems(defaultZipEntries); i++) + { + if (defaultZipEntries[i].type == RESOURCE_TYPE_CONST) continue; + + /* can reuse value.data for value.bmp case too */ + Mem_Free(defaultZipEntries[i].value.data); + defaultZipEntries[i].value.data = NULL; + defaultZipEntries[i].size = 0; + } +} + /*########################################################################################################################* *------------------------------------------------default.zip entry generators---------------------------------------------* @@ -980,19 +1058,10 @@ static cc_bool DefaultZip_SelectEntry(const cc_string* path) { } static void MCCTextures_CheckExistence(void) { - cc_string path = String_FromReadonly(Game_Version.DefaultTexpack); - struct Stream stream; - cc_result res; + cc_string path = String_FromReadonly(Game_Version.DefaultTexpack); + zipEntriesFound = 0; - res = Stream_OpenFile(&stream, &path); - if (res == ReturnCode_FileNotFound) return; - if (res) { Logger_SysWarn2(res, "opening", &path); return; } - - res = Zip_Extract(&stream, DefaultZip_SelectEntry, NULL); - if (res) Logger_SysWarn2(res, "inspecting", &path); - - /* No point logging error for closing readonly file */ - (void)stream.Close(&stream); + ZipFile_InspectEntries(&path, DefaultZip_SelectEntry); /* >= in case somehow have say "gui.png", "GUI.png" */ allZipEntriesExist = zipEntriesFound >= Array_Elems(defaultZipEntries); @@ -1048,6 +1117,7 @@ static const char* MCCTextures_GetRequestName(int reqID) { static void MCCTextures_CreateDefaultZip(void) { cc_string path = String_FromReadonly(Game_Version.DefaultTexpack); ZipFile_Create(&path, defaultZipEntries, Array_Elems(defaultZipEntries)); + MCCTextures_ResetState(); } static void MCCTextures_CheckSource(struct ZipfileSource* source) { @@ -1077,22 +1147,6 @@ static void MCCTextures_CheckStatus(void) { } } -static void MCCTextures_ResetState(void) { - int i; - allZipEntriesExist = false; - zipEntriesFound = 0; - - for (i = 0; i < Array_Elems(defaultZipEntries); i++) - { - if (defaultZipEntries[i].type == RESOURCE_TYPE_CONST) continue; - - /* can reuse value.data for value.bmp case too */ - Mem_Free(defaultZipEntries[i].value.data); - defaultZipEntries[i].value.data = NULL; - defaultZipEntries[i].size = 0; - } -} - static const struct AssetSet mccTexsAssetSet = { MCCTextures_CheckExistence, MCCTextures_CountMissing, From 9c0bdb68e7310c927db1c9df4e332280f654ed67 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 3 Apr 2024 19:00:00 +1100 Subject: [PATCH 4/6] Load sounds from zip instead --- src/Audio.c | 49 +++++++++++++++++++++++++++---------------------- src/Resources.c | 16 +++++++--------- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/Audio.c b/src/Audio.c index f8ece07b8..063a8437d 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -12,6 +12,7 @@ #include "Stream.h" #include "Utils.h" #include "Options.h" +#include "Deflate.h" #ifdef CC_BUILD_ANDROID /* TODO: Refactor maybe to not rely on checking WinInfo.Handle != NULL */ #include "Window.h" @@ -100,30 +101,18 @@ static cc_result Sound_ReadWaveData(struct Stream* stream, struct Sound* snd) { } } -static cc_result Sound_ReadWave(const cc_string* path, struct Sound* snd) { - struct Stream stream; - cc_result res; - - res = Stream_OpenFile(&stream, path); - if (res) return res; - res = Sound_ReadWaveData(&stream, snd); - - /* No point logging error for closing readonly file */ - (void)stream.Close(&stream); - return res; -} - -static struct SoundGroup* Soundboard_Find(struct Soundboard* board, const cc_string* name) { +static struct SoundGroup* Soundboard_FindGroup(struct Soundboard* board, const cc_string* name) { struct SoundGroup* groups = board->groups; int i; - for (i = 0; i < SOUND_COUNT; i++) { + for (i = 0; i < SOUND_COUNT; i++) + { if (String_CaselessEqualsConst(name, Sound_Names[i])) return &groups[i]; } return NULL; } -static void Soundboard_Load(struct Soundboard* board, const cc_string* boardName, const cc_string* file) { +static void Soundboard_Load(struct Soundboard* board, const cc_string* boardName, const cc_string* file, struct Stream* stream) { struct SoundGroup* group; struct Sound* snd; cc_string name = *file; @@ -140,7 +129,7 @@ static void Soundboard_Load(struct Soundboard* board, const cc_string* boardName name = String_UNSAFE_SubstringAt(&name, boardName->length); name = String_UNSAFE_Substring(&name, 0, name.length - 1); - group = Soundboard_Find(board, &name); + group = Soundboard_FindGroup(board, &name); if (!group) { Chat_Add1("&cUnknown sound group '%s'", &name); return; } @@ -149,7 +138,7 @@ static void Soundboard_Load(struct Soundboard* board, const cc_string* boardName } snd = &group->sounds[group->count]; - res = Sound_ReadWave(file, snd); + res = Sound_ReadWaveData(stream, snd); if (res) { Logger_SysWarn2(res, "decoding", file); @@ -220,12 +209,28 @@ static void Audio_PlayBlockSound(void* obj, IVec3 coords, BlockID old, BlockID n } } -static void Sounds_LoadFile(const cc_string* path, void* obj) { +static cc_bool SelectZipEntry(const cc_string* path) { return true; } +static cc_result ProcessZipEntry(const cc_string* path, struct Stream* stream, struct ZipEntry* source) { static const cc_string dig = String_FromConst("dig_"); static const cc_string step = String_FromConst("step_"); - Soundboard_Load(&digBoard, &dig, path); - Soundboard_Load(&stepBoard, &step, path); + Soundboard_Load(&digBoard, &dig, path, stream); + Soundboard_Load(&stepBoard, &step, path, stream); + return 0; +} + +static void Sounds_ExtractZip(const cc_string* path) { + struct Stream stream; + cc_result res; + + res = Stream_OpenFile(&stream, path); + if (res) { Logger_SysWarn2(res, "opening", path); return res; } + + res = Zip_Extract(&stream, SelectZipEntry, ProcessZipEntry); + if (res) { Logger_SysWarn2(res, "extracting", path); return res; } + + /* No point logging error for closing readonly file */ + (void)stream.Close(&stream); } /* TODO this is a pretty terrible solution */ @@ -281,7 +286,7 @@ static void Sounds_Start(void) { #ifdef CC_BUILD_WEBAUDIO InitWebSounds(); #else - Directory_Enum(&audio_dir, NULL, Sounds_LoadFile); + Sounds_ExtractZip(&Sounds_DefaultZipPath); #endif } diff --git a/src/Resources.c b/src/Resources.c index a868c2ada..23388a153 100644 --- a/src/Resources.c +++ b/src/Resources.c @@ -704,30 +704,28 @@ static const char* CCTextures_GetRequestName(int reqID) { /*########################################################################################################################* *-------------------------------------------------CC texture assets processing -------------------------------------------* *#########################################################################################################################*/ -#ifdef CC_BUILD_MOBILE /* Android needs the touch.png */ /* TODO: Unify both android and desktop platforms to both just extract from default.zip */ static cc_bool CCTextures_SelectEntry(const cc_string* path) { return String_CaselessEqualsConst(path, "touch.png"); } + static cc_result CCTextures_ProcessEntry(const cc_string* path, struct Stream* data, struct ZipEntry* source) { struct ResourceZipEntry* e = ZipEntries_Find(path); + if (!e) return 0; /* TODO exteact on PC too */ + return ZipEntry_ExtractData(e, data, source); } static cc_result CCTextures_ExtractZip(struct HttpRequest* req) { struct Stream src; - Stream_WriteAllTo(&ccTexPack, req->data, req->size); - Stream_ReadonlyMemory(&src, req->data, req->size); + cc_result res; + + Stream_ReadonlyMemory(&src, req->data, req->size); + if ((res = Zip_Extract(&src, CCTextures_SelectEntry, CCTextures_ProcessEntry))) return res; - return Zip_Extract(&src, - CCTextures_SelectEntry, CCTextures_ProcessEntry); -} -#else -static cc_result CCTextures_ExtractZip(struct HttpRequest* req) { return Stream_WriteAllTo(&ccTexPack, req->data, req->size); } -#endif static void CCTextures_CheckStatus(void) { struct HttpRequest item; From b98cb2fc74091689164e4fa0b0b344f12d5e5ba5 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 3 Apr 2024 19:22:31 +1100 Subject: [PATCH 5/6] Change messaging for required vs optional resources, support loading classicube.zip as fallback for sounds --- src/Audio.c | 16 +++++++++++----- src/Audio.h | 3 ++- src/LScreens.c | 8 +++++--- src/Launcher.c | 2 +- src/Resources.c | 32 +++++++++++++++++--------------- src/Resources.h | 6 ++++-- 6 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/Audio.c b/src/Audio.c index 063a8437d..3c0245613 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -17,8 +17,10 @@ /* TODO: Refactor maybe to not rely on checking WinInfo.Handle != NULL */ #include "Window.h" #endif + int Audio_SoundsVolume, Audio_MusicVolume; -const cc_string Sounds_DefaultZipPath = String_FromConst("audio/default.zip"); +const cc_string Sounds_ZipPathMC = String_FromConst("audio/default.zip"); +const cc_string Sounds_ZipPathCC = String_FromConst("audio/classicube.zip"); static const cc_string audio_dir = String_FromConst("audio"); struct Sound { @@ -219,18 +221,19 @@ static cc_result ProcessZipEntry(const cc_string* path, struct Stream* stream, s return 0; } -static void Sounds_ExtractZip(const cc_string* path) { +static cc_result Sounds_ExtractZip(const cc_string* path) { struct Stream stream; cc_result res; res = Stream_OpenFile(&stream, path); - if (res) { Logger_SysWarn2(res, "opening", path); return res; } + if (res) { Logger_SysWarn2(res, "opening", path); return res; } res = Zip_Extract(&stream, SelectZipEntry, ProcessZipEntry); - if (res) { Logger_SysWarn2(res, "extracting", path); return res; } + if (res) Logger_SysWarn2(res, "extracting", path); /* No point logging error for closing readonly file */ (void)stream.Close(&stream); + return res; } /* TODO this is a pretty terrible solution */ @@ -275,6 +278,7 @@ static void InitWebSounds(void) { static cc_bool sounds_loaded; static void Sounds_Start(void) { + cc_result res; if (!AudioBackend_Init()) { AudioBackend_Free(); Audio_SoundsVolume = 0; @@ -286,7 +290,9 @@ static void Sounds_Start(void) { #ifdef CC_BUILD_WEBAUDIO InitWebSounds(); #else - Sounds_ExtractZip(&Sounds_DefaultZipPath); + res = Sounds_ExtractZip(&Sounds_ZipPathMC); + if (res == ReturnCode_FileNotFound) + Sounds_ExtractZip(&Sounds_ZipPathCC); #endif } diff --git a/src/Audio.h b/src/Audio.h index c8dd34cf4..e054d1c2d 100644 --- a/src/Audio.h +++ b/src/Audio.h @@ -34,7 +34,8 @@ extern int Audio_SoundsVolume; /* Volume music is played at, from 0-100. */ /* NOTE: Use Audio_SetMusic, don't change this directly. */ extern int Audio_MusicVolume; -extern const cc_string Sounds_DefaultZipPath; +extern const cc_string Sounds_ZipPathMC; +extern const cc_string Sounds_ZipPathCC; void Audio_SetMusic(int volume); void Audio_SetSounds(int volume); diff --git a/src/LScreens.c b/src/LScreens.c index 539df3b5f..a4a5e25b5 100644 --- a/src/LScreens.c +++ b/src/LScreens.c @@ -1012,9 +1012,11 @@ static void CheckResourcesScreen_Next(void* w) { } static void CheckResourcesScreen_AddWidgets(struct CheckResourcesScreen* s) { + const char* line1_msg = Resources_MissingRequired ? "Some required resources weren't found" + : "Some optional resources weren't found"; s->lblStatus.small = true; - LLabel_Add(s, &s->lblLine1, "Some required resources weren't found", cres_lblLine1); + LLabel_Add(s, &s->lblLine1, line1_msg, cres_lblLine1); LLabel_Add(s, &s->lblLine2, "Okay to download?", cres_lblLine2); LLabel_Add(s, &s->lblStatus, "", cres_lblStatus); @@ -1030,7 +1032,7 @@ static void CheckResourcesScreen_Activated(struct LScreen* s_) { float size; CheckResourcesScreen_AddWidgets(s); - size = Resources_Size / 1024.0f; + size = Resources_MissingSize / 1024.0f; String_InitArray(str, buffer); String_Format1(&str, "&eDownload size: %f2 megabytes", &size); LLabel_SetText(&s->lblStatus, &str); @@ -1121,7 +1123,7 @@ static void FetchResourcesScreen_UpdateStatus(struct FetchResourcesScreen* s, in String_InitArray(str, strBuffer); count = Fetcher_Downloaded + 1; - String_Format3(&str, "&eFetching %c.. (%i/%i)", name, &count, &Resources_Count); + String_Format3(&str, "&eFetching %c.. (%i/%i)", name, &count, &Resources_MissingCount); if (String_Equals(&str, &s->lblStatus.text)) return; LLabel_SetText(&s->lblStatus, &str); diff --git a/src/Launcher.c b/src/Launcher.c index 8293dc74e..79d80cf83 100644 --- a/src/Launcher.c +++ b/src/Launcher.c @@ -260,7 +260,7 @@ void Launcher_Run(void) { #ifdef CC_BUILD_RESOURCES Resources_CheckExistence(); - if (Resources_Count) { + if (Resources_MissingCount) { CheckResourcesScreen_SetActive(); } else { MainScreen_SetActive(); diff --git a/src/Resources.c b/src/Resources.c index 23388a153..fba5474ca 100644 --- a/src/Resources.c +++ b/src/Resources.c @@ -33,7 +33,8 @@ struct AssetSet { void (*ResetState)(void); }; -int Resources_Count, Resources_Size; +int Resources_MissingCount, Resources_MissingSize; +cc_bool Resources_MissingRequired; union ResourceValue { cc_uint8* data; @@ -58,7 +59,7 @@ static cc_result ZipEntry_ExtractData(struct ResourceZipEntry* e, struct Stream* /*########################################################################################################################* -*------------------------------------------------=-----Utility functions ------------------------=------------------------* +*------------------------------------------------------Utility functions -------------------------------------------------* *#########################################################################################################################*/ static void ZipFile_InspectEntries(const cc_string* path, Zip_SelectEntry selector) { struct Stream stream; @@ -413,8 +414,8 @@ static void MusicAssets_CountMissing(void) { { if (musicAssets[i].downloaded) continue; - Resources_Size += musicAssets[i].size; - Resources_Count++; + Resources_MissingSize += musicAssets[i].size; + Resources_MissingCount++; } } @@ -578,7 +579,7 @@ static cc_bool SoundAssets_CheckEntry(const cc_string* path) { static void SoundAssets_CheckExistence(void) { soundEntriesFound = 0; - ZipFile_InspectEntries(&Sounds_DefaultZipPath, SoundAssets_CheckEntry); + ZipFile_InspectEntries(&Sounds_ZipPathMC, SoundAssets_CheckEntry); /* >= in case somehow have say "gui.png", "GUI.png" */ allSoundsExist = soundEntriesFound >= Array_Elems(soundAssets); @@ -587,8 +588,8 @@ static void SoundAssets_CheckExistence(void) { static void SoundAssets_CountMissing(void) { if (allSoundsExist) return; - Resources_Count += Array_Elems(soundAssets); - Resources_Size += 417; + Resources_MissingCount += Array_Elems(soundAssets); + Resources_MissingSize += 417; } @@ -608,7 +609,7 @@ static void SoundAsset_CreateZip(void) { entries[i].size = soundAssets[i].size; } - ZipFile_Create(&Sounds_DefaultZipPath, entries, Array_Elems(soundAssets)); + ZipFile_Create(&Sounds_ZipPathMC, entries, Array_Elems(soundAssets)); SoundAssets_ResetState(); } @@ -681,8 +682,9 @@ static void CCTextures_CheckExistence(void) { static void CCTextures_CountMissing(void) { if (ccTexturesExist) return; - Resources_Count++; - Resources_Size += 83; + Resources_MissingCount++; + Resources_MissingSize += 83; + Resources_MissingRequired = true; } @@ -1076,8 +1078,8 @@ static void MCCTextures_CountMissing(void) { if (Game_Version.Version > VERSION_0023) numDefaultZipSources--; for (i = 0; i < numDefaultZipSources; i++) { - Resources_Count++; - Resources_Size += defaultZipSources[i].size; + Resources_MissingCount++; + Resources_MissingSize += defaultZipSources[i].size; } } @@ -1171,8 +1173,8 @@ static const struct AssetSet* const asset_sets[] = { static void ResetState() { int i; - Resources_Count = 0; - Resources_Size = 0; + Resources_MissingCount = 0; + Resources_MissingSize = 0; for (i = 0; i < Array_Elems(asset_sets); i++) { @@ -1258,7 +1260,7 @@ void Fetcher_Update(void) { asset_sets[i]->CheckStatus(); } - if (Fetcher_Downloaded != Resources_Count) return; + if (Fetcher_Downloaded != Resources_MissingCount) return; Fetcher_Finish(); } #endif diff --git a/src/Resources.h b/src/Resources.h index 427da4221..4e629e55d 100644 --- a/src/Resources.h +++ b/src/Resources.h @@ -8,9 +8,11 @@ struct HttpRequest; typedef void (*FetcherErrorCallback)(struct HttpRequest* req); /* Number of resources that need to be downloaded */ -extern int Resources_Count; +extern int Resources_MissingCount; /* Total size of resources that need to be downloaded */ -extern int Resources_Size; +extern int Resources_MissingSize; +/* Whether required resources need to be downloaded */ +extern cc_bool Resources_MissingRequired; /* Checks existence of all assets */ void Resources_CheckExistence(void); From d31122eb0d9be5526e7dcf7370cee836a28bbe68 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 3 Apr 2024 19:52:39 +1100 Subject: [PATCH 6/6] Swap .wav audio endian so that it is read/written as little endian on big endian machines --- src/Audio.c | 7 ++++++- src/Resources.c | 7 +++++-- src/Utils.c | 13 +++++++++++++ src/Utils.h | 1 + 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/Audio.c b/src/Audio.c index 3c0245613..435f37579 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -95,7 +95,12 @@ static cc_result Sound_ReadWaveData(struct Stream* stream, struct Sound* snd) { if ((res = Audio_AllocChunks(size, &snd->data, 1))) return res; snd->size = size; - return Stream_Read(stream, (cc_uint8*)snd->data, size); + res = Stream_Read(stream, (cc_uint8*)snd->data, size); + + #ifdef CC_BUILD_BIGENDIAN + Utils_SwapEndian16((cc_int16*)snd->data, size / 2); + #endif + return res; } /* Skip over unhandled data */ diff --git a/src/Resources.c b/src/Resources.c index fba5474ca..167fc7aba 100644 --- a/src/Resources.c +++ b/src/Resources.c @@ -144,8 +144,11 @@ static cc_result SoundPatcher_WriteWav(struct Stream* s, struct VorbisState* ctx count = Vorbis_OutputFrame(ctx, samples); len += count * 2; - /* TODO: Do we need to account for big endian */ - res = Stream_Write(s, samples, count * 2); + +#ifdef CC_BUILD_BIGENDIAN + Utils_SwapEndian16(samples, count); +#endif + res = Stream_Write(s, (cc_uint8*)samples, count * 2); if (res) break; } diff --git a/src/Utils.c b/src/Utils.c index 9de401d21..6ec7a57b7 100644 --- a/src/Utils.c +++ b/src/Utils.c @@ -138,6 +138,19 @@ void Utils_Resize(void** buffer, int* capacity, cc_uint32 elemSize, int defCapac } } +void Utils_SwapEndian16(cc_int16* values, int numValues) { + cc_uint8* data = (cc_uint8*)values; + int i; + + for (i = 0; i < numValues * 2; i += 2) + { + cc_uint8 tmp = data[i + 0]; + data[i + 0] = data[i + 1]; + data[i + 1] = tmp; + } +} + + static const char base64_table[64] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', diff --git a/src/Utils.h b/src/Utils.h index 7d8f245ad..78995c0ef 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -45,6 +45,7 @@ cc_uint32 Utils_CRC32(const cc_uint8* data, cc_uint32 length); /* NOTE: This cannot be just indexed by byte value - see Utils_CRC32 implementation. */ extern const cc_uint32 Utils_Crc32Table[256]; CC_NOINLINE void Utils_Resize(void** buffer, int* capacity, cc_uint32 elemSize, int defCapacity, int expandElems); +void Utils_SwapEndian16(cc_int16* values, int numValues); /* Converts blocks of 3 bytes into 4 ASCII characters. (pads if needed) */ /* Returns the number of ASCII characters written. */