diff --git a/OTRExporter/OTRExporter/Exporter.cpp b/OTRExporter/OTRExporter/Exporter.cpp index b8b0612f5..f2daa4279 100644 --- a/OTRExporter/OTRExporter/Exporter.cpp +++ b/OTRExporter/OTRExporter/Exporter.cpp @@ -3,7 +3,7 @@ void OTRExporter::WriteHeader(ZResource* res, const fs::path& outPath, BinaryWriter* writer, Ship::ResourceType resType, Ship::Version resVersion) { - writer->Write((uint8_t)Endianess::Little); // 0x00 + writer->Write((uint8_t)Endianness::Little); // 0x00 writer->Write((uint8_t)0); // 0x01 writer->Write((uint8_t)0); // 0x02 writer->Write((uint8_t)0); // 0x03 diff --git a/ZAPDTR/ZAPDUtils/Utils/BinaryReader.cpp b/ZAPDTR/ZAPDUtils/Utils/BinaryReader.cpp index 94ca98a01..5916ce982 100644 --- a/ZAPDTR/ZAPDUtils/Utils/BinaryReader.cpp +++ b/ZAPDTR/ZAPDUtils/Utils/BinaryReader.cpp @@ -18,6 +18,16 @@ void BinaryReader::Close() stream->Close(); } +void BinaryReader::SetEndianness(Endianness endianness) +{ + this->endianness = endianness; +} + +Endianness BinaryReader::GetEndianness() const +{ + return endianness; +} + void BinaryReader::Seek(uint32_t offset, SeekOffsetType seekType) { stream->Seek(offset, seekType); @@ -28,11 +38,16 @@ uint32_t BinaryReader::GetBaseAddress() return stream->GetBaseAddress(); } -void BinaryReader::Read([[maybe_unused]] char* buffer, int32_t length) +void BinaryReader::Read(int32_t length) { stream->Read(length); } +void BinaryReader::Read(char* buffer, int32_t length) +{ + stream->Read(buffer, length); +} + char BinaryReader::ReadChar() { return (char)stream->ReadByte(); @@ -53,6 +68,10 @@ int16_t BinaryReader::ReadInt16() int16_t result = 0; stream->Read((char*)&result, sizeof(int16_t)); + + if (endianness != Endianness::Native) + result = BSWAP16(result); + return result; } @@ -61,6 +80,10 @@ int32_t BinaryReader::ReadInt32() int32_t result = 0; stream->Read((char*)&result, sizeof(int32_t)); + + if (endianness != Endianness::Native) + result = BSWAP32(result); + return result; } @@ -69,6 +92,10 @@ uint16_t BinaryReader::ReadUInt16() uint16_t result = 0; stream->Read((char*)&result, sizeof(uint16_t)); + + if (endianness != Endianness::Native) + result = BSWAP16(result); + return result; } @@ -77,6 +104,10 @@ uint32_t BinaryReader::ReadUInt32() uint32_t result = 0; stream->Read((char*)&result, sizeof(uint32_t)); + + if (endianness != Endianness::Native) + result = BSWAP32(result); + return result; } @@ -85,6 +116,10 @@ uint64_t BinaryReader::ReadUInt64() uint64_t result = 0; stream->Read((char*)&result, sizeof(uint64_t)); + + if (endianness != Endianness::Native) + result = BSWAP64(result); + return result; } @@ -94,6 +129,9 @@ float BinaryReader::ReadSingle() stream->Read((char*)&result, sizeof(float)); + if (endianness != Endianness::Native) + result = BitConverter::ToFloatBE((uint8_t*)&result, 0); + if (std::isnan(result)) throw std::runtime_error("BinaryReader::ReadSingle(): Error reading stream"); @@ -105,6 +143,10 @@ double BinaryReader::ReadDouble() double result = NAN; stream->Read((char*)&result, sizeof(double)); + + if (endianness != Endianness::Native) + result = BitConverter::ToDoubleBE((uint8_t*)&result, 0); + if (std::isnan(result)) throw std::runtime_error("BinaryReader::ReadDouble(): Error reading stream"); diff --git a/ZAPDTR/ZAPDUtils/Utils/BinaryReader.h b/ZAPDTR/ZAPDUtils/Utils/BinaryReader.h index a1994aa4a..0b18351c8 100644 --- a/ZAPDTR/ZAPDUtils/Utils/BinaryReader.h +++ b/ZAPDTR/ZAPDUtils/Utils/BinaryReader.h @@ -8,6 +8,7 @@ #include "../Vec2f.h" #include "../Vec3f.h" #include "../Vec3s.h" +#include "BitConverter.h" #include "Stream.h" class BinaryReader @@ -18,9 +19,13 @@ public: void Close(); + void SetEndianness(Endianness endianness); + Endianness GetEndianness() const; + void Seek(uint32_t offset, SeekOffsetType seekType); uint32_t GetBaseAddress(); + void Read(int32_t length); void Read(char* buffer, int32_t length); char ReadChar(); int8_t ReadByte(); @@ -41,4 +46,5 @@ public: protected: std::shared_ptr stream; + Endianness endianness = Endianness::Native; }; \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/Utils/BinaryWriter.cpp b/ZAPDTR/ZAPDUtils/Utils/BinaryWriter.cpp index c456bdeb3..aa7840f01 100644 --- a/ZAPDTR/ZAPDUtils/Utils/BinaryWriter.cpp +++ b/ZAPDTR/ZAPDUtils/Utils/BinaryWriter.cpp @@ -10,6 +10,11 @@ BinaryWriter::BinaryWriter(std::shared_ptr nStream) stream = nStream; } +void BinaryWriter::SetEndianness(Endianness endianness) +{ + this->endianness = endianness; +} + void BinaryWriter::Close() { stream->Close(); @@ -47,16 +52,25 @@ void BinaryWriter::Write(uint8_t value) void BinaryWriter::Write(int16_t value) { + if (endianness != Endianness::Native) + value = BSWAP16(value); + stream->Write((char*)&value, sizeof(int16_t)); } void BinaryWriter::Write(uint16_t value) { + if (endianness != Endianness::Native) + value = BSWAP16(value); + stream->Write((char*)&value, sizeof(uint16_t)); } void BinaryWriter::Write(int32_t value) { + if (endianness != Endianness::Native) + value = BSWAP32(value); + stream->Write((char*)&value, sizeof(int32_t)); } @@ -68,33 +82,48 @@ void BinaryWriter::Write(int32_t valueA, int32_t valueB) void BinaryWriter::Write(uint32_t value) { + if (endianness != Endianness::Native) + value = BSWAP32(value); + stream->Write((char*)&value, sizeof(uint32_t)); } void BinaryWriter::Write(int64_t value) { + if (endianness != Endianness::Native) + value = BSWAP64(value); + stream->Write((char*)&value, sizeof(int64_t)); } void BinaryWriter::Write(uint64_t value) { + if (endianness != Endianness::Native) + value = BSWAP64(value); + stream->Write((char*)&value, sizeof(uint64_t)); } void BinaryWriter::Write(float value) { + if (endianness != Endianness::Native) + value = BitConverter::ToFloatBE((uint8_t*)&value, 0); + stream->Write((char*)&value, sizeof(float)); } void BinaryWriter::Write(double value) { + if (endianness != Endianness::Native) + value = BitConverter::ToDoubleBE((uint8_t*)&value, 0); + stream->Write((char*)&value, sizeof(double)); } void BinaryWriter::Write(const std::string& str) { int strLen = str.size(); - stream->Write((char*)&strLen, sizeof(int)); + Write(strLen); for (char c : str) stream->WriteByte(c); diff --git a/ZAPDTR/ZAPDUtils/Utils/BinaryWriter.h b/ZAPDTR/ZAPDUtils/Utils/BinaryWriter.h index e6dd84105..67c8fcd1e 100644 --- a/ZAPDTR/ZAPDUtils/Utils/BinaryWriter.h +++ b/ZAPDTR/ZAPDUtils/Utils/BinaryWriter.h @@ -4,6 +4,7 @@ #include #include #include +#include "BitConverter.h" #include "Stream.h" class BinaryWriter @@ -12,6 +13,8 @@ public: BinaryWriter(Stream* nStream); BinaryWriter(std::shared_ptr nStream); + void SetEndianness(Endianness endianness); + std::shared_ptr GetStream(); uint64_t GetBaseAddress(); uint64_t GetLength(); @@ -34,4 +37,5 @@ public: protected: std::shared_ptr stream; + Endianness endianness = Endianness::Native; }; \ No newline at end of file diff --git a/ZAPDTR/ZAPDUtils/Utils/BitConverter.h b/ZAPDTR/ZAPDUtils/Utils/BitConverter.h index 708d4b537..b62891d3d 100644 --- a/ZAPDTR/ZAPDUtils/Utils/BitConverter.h +++ b/ZAPDTR/ZAPDUtils/Utils/BitConverter.h @@ -5,6 +5,28 @@ #include #include +#ifdef _MSC_VER +#define BSWAP16 _byteswap_ushort +#define BSWAP32 _byteswap_ulong +#define BSWAP64 _byteswap_uint64 +#else +#define BSWAP16 __builtin_bswap16 +#define BSWAP32 __builtin_bswap32 +#define BSWAP64 __builtin_bswap64 +#endif + +enum class Endianness +{ + Little = 0, + Big = 1, + +#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) || defined(__BIG_ENDIAN__) + Native = Big, +#else + Native = Little, +#endif +}; + class BitConverter { public: diff --git a/ZAPDTR/ZAPDUtils/Utils/Stream.h b/ZAPDTR/ZAPDUtils/Utils/Stream.h index e73a9a70d..e72d794b6 100644 --- a/ZAPDTR/ZAPDUtils/Utils/Stream.h +++ b/ZAPDTR/ZAPDUtils/Utils/Stream.h @@ -10,13 +10,6 @@ enum class SeekOffsetType End }; -// TODO: Eventually account for endianess in binaryreader and binarywriter -enum class Endianess -{ - Little = 0, - Big = 1, -}; - class Stream { public: diff --git a/libultraship/libultraship/Cutscene.cpp b/libultraship/libultraship/Cutscene.cpp index 420d491f1..a1e2421eb 100644 --- a/libultraship/libultraship/Cutscene.cpp +++ b/libultraship/libultraship/Cutscene.cpp @@ -1,5 +1,103 @@ #include "Cutscene.h" +enum class CutsceneCommands +{ + Cmd00 = 0x0000, + SetCameraPos = 0x0001, + SetCameraFocus = 0x0002, + SpecialAction = 0x0003, + SetLighting = 0x0004, + SetCameraPosLink = 0x0005, + SetCameraFocusLink = 0x0006, + Cmd07 = 0x0007, + Cmd08 = 0x0008, + Cmd09 = 0x0009, + Unknown = 0x001A, + Textbox = 0x0013, + SetActorAction0 = 0x000A, + SetActorAction1 = 0x000F, + SetActorAction2 = 0x000E, + SetActorAction3 = 0x0019, + SetActorAction4 = 0x001D, + SetActorAction5 = 0x001E, + SetActorAction6 = 0x002C, + SetActorAction7 = 0x001F, + SetActorAction8 = 0x0031, + SetActorAction9 = 0x003E, + SetActorAction10 = 0x008F, + SetSceneTransFX = 0x002D, + Nop = 0x000B, + PlayBGM = 0x0056, + StopBGM = 0x0057, + FadeBGM = 0x007C, + SetTime = 0x008C, + Terminator = 0x03E8, + End = 0xFFFF, + Error = 0xFEAF, +}; + +static inline uint32_t read_CMD_BBBB(BinaryReader* reader) +{ + uint32_t v; + reader->Read((char*)&v, sizeof(uint32_t)); + + return v; +} + +static inline uint32_t read_CMD_BBH(BinaryReader* reader) +{ + uint32_t v; + reader->Read((char*)&v, sizeof(uint32_t)); + + // swap the half word to match endianness + if (reader->GetEndianness() != Endianness::Native) + { + uint8_t* b = (uint8_t*)&v; + uint8_t tmp = b[2]; + b[2] = b[3]; + b[3] = tmp; + } + + return v; +} + +static inline uint32_t read_CMD_HBB(BinaryReader* reader) +{ + uint32_t v; + reader->Read((char*)&v, sizeof(uint32_t)); + + // swap the half word to match endianness + if (reader->GetEndianness() != Endianness::Native) + { + uint8_t* b = (uint8_t*)&v; + uint8_t tmp = b[0]; + b[0] = b[1]; + b[1] = tmp; + } + + return v; +} + +static inline uint32_t read_CMD_HH(BinaryReader* reader) +{ + uint32_t v; + reader->Read((char*)&v, sizeof(uint32_t)); + + // swap the half words to match endianness + if (reader->GetEndianness() != Endianness::Native) + { + uint8_t* b = (uint8_t*)&v; + uint8_t tmp = b[0]; + b[0] = b[1]; + b[1] = tmp; + tmp = b[2]; + b[2] = b[3]; + b[3] = tmp; + } + + return v; +} + void Ship::CutsceneV0::ParseFileBinary(BinaryReader* reader, Resource* res) { Cutscene* cs = (Cutscene*)res; @@ -9,11 +107,415 @@ void Ship::CutsceneV0::ParseFileBinary(BinaryReader* reader, Resource* res) uint32_t numEntries = reader->ReadUInt32(); cs->commands.reserve(numEntries); - for (uint32_t i = 0; i < numEntries; i++) - { - uint32_t data = reader->ReadUInt32(); - uint16_t opcode = data >> 16; + uint32_t numCommands = reader->ReadUInt32(); + cs->commands.push_back(numCommands); - cs->commands.push_back(data); + // endFrame + cs->commands.push_back(reader->ReadUInt32()); + + while (true) + { + uint32_t commandId = reader->ReadUInt32(); + cs->commands.push_back(commandId); + + switch (commandId) + { + case (uint32_t)CutsceneCommands::SetCameraPos: + { + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + + while (true) + { + uint32_t val = read_CMD_BBH(reader); + int8_t continueFlag = ((int8_t*)&val)[0]; + + cs->commands.push_back(val); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + + if (continueFlag == -1) + break; + } + } + break; + case (uint32_t)CutsceneCommands::SetCameraFocus: + { + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + + while (true) + { + uint32_t val = read_CMD_BBH(reader); + int8_t continueFlag = ((int8_t*)&val)[0]; + + cs->commands.push_back(val); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + + if (continueFlag == -1) + break; + } + break; + } + case (uint32_t)CutsceneCommands::SpecialAction: + { + uint32_t size = reader->ReadUInt32(); + cs->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) + { + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + } + break; + } + case (uint32_t)CutsceneCommands::SetLighting: + { + uint32_t size = reader->ReadUInt32(); + cs->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) + { + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + } + break; + } + case (uint32_t)CutsceneCommands::SetCameraPosLink: + { + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + + while (true) + { + uint32_t val = read_CMD_BBH(reader); + int8_t continueFlag = ((int8_t*)&val)[0]; + + cs->commands.push_back(val); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + + if (continueFlag == -1) + break; + } + break; + } + case (uint32_t)CutsceneCommands::SetCameraFocusLink: + { + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + + while (true) + { + uint32_t val = read_CMD_BBH(reader); + int8_t continueFlag = ((int8_t*)&val)[0]; + + cs->commands.push_back(val); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + + if (continueFlag == -1) + break; + } + break; + } + case (uint32_t)CutsceneCommands::Cmd09: + { + uint32_t size = reader->ReadUInt32(); + cs->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) + { + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HBB(reader)); + cs->commands.push_back(read_CMD_BBH(reader)); + } + break; + } + case 0x15: + case (uint32_t)CutsceneCommands::Unknown: + { + uint32_t size = reader->ReadUInt32(); + cs->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) + { + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + } + } + break; + case (uint32_t)CutsceneCommands::Textbox: + { + uint32_t size = reader->ReadUInt32(); + cs->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) + { + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + } + break; + } + case (uint32_t)CutsceneCommands::SetActorAction0: + case (uint32_t)CutsceneCommands::SetActorAction1: + case 17: + case 18: + case 23: + case 34: + case 39: + case 46: + case 76: + case 85: + case 93: + case 105: + case 107: + case 110: + case 119: + case 123: + case 138: + case 139: + case 144: + case (uint32_t)CutsceneCommands::SetActorAction2: + case 16: + case 24: + case 35: + case 40: + case 48: + case 64: + case 68: + case 70: + case 78: + case 80: + case 94: + case 116: + case 118: + case 120: + case 125: + case 131: + case 141: + case (uint32_t)CutsceneCommands::SetActorAction3: + case 36: + case 41: + case 50: + case 67: + case 69: + case 72: + case 74: + case 81: + case 106: + case 117: + case 121: + case 126: + case 132: + case (uint32_t)CutsceneCommands::SetActorAction4: + case 37: + case 42: + case 51: + case 53: + case 63: + case 65: + case 66: + case 75: + case 82: + case 108: + case 127: + case 133: + case (uint32_t)CutsceneCommands::SetActorAction5: + case 38: + case 43: + case 47: + case 54: + case 79: + case 83: + case 128: + case 135: + case (uint32_t)CutsceneCommands::SetActorAction6: + case 55: + case 77: + case 84: + case 90: + case 129: + case 136: + case (uint32_t)CutsceneCommands::SetActorAction7: + case 52: + case 57: + case 58: + case 88: + case 115: + case 130: + case 137: + case (uint32_t)CutsceneCommands::SetActorAction8: + case 60: + case 89: + case 111: + case 114: + case 134: + case 142: + case (uint32_t)CutsceneCommands::SetActorAction9: + case (uint32_t)CutsceneCommands::SetActorAction10: + { + uint32_t size = reader->ReadUInt32(); + cs->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) + { + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + } + + break; + } + case (uint32_t)CutsceneCommands::SetSceneTransFX: + { + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + break; + } + case (uint32_t)CutsceneCommands::PlayBGM: + { + uint32_t size = reader->ReadUInt32(); + cs->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) + { + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + } + break; + } + case (uint32_t)CutsceneCommands::StopBGM: + { + uint32_t size = reader->ReadUInt32(); + cs->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) + { + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + } + break; + } + case (uint32_t)CutsceneCommands::FadeBGM: + { + uint32_t size = reader->ReadUInt32(); + cs->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) + { + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(reader->ReadUInt32()); + } + break; + } + case (uint32_t)CutsceneCommands::SetTime: + { + uint32_t size = reader->ReadUInt32(); + cs->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) + { + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HBB(reader)); + cs->commands.push_back(reader->ReadUInt32()); + } + break; + } + case (uint32_t)CutsceneCommands::Terminator: + { + cs->commands.push_back(reader->ReadUInt32()); + cs->commands.push_back(read_CMD_HH(reader)); + cs->commands.push_back(read_CMD_HH(reader)); + break; + } + case 0xFFFFFFFF: // CS_END + { + cs->commands.push_back(reader->ReadUInt32()); + return; + } + default: +#ifdef _DEBUG + printf("CutsceneV0: Unknown command %x\n", commandId); +#endif + // error? + break; + } } } diff --git a/libultraship/libultraship/DisplayList.cpp b/libultraship/libultraship/DisplayList.cpp index 14f9f8410..b2934ee68 100644 --- a/libultraship/libultraship/DisplayList.cpp +++ b/libultraship/libultraship/DisplayList.cpp @@ -14,23 +14,25 @@ namespace Ship while (true) { - uint64_t data = reader->ReadUInt64(); + uint32_t w0 = reader->ReadUInt32(); + uint32_t w1 = reader->ReadUInt32(); if (sizeof(uintptr_t) < 8){ - dl->instructions.push_back(data); + dl->instructions.push_back(((uint64_t) w0 << 32) | w1); - uint8_t opcode = data >> 24; + uint8_t opcode = w0 >> 24; // These are 128-bit commands, so read an extra 64 bits... - if (opcode == G_SETTIMG_OTR || opcode == G_DL_OTR || opcode == G_VTX_OTR || opcode == G_BRANCH_Z_OTR || opcode == G_MARKER || opcode == G_MTX_OTR) - dl->instructions.push_back(reader->ReadUInt64()); + if (opcode == G_SETTIMG_OTR || opcode == G_DL_OTR || opcode == G_VTX_OTR || opcode == G_BRANCH_Z_OTR || opcode == G_MARKER || opcode == G_MTX_OTR) { + w0 = reader->ReadUInt32(); + w1 = reader->ReadUInt32(); + + dl->instructions.push_back(((uint64_t) w0 << 32) | w1); + } if (opcode == G_ENDDL) break; } else { - uint32_t w0 = (uint32_t)data; - uint32_t w1 = (uint32_t)(data >> 32); - dl->instructions.push_back(w0); dl->instructions.push_back(w1); @@ -38,10 +40,8 @@ namespace Ship if (opcode == G_SETTIMG_OTR || opcode == G_DL_OTR || opcode == G_VTX_OTR || opcode == G_BRANCH_Z_OTR || opcode == G_MARKER || opcode == G_MTX_OTR) { - data = reader->ReadUInt64(); - - w0 = (uint32_t)data; - w1 = (uint32_t)(data >> 32); + w0 = reader->ReadUInt32(); + w1 = reader->ReadUInt32(); dl->instructions.push_back(w0); dl->instructions.push_back(w1); diff --git a/libultraship/libultraship/Factories/ResourceLoader.cpp b/libultraship/libultraship/Factories/ResourceLoader.cpp index 28a651b83..194fc74e8 100644 --- a/libultraship/libultraship/Factories/ResourceLoader.cpp +++ b/libultraship/libultraship/Factories/ResourceLoader.cpp @@ -25,12 +25,12 @@ namespace Ship auto memStream = std::make_shared(FileToLoad->buffer.get(), FileToLoad->dwBufferSize); auto reader = std::make_shared(memStream); - Endianess endianess = (Endianess)reader->ReadByte(); + Endianness endianness = (Endianness)reader->ReadByte(); for (int i = 0; i < 3; i++) reader->ReadByte(); - // OTRTODO: Setup the binaryreader to use the resource's endianess + reader->SetEndianness(endianness); ResourceType resourceType = (ResourceType)reader->ReadUInt32(); Resource* result = nullptr; diff --git a/libultraship/libultraship/Resource.h b/libultraship/libultraship/Resource.h index 6bdae983e..f7ea98e93 100644 --- a/libultraship/libultraship/Resource.h +++ b/libultraship/libultraship/Resource.h @@ -51,12 +51,6 @@ namespace Ship F64 = 10 }; - enum class Endianess - { - Little = 0, - Big = 1, - }; - enum class Version { // BR @@ -90,7 +84,7 @@ namespace Ship class ResourceFile { public: - Endianess endianess; // 0x00 - Endianess of the file + Endianness endianness; // 0x00 - Endianness of the file uint32_t resourceType; // 0x01 - 4 byte MAGIC Version version; // 0x05 - Based on Ship release numbers uint64_t id; // 0x09 - Unique Resource ID diff --git a/libultraship/libultraship/SDLAudioPlayer.cpp b/libultraship/libultraship/SDLAudioPlayer.cpp index 3c15f720e..6e14c4be0 100644 --- a/libultraship/libultraship/SDLAudioPlayer.cpp +++ b/libultraship/libultraship/SDLAudioPlayer.cpp @@ -10,7 +10,7 @@ namespace Ship { SDL_AudioSpec want, have; SDL_zero(want); want.freq = this->GetSampleRate(); - want.format = AUDIO_S16; + want.format = AUDIO_S16SYS; want.channels = 2; want.samples = 1024; want.callback = NULL; diff --git a/libultraship/libultraship/endianness.h b/libultraship/libultraship/endianness.h new file mode 100644 index 000000000..87bec316b --- /dev/null +++ b/libultraship/libultraship/endianness.h @@ -0,0 +1,67 @@ +#ifndef ENDIANESS_H +#define ENDIANESS_H + +#ifdef _MSC_VER +#include + +#define BOMSWAP16 _byteswap_ushort +#define BOMSWAP32 _byteswap_ulong +#define BOMSWAP64 _byteswap_uint64 + +#define BOMSWAP16_CONST(x) \ + ((((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00)) +#define BOMSWAP32_CONST(x) \ + ((((x) >> 24) & 0x000000FF) | (((x) >> 8) & 0x0000FF00) | \ + (((x) << 8) & 0x00FF0000) | (((x) << 24) & 0xFF000000)) +#define BOMSWAP64_CONST(x) \ + ((((x) >> 56) & 0x00000000000000FF) | (((x) >> 40) & 0x000000000000FF00) | \ + (((x) >> 24) & 0x0000000000FF0000) | (((x) >> 8) & 0x00000000FF000000) | \ + (((x) << 8) & 0x000000FF00000000) | (((x) << 24) & 0x0000FF0000000000) | \ + (((x) << 40) & 0x00FF000000000000) | (((x) << 56) & 0xFF00000000000000)) +#else +#define BOMSWAP16 __builtin_bswap16 +#define BOMSWAP32 __builtin_bswap32 +#define BOMSWAP64 __builtin_bswap64 + +#define BOMSWAP16_CONST __builtin_bswap16 +#define BOMSWAP32_CONST __builtin_bswap32 +#define BOMSWAP64_CONST __builtin_bswap64 +#endif + +#if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) || defined(__BIG_ENDIAN__) +#ifndef IS_BIGENDIAN +#define IS_BIGENDIAN +#endif +#endif + +#ifdef IS_BIGENDIAN +#define BE16SWAP(x) (x) +#define BE32SWAP(x) (x) +#define BE64SWAP(x) (x) +#define LE16SWAP(x) BOMSWAP16(x) +#define LE32SWAP(x) BOMSWAP32(x) +#define LE64SWAP(x) BOMSWAP64(x) + +#define BE16SWAP_CONST(x) (x) +#define BE32SWAP_CONST(x) (x) +#define BE64SWAP_CONST(x) (x) +#define LE16SWAP_CONST(x) BOMSWAP16_CONST(x) +#define LE32SWAP_CONST(x) BOMSWAP32_CONST(x) +#define LE64SWAP_CONST(x) BOMSWAP64_CONST(x) +#else +#define BE16SWAP(x) BOMSWAP16(x) +#define BE32SWAP(x) BOMSWAP32(x) +#define BE64SWAP(x) BOMSWAP64(x) +#define LE16SWAP(x) (x) +#define LE32SWAP(x) (x) +#define LE64SWAP(x) (x) + +#define BE16SWAP_CONST(x) BOMSWAP16_CONST(x) +#define BE32SWAP_CONST(x) BOMSWAP32_CONST(x) +#define BE64SWAP_CONST(x) BOMSWAP64_CONST(x) +#define LE16SWAP_CONST(x) (x) +#define LE32SWAP_CONST(x) (x) +#define LE64SWAP_CONST(x) (x) +#endif + +#endif diff --git a/soh/include/color.h b/soh/include/color.h index 1a833b0d4..6c8e4c1ce 100644 --- a/soh/include/color.h +++ b/soh/include/color.h @@ -1,6 +1,8 @@ #ifndef COLOR_H #define COLOR_H +#include "endianness.h" + typedef struct { u8 r, g, b; } Color_RGB8; @@ -12,7 +14,11 @@ typedef struct { // only use when necessary for alignment purposes typedef union { struct { +#ifdef IS_BIGENDIAN + u8 r, g, b, a; +#else u8 a, b, g, r; +#endif }; u32 rgba; } Color_RGBA8_u32; diff --git a/soh/include/command_macros_base.h b/soh/include/command_macros_base.h index bae557909..a0b31bb7f 100644 --- a/soh/include/command_macros_base.h +++ b/soh/include/command_macros_base.h @@ -6,6 +6,15 @@ * Each macro packs bytes (B), halfwords (H) and words (W, for consistency) into a single word */ +#ifdef IS_BIGENDIAN +#define CMD_BBBB(a, b, c, d) (_SHIFTL(a, 24, 8) | _SHIFTL(b, 16, 8) | _SHIFTL(c, 8, 8) | _SHIFTL(d, 0, 8)) + +#define CMD_BBH(a, b, c) (_SHIFTL(a, 24, 8) | _SHIFTL(b, 16, 8) | _SHIFTL(c, 0, 16)) + +#define CMD_HBB(a, b, c) (_SHIFTL(a, 16, 16) | _SHIFTL(b, 8, 8) | _SHIFTL(c, 0, 8)) + +#define CMD_HH(a, b) (_SHIFTL(a, 16, 16) | _SHIFTL(b, 0, 16)) +#else #define CMD_BBBB(a, b, c, d) (_SHIFTL(a, 0, 8) | _SHIFTL(b, 8, 8) | _SHIFTL(c, 16, 8) | _SHIFTL(d, 24, 8)) #define CMD_BBH(a, b, c) (_SHIFTL(a, 0, 8) | _SHIFTL(b, 8, 8) | _SHIFTL(c, 16, 16)) @@ -13,6 +22,7 @@ #define CMD_HBB(a, b, c) (_SHIFTL(a, 0, 16) | _SHIFTL(b, 16, 8) | _SHIFTL(c, 24, 8)) #define CMD_HH(a, b) (_SHIFTL(a, 0, 16) | _SHIFTL(b, 16, 16)) +#endif #define CMD_W(a) (a) diff --git a/soh/include/macros.h b/soh/include/macros.h index 2c84434fe..f2e339e34 100644 --- a/soh/include/macros.h +++ b/soh/include/macros.h @@ -1,6 +1,8 @@ #ifndef MACROS_H #define MACROS_H +#include "endianness.h" + #define ARRAY_COUNT(arr) (s32)(sizeof(arr) / sizeof(arr[0])) #define ARRAY_COUNTU(arr) (u32)(sizeof(arr) / sizeof(arr[0])) @@ -254,12 +256,5 @@ extern GraphicsContext* __gfxCtx; #define SEG_ADDR(seg, addr) (addr | (seg << 24) | 1) -#ifdef _MSC_VER -#define BOMSWAP16 _byteswap_ushort -#define BOMSWAP32 _byteswap_ulong -#else -#define BOMSWAP16 __builtin_bswap16 -#define BOMSWAP32 __builtin_bswap32 -#endif #endif diff --git a/soh/include/z64audio.h b/soh/include/z64audio.h index c765aa4ed..47bd0b691 100644 --- a/soh/include/z64audio.h +++ b/soh/include/z64audio.h @@ -1,6 +1,8 @@ #ifndef Z64_AUDIO_H #define Z64_AUDIO_H +#include "endianness.h" + #define MK_CMD(b0,b1,b2,b3) ((((b0) & 0xFF) << 0x18) | (((b1) & 0xFF) << 0x10) | (((b2) & 0xFF) << 0x8) | (((b3) & 0xFF) << 0)) #define NO_LAYER ((SequenceLayer*)(-1)) @@ -685,6 +687,35 @@ typedef struct { } AudioPreloadReq; // size = 0x14 typedef struct { +#ifdef IS_BIGENDIAN + union{ + u32 opArgs; + struct { + u8 op; + u8 arg0; + u8 arg1; + u8 arg2; + }; + }; + union { + void* data; + f32 asFloat; + s32 asInt; + struct { + u16 asUShort; + u8 pad2[2]; + }; + struct { + s8 asSbyte; + u8 pad1[3]; + }; + struct { + u8 asUbyte; + u8 pad0[3]; + }; + u32 asUInt; + }; +#else union{ u32 opArgs; struct { @@ -712,6 +743,7 @@ typedef struct { }; u32 asUInt; }; +#endif } AudioCmd; typedef struct { diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 393619cce..053d2d801 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -117,8 +117,7 @@ extern "C" void InitOTR() { if (!t->bHasLoadError) { - //uint32_t gameVersion = BitConverter::ToUInt32BE((uint8_t*)t->buffer.get(), 0); - uint32_t gameVersion = *((uint32_t*)t->buffer.get()); + uint32_t gameVersion = LE32SWAP(*((uint32_t*)t->buffer.get())); OTRGlobals::Instance->context->GetResourceManager()->SetGameVersion(gameVersion); } @@ -795,8 +794,8 @@ extern "C" SoundFont* ResourceMgr_LoadAudioSoundFont(const char* path) { for (size_t k = 0; k < soundFont->drums[i].env.size(); k++) { - drum->envelope[k].delay = BOMSWAP16(soundFont->drums[i].env[k]->delay); - drum->envelope[k].arg = BOMSWAP16(soundFont->drums[i].env[k]->arg); + drum->envelope[k].delay = BE16SWAP(soundFont->drums[i].env[k]->delay); + drum->envelope[k].arg = BE16SWAP(soundFont->drums[i].env[k]->arg); } } @@ -827,8 +826,8 @@ extern "C" SoundFont* ResourceMgr_LoadAudioSoundFont(const char* path) { for (int k = 0; k < soundFont->instruments[i].env.size(); k++) { - inst->envelope[k].delay = BOMSWAP16(soundFont->instruments[i].env[k]->delay); - inst->envelope[k].arg = BOMSWAP16(soundFont->instruments[i].env[k]->arg); + inst->envelope[k].delay = BE16SWAP(soundFont->instruments[i].env[k]->delay); + inst->envelope[k].arg = BE16SWAP(soundFont->instruments[i].env[k]->arg); } } if (soundFont->instruments[i].lowNotesSound != nullptr) diff --git a/soh/src/code/audio_data.c b/soh/src/code/audio_data.c index 5fe49139b..37e817688 100644 --- a/soh/src/code/audio_data.c +++ b/soh/src/code/audio_data.c @@ -544,10 +544,10 @@ u8 gDefaultShortNoteGateTimeTable[] = { }; AdsrEnvelope gDefaultEnvelope[] = { - { 0x0100, 0x007D }, - { 0xE803, 0x007D }, - { 0xFFFF, 0x0000 }, - { 0x0000, 0x0000 }, + { BE16SWAP_CONST(1), BE16SWAP_CONST(32000) }, + { BE16SWAP_CONST(1000), BE16SWAP_CONST(32000) }, + { BE16SWAP_CONST(-1), BE16SWAP_CONST(0) }, + { BE16SWAP_CONST(0), BE16SWAP_CONST(0) }, }; NoteSubEu gZeroNoteSub = { 0 }; diff --git a/soh/src/code/audio_effects.c b/soh/src/code/audio_effects.c index d5aa3644f..f77462f98 100644 --- a/soh/src/code/audio_effects.c +++ b/soh/src/code/audio_effects.c @@ -246,7 +246,7 @@ f32 Audio_AdsrUpdate(AdsrState* adsr) { retry: case ADSR_STATE_LOOP: - adsr->delay = (s16)BOMSWAP16(adsr->envelope[adsr->envIndex].delay); + adsr->delay = (s16)BE16SWAP(adsr->envelope[adsr->envIndex].delay); switch (adsr->delay) { case ADSR_DISABLE: adsr->action.s.state = ADSR_STATE_DISABLED; @@ -255,7 +255,7 @@ f32 Audio_AdsrUpdate(AdsrState* adsr) { adsr->action.s.state = ADSR_STATE_HANG; break; case ADSR_GOTO: - adsr->envIndex = (s16)BOMSWAP16(adsr->envelope[adsr->envIndex].arg); + adsr->envIndex = (s16)BE16SWAP(adsr->envelope[adsr->envIndex].arg); goto retry; case ADSR_RESTART: adsr->action.s.state = ADSR_STATE_INITIAL; @@ -266,7 +266,7 @@ f32 Audio_AdsrUpdate(AdsrState* adsr) { if (adsr->delay == 0) { adsr->delay = 1; } - adsr->target = (s16)BOMSWAP16(adsr->envelope[adsr->envIndex].arg) / 32767.0f; + adsr->target = (s16)BE16SWAP(adsr->envelope[adsr->envIndex].arg) / 32767.0f; adsr->target = adsr->target * adsr->target; adsr->velocity = (adsr->target - adsr->current) / adsr->delay; adsr->action.s.state = ADSR_STATE_FADE; diff --git a/soh/src/code/audio_seqplayer.c b/soh/src/code/audio_seqplayer.c index b8fbd9e1f..dd9c6e1cc 100644 --- a/soh/src/code/audio_seqplayer.c +++ b/soh/src/code/audio_seqplayer.c @@ -1340,13 +1340,13 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) { break; case 0xB2: offset = (u16)parameters[0]; - channel->unk_22 = BOMSWAP16(*(u16*)(seqPlayer->seqData + (uintptr_t)(offset + scriptState->value * 2))); + channel->unk_22 = BE16SWAP(*(u16*)(seqPlayer->seqData + (uintptr_t)(offset + scriptState->value * 2))); break; case 0xB4: channel->dynTable = (void*)&seqPlayer->seqData[channel->unk_22]; break; case 0xB5: - channel->unk_22 = BOMSWAP16(((u16*)(channel->dynTable))[scriptState->value]); + channel->unk_22 = BE16SWAP(((u16*)(channel->dynTable))[scriptState->value]); break; case 0xB6: scriptState->value = (*channel->dynTable)[0][scriptState->value]; diff --git a/soh/src/code/z_room.c b/soh/src/code/z_room.c index 04f2d421b..d73533ff8 100644 --- a/soh/src/code/z_room.c +++ b/soh/src/code/z_room.c @@ -217,13 +217,12 @@ void func_80095D04(GlobalContext* globalCtx, Room* room, u32 flags) { CLOSE_DISPS(globalCtx->state.gfxCtx); } -//#define JPEG_MARKER 0xFFD8FFE0 -#define JPEG_MARKER 0xE0FFD8FF +#define JPEG_MARKER 0xFFD8FFE0 s32 func_80096238(void* data) { OSTime time; - if (*(u32*)data == JPEG_MARKER) + if (BE32SWAP(*(u32*)data) == JPEG_MARKER) { char* decodedJpeg = ResourceMgr_LoadJPEG(data, 320 * 240 * 2); //char* decodedJpeg = ResourceMgr_LoadJPEG(data, 480 * 240 * 2);