diff --git a/src/JSystem/J3DGraphBase/J3DMaterial.cpp b/src/JSystem/J3DGraphBase/J3DMaterial.cpp new file mode 100644 index 00000000..b3a8ca32 --- /dev/null +++ b/src/JSystem/J3DGraphBase/J3DMaterial.cpp @@ -0,0 +1,17 @@ +#include "JSystem/J3DGraphBase/J3DMaterial.hpp" + +J3DAlphaComp::J3DAlphaComp() { + u16 val = sUnk; + _2 = 0; + _0 = val; + _3 = 0; +} + +#ifdef NON_MATCHING +// some scheduling issues +void J3DCurrentMtx::setCurrentTexMtx(u8 a1, u8 a2, u8 a3, u8 a4, u8 a5, u8 a6, u8 a7, u8 a8) { + _0 = (a4 << 24) | (a3 << 18) & 0x3FC0000 | (a1 << 6) & 0x3FC0 | (a2 << 12) & 0xFF000; + _4 = (a8 << 18) | (a7 << 12) & 0xFF000 | a5 & 0xFFF00FFF | (a6 << 6) & 0x3FC0; +} +#endif + diff --git a/src/JSystem/J3DGraphBase/J3DVertex.cpp b/src/JSystem/J3DGraphBase/J3DVertex.cpp new file mode 100644 index 00000000..9c635917 --- /dev/null +++ b/src/JSystem/J3DGraphBase/J3DVertex.cpp @@ -0,0 +1,11 @@ +#include "JSystem/J3DGraphBase/J3DVertex.hpp" + +J3DDrawMtxData::J3DDrawMtxData() { + mDrawMatrixCount = 0; + _4 = 0; + mDrawMtxArray = nullptr; +} + +J3DDrawMtxData::~J3DDrawMtxData() { + +} \ No newline at end of file diff --git a/src/JSystem/JAudio2/JASSeqCtrl.cpp b/src/JSystem/JAudio2/JASSeqCtrl.cpp new file mode 100644 index 00000000..f5320a66 --- /dev/null +++ b/src/JSystem/JAudio2/JASSeqCtrl.cpp @@ -0,0 +1,115 @@ +#include "JSystem/JAudio2/JASSeqCtrl.hpp" +#include "JSystem/JAudio2/JASTrack.hpp" + +JASSeqParser JASSeqCtrl::sDefaultParser = JASSeqParser(); + +JASSeqCtrl::JASSeqCtrl() { + JASSeqReader::init(); + mParser = &sDefaultParser; + mTimer = 0; + mCursorSwap = nullptr; + _48 = 0; + _4C = 0; + _4E = 0; + mIntTimer = 0; + _51 = false; + _54 = 0; + _58 = 0; + JASSeqReader::init(); +} + +void JASSeqCtrl::init() { + JASSeqReader::init(); + mParser = &sDefaultParser; + mTimer = 0; + mCursorSwap = nullptr; + _48 = 0; + _4C = 0; + _4E = 0; + mIntTimer = 0; + _54 = 0; + _58 = 0; + _51 = false; +} + +void JASSeqCtrl::start(void *, u32 offset) { + JASSeqReader::init(); + mSeqCursor = (void *)((u8 *)mSeqBuff + offset); +} + +int JASSeqCtrl::tickProc(JASTrack *track) { + if(!mSeqBuff) return 0; + interrupt(JASSeqCtrl::INTR_6); + timerProcess(); + if(_51) { + if(!track->checkNoteStop(0)) return 0; + _51 = false; + } + if(mTimer > 0) mTimer--; + checkIntr(); + + while((!mTimer || mCursorSwap) && !_51) { + if(mParser->parse(track) < 0) return -1; + } + + return 0; +} + +void JASSeqCtrl::interrupt(JASSeqCtrl::IntrType interrupt) { + u32 mask = 1 << interrupt; + if(!(_4E & mask)) return; + _4C |= mask; +} + +void JASSeqCtrl::setIntrMask(u32 mask) { + _4E |= mask; +} + +void JASSeqCtrl::clrIntrMask(u32 mask) { + _4E &= ~mask; +} + +bool JASSeqCtrl::retIntr() { + if(!mCursorSwap) return false; + mSeqCursor = mCursorSwap; + mCursorSwap = nullptr; + return true; +} + +s32 JASSeqCtrl::findIntr() { + u32 intr = _4E & _4C; + for(u32 i = 0; intr != 0; i++) { + if(intr & 1) { + _4C &= ~(1 << i); + return i; + } + else intr >>= 1; + } + return -1; +} + +void JASSeqCtrl::checkIntr() { + s32 intr; + if(!mCursorSwap && (intr = findIntr()) >= 0) { + intr = intr * 3 + _48; + u32 offset = calcSeekAmt(intr); + mCursorSwap = mSeqCursor; + mSeqCursor = (void *)((u8 *)mSeqBuff + offset); + } +} + +void JASSeqCtrl::timerProcess() { + if(_54 != 0) { + if(!--_54) { + interrupt(INTR_5); + if(mIntTimer) { + if(--mIntTimer) { + _54 = _58; + } + } + else _54 = _58; + } + } +} + +JASSeqParser::JASSeqParser() {} diff --git a/src/JSystem/JAudio2/JASSeqParser.cpp b/src/JSystem/JAudio2/JASSeqParser.cpp new file mode 100644 index 00000000..d6a6e42e --- /dev/null +++ b/src/JSystem/JAudio2/JASSeqParser.cpp @@ -0,0 +1,934 @@ +#include "JSystem/JAudio2/JASSeqParser.hpp" +#include "JSystem/JAudio2/JASTrack.hpp" +#include "JSystem/JMath/random.hpp" +#include "JSystem/JAudio2/JASReport.hpp" + +// At address 80560cb8 +const static s16 sIIRCutoff[0x208] = { + 0x0000, 0x0000, 0x0000, 0x8048, 0x947C, 0x8048, 0x96D0, 0x8048, + 0x94C8, 0x8048, 0x95D4, 0x8048, 0x9534, 0x8048, 0x954C, 0x8048, + 0x9590, 0x8048, 0x9708, 0x0F5C, 0x0A3D, 0x4665, 0x1E73, 0x0F5E, + 0x0A3D, 0x4664, 0x1E73, 0x0F63, 0x0A3C, 0x4661, 0x1E71, 0x0F6C, + 0x0A3C, 0x465B, 0x1E6F, 0x0F79, 0x0A3A, 0x4653, 0x1E6B, 0x0F89, + 0x0A39, 0x4649, 0x1E67, 0x0F9C, 0x0A37, 0x463D, 0x1E62, 0x0FB4, + 0x0A35, 0x462E, 0x1E5B, 0x0FCE, 0x0A33, 0x461D, 0x1E54, 0x0FED, + 0x0A30, 0x460A, 0x1E4C, 0x100F, 0x0A2D, 0x45F5, 0x1E43, 0x1034, + 0x0A29, 0x45DE, 0x1E39, 0x105D, 0x0A26, 0x45C4, 0x1E2D, 0x108A, + 0x0A22, 0x45A8, 0x1E21, 0x10BA, 0x0A1D, 0x458A, 0x1E14, 0x10EE, + 0x0A18, 0x456A, 0x1E06, 0x1126, 0x0A13, 0x4547, 0x1DF7, 0x1161, + 0x0A0E, 0x4522, 0x1DE7, 0x119F, 0x0A08, 0x44FB, 0x1DD6, 0x11E1, + 0x0A02, 0x44D2, 0x1DC5, 0x1227, 0x09FC, 0x44A6, 0x1DB2, 0x1270, + 0x09F5, 0x4478, 0x1D9E, 0x12BD, 0x09EE, 0x4448, 0x1D89, 0x130E, + 0x09E7, 0x4416, 0x1D73, 0x1362, 0x09DF, 0x43E1, 0x1D5D, 0x13B9, + 0x09D7, 0x43AB, 0x1D45, 0x1415, 0x09CF, 0x4372, 0x1D2C, 0x1473, + 0x09C7, 0x4336, 0x1D13, 0x14D6, 0x09BE, 0x42F9, 0x1CF8, 0x153C, + 0x09B4, 0x42B9, 0x1CDD, 0x15A5, 0x09AB, 0x4277, 0x1CC0, 0x1612, + 0x09A1, 0x4233, 0x1CA3, 0x1683, 0x0997, 0x41ED, 0x1C84, 0x16F7, + 0x098C, 0x41A4, 0x1C65, 0x176F, 0x0981, 0x4159, 0x1C44, 0x17EA, + 0x0976, 0x410C, 0x1C23, 0x1869, 0x096A, 0x40BD, 0x1C01, 0x18EB, + 0x095F, 0x406B, 0x1BDD, 0x1972, 0x0952, 0x4018, 0x1BB9, 0x19FB, + 0x0946, 0x3FC2, 0x1B94, 0x1A88, 0x0939, 0x3F69, 0x1B6E, 0x1B19, + 0x092C, 0x3F0F, 0x1B47, 0x1BAE, 0x091E, 0x3EB2, 0x1B1E, 0x1C46, + 0x0911, 0x3E53, 0x1AF5, 0x1CE1, 0x0902, 0x3DF2, 0x1ACB, 0x1D80, + 0x08F4, 0x3D8E, 0x1AA0, 0x1E23, 0x08E5, 0x3D29, 0x1A74, 0x1EC9, + 0x08D6, 0x3CC1, 0x1A47, 0x1F73, 0x08C7, 0x3C57, 0x1A19, 0x2020, + 0x08B7, 0x3BEA, 0x19EB, 0x20D1, 0x08A7, 0x3B7C, 0x19BB, 0x2186, + 0x0896, 0x3B0B, 0x198A, 0x223E, 0x0886, 0x3A98, 0x1958, 0x22FA, + 0x0875, 0x3A22, 0x1925, 0x23B9, 0x0863, 0x39AB, 0x18F2, 0x247C, + 0x0851, 0x3931, 0x18BD, 0x2542, 0x083F, 0x38B5, 0x1887, 0x260C, + 0x082D, 0x3837, 0x1851, 0x26DA, 0x081A, 0x37B6, 0x1819, 0x27AB, + 0x0807, 0x3734, 0x17E1, 0x2880, 0x07F4, 0x36AF, 0x17A7, 0x2958, + 0x07E0, 0x3628, 0x176D, 0x2A34, 0x07CC, 0x359E, 0x1731, 0x2B14, + 0x07B8, 0x3512, 0x16F5, 0x2BF7, 0x07A3, 0x3485, 0x16B7, 0x2CDD, + 0x078E, 0x33F4, 0x1679, 0x2DC8, 0x0779, 0x3362, 0x163A, 0x2EB5, + 0x0764, 0x32CD, 0x15FA, 0x2FA7, 0x074E, 0x3237, 0x15B8, 0x309C, + 0x0737, 0x319E, 0x1576, 0x3194, 0x0721, 0x3102, 0x1533, 0x3290, + 0x070A, 0x3065, 0x14EF, 0x3390, 0x06F3, 0x2FC5, 0x14AA, 0x3493, + 0x06DB, 0x2F23, 0x1464, 0x359A, 0x06C3, 0x2E7F, 0x141C, 0x36A4, + 0x06AB, 0x2DD8, 0x13D4, 0x37B2, 0x0692, 0x2D2F, 0x138C, 0x38C4, + 0x067A, 0x2C85, 0x1342, 0x39D9, 0x0660, 0x2BD7, 0x12F7, 0x3AF1, + 0x0647, 0x2B28, 0x12AB, 0x3C0E, 0x062D, 0x2A76, 0x125E, 0x3D2E, + 0x0613, 0x29C2, 0x1210, 0x3E51, 0x05F8, 0x290C, 0x11C1, 0x3F78, + 0x05DE, 0x2854, 0x1172, 0x40A3, 0x05C2, 0x2799, 0x1121, 0x41D1, + 0x05A7, 0x26DC, 0x10CF, 0x4302, 0x058B, 0x261D, 0x107D, 0x4438, + 0x056F, 0x255C, 0x1029, 0x4571, 0x0553, 0x2499, 0x0FD4, 0x46AD, + 0x0536, 0x23D3, 0x0F7F, 0x47ED, 0x0519, 0x230B, 0x0F28, 0x4931, + 0x04FB, 0x2241, 0x0ED1, 0x4A78, 0x04DE, 0x2174, 0x0E78, 0x4BC2, + 0x04C0, 0x20A5, 0x0E1F, 0x4D11, 0x04A1, 0x1FD4, 0x0DC5, 0x4E63, + 0x0482, 0x1F01, 0x0D69, 0x4FB8, 0x0463, 0x1E2C, 0x0D0D, 0x5111, + 0x0444, 0x1D54, 0x0CB0, 0x526E, 0x0424, 0x1C7A, 0x0C51, 0x53CE, + 0x0404, 0x1B9E, 0x0BF2, 0x5532, 0x03E4, 0x1AC0, 0x0B92, 0x5699, + 0x03C3, 0x19DF, 0x0B31, 0x5804, 0x03A2, 0x18FD, 0x0ACF, 0x5972, + 0x0381, 0x1818, 0x0A6C, 0x5AE5, 0x035F, 0x1730, 0x0A08, 0x5C5A, + 0x033D, 0x1647, 0x09A3, 0x5DD3, 0x031B, 0x155B, 0x093D, 0x5F50, + 0x02F9, 0x146D, 0x08D6, 0x60D1, 0x02D6, 0x137D, 0x086E, 0x6255, + 0x02B2, 0x128A, 0x0805, 0x63DC, 0x028F, 0x1196, 0x079B, 0x6567, + 0x026B, 0x109F, 0x0730, 0x66F6, 0x0247, 0x0FA6, 0x06C5, 0x6888, + 0x0222, 0x0EAA, 0x0658, 0x6A1E, 0x01FD, 0x0DAD, 0x05EA, 0x6BB7, + 0x01D8, 0x0CAD, 0x057B, 0x6D54, 0x01B2, 0x0BAB, 0x050C, 0x6EF5, + 0x018D, 0x0AA6, 0x049B, 0x7099, 0x0166, 0x09A0, 0x042A, 0x7241, + 0x0140, 0x0897, 0x03B7, 0x73EC, 0x0119, 0x078C, 0x0344, 0x759B, + 0x00F2, 0x067F, 0x02CF, 0x774D, 0x00CA, 0x056F, 0x025A, 0x7903, + 0x00A3, 0x045D, 0x01E3, 0x7ABD, 0x007A, 0x0349, 0x016C, 0x7C7A +}; + +JASSeqParser::Command JASSeqParser::sCmdInfo[0x60] = { + {nullptr}, {nullptr}, {nullptr}, {nullptr}, {nullptr}, {nullptr}, + {nullptr}, {nullptr}, {nullptr}, {nullptr}, {nullptr}, {nullptr}, + {nullptr}, {nullptr}, {nullptr}, {nullptr}, {nullptr}, + {&JASSeqParser::cmdNoteOn, 3}, + {&JASSeqParser::cmdNoteOff, 1}, + {&JASSeqParser::cmdNote, 4, 0x40}, + {&JASSeqParser::cmdSetLastNote, 1}, + {nullptr}, {nullptr}, {nullptr}, + {&JASSeqParser::cmdParamE, 2}, + {&JASSeqParser::cmdParamI, 2, 4}, + {&JASSeqParser::cmdParamEI, 3, 0x10}, + {&JASSeqParser::cmdParamII, 3, 0x14}, + {nullptr}, {nullptr}, {nullptr}, {nullptr}, {nullptr}, + {&JASSeqParser::cmdOpenTrack, 2, 8}, + {&JASSeqParser::cmdCloseTrack, 1}, + {&JASSeqParser::cmdCall, 1, 2}, + {&JASSeqParser::cmdCallF, 2, 8}, + {&JASSeqParser::cmdRet, 0}, + {&JASSeqParser::cmdRetF, 1}, + {&JASSeqParser::cmdJmp, 1, 2}, + {&JASSeqParser::cmdJmpF, 2, 8}, + {&JASSeqParser::cmdJmpTable, 2, 0xb}, + {&JASSeqParser::cmdCallTable, 2, 0xb}, + {&JASSeqParser::cmdLoopS, 1, 1}, + {&JASSeqParser::cmdLoopE, 0}, + {nullptr}, {nullptr}, {nullptr}, + {&JASSeqParser::cmdReadPort, 2}, + {&JASSeqParser::cmdWritePort, 2, 0xc}, + {&JASSeqParser::cmdCheckPortImport, 1}, + {&JASSeqParser::cmdCheckPortExport, 1}, + {&JASSeqParser::cmdParentWritePort, 2, 0xc}, + {&JASSeqParser::cmdChildWritePort, 2, 0xc}, + {&JASSeqParser::cmdParentReadPort, 2}, + {&JASSeqParser::cmdChildReadPort, 2}, + {&JASSeqParser::cmdRegLoad, 2, 4}, + {&JASSeqParser::cmdReg, 3, 0x30}, + {&JASSeqParser::cmdReg, 3, 0x10}, + {&JASSeqParser::cmdRegUni, 2}, + {&JASSeqParser::cmdRegTblLoad, 4, 0xe0}, + {nullptr}, {nullptr}, {nullptr}, + {&JASSeqParser::cmdTempo, 1, 1}, + {&JASSeqParser::cmdBankPrg, 1, 1}, + {&JASSeqParser::cmdBank, 1}, + {&JASSeqParser::cmdPrg, 1}, + {nullptr}, {nullptr}, {nullptr}, + {&JASSeqParser::cmdEnvScaleSet, 2, 4}, + {&JASSeqParser::cmdEnvSet, 2, 8}, + {&JASSeqParser::cmdSimpleADSR, 5, 0x155}, + {&JASSeqParser::cmdBusConnect, 2, 4}, + {&JASSeqParser::cmdIIRCutOff, 1}, + {&JASSeqParser::cmdIIRSet, 4, 0x55}, + {&JASSeqParser::cmdFIRSet, 1, 2}, + {nullptr}, {nullptr}, + {&JASSeqParser::cmdWait, 0}, + {&JASSeqParser::cmdWaitByte, 1}, + {nullptr}, + {&JASSeqParser::cmdSetIntTable, 1, 2}, + {&JASSeqParser::cmdSetInterrupt, 1, 1}, + {&JASSeqParser::cmdDisInterrupt, 1, 1}, + {&JASSeqParser::cmdClrI, 0}, + {&JASSeqParser::cmdRetI, 0}, + {&JASSeqParser::cmdIntTimer, 2, 4}, + {&JASSeqParser::cmdSyncCPU, 1, 1}, + {nullptr}, {nullptr}, {nullptr}, + {&JASSeqParser::cmdPrintf, 0}, + {&JASSeqParser::cmdNop, 0}, + {&JASSeqParser::cmdFinish, 0} +}; + +JASSeqParser::Command JASSeqParser::sExtCmdInfo[0xff] = { + {nullptr}, + {&JASSeqParser::cmdDump}, + {nullptr}, {nullptr}, {nullptr}, {nullptr}, {nullptr} +}; + +bool JASSeqParser::conditionCheck(JASTrack *track, BranchCondition cond) { + u16 res = track->mRegs.read(JASRegisterParam::REG_F); + switch(cond) { + case JASSeqParser::COND_ALWAYS: + return true; + case JASSeqParser::COND_NULL: + return !res; + case JASSeqParser::COND_NONNULL: + return res; + case JASSeqParser::COND_1: + return !(res - 1); + case JASSeqParser::COND_NEGATIVE: + return res >= 0x8000; + case JASSeqParser::COND_POSITIVE: + return res < 0x8000; + } + return false; +} + +void JASSeqParser::writeReg(JASTrack *track, u32 reg, u32 value) { + track->mRegs.write(JASRegisterParam::REG_F, value); + if(reg < 0x40) track->mRegs.write((JASRegisterParam::RegID)reg, value); + else switch(reg - 0x40) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 0xA: + case 0xB: + case 0xC: + case 0xD: + case 0xE: + case 0xF: + track->mPorts.mPorts[reg - 0x40] = value; + break; + case 0x22: + track->setTimebase(value); + break; + case 0x23: + track->mTransposeAmt = value; + break; + case 0x24: + track->_230 = value; + break; + case 0x25: + track->mGateLatency = value; + break; + case 0x26: + track->_220 = value; + break; + case 0x27: + track->mBank = (u8)value; + break; + case 0x28: + track->mPrg = (u8)value; + break; + case 0x29: + track->_218 = value; + track->_218 /= 32767f; + break; + case 0x2A: + track->_231 = value; + track->_232 = value >> 8; + break; + case 0x2B: + track->_231 = value; + break; + case 0x2C: + track->_232 = value; + break; + case 0x2D: + track->_224 = value; + break; + case 0x2E: + track->_1E0 = value; + track->_1E0 /= 1524f; + break; + case 0x2F: + track->_1E0 = value; + track->_1E0 /= 12192f; + break; + case 0x30: + track->_1E8 = value; + track->_1E8 *= 0.00390625f; + break; + case 0x31: + track->_1E4 = value; + track->_1E4 *= 0.015625f; + break; + case 0x32: + track->_1EC = value; + track->_1EC *= 0.015625f; + break; + case 0x33: + track->_1F0 = value; + break; + case 0x34: + track->_1F2 = value; + break; + } +} + +u32 JASSeqParser::readReg(JASTrack *track, u32 reg) const { + if(reg < 0x40) return track->mRegs.read((JASRegisterParam::RegID)reg); + else { + u32 ret = 0; + switch(reg - 0x40) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 0xA: + case 0xB: + case 0xC: + case 0xD: + case 0xE: + case 0xF: + ret = track->mPorts.mPorts[reg - 0x40]; + break; + // Create a bitmap of the current track's children + case 0x20: + u16 currBit = 1; + JASTrack *child; + for(u32 i = 0; i < 0x10; i++) { + if(child = track->mChildren[i]) { + if(child->_240 == 1) ret |= currBit; + } + currBit <<= 1; + } + break; + case 0x21: + if(!track->mNumStacks) return 0; + ret = track->mPorts.mPorts[track->mNumStacks - 0x20 + 5]; + break; + case 0x22: + ret = track->mTimebase; + break; + case 0x23: + ret = track->mTransposeAmt; + break; + case 0x24: + ret = track->_230; + break; + case 0x25: + ret = track->mGateLatency; + break; + case 0x26: + ret = track->_220; + break; + case 0x27: + ret = track->mBank; + break; + case 0x28: + ret = track->mPrg; + break; + case 0x29: { + f32 tmp = track->_218; + ret = tmp * 32767f; + break; + } + case 0x2A: + ret = track->_232 | track->_231; + break; + case 0x2B: + ret = track->_231; + break; + case 0x2C: + ret = track->_232; + break; + case 0x2D: + ret = track->_224; + break; + case 0x2E: { + f32 tmp = track->_1E0; + ret = tmp * 1524f; + break; + } + case 0x2F: { + f32 tmp = track->_1E0; + ret = tmp * 12192f; + break; + } + case 0x30: { + f32 tmp = track->_1E8; + ret = tmp * 256f; + break; + } + case 0x31: { + f32 tmp = track->_1E4; + ret = tmp * 64f; + break; + } + case 0x32: { + f32 tmp = track->_1EC; + ret = tmp * 64f; + break; + } + case 0x33: + ret = track->_1F0; + break; + case 0x34: + ret = track->_1F2; + break; + } + return ret; + } +} + +s32 JASSeqParser::cmdOpenTrack(JASTrack *track, u32 *args) { + u32 arg0 = args[0], arg1 = args[1]; + JASTrack *child = track->openChild(arg0); + if(!child) return 0; + child->setSeqData(track->mSeqBuff, arg1); + child->start(); + return 0; +} + +s32 JASSeqParser::cmdCloseTrack(JASTrack *track, u32 *args) { + track->closeChild(args[0]); + return 0; +} + +s32 JASSeqParser::cmdCall(JASTrack *track, u32 *args) { + track->call(args[0]); + return 0; +} + +s32 JASSeqParser::cmdCallF(JASTrack *track, u32 *args) { + if(conditionCheck(track, (BranchCondition)args[0])) track->call(args[1]); + return 0; +} + +s32 JASSeqParser::cmdRet(JASTrack *track, u32 *args) { + track->ret(); + return 0; +} +s32 JASSeqParser::cmdRetF(JASTrack *track, u32 *args) { + if(conditionCheck(track, (BranchCondition)args[0])) { + track->ret(); + return 0; + } + else return 0; +} +s32 JASSeqParser::cmdJmp(JASTrack *track, u32 *args) { + track->mSeqCursor = (void *)((u8 *)track->mSeqBuff + args[0]); + return 0; +} +s32 JASSeqParser::cmdJmpF(JASTrack *track, u32 *args) { + if(conditionCheck(track, (BranchCondition)args[0])) { + track->mSeqCursor = (void *)((u8 *)track->mSeqBuff + args[1]); + } + return 0; +} + +inline void mult3(u32 &a) { + a = a * 2 + a; +} + +s32 JASSeqParser::cmdJmpTable(JASTrack *track, u32 *args) { + u32 idx = args[0]; + mult3(idx); + track->mSeqCursor = (void *)((u8 *)track->mSeqBuff + track->calcSeekAmt(args[1] + idx)); + return 0; +} + +s32 JASSeqParser::cmdCallTable(JASTrack *track, u32 *args) { + u32 idx = args[0]; + mult3(idx); + track->call(track->calcSeekAmt(args[1] + idx)); + return 0; +} + +s32 JASSeqParser::cmdLoopS(JASTrack *track, u32 *args) { + track->loopStart(args[0]); + return 0; +} +s32 JASSeqParser::cmdLoopE(JASTrack *track, u32 *args) { + track->loopEnd(); + return 0; +} +s32 JASSeqParser::cmdNote(JASTrack *track, u32 *args) { + execNoteOnGate(track, args[1], args[2], args[3], args[0]); + return 0; +} +s32 JASSeqParser::cmdNoteOn(JASTrack *track, u32 *args) { + execNoteOnMidi(track, args[1], args[0], args[2]); + return 0; +} +s32 JASSeqParser::cmdNoteOff(JASTrack *track, u32 *args) { + execNoteOff(track, args[0]); + return 0; +} +s32 JASSeqParser::cmdReadPort(JASTrack *track, u32 *args) { + u16 res = track->readPortSelf(args[0]); + writeReg(track, args[1], res); + return 0; +} +s32 JASSeqParser::cmdWritePort(JASTrack *track, u32 *args) { + track->writePortSelf(args[0], args[1]); + return 0; +} +s32 JASSeqParser::cmdParentWritePort(JASTrack *track, u32 *args) { + if(track->mParent) track->mParent->writePort(args[0], args[1]); + return 0; +} +s32 JASSeqParser::cmdChildWritePort(JASTrack *track, u32 *args) { + u8 offset = args[0] >> 4 & 0xf; + u8 port = args[0]; + JASTrack *child = track->mChildren[offset]; + if(child) child->writePort(port & 0xf, args[1]); + return 0; +} +s32 JASSeqParser::cmdParentReadPort(JASTrack *track, u32 *args) { + if(track->mParent) { + u16 res = track->mParent->readPort(args[0]); + writeReg(track, args[1], res); + } + return 0; +} +s32 JASSeqParser::cmdChildReadPort(JASTrack *track, u32 *args) { + u8 offset = args[0] >> 4 & 0xf; + u8 port = args[0]; + JASTrack *child = track->mChildren[offset]; + if(child) { + u16 res = child->readPort(port & 0xf); + writeReg(track, args[1], res); + } + return 0; +} +s32 JASSeqParser::cmdCheckPortImport(JASTrack *track, u32 *args) { + track->mRegs.write(JASRegisterParam::REG_F, track->mPorts.checkImport(args[0])); + return 0; +} +s32 JASSeqParser::cmdCheckPortExport(JASTrack *track, u32 *args) { + track->mRegs.write(JASRegisterParam::REG_F, track->mPorts.checkExport(args[0])); + return 0; +} +s32 JASSeqParser::cmdWait(JASTrack *track, u32 *args) { + track->mTimer = track->readMidiValue(); + return 0; +} +s32 JASSeqParser::cmdWaitByte(JASTrack *track, u32 *args) { + track->mTimer = args[0]; + return 0; +} +s32 JASSeqParser::cmdSetLastNote(JASTrack *track, u32 *args) { + if(args[0] < 0x100) track->setLatestKey(args[0]); + return 0; +} +s32 JASSeqParser::cmdEnvScaleSet(JASTrack *track, u32 *args) { + track->setOscScale(args[0], args[1] / 16383f); + return 0; +} +s32 JASSeqParser::cmdEnvSet(JASTrack *track, u32 *args) { + track->setOscTable(args[0], (const JASOscillator::Point *)((u8 *)track->mSeqBuff + args[1])); + return 0; +} +s32 JASSeqParser::cmdSimpleADSR(JASTrack *track, u32 *args) { + track->setOscAdsr(args[0], args[1], args[2], args[3], args[4]); + return 0; +} +s32 JASSeqParser::cmdBusConnect(JASTrack *track, u32 *args) { + track->connectBus(args[0], args[1]); + return 0; +} +s32 JASSeqParser::cmdSetIntTable(JASTrack *track, u32 *args) { + track->_48 = args[0]; + return 0; +} +s32 JASSeqParser::cmdSetInterrupt(JASTrack *track, u32 *args) { + track->setIntrMask(args[0]); + return 0; +} +s32 JASSeqParser::cmdDisInterrupt(JASTrack *track, u32 *args) { + track->clrIntrMask(args[0]); + return 0; +} +s32 JASSeqParser::cmdClrI(JASTrack *track, u32 *args) { + track->mCursorSwap = nullptr; + track->checkIntr(); + return 0; +} +s32 JASSeqParser::cmdRetI(JASTrack *track, u32 *args) { + track->retIntr(); + track->checkIntr(); + return 0; +} +s32 JASSeqParser::cmdIntTimer(JASTrack *track, u32 *args) { + u32 arg0 = args[0], arg1 = args[1]; + track->mIntTimer = arg0; + track->_54 = arg1; + track->_58 = arg1; + return 0; +} +s32 JASSeqParser::cmdSyncCPU(JASTrack *track, u32 *args) { + u16 value = -1; + if(sCallbackFunc) value = sCallbackFunc(track, args[0]); + track->mRegs.write(JASRegisterParam::REG_F, value); + return 0; +} +s32 JASSeqParser::cmdTempo(JASTrack *track, u32 *args) { + track->setTempo(args[0]); + return 0; +} +s32 JASSeqParser::cmdFinish(JASTrack *track, u32 *args) { + return -1; +} +s32 JASSeqParser::cmdNop(JASTrack *track, u32 *args) { + return 0; +} +s32 JASSeqParser::cmdFIRSet(JASTrack *track, u32 *args) { + track->setFIR((const s16 *)((u8 *)track->mSeqBuff + args[0])); + return 0; +} +s32 JASSeqParser::cmdIIRSet(JASTrack *track, u32 *args) { + s16 iir[4]; + for(u32 i = 0; i < 4; i++) { + iir[i] = args[i]; + } + track->setIIR(iir); + return 0; +} +s32 JASSeqParser::cmdIIRCutOff(JASTrack *track, u32 *args) { + if(args[0] < 0x80) track->setIIR(sIIRCutoff + args[0] * 4); + return 0; +} +s32 JASSeqParser::cmdBankPrg(JASTrack *track, u32 *args) { + u32 arg0 = args[0]; + track->mBank = (u8)(arg0 >> 8); + track->mPrg = (u8)arg0; + return 0; +} +s32 JASSeqParser::cmdBank(JASTrack *track, u32 *args) { + track->mBank = (u8)args[0]; + return 0; +} +s32 JASSeqParser::cmdPrg(JASTrack *track, u32 *args) { + track->mPrg = (u8)args[0]; + return 0; +} +s32 JASSeqParser::cmdParamI(JASTrack *track, u32 *args) { + track->setParam(args[0], (s16)args[1] / 32767f, 0); + return 0; +} +s32 JASSeqParser::cmdParamII(JASTrack *track, u32 *args) { + track->setParam(args[0], (s16)args[1] / 32767f, args[2]); + return 0; +} +s32 JASSeqParser::cmdParamE(JASTrack *track, u32 *args) { + s16 arg1 = args[1] << 8; + if(!(args[1] & 0x80)) arg1 |= (s16)(args[1] << 1); + track->setParam(args[0], arg1 / 32767f, 0); + return 0; +} +s32 JASSeqParser::cmdParamEI(JASTrack *track, u32 *args) { + s16 arg1 = args[1] << 8; + if(!(args[1] & 0x80)) arg1 |= (s16)(args[1] << 1); + track->setParam(args[0], arg1 / 32767f, args[2]); + return 0; +} +s32 JASSeqParser::cmdReg(JASTrack *track, u32 *args) { + u32 arg1 = args[1], arg2 = args[2]; + switch(args[0]) { + case 0: + break; + case 1: + arg2 += readReg(track, arg1); + break; + case 2: + arg2 = readReg(track, arg1) - arg2; + break; + case 3: + arg2 = readReg(track, arg1) - arg2; + arg1 = 3; + break; + case 4: + arg2 *= readReg(track, arg1); + arg1 = 0x21; + break; + case 5: + arg2 &= readReg(track, arg1); + break; + case 6: + arg2 |= readReg(track, arg1); + break; + case 7: + arg2 ^= readReg(track, arg1); + break; + case 8: + static JMath::TRandom_fast_ oRandom(0); + arg2 = (oRandom.rand() >> 9) % arg2; + break; + case 9: + arg2 = readReg(track, arg1) << arg2; + break; + case 10: + arg2 = readReg(track, arg1) >> arg2; + break; + default: + return 0; + } + writeReg(track, arg1, arg2); + return 0; +} +s32 JASSeqParser::cmdRegLoad(JASTrack *track, u32 *args) { + writeReg(track, args[0], args[1]); + return 0; +} +s32 JASSeqParser::cmdRegUni(JASTrack *track, u32 *args) { + u32 arg1 = args[1], reg; + switch(args[0]) { + case 0xb: + reg = -readReg(track, arg1); + break; + default: + return 0; + } + writeReg(track, arg1, reg); + return 0; +} +s32 JASSeqParser::cmdRegTblLoad(JASTrack *track, u32 *args) { + u32 arg1 = args[1], arg3 = args[2], arg2 = args[3]; + switch(args[0]) { + case 0xc: + arg3 = *((u8 *)track->mSeqBuff + arg3 + arg2); + break; + case 0xd: + arg3 = *((u16 *)((u8 *)track->mSeqBuff + arg3) + arg2); + break; + case 0xe: + mult3(arg2); + arg3 = track->calcSeekAmt(arg3 + arg2); + break; + case 0xf: + arg3 = *((u32 *)((u8 *)track->mSeqBuff + arg3) + arg2); + break; + case 0x10: + arg3 = *(u32 *)((u8 *)track->mSeqBuff + arg2 + arg3); + break; + default: + return 0; + } + writeReg(track, arg1, arg3); + return 0; +} + +s32 JASSeqParser::cmdDump(JASTrack *track, u32 *args) { + JASReport("--------------- JASTrack (%8x) dump ----------------", track); + + JASReport ( + " Base: 0x%08x Cur: 0x%08x(0x%06x)", + track->mSeqBuff, + track->mSeqCursor, + (u8 *)track->mSeqCursor - (u8 *)track->mSeqBuff + ); + + JASReport(""); + + + u32 ra = track->mRegs.read(JASRegisterParam::REG_A), + rb = track->mRegs.read(JASRegisterParam::REG_B), + rs = track->mRegs.read(JASRegisterParam::REG_S); + JASReport(" REG_A: 0x%04x REG_B: 0x%04x REG_S: 0x%04x", ra, rb, rs); + + u32 rx = track->mRegs.read(JASRegisterParam::REG_X), + ry = track->mRegs.read(JASRegisterParam::REG_Y), + rf = track->mRegs.read(JASRegisterParam::REG_F); + JASReport(" REG_X: 0x%04x REG_Y: 0x%04x REG_F: 0x%04x", rx, ry, rf); + JASReport(""); + + + JASReport( + " PORT 0-3: 0x%04x 0x%04x 0x%04x 0x%04x", + track->mPorts.mPorts[0], + track->mPorts.mPorts[1], + track->mPorts.mPorts[2], + track->mPorts.mPorts[3] + ); + JASReport( + " PORT 4-7: 0x%04x 0x%04x 0x%04x 0x%04x", + track->mPorts.mPorts[4], + track->mPorts.mPorts[5], + track->mPorts.mPorts[6], + track->mPorts.mPorts[7] + ); + JASReport( + " PORT 8-B: 0x%04x 0x%04x 0x%04x 0x%04x", + track->mPorts.mPorts[8], + track->mPorts.mPorts[9], + track->mPorts.mPorts[0xA], + track->mPorts.mPorts[0xB] + ); + JASReport( + " PORT C-F: 0x%04x 0x%04x 0x%04x 0x%04x", + track->mPorts.mPorts[0xC], + track->mPorts.mPorts[0xD], + track->mPorts.mPorts[0xE], + track->mPorts.mPorts[0xF] + ); + JASReport(""); + + return 0; +} + +s32 JASSeqParser::cmdPrintf(JASTrack *track, u32 *args) { + char stack_1C[0x80]; + u32 stack_C[4]; + u8 stack_8[4]; + u32 r1f = 0, i; + for(i = 0; i < 0x80; i++) { + char currChar = *(((char *)track->mSeqCursor)++); + stack_1C[i] = currChar; + if(!currChar) break; + if(currChar == '\\') { + char currChar = *(((char *)track->mSeqCursor)++); + if(!(stack_1C[i] = currChar)) break; + switch(currChar) { + case 'n': + stack_1C[i] = 0xd; + continue; + default: + continue; + } + } + else if(currChar == '%') { + char currChar2 = *(((char *)track->mSeqCursor)++); + if(!(stack_1C[++i] = currChar2)) break; + switch(currChar2) { + case 'd': + stack_8[r1f] = 0; + break; + case 'x': + stack_8[r1f] = 1; + break; + case 's': + stack_8[r1f] = 2; + break; + case 'r': + stack_8[r1f] = 3; + stack_1C[i] = 'd'; + break; + case 'R': + stack_8[r1f] = 4; + stack_1C[i] = 'x'; + break; + } + } + else continue; + r1f++; + } + for(i = 0; i < r1f; i++) { + u8 curr = stack_8[i]; + u8 *tmp2 = (u8 *)track->mSeqCursor; + ((u8 *)track->mSeqCursor)++; + stack_C[i] = *tmp2; + switch(curr) { + case 2: + stack_C[i] = (u32)((u8 *)track->mSeqBuff + stack_C[i]); + break; + case 3: + case 4: + stack_C[i] = readReg(track, (u8)stack_C[i]); + break; + } + } + JASReport(stack_1C, stack_C[0], stack_C[1], stack_C[2], stack_C[3]); + return 0; +} + +void JASSeqParser::execNoteOnGate(JASTrack *track, u32 a, u32 b, u32 c, u32 d) { + u32 arg = 0; + if(d >> 6 & 1) arg |= 2; + if(d >> 7 & 1) arg |= 1; + if(!c) arg |= 4; + track->gateOn(a, b, c, arg); + if(c) track->mTimer = c; + else track->_51 = true; +} + +void JASSeqParser::execNoteOnMidi(JASTrack *track, u32 a, u32 b, u32 c) { + track->noteOn(a, b, c); +} + +void JASSeqParser::execNoteOff(JASTrack *track, u32 a) { + track->noteOff(a, 0); +} + +s32 JASSeqParser::execCommand(JASTrack *track, CommandFunc command, u32 a, u32 *args) { + return (this->*command)(track, args); +} + +s32 JASSeqParser::parseNoteOff(JASTrack *track, u8 a) { + a &= 7; + if(a) execNoteOff(track, a); + return 0; +} + +s32 JASSeqParser::parseNoteOn(JASTrack *track, u8 a) { + u8 note = *(((u8 *)track->mSeqCursor)++); + u8 lower = note & 7; + u8 note2 = *(((u8 *)track->mSeqCursor)++); + if(!lower) execNoteOnGate(track, a, note2, track->readMidiValue(), note); + else execNoteOnMidi(track, lower, a, note2); + return 0; +} + +struct u24 { + u8 _0[3]; +}; + +s32 JASSeqParser::parseCommand(JASTrack *track, u8 cmdCode, u16 c) { + Command *cmd; + + if(cmdCode != 0xB0) { + cmd = sCmdInfo + (cmdCode - 0xA0); + } + else { + cmd = sExtCmdInfo + *(((u8 *)track->mSeqCursor)++); + } + + u32 b = cmd->argWidths | c; + u32 args[8]; + + for(int i = 0; i < cmd->numArgs; i++) { + u32 arg = 0; + switch(b & 3) { + case 0: + arg = *(((u8 *)track->mSeqCursor)++); + break; + case 1: + arg = *(((u16 *)track->mSeqCursor)++); + break; + case 2: + // Access a 24-bit field + arg = *((u32 *)((u8 *)(((u24 *)track->mSeqCursor)++) - 1)) & 0xffffff; + break; + case 3: + arg = readReg(track, *(((u8 *)track->mSeqCursor)++)); + break; + } + args[i] = arg; + b = (u16)b >> 2; + } + CommandFunc func = cmd->func; + if(func == nullptr) return 0; + return execCommand(track, func, cmd->numArgs, args); +} + +s32 JASSeqParser::parseRegCommand(JASTrack *track, int a) { + u8 data = *(((u8 *)track->mSeqCursor)++); + u16 width = 0; + u16 b = 3; + for(int i = 0; i < a; i++) { + if(data & 0x80) width |= b; + data <<= 1; + b <<= 2; + } + return parseCommand(track, *(((u8 *)track->mSeqCursor)++), width); +} + +s32 JASSeqParser::parse(JASTrack *track) { + u8 data = *(((u8 *)track->mSeqCursor)++); + if(!(data & 0x80)) return parseNoteOn(track, data); + switch(data & 0xf0) { + case 0x80: + return parseNoteOff(track, data & 0xf); + case 0x90: + return parseRegCommand(track, (data & 7) + 1); + default: + return parseCommand(track, data, 0); + } +} diff --git a/src/JSystem/JAudio2/JASSeqReader.cpp b/src/JSystem/JAudio2/JASSeqReader.cpp new file mode 100644 index 00000000..6f2a1157 --- /dev/null +++ b/src/JSystem/JAudio2/JASSeqReader.cpp @@ -0,0 +1,84 @@ +#include "JSystem/JAudio2/JASSeqReader.hpp" + +void JASSeqReader::init() { + mSeqBuff = nullptr; + mSeqCursor = nullptr; + mNumStacks = 0; + for(u32 i = 0; i < 8; i++) { + mStackPtrs[i] = nullptr; + mLoopTimers[i] = nullptr; + } +} + +void JASSeqReader::init(void *buf) { + mSeqBuff = buf; + mSeqCursor = buf; + mNumStacks = 0; + for(u32 i = 0; i < 8; i++) { + mStackPtrs[i] = nullptr; + mLoopTimers[i] = nullptr; + } +} + +bool JASSeqReader::call(u32 num) { + if(mNumStacks >= 8) return false; + else { + mStackPtrs[mNumStacks++] = mSeqCursor; + mSeqCursor = (void *)((u8 *)mSeqBuff + num); + return true; + } +} + +bool JASSeqReader::loopStart(u32 loopTimer) { + if(mNumStacks >= 8) return false; + else { + mStackPtrs[mNumStacks] = mSeqCursor; + mLoopTimers[mNumStacks++] = loopTimer; + return true; + } +} + +bool JASSeqReader::loopEnd() { + if(mNumStacks == 0) return false; + else { + u16 loopTimer = mLoopTimers[mNumStacks - 1]; + if(loopTimer > 0) loopTimer--; + if(loopTimer == 0) { + mNumStacks--; + return true; + } + mLoopTimers[mNumStacks - 1] = loopTimer; + mSeqCursor = mStackPtrs[mNumStacks - 1]; + return true; + } +} + +bool JASSeqReader::ret() { + if(mNumStacks == 0) return false; + else { + mSeqCursor = mStackPtrs[--mNumStacks]; + return true; + } +} + +u32 JASSeqReader::readMidiValue() { + u8 byte = *(((u8 *)mSeqCursor)++); + if(!(byte & 0x80)) return byte; + u32 byte2 = byte & 0x7f; + s32 i = 0; + u8 byte4; + while(true) { + if(i > 2) return 0; + byte2 = byte2 << 7; + byte4 = *(((u8 *)mSeqCursor)++); + byte2 |= byte4 & 0x7f; + if(!(byte4 & 0x80)) break; + i++; + } + return byte2; +} + +void* JASSeqReader::getStackPtr(u32 idx) const { + if(idx >= mNumStacks) return nullptr; + else return mStackPtrs[idx]; +} diff --git a/src/JSystem/JAudio2/JASTrack.cpp b/src/JSystem/JAudio2/JASTrack.cpp new file mode 100644 index 00000000..1a8333cc --- /dev/null +++ b/src/JSystem/JAudio2/JASTrack.cpp @@ -0,0 +1,865 @@ +#include "JSystem/JAudio2/JASTrack.hpp" +#include "JSystem/JAudio2/JASChannel.hpp" +#include "JSystem/JAudio2/JASSoundParams.hpp" +#include "JSystem/JAudio2/JASAiCtrl.hpp" +#include "JSystem/JAudio2/JASDriverIF.hpp" +#include "JSystem/JAudio2/JASLfo.hpp" + +#include +#include + +static const JASOscillator::Point sDefaultAdsr[4] = { + {0, 0, 0x7fff}, + {0, 0, 0x7fff}, + {0, 0, 0}, + {0xe, 0, 0} +}; + +const JASOscillator::Data JASTrack::sEnvOsc = {0, 1.0f, 0, 0, 1.0f, 0.0f}; + +const JASOscillator::Data JASTrack::sPitchEnvOsc = {1, 1.0f, 0, 0, 1.0f, 0.0f}; + +JASTrack::JASTrack() : JASSeqCtrl(), mRegs(), mInitialMgr(this), mNumChannels(1), _240(0), mNode() { + mMgrs[0] = &mInitialMgr; + for(u32 i = 1; i < 4; i++) { + mMgrs[i] = nullptr; + } + init(); +} + + +JASTrack::~JASTrack() { + for(int i = 1; i < 4; i++) { + delete mMgrs[i]; + } +} + +void JASTrack::setChannelMgrCount(u32 count) { + mNumChannels = 1; + for(u32 i = 1; i < count; i++, mNumChannels++) { + if(mMgrs[i]) continue; + if(!(mMgrs[i] = new TChannelMgr(this))) return; + } + for(u32 i = mNumChannels; i < 4; i++) { + if(mMgrs[i]) { + delete mMgrs[i]; + mMgrs[i] = nullptr; + } + } +} + +void JASTrack::init() { + JASSeqCtrl::init(); + mPorts.init(); + initTimed(); + mRegs.init(); + + memcpy(_E4, &sEnvOsc, 0x18); + memcpy(_E4 + 1, &sPitchEnvOsc, 0x18); + for(int i = 0; i < 4; i++) { + mAdsr[i] = sDefaultAdsr[i]; + } + + mParent = nullptr; + + for(u32 i = 0; i < 0x10; i++) { + mChildren[i] = nullptr; + } + + mMgrs[0]->init(); + mNumChannels = 1; + for(int i = 1; i < 4; i++) { + if(mMgrs[i]) { + delete mMgrs[i]; + mMgrs[i] = nullptr; + } + } + + mBankTable = &sDefaultBankTable; + + mPlaytime = 1f; + mSampleInterval = 1f; + + _1E0 = 0f; + _1E4 = 1f; + _1E8 = 0f; + _1EC = 1f; + + _1F0 = 0; + _1F2 = 0; + + _218 = 1f; + _224 = 0; + _220 = 0; + mTempo = 120; + mTimebase = 48; + mTempoRate = 1.0f; + updateTempo(); + + mTransposeAmt = 0; + mPitch = 0x3C; + + mBank = 0; + mPrg = 0xF0; + _230 = 0xC; + _231 = 0x40; + _232 = 0; + mGateLatency = 100; + + mBuses[0] = 0x150; + mBuses[1] = 0x210; + mBuses[2] = 0x352; + mBuses[3] = 0x412; + mBuses[4] = 0; + mBuses[5] = 0; + + for(u32 i = 0; i < 8; i++) { + mFIRFilter[i] = 0; + } + mFIRFilter[0] = 0x7fff; + for(u32 i = 0; i < 8; i++) { + mIIRFilter[i] = 0; + } + mIIRFilter[0] = 0x7fff; + mFilterMode = 0; + + mPauseFlag = false; + mIsMute = false; + mIsDirectlyPlayed = true; + mInvalidateSeq = true; + mIsOwnedByParent = false; + mReadyToPlay = false; + mIsStopped = false; + byteRepr = byteRepr; + _240 = 0; +} + +void JASTrack::initTimed() { + _9C[0]._0 = 1f; + _9C[1]._0 = 0f; + _9C[3]._0 = 0.5f; + _9C[2]._0 = 0f; + _9C[4]._0 = 0f; + _9C[5]._0 = 0f; + + for(u32 i = 0; i < 6; i++) { + _9C[i]._8 = 0; + _9C[i]._4 = _9C[i]._0; + } +} + +void JASTrack::inherit(const JASTrack &rParent) { + mIsDirectlyPlayed = rParent.mIsDirectlyPlayed; + + mBank = rParent.mBank; + mPrg = rParent.mPrg; + + _231 = rParent._231; + _232 = rParent._232; + + _220 = rParent._220; + + for(u32 i = 0; i < 8; i++) { + mFIRFilter[i] = rParent.mFIRFilter[i]; + } + for(u32 i = 0; i < 8; i++) { + mIIRFilter[i] = rParent.mIIRFilter[i]; + } + mFilterMode = rParent.mFilterMode; + + for(u32 i = 0; i < 6; i++) { + mBuses[i] = rParent.mBuses[i]; + } +} + +void JASTrack::assignExtBuffer(u32 mgr, JASSoundParams *buffer) { + mMgrs[mgr]->_48 = buffer; +} + +void JASTrack::setSeqData(void *data, u32 offset) { + JASSeqCtrl::start(data, offset); +} + +void JASTrack::startSeq() { + { + JASCriticalSection lock; + sTrackList.append(this); + _240 = 1; + } + +} + +void JASTrack::stopSeq() { + { + JASCriticalSection lock; + mIsStopped = true; + } +} + +void JASTrack::start() { + _240 = 1; +} + +void JASTrack::close() { + for(int i = 0; i < 0x10; i++) { + JASTrack *currChild; + currChild = mChildren[i]; + if(currChild) { + currChild->close(); + if(currChild->mIsOwnedByParent) { + delete currChild; + mChildren[i] = nullptr; + } + } + } + for(u32 i = 0; i < mNumChannels; i++) { + if(mMgrs[i]) mMgrs[i]->releaseAll(); + } + mParent = nullptr; + _240 = 2; +} + +bool JASTrack::connectChild(u32 idx, JASTrack *child) { + if(mChildren[idx]) return false; + child->mParent = this; + mChildren[idx] = child; + return true; +} + +void JASTrack::closeChild(u32 idx) { + JASTrack *child; + if(child = mChildren[idx]) { + getRootTrack()->updateSeq(false, 1f); + child->close(); + if(child->mIsOwnedByParent) { + delete child; + mChildren[idx] = nullptr; + } + } +} + +JASTrack* JASTrack::openChild(u32 idx) { + JASTrack *child; + child = mChildren[idx]; + if(child) { + switch(child->_240) { + case 0: break; + case 1: + getRootTrack()->updateSeq(false, 1f); + child->close(); + case 2: + bool tmp = child->mIsOwnedByParent; + child->init(); + child->mIsOwnedByParent = tmp; + mChildren[idx] = nullptr; + connectChild(idx, child); + break; + } + } + else { + if(!(child = new JASTrack())) return nullptr; + child->mIsOwnedByParent = true; + connectChild(idx, child); + } + child->setChannelMgrCount(mNumChannels); + child->inherit(*this); + return child; +} + +void JASTrack::connectBus(int idx, int bus) { + mBuses[idx] = bus; +} + +void JASTrack::setLatestKey(u8 key) { + mPitch = key; + mPitch += getTransposeTotal(); +} + +bool JASTrack::noteOn(u32 channelNum, u32 pitch, u32 c) { + if(isMute()) return false; + bool ret = true; + pitch += getTransposeTotal(); + for(u32 i = 0; i < mNumChannels; i++) { + if(mMgrs[i]) { + mMgrs[i]->noteOff(channelNum, 0); + JASChannel *channel; + if(!(channel = channelStart(mMgrs[i], pitch, c, 0))) ret = false; + mMgrs[i]->mChannels[channelNum] = channel; + } + } + return ret; +} + +bool JASTrack::gateOn(u32 transposedPitch, u32 velocity, f32 seqTime, u32 flags) { + + transposedPitch += getTransposeTotal(); + if(mGateLatency != 100) seqTime *= mGateLatency / 100f; + s32 pitchDelta; + u32 isSweep; + u32 dspTime = seqTimeToDspTime(seqTime); + isSweep = flags & 1; + + // We only can schedule future notes if we do not want to immediately play the next note? + u32 updateTimer = (flags & 6) != 0 ? 0 : dspTime; + + u32 pitch; + if(isSweep) pitch = mPitch; + else pitch = transposedPitch; + pitchDelta = transposedPitch - pitch; + for(u32 i = 0; i < mNumChannels; i++) { + TChannelMgr *mgr = mMgrs[i]; + if(mgr) { + if(mReadyToPlay) { + mgr->noteOff(0, 0); + if(!isMute()) { + mgr->mChannels[0] = channelStart(mgr, pitch, velocity, updateTimer); + } + } + else { + JASChannel *channel = mgr->mChannels[0]; + if(channel) { + channel->setKey(pitch - channel->_E1); + channel->setVelocity(velocity); + channel->setUpdateTimer(updateTimer); + } + } + JASChannel *channel; + if(isSweep && (channel = mgr->mChannels[0])) { + channel->setKeySweepTarget(pitchDelta, dspTime); + } + } + } + mPitch = transposedPitch; + mReadyToPlay = flags & 2; + return true; +} + +bool JASTrack::noteOff(u32 a, u16 b) { + bool ret = true; + for(u32 i = 0; i < mNumChannels; i++) { + TChannelMgr *mgr = mMgrs[i]; + if(mgr) { + if(!mgr->noteOff(a, b)) ret = false; + } + } + return ret; +} + +bool JASTrack::checkNoteStop(u32 channel) const { + for(u32 i = 0; i < mNumChannels; i++) { + TChannelMgr *mgr = mMgrs[i]; + if(mgr) { + if(mgr->mChannels[channel]) return false; + } + } + return true; +} + +void JASTrack::overwriteOsc(JASChannel *channel) { + for(u32 i = 0; i < 2; i++) { + if(_E4[i]._8) { + channel->setOscInit(i, _E4 + i); + } + } +} + +void JASTrack::updateTimedParam() { + for(u32 i = 0; i < 6; i++) { + if(_9C[i]._8) { + _9C[i]._0 += (_9C[i]._4 - _9C[i]._0) / _9C[i]._8; + _9C[i]._8--; + } + } +} + +void JASTrack::updateTrack(f32 num) { + updateTempo(); + for(u32 i = 0; i < mNumChannels; i++) { + TChannelMgr *mgr = mMgrs[i]; + if(mgr) { + f32 fr8 = _9C[0]._0; + fr8 *= fr8; + f32 fr9 = 1f; + f32 fra = _9C[1]._0 * _230 * 0.333333343267f; + f32 frb = (_9C[3]._0 - 0.5f) * _218; + f32 frc = _9C[2]._0; + f32 frd = _9C[4]._0; + JASSoundParams *params = mgr->_48; + if(params) { + fr8 *= params->_0[0]; + fr9 *= params->_0[2]; + frb += params->_0[3] - 0.5f; + frc += params->_0[1]; + frd += params->_0[4]; + } + frb *= num; + if(!mParent) { + mgr->mChannelParams._0[0] = fr8; + mgr->mChannelParams._0[1] = fr9; + mgr->mChannelParams._0[3] = frb; + mgr->mChannelParams._0[4] = frc; + mgr->mChannelParams._0[5] = frd; + mgr->mChannelParams._0[2] = fra; + } + else { + TChannelMgr *mgrParent = mParent->mMgrs[i]; + if(!mgrParent) mgrParent = mParent->mMgrs[0]; + mgr->mChannelParams._0[0] = mgrParent->mChannelParams._0[0] * fr8; + mgr->mChannelParams._0[1] = mgrParent->mChannelParams._0[1] * fr9; + mgr->mChannelParams._0[3] = mgrParent->mChannelParams._0[3] - 0.5f + frb; + mgr->mChannelParams._0[4] = mgrParent->mChannelParams._0[4] + frc; + mgr->mChannelParams._0[5] = mgrParent->mChannelParams._0[5] + frd; + mgr->mChannelParams._0[2] = mgrParent->mChannelParams._0[2] + fra; + } + mgr->mChannelParams._0[3] += 0.5f; + } + } +} + +void JASTrack::updateTempo() { + if(!mParent) { + f32 rate = JASDriver::getDacRate(); + mSampleInterval = mTempoRate * (1.33333337307f * (mTimebase * mTempo) / rate); + } + else { + mTempo = mParent->mTempo; + mTimebase = mParent->mTimebase; + mSampleInterval = mParent->mSampleInterval; + } +} + +void JASTrack::updateSeq(bool update, f32 num) { + if(!update) update = mInvalidateSeq; + mInvalidateSeq = false; + if(update) updateTrack(num); + num *= _218; + for(int i = 0; i < 0x10; i++) { + JASTrack *child = mChildren[i]; + if(child && child->_240 == 1) child->updateSeq(update, num); + } +} + +u32 JASTrack::seqTimeToDspTime(f32 seqTime) { + if(mIsDirectlyPlayed) seqTime /= mSampleInterval; + else { + seqTime *= 120f / mTimebase; + seqTime *= JASDriver::getSubFrames() / 10f; + } + return seqTime; +} + +void JASTrack::setParam(u32 param, f32 value, u32 b) { + Timed &timed = _9C[param]; + timed._4 = value; + if(!b) timed._0 = timed._4; + timed._8 = b; +} + +void JASTrack::noteOffAll(u16 a) { + for(u32 i = 0; i < 8; i++) { + noteOff((u8)i, a); + } + for(int i = 0; i < 0x10; i++) { // Probably a template + JASTrack *child = mChildren[i]; + if(child && child->_240 == 1) child->noteOffAll(a); + } +} + +void JASTrack::mute(bool isMute) { + mIsMute = isMute; + if(!isMute) return; + noteOffAll(10); +} + +void JASTrack::setOscScale(u32 a, f32 scale) { + _E4[a]._10 = scale; +} + +void JASTrack::setOscTable(u32 a, const JASOscillator::Point *point) { + _E4[a]._8 = point; + if(a == 0) return; + _E4[a]._C = 0; +} + +void JASTrack::setOscAdsr(s16 attack, s16 delay, s16 sustain, s16 release, u16 e) { + memcpy(_E4, &sEnvOsc, 0x18); + mAdsr[0]._2 = attack; + _E4[0]._8 = mAdsr; + mAdsr[1]._2 = delay; + mAdsr[2]._2 = sustain; + mAdsr[2]._4 = release; + _224 = e; +} + +void JASTrack::setFIR(const s16 *FIRFilter) { + for(u32 i = 0; i < 8; i++) { + mFIRFilter[i] = FIRFilter[i]; + } + mFilterMode &= 0x20; + mFilterMode |= 8; +} + +void JASTrack::setIIR(const s16 *IIRFilter) { + for(u32 i = 0; i < 8; i++) { + mIIRFilter[i] = IIRFilter[i]; + } + mFilterMode |= 0x20; +} + +u16 JASTrack::readPortSelf(u32 port) { + return mPorts.readImport(port); +} + +void JASTrack::writePortSelf(u32 port, u16 value) { + mPorts.writeExport(port, value); +} + +void JASTrack::writePort(u32 port, u16 value) { + mPorts.writeImport(port, value); + if(port <= 1) { + JASSeqCtrl::interrupt(port == 0 ? JASSeqCtrl::INTR_2 : JASSeqCtrl::INTR_3); + } +} + +u16 JASTrack::readPort(u32 port) { + return mPorts.readExport(port); +} + +void JASTrack::setChannelPauseFlag(bool pauseFlag) { + for(int i = 0; i < mNumChannels; i++) { + TChannelMgr *mgr = mMgrs[i]; + if(mgr) mgr->setPauseFlag(pauseFlag); + } + for(int i = 0; i < 0x10; i++) { + JASTrack *child = mChildren[i]; + if(child) child->setChannelPauseFlag(pauseFlag); + } +} + +void JASTrack::pause(bool pauseFlag) { + if(mPauseFlag != pauseFlag) { + mPauseFlag = pauseFlag; + setChannelPauseFlag(pauseFlag); + JASSeqCtrl::interrupt((JASSeqCtrl::IntrType)!pauseFlag); + } +} + +s32 JASTrack::getTransposeTotal() const { + if(mParent) return mParent->getTransposeTotal() + mTransposeAmt; + else return mTransposeAmt; +} + +bool JASTrack::isMute() const { + bool ret; + if(mParent) { + ret = false; + if(mIsMute || mParent->isMute()) ret = true; + } + else ret = mIsMute; + return ret; +} + +void JASTrack::setTempo(u16 tempo) { + mTempo = tempo; + mInvalidateSeq = true; + updateTempo(); +} + +void JASTrack::setTempoRate(f32 rate) { + mTempoRate = rate; + mInvalidateSeq = true; + updateTempo(); +} + +void JASTrack::setTimebase(u16 timebase) { + mTimebase = timebase; + mInvalidateSeq = true; + updateTempo(); +} + +void JASTrack::updateChannel(JASChannel *channel, JASDsp::TChannel *dspChannel) { + channel->setVibrate(_1E0, _1E4); + channel->setTremolo(_1E8, _1EC); + if(mFilterMode & 0x20) dspChannel->setIIRFilterParam(mIIRFilter); + if(mFilterMode & 0x1F) dspChannel->setFIR8FilterParam(mFIRFilter); + dspChannel->setFilterMode(mFilterMode); + dspChannel->setDistFilter(32767f * _9C[5]._0); +} + +void JASTrack::channelUpdateCallback ( + u32 a, JASChannel *channel, JASDsp::TChannel *dspChannel, void *data +) { + TChannelMgr *mgr = (TChannelMgr *)data; + JASTrack *track = mgr->mParentTrack; + switch(a) { + case 0: + case 1: + channel->setParams(mgr->mChannelParams); + track->updateChannel(channel, dspChannel); + break; + case 3: + channel->release(0); + channel->free(); + mgr->mChannels[0] = nullptr; + break; + case 2: + for(u32 i = 0; i < 8; i++) { + if(channel == mgr->mChannels[i]) { + mgr->mChannels[i] = nullptr; + return; + } + } + break; + } +} + +JASTrack* JASTrack::getRootTrack() { + JASTrack *next, *parent = this; + for(; next = parent->mParent; parent = next); + return parent; +} + +int JASTrack::tickProc() { + if(mPauseFlag) return 0; + int succ = JASSeqCtrl::tickProc(this); + updateTimedParam(); + mInvalidateSeq = true; + if(succ < 0) return -1; + for(int i = 0; i < 0x10; i++) { + JASTrack *child = mChildren[i]; + if(child && child->_240 == 1) { + if(child->tickProc() < 0) { + getRootTrack()->updateSeq(false, 1f); + child->close(); + if(child->mIsOwnedByParent) { + delete child; + mChildren[i] = nullptr; + } + } + } + } + return 0; +} + +s32 JASTrack::seqMain() { + if(mIsStopped) { + updateSeq(true, 1f); + close(); + return -1; + } + f32 step = 1f; + while(mPlaytime >= step) { + mPlaytime -= step; + if(tickProc() < 0) { + updateSeq(false, 1f); + close(); + return -1; + } + } + mPlaytime += mSampleInterval; + updateSeq(false, step); + return 0; +} + +s32 JASTrack::TList::cbSeqMain(void *self) { + ((JASTrack::TList *)self)->seqMain(); + return 0; +} + +void JASTrack::TList::append(JASTrack *track) { + if(!mIsInit) { + if(!JASDriver::registerSubFrameCallback(cbSeqMain, this)) return; + mIsInit = true; + } + mList.Push_back(track); +} + +void JASTrack::TList::seqMain() { + InternalList::iterator iter, next; + for(iter = InternalList::iterator(mList.begin()); iter != mList.end(); iter = next) { + next = iter; + ++next; + if(iter->seqMain() < 0) { + mList.Remove(*iter); + if(iter->mIsOwnedByParent) delete *iter; + } + } +} + +JASTrack::TChannelMgr::TChannelMgr(JASTrack *track) + : mChannelParams(), _48(0), mParentTrack(track) { + for(u32 i = 0; i < 8; i++) { + mChannels[i] = nullptr; + } + for(u32 i = 0; i < 8; i++) { + _38[i] = 0; + } +} + +void JASTrack::TChannelMgr::init() { + _48 = nullptr; + mChannelParams.init(); + for(u32 i = 0; i < 8; i++) { + mChannels[i] = nullptr; + } + for(u32 i = 0; i < 8; i++) { + _38[i] = 0; + } +} + +void JASTrack::TChannelMgr::releaseAll() { + for(int i = 0; i < 8; i++) { + JASChannel *channel; + if(channel = mChannels[i]) { + channel->release(0); + channel->free(); + mChannels[i] = nullptr; + } + } +} + +bool JASTrack::TChannelMgr::noteOff(u32 a, u16 b) { + JASChannel *channel = mChannels[a]; + if(!channel) return false; + + if(b == 0) channel->release(0); + else channel->release(b); + + channel->free(); + mChannels[a] = nullptr; + return true; +} + +void JASTrack::TChannelMgr::setPauseFlag(bool flag) { + for(int i = 0; i < 8; i++) { + JASChannel *channel = mChannels[i]; + if(channel) channel->setPauseFlag(flag); + } +} + +JASDefaultBankTable JASTrack::sDefaultBankTable = JASDefaultBankTable(); + +JASTrack::TList JASTrack::sTrackList = JASTrack::TList(); + +namespace JGadget { + + TLinkListNode::TLinkListNode() : mPrev(nullptr), mNext(nullptr) {} + + TLinkListNode* TNodeLinkList::end() { + return iterator(&mEnd).curr; + } + + TNodeLinkList::iterator::iterator(TLinkListNode *node) { + curr = node; + } + + TNodeLinkList::iterator::iterator(const TNodeLinkList::iterator &rOther) : curr(rOther.curr) {} + + TNodeLinkList::iterator::iterator() {} + + TLinkListNode* TNodeLinkList::begin() { + return iterator(mEnd.getNext()).curr; + } + + TLinkListNode* TLinkListNode::getNext() const { + return mNext; + } + + TNodeLinkList::iterator& TNodeLinkList::iterator::operator++() { + curr = curr->getNext(); + return *this; + } + + TLinkListNode* TNodeLinkList::iterator::operator->() const { + return curr; + } + + bool operator!= ( + JASTrack::TList::InternalList::iterator a, + JASTrack::TList::InternalList::iterator b + ) { + return !(a == b); + } + + bool operator== ( + JASTrack::TList::InternalList::iterator a, + JASTrack::TList::InternalList::iterator b + ) { + return CALL_INLINE_FUNC(TNodeLinkList::iterator, a.curr) + == CALL_INLINE_FUNC(TNodeLinkList::iterator, b.curr); + } + + bool operator==(TNodeLinkList::iterator a, TNodeLinkList::iterator b) { + return a.curr == b.curr; + } + + TNodeLinkList::TNodeLinkList() : mEnd() { + Initialize_(); + } +} + +JASTrack::TList::~TList() {} + +JASTrack::TList::TList() : mList(), mIsInit(false) {} + +JASCriticalSection::JASCriticalSection() { + success = OSDisableInterrupts(); +} + +JASDefaultBankTable::JASDefaultBankTable() : JASBankTable(), JASGlobalInstance(true) {} + +JASDefaultBankTable::~JASDefaultBankTable() {} + +void JASChannel::setUpdateTimer(u32 timer) { + _14 = timer; +} + +void JASChannel::setKey(s32 key) { + _C8 = key; +} + +void JASChannel::setVelocity(u32 velocity) { + _CA = velocity; +} + +void JASChannel::setVibrate(f32 a, f32 b) { + _5C.setDepth(a); + _5C.setPitch(b); +} + +void JASChannel::setTremolo(f32 a, f32 b) { + _74.setDepth(a); + _74.setPitch(b); +} + +void JASChannelParams::init() { + _0[0] = 1f; + _0[1] = 1f; + _0[2] = 0f; + _0[3] = 0.5f; + _0[4] = 0f; + _0[5] = 0f; +} + +JASChannelParams::JASChannelParams() { + _0[0] = 1f; + _0[1] = 1f; + _0[2] = 0f; + _0[3] = 0.5f; + _0[4] = 0f; + _0[5] = 0f; +} + +void JASChannel::setPauseFlag(bool flag) { + _4 = flag; +} + +void JASLfo::setDepth(f32 depth) { + _C = depth; +} + +void JASLfo::setPitch(f32 pitch) { + _10 = pitch; +} + +JASBankList::JASBankList() {} diff --git a/src/JSystem/JAudio2/JASTrackPort.cpp b/src/JSystem/JAudio2/JASTrackPort.cpp new file mode 100644 index 00000000..5f592b24 --- /dev/null +++ b/src/JSystem/JAudio2/JASTrackPort.cpp @@ -0,0 +1,37 @@ +#include "JSystem/JAudio2/JASTrackPort.hpp" + +void JASTrackPort::init() { + for(u32 i = 0; i < 0x10; i++) { + mPorts[i] = 0; + } + mImport = 0; + mExport = 0; +} + +u16 JASTrackPort::readImport(u32 port) { + mImport &= ~(1 << port); + return mPorts[port]; +} + +u16 JASTrackPort::readExport(u32 port) { + mExport &= ~(1 << port); + return mPorts[port]; +} + +void JASTrackPort::writeImport(u32 port, u16 value) { + mImport |= 1 << port; + mPorts[port] = value; +} + +void JASTrackPort::writeExport(u32 port, u16 value) { + mExport |= 1 << port; + mPorts[port] = value; +} + +bool JASTrackPort::checkImport(u32 port) const { + return mImport & (1 << port); +} + +bool JASTrackPort::checkExport(u32 port) const { + return mExport & (1 << port); +} diff --git a/src/JSystem/JGadget/hashcode.cpp b/src/JSystem/JGadget/hashcode.cpp new file mode 100644 index 00000000..b21ae72f --- /dev/null +++ b/src/JSystem/JGadget/hashcode.cpp @@ -0,0 +1,21 @@ +#include "JSystem/JGadget/hashcode.hpp" +#include "JSystem/JGadget/predicate.hpp" + +namespace JGadget { + namespace { + template + inline u32 getHashCode_(const T *data, TPRIsEnd_value_ p) { + u32 hash = 0; + while(!p(*data)) { + hash = *data + hash * 31; + data++; + } + return hash; + } + } + u32 getHashCode(const char *data) { + TPRIsEnd_value_ p('\0'); + return getHashCode_(data, p); + } + +} diff --git a/src/JSystem/JGadget/linklist.cpp b/src/JSystem/JGadget/linklist.cpp new file mode 100644 index 00000000..68c4ba0e --- /dev/null +++ b/src/JSystem/JGadget/linklist.cpp @@ -0,0 +1,53 @@ +#include "JSystem/JGadget/linklist.hpp" +#include "JSystem/JGadget/predicate.hpp" + +namespace JGadget { + + inline const JGadget::TLinkListNode *getNode(const JGadget::TNodeLinkList::iterator &self) { + return self.curr; + } + + TNodeLinkList::~TNodeLinkList() {} + + void TNodeLinkList::splice(iterator a, TNodeLinkList &list, iterator b) { + TLinkListNode *&curr = b.curr; + TLinkListNode *&aCurr = a.curr; + TLinkListNode *next = curr->mNext; + bool flag = true; + if(aCurr != curr && aCurr != next) flag = false; + if(!flag) { + TLinkListNode *nodeB = b.curr; + list.Erase(nodeB); + Insert(CALL_INLINE_FUNC(iterator, a.curr), nodeB); + } + } + + TLinkListNode* TNodeLinkList::Insert(iterator iter, TLinkListNode *node) { + TLinkListNode *next = iter.curr; + TLinkListNode *prev = next->mPrev; + node->mNext = next; + node->mPrev = prev; + next->mPrev = node; + prev->mNext = node; + mLen++; + return node; + } + + TLinkListNode* TNodeLinkList::Erase(TLinkListNode *node) { + TLinkListNode *next = node->mNext, *prev = node->mPrev; + next->mPrev = prev; + prev->mNext = next; + mLen--; + return next; + } + + void TNodeLinkList::Remove(TLinkListNode *node) { + remove_if(TPRIsEqual_pointer_(node)); + } + + void TNodeLinkList::Initialize_() { + mLen = 0; + mEnd.mNext = &mEnd; + mEnd.mPrev = &mEnd; + } +} diff --git a/src/JSystem/JKernel/JKRAramArchive.cpp b/src/JSystem/JKernel/JKRAramArchive.cpp new file mode 100644 index 00000000..146d87a3 --- /dev/null +++ b/src/JSystem/JKernel/JKRAramArchive.cpp @@ -0,0 +1,67 @@ +#include "JSystem/JKernel/JKRAram.hpp" +#include "JSystem/JKernel/JKRAramArchive.hpp" +#include "JSystem/JKernel/JKRHeap.hpp" + +JKRAramArchive::JKRAramArchive(long entryNum, EMountDirection mountDir) : JKRArchive(entryNum, MOUNT_MODE_ARAM) { + mMountDir = mountDir; + + if (!open(entryNum)) { + return; + } + + mLoaderType = RARC_MAGIC; + mLoaderName = mStringTable + mDirs->mNameOffset; + + prependVolumeList(&mLoaderLink); + + mIsMounted = true; +} + +/*JKRAramArchive::~JKRAramArchive() { + if (mIsMounted == true) { + if (mInfoBlock != nullptr) { + SDIFileEntry *current = mFiles; + + for (s32 i = 0; i < mInfoBlock->mNrFiles; i++) { + if (current->mFileData != nullptr) { + JKRHeap::free(current->mFileData, mHeap); + } + + current++; + } + } + + if (mExpandSizes != nullptr) { + JKRHeap::free(mExpandSizes, nullptr); + } + + // 0x68 + // 0x64 + + mIsMounted = false; + } +}*/ + +/*s32 JKRAramArchive::getExpandedResSize(const void *pResource) const { + if (mExpandSizes == nullptr) { + return getResSize(pResource); + } + + SDIFileEntry *file = findPtrResource(pResource); + + if (file == nullptr) { + return -1; + } + + if ((file->mFlag & FILE_FLAG_COMPRESSED) == 0) { + return getResSize(pResource); + } + + u32 expandSize = getExpandSize(file); + + if (expandSize != 0) { + return expandSize; + } + + JKRAram::aramToMainRam() +}*/ diff --git a/src/JSystem/JKernel/JKRArchivePri.cpp b/src/JSystem/JKernel/JKRArchivePri.cpp new file mode 100644 index 00000000..5a7d7db5 --- /dev/null +++ b/src/JSystem/JKernel/JKRArchivePri.cpp @@ -0,0 +1,275 @@ +#include "JSystem/JKernel/JKRArchive.hpp" +#include "JSystem/JKernel/JKRHeap.hpp" +#include + +#ifdef NON_MATCHING +// tolower() is inlined +const char *JKRArchive::CArcName::store(const char *pName) { + mHash = 0; + u32 length = 0; + + for (; *pName != 0; pName++) { + char lowerChar = tolower(*pName); + + mHash = lowerChar + mHash * 3; + + if (length < MAX_NAME_LENGTH) { + mName[length++] = lowerChar; + } + } + + mLength = static_cast(length); + mName[length] = 0; + + return &mLength[length]; +} +#endif + +#ifdef NON_MATCHING +// tolower() is inlined +const char *JKRArchive::CArcName::store(const char *pName, char stopChar) { + mHash = 0; + u32 length = 0; + + for (; *pName != stopChar; pName++) { + char lowerChar = tolower(*pName); + + mHash = lowerChar + mHash * 3; + + if (length < MAX_NAME_LENGTH) { + mName[length++] = lowerChar; + } + } + + mLength = static_cast(length); + mName[length] = 0; + + if (*pName == 0) { + return nullptr; + } + + return pName + 1; +} +#endif + +JKRArchive::JKRArchive() { + mIsMounted = false; + mMountDir = MOUNT_DIRECTION_1; +} + +JKRArchive::JKRArchive(long entryNum, EMountMode mountMode) { + mIsMounted = false; + mMountMode = mountMode; + _34 = 1; + _58 = 1; + mHeap = JKRHeap::findFromRoot(this); + + if (mHeap == nullptr) { + mHeap = JKRHeap::sCurrentHeap; + } + + mEntryNum = entryNum; + + if (gCurrentFileLoader == nullptr) { + sCurrentDirIndex = 0; + gCurrentFileLoader = this; + } +} + +JKRArchive::~JKRArchive() { + +} + +void JKRArchive::setExpandSize(SDIFileEntry *pFile, unsigned long size) { + u32 fileIndex = static_cast(pFile - mFiles); + + if (mExpandSizes == nullptr || fileIndex >= mInfoBlock->mNrFiles) { + return; + } + + mExpandSizes[fileIndex] = size; +} + +u32 JKRArchive::getExpandSize(SDIFileEntry *pFile) const { + u32 fileIndex = static_cast(pFile - mFiles); + + if (mExpandSizes == nullptr || fileIndex >= mInfoBlock->mNrFiles) { + return 0; + } + + return mExpandSizes[fileIndex]; +} + + +bool JKRArchive::isSameName(CArcName &rName, unsigned long nameOffset, unsigned short hash) const { + if (rName.mHash != hash) { + return false; + } + + return strcmp(mStringTable + nameOffset, rName.mName) == 0; +} + +JKRArchive::SDIDirEntry *JKRArchive::findResType(unsigned long a1) const { + SDIDirEntry *current = mDirs; + + for (u32 i = 0; i < mInfoBlock->mNrDirs; i++) { + if (current->mID == a1) { + return current; + } + + current++; + } + + return nullptr; +} + +#ifdef NON_MATCHING +// Register mismatch +JKRArchive::SDIDirEntry *JKRArchive::findDirectory(const char *pName, unsigned long dirIndex) const { + SDIDirEntry *dir; + SDIFileEntry *currentFile; + s32 i; + + if (pName == nullptr) { + return &mDirs[dirIndex]; + } + + CArcName name; + const char *next = name.store(pName, '/'); + + dir = &mDirs[dirIndex]; + currentFile = &mFiles[dir->mFirstFileIndex]; + + for (i = 0; i < dir->mNrFiles; i++) { + if (isSameName(name, currentFile->mNameOffset, currentFile->mHash)) { + if ((currentFile->mFlag & FILE_FLAG_FOLDER) != 0) { + return findDirectory(next, currentFile->mDirIndex); + } + + break; + } + + currentFile++; + } + + return nullptr; +} +#endif + +JKRArchive::SDIFileEntry *JKRArchive::findTypeResource(unsigned long a1, const char *pName) const { + if (a1 != 0) { + CArcName name; + name.store(pName); + + SDIDirEntry *dir = findResType(a1); + + if (dir != nullptr) { + SDIFileEntry *current = &mFiles[dir->mFirstFileIndex]; + + for (s32 i = 0; i < dir->mNrFiles; i++) { + if (isSameName(name, current->mNameOffset, current->mHash)) { + return current; + } + + current++; + } + } + } + + return nullptr; +} + +#ifdef NON_MATCHING +// Register mismatch +JKRArchive::SDIFileEntry *JKRArchive::findFsResource(const char *pName, unsigned long dirIndex) const { + if (pName != nullptr) { + SDIDirEntry *dir; + SDIFileEntry *currentFile; + s32 i; + + CArcName name; + const char *next = name.store(pName, '/'); + + dir = &mDirs[dirIndex]; + currentFile = &mFiles[dir->mFirstFileIndex]; + + for (s32 i = 0; i < dir->mNrFiles; i++) { + if (isSameName(name, currentFile->mNameOffset, currentFile->mHash)) { + if ((currentFile->mFlag & FILE_FLAG_FOLDER) != 0) { + return findFsResource(next, currentFile->mDirIndex); + } + else if (next == nullptr) { + return currentFile; + } + else { + return nullptr; + } + } + + currentFile++; + } + } + + return nullptr; +} +#endif + +JKRArchive::SDIFileEntry *JKRArchive::findIdxResource(unsigned long index) const { + if (index < mInfoBlock->mNrFiles) { + return &mFiles[index]; + } + + return nullptr; +} + +JKRArchive::SDIFileEntry *JKRArchive::findNameResource(const char *pName) const { + SDIFileEntry *current = mFiles; + + CArcName name; + name.store(pName); + + for (s32 i = 0; i < mInfoBlock->mNrFiles; i++) { + if (isSameName(name, current->mNameOffset, current->mHash)) { + return current; + } + + current++; + } + + return nullptr; +} + +JKRArchive::SDIFileEntry *JKRArchive::findPtrResource(const void *pResource) const { + SDIFileEntry *current = mFiles; + + for (s32 i = 0; i < mInfoBlock->mNrFiles; i++) { + if (current->mFileData == pResource) { + return current; + } + + current++; + } + + return nullptr; +} + +JKRArchive::SDIFileEntry *JKRArchive::findIdResource(unsigned short fileID) const { + if (fileID != 0xFFFF) { + SDIFileEntry *current = mFiles; + SDIFileEntry *indexed = &mFiles[fileID]; + + if (indexed->mFileID == fileID && (indexed->mFlag & FILE_FLAG_FILE) != 0) { + return indexed; + } + + for (s32 i = 0; i < mInfoBlock->mNrFiles; i++) { + if (current->mFileID == fileID && (current->mFlag & FILE_FLAG_FILE) != 0) { + return current; + } + + current++; + } + } + + return nullptr; +} diff --git a/src/JSystem/JKernel/JKRArchivePub.cpp b/src/JSystem/JKernel/JKRArchivePub.cpp new file mode 100644 index 00000000..dc085110 --- /dev/null +++ b/src/JSystem/JKernel/JKRArchivePub.cpp @@ -0,0 +1,356 @@ +#include "JSystem/JKernel/JKRAramArchive.hpp" +#include "JSystem/JKernel/JKRArchive.hpp" +#include "JSystem/JKernel/JKRCompArchive.hpp" +#include "JSystem/JKernel/JKRDvdArchive.hpp" +#include "JSystem/JKernel/JKRFileFinder.hpp" +#include "JSystem/JKernel/JKRHeap.hpp" +#include "JSystem/JKernel/JKRMemArchive.hpp" +#include "revolution.h" + +bool JKRArchive::becomeCurrent(const char *pName) { + SDIDirEntry *dir; + + if (*pName == '/') { + const char *pDir = pName + 1; + + if (*pDir == 0) { + pDir = nullptr; + } + + dir = findDirectory(pDir, 0); + } + else { + dir = findDirectory(pName, sCurrentDirIndex); + } + + bool validDir = dir != nullptr; + + if (validDir) { + JKRFileLoader::gCurrentFileLoader = this; + sCurrentDirIndex = static_cast(dir - mDirs); + } + + return validDir; +} + +void *JKRArchive::getResource(const char *pName) { + SDIFileEntry *file; + + if (*pName == '/') { + file = findFsResource(pName + 1, 0); + } + else { + file = findFsResource(pName, sCurrentDirIndex); + } + + if (file != nullptr) { + return fetchResource(file, nullptr); + } + + return nullptr; +} + +void *JKRArchive::getResource(unsigned long a1, const char *pName) { + SDIFileEntry *file; + + if (a1 == NULL_MAGIC || a1 == QUESTIONMARK_MAGIC) { + file = findNameResource(pName); + } + else { + file = findTypeResource(a1, pName); + } + + if (file != nullptr) { + return fetchResource(file, nullptr); + } + + return nullptr; +} + +u32 JKRArchive::readResource(void *a1, unsigned long a2, const char *pName) { + SDIFileEntry *file; + + if (*pName == '/') { + file = findFsResource(pName + 1, 0); + } + else { + file = findFsResource(pName, sCurrentDirIndex); + } + + if (file != nullptr) { + u32 local_18; + fetchResource(a1, a2, file, &local_18); + + return local_18; + } + + return 0; +} + +u32 JKRArchive::readResource(void *a1, unsigned long a2, unsigned long a3, const char *pName) { + SDIFileEntry *file; + + if (a3 == NULL_MAGIC || a3 == QUESTIONMARK_MAGIC) { + file = findNameResource(pName); + } + else { + file = findTypeResource(a3, pName); + } + + if (file != nullptr) { + u32 local_18; + fetchResource(a1, a2, file, &local_18); + + return local_18; + } + + return 0; +} + +void JKRArchive::removeResourceAll() { + if (mInfoBlock != nullptr && mMountMode != MOUNT_MODE_DVD) { + SDIFileEntry *current = mFiles; + + for (u32 i = 0; i < mInfoBlock->mNrFiles; i++) { + if (current->mFileData != nullptr) { + JKRHeap::free(current->mFileData, mHeap); + current->mFileData = nullptr; + } + + current++; + } + } +} + +bool JKRArchive::removeResource(void *pResource) { + SDIFileEntry *file = findPtrResource(pResource); + + if (file == nullptr) { + return false; + } + + file->mFileData = nullptr; + JKRHeap::free(pResource, mHeap); + + return true; +} + +bool JKRArchive::detachResource(void *pResource) { + SDIFileEntry *file = findPtrResource(pResource); + + if (file == nullptr) { + return false; + } + + file->mFileData = nullptr; + + return true; +} + +s32 JKRArchive::getResSize(const void *pResource) const { + SDIFileEntry *file = findPtrResource(pResource); + + if (file == nullptr) { + return -1; + } + + return file->mDataSize; +} + +s32 JKRArchive::countFile(const char *pName) const { + SDIDirEntry *dir; + + if (*pName == '/') { + pName++; + + if (*pName == 0) { + pName = nullptr; + } + + dir = findDirectory(pName, 0); + } + else { + dir = findDirectory(pName, sCurrentDirIndex); + } + + if (dir != nullptr) { + return dir->mNrFiles; + } + + return 0; +} + +JKRArcFinder *JKRArchive::getFirstFile(const char *pName) const { + SDIDirEntry *dir; + + if (*pName == '/') { + pName++; + + if (*pName == 0) { + pName = nullptr; + } + + dir = findDirectory(pName, 0); + } + else { + dir = findDirectory(pName, sCurrentDirIndex); + } + + if (dir != nullptr) { + // Bad to cast to non-const + return new(JKRHeap::sGameHeap, 0) JKRArcFinder(const_cast(this), dir->mFirstFileIndex, dir->mNrFiles); + } + + return nullptr; +} + +JKRArchive *JKRArchive::check_mount_already(long entryNum) { + JSUPtrLink *current = JKRFileLoader::sFileLoaderList.mHead; + + while (current != nullptr) { + JKRArchive *archive = reinterpret_cast(current->mData); + + if (archive->mLoaderType == RARC_MAGIC && archive->mEntryNum == entryNum) { + archive->_34++; + return archive; + } + + current = current->mNext; + } + + return nullptr; +} + +JKRArchive *JKRArchive::check_mount_already(long entryNum, JKRHeap *pHeap) { + if (pHeap == nullptr) { + pHeap = JKRHeap::sCurrentHeap; + } + + JSUPtrLink *current = JKRFileLoader::sFileLoaderList.mHead; + + while (current != nullptr) { + JKRArchive *archive = reinterpret_cast(current->mData); + + if (archive->mLoaderType == RARC_MAGIC && archive->mEntryNum == entryNum && archive->mHeap == pHeap) { + archive->_34++; + return archive; + } + + current = current->mNext; + } + + return nullptr; +} + +void JKRArchive::mount(const char *pName, EMountMode mountMode, JKRHeap *pHeap, EMountDirection mountDir) { + s32 entryNum = DVDConvertPathToEntrynum(pName); + + if (entryNum >= 0) { + mount(entryNum, mountMode, pHeap, mountDir); + } +} + +JKRArchive *JKRArchive::mount(long entryNum, EMountMode mountMode, JKRHeap *pHeap, EMountDirection mountDir) { + JKRArchive *archive = check_mount_already(entryNum, pHeap); + + if (archive != nullptr) { + return archive; + } + + s32 uVar1 = -4; + + if (mountDir == MOUNT_DIRECTION_1) { + uVar1 = 4; + } + + switch (mountMode) { + case MOUNT_MODE_MEM: + archive = new(pHeap, uVar1) JKRMemArchive(entryNum, mountDir); + break; + case MOUNT_MODE_ARAM: + archive = new(pHeap, uVar1) JKRAramArchive(entryNum, mountDir); + break; + case MOUNT_MODE_DVD: + archive = new(pHeap, uVar1) JKRDvdArchive(entryNum, mountDir); + break; + case MOUNT_MODE_COMP: + archive = new(pHeap, uVar1) JKRCompArchive(entryNum, mountDir); + break; + } + + if (archive != nullptr && archive->mMountMode == MOUNT_MODE_0) { + delete archive; + archive = nullptr; + } + + return archive; +} + +bool JKRArchive::getDirEntry(SDirEntry *pDir, unsigned long fileIndex) const { + SDIFileEntry *file = findIdxResource(fileIndex); + + if (file == nullptr) { + return false; + } + + pDir->mFileFlag = file->mFlag; + pDir->mFileID = file->mFileID; + pDir->mName = mStringTable + file->mNameOffset; + + return true; +} + +void *JKRArchive::getIdxResource(unsigned long fileIndex) { + SDIFileEntry *file = findIdxResource(fileIndex); + + if (file != nullptr) { + return fetchResource(file, 0); + } + + return nullptr; +} + +void *JKRArchive::getResource(unsigned short fileID) { + SDIFileEntry *file = findIdResource(fileID); + + if (file != nullptr) { + return fetchResource(file, 0); + } + + return nullptr; +} + +u32 JKRArchive::readResource(void *pResource, unsigned long a2, unsigned short fileID) { + SDIFileEntry *file = findIdResource(fileID); + + if (file != nullptr) { + u32 local_18; + fetchResource(pResource, a2, file, &local_18); + + return local_18; + } + + return 0; +} + +u32 JKRArchive::countResource() const { + u32 count = 0; + + for (u32 i = 0; i < mInfoBlock->mNrFiles; i++) { + if ((mFiles[i].mFlag & FILE_FLAG_FILE) != 0) { + count++; + } + } + + return count; +} + +u32 JKRArchive::getFileAttribute(unsigned long fileIndex) const { + SDIFileEntry *file = findIdxResource(fileIndex); + + if (file != nullptr) { + return file->mFlag; + } + + return 0; +} diff --git a/src/JSystem/JKernel/JKRDecomp.cpp b/src/JSystem/JKernel/JKRDecomp.cpp new file mode 100644 index 00000000..b8ed5c13 --- /dev/null +++ b/src/JSystem/JKernel/JKRDecomp.cpp @@ -0,0 +1,226 @@ +#include "JSystem/JKernel/JKRDecomp.hpp" +#include "JSystem/JKernel/JKRHeap.hpp" +#include "JSystem/JKernel/JKRAramPiece.hpp" +#include "revolution.h" + +#define NR_MESSAGES 8 + +namespace { + JKRDecomp *gDecompInstance; // 0x806B71D8 + OSMessage gMessage[NR_MESSAGES]; // 0x8060D038 + OSMessageQueue gMessageQueue; // 0x8060D058 +} + +JKRDecompCommand::JKRDecompCommand() { + OSInitMessageQueue(&mMessageQueue, &mMessage, 1); + mThis = this; // Probably a pointer to the data stored at 0x00 instead + _14 = 0; + _1C = nullptr; + _20 = 0; +} + +JKRDecomp::JKRDecomp(long a1) : JKRThread(0x4000, 0x10, a1) { + OSResumeThread(mThread); +} + +JKRDecomp::~JKRDecomp() { + +} + +s32 JKRDecomp::run() { + OSInitMessageQueue(&gMessageQueue, &gMessage[0], NR_MESSAGES); + + JKRDecompCommand *commandPtr; + + while (true) { + OSReceiveMessage(&gMessageQueue, reinterpret_cast(&commandPtr), OS_MESSAGE_BLOCK); + + JKRDecompCommand &command = *commandPtr; + + decode( + command.mSrc, + command.mDst, + command.mCompressedSize, + command.mDecompressedSize + ); + + if (command._20 != 0) { + if (command._20 == 1) { + JKRAramPiece::sendCommand(command.mAmCommand); + } + + continue; + } + + if (command._14 != nullptr) { + command._14(reinterpret_cast(&command)); + continue; + } + + if (command._1C != nullptr) { + OSSendMessage(command._1C, reinterpret_cast(1), OS_MESSAGE_NOBLOCK); + } + else { + OSSendMessage(&command.mMessageQueue, reinterpret_cast(1), OS_MESSAGE_NOBLOCK); + } + } +} + +JKRDecomp *JKRDecomp::create(long a1) { + if (gDecompInstance == nullptr) { + gDecompInstance = new(JKRHeap::sGameHeap, 0) JKRDecomp(a1); + } + + return gDecompInstance; +} + +JKRDecompCommand *JKRDecomp::prepareCommand(unsigned char *pSrc, unsigned char *pDst, unsigned long compressedSize, unsigned long decompressedSize, void (*a5)(unsigned long)) { + JKRDecompCommand *command = new(JKRHeap::sGameHeap, -4) JKRDecompCommand(); + + command->mSrc = pSrc; + command->mDst = pDst; + command->mCompressedSize = compressedSize; + command->mDecompressedSize = decompressedSize; + command->_14 = a5; + + return command; +} + +void JKRDecomp::sendCommand(JKRDecompCommand *pCommand) { + OSSendMessage(&gMessageQueue, pCommand, OS_MESSAGE_NOBLOCK); +} + +bool JKRDecomp::sync(JKRDecompCommand *pCommand, int noBlock) { + OSMessage message; + + if (noBlock == 0) { + OSReceiveMessage(&pCommand->mMessageQueue, &message, OS_MESSAGE_BLOCK); + return true; + } + else { + return OSReceiveMessage(&pCommand->mMessageQueue, &message, OS_MESSAGE_NOBLOCK) != 0; + } +} + +bool JKRDecomp::orderSync(unsigned char *pSrc, unsigned char *pDst, unsigned long compressedSize, unsigned long decompressedSize) { + JKRDecompCommand *command = prepareCommand(pSrc, pDst, compressedSize, decompressedSize,nullptr); + + OSSendMessage(&gMessageQueue, command, OS_MESSAGE_NOBLOCK); + bool received = sync(command, 0); + + delete command; + + return received; +} + +void JKRDecomp::decode(unsigned char *pSrc, unsigned char *pDst, unsigned long compressedSize, unsigned long decompressedSize) { + EJKRCompression compression = checkCompressed(pSrc); + + if (compression == JKR_COMPRESSION_SZP) { + decodeSZP(pSrc, pDst, compressedSize, decompressedSize); + } + else if (compression == JKR_COMPRESSION_SZS) { + decodeSZS(pSrc, pDst, compressedSize, decompressedSize); + } +} + +/*void JKRDecomp::decodeSZP(unsigned char *pSrc, unsigned char *pDst, unsigned long compressedSize, unsigned long decompressedSize) { + +}*/ + +#ifdef NON_MATCHING // Wrong registers +void JKRDecomp::decodeSZS(u8 *pSrc, u8 *pDst, u32 compressedSize, u32 a4) { + u32 decompSize = ((s32)pDst + *(u32*)(pSrc + 4)) - a4; + u8 byte1, byte2; + s32 validBitCount = 0; + u32 curBlock; + + if (compressedSize == 0) { + return; + } + + if (a4 > *(u32*)pSrc) { + return; + } + + pSrc += 0x10; + + do { + if (validBitCount == 0) { + curBlock = *pSrc; + validBitCount = 8; + pSrc++; + } + + if ((curBlock & 0x80) != 0) { + if (a4 == 0) { + compressedSize--; + *pDst++ = *pSrc; + + if (compressedSize == 0) { + return; + } + } + else { + a4--; + } + + pSrc++; + } + else { + // This bit specifically + byte1 = *pSrc++; + byte2 = *pSrc++; + + u8* copySrc = pDst; + copySrc -= ((byte1 & 0xF) << 8) | byte2;; + u32 numBytes = byte1 >> 4; + + if (numBytes == 0) { + numBytes = *pSrc++ + 0x12; + } + else { + numBytes += 2; + } + + do { + if (a4 == 0) { + compressedSize--; + *pDst = *(copySrc - 1); + pDst++; + + if (compressedSize == 0) { + return; + } + } + else { + a4--; + } + + copySrc++; + } while (--numBytes != 0); + } + + curBlock <<= 1; + validBitCount--; + } while ((u32)pDst != decompSize); +} +#endif + +EJKRCompression JKRDecomp::checkCompressed(unsigned char *pSrc) { + if (pSrc[0] == 'Y' && pSrc[1] == 'a' && pSrc[3] == '0') { + if (pSrc[2] == 'y') { + return JKR_COMPRESSION_SZP; + } + + if (pSrc[2] == 'z') { + return JKR_COMPRESSION_SZS; + } + } + + if (pSrc[0] == 'A' && pSrc[1] == 'S' && pSrc[2] == 'R') { + return JKR_COMPRESSION_ASR; + } + + return JKR_COMPRESSION_NONE; +} diff --git a/src/JSystem/JKernel/JKRDisposer.cpp b/src/JSystem/JKernel/JKRDisposer.cpp new file mode 100644 index 00000000..895f03d1 --- /dev/null +++ b/src/JSystem/JKernel/JKRDisposer.cpp @@ -0,0 +1,16 @@ +#include "JSystem/JKernel/JKRDisposer.hpp" +#include "JSystem/JKernel/JKRHeap.hpp" + +JKRDisposer::JKRDisposer() : mLink(this) { + mHeap = JKRHeap::findFromRoot(this); + + if (mHeap) { + mHeap->mDisposerList.append(&mLink); + } +} + +JKRDisposer::~JKRDisposer() { + if (mHeap) { + mHeap->mDisposerList.remove(&mLink); + } +} diff --git a/src/JSystem/JKernel/JKRDvdArchive.cpp b/src/JSystem/JKernel/JKRDvdArchive.cpp new file mode 100644 index 00000000..b99927d9 --- /dev/null +++ b/src/JSystem/JKernel/JKRDvdArchive.cpp @@ -0,0 +1,16 @@ +#include "JSystem/JKernel/JKRDvdArchive.hpp" + +JKRDvdArchive::JKRDvdArchive(long entryNum, EMountDirection mountDir) : JKRArchive(entryNum, MOUNT_MODE_DVD) { + mMountDir = mountDir; + + if (!open(entryNum)) { + return; + } + + mLoaderType = RARC_MAGIC; + mLoaderName = mStringTable + mDirs->mNameOffset; + + prependVolumeList(&mLoaderLink); + + mIsMounted = true; +} \ No newline at end of file diff --git a/src/JSystem/JKernel/JKRExpHeap.cpp b/src/JSystem/JKernel/JKRExpHeap.cpp new file mode 100644 index 00000000..e1f10c57 --- /dev/null +++ b/src/JSystem/JKernel/JKRExpHeap.cpp @@ -0,0 +1,225 @@ +#include "JSystem/JKernel/JKRExpHeap.hpp" +#include "JSystem/JUtility/JUTConsole.hpp" +#include + +#define ALIGN_PREV(X, N) ((X) & ~((N)-1)) +#define ALIGN_NEXT(X, N) ALIGN_PREV(((X) + (N)-1), N) + +static u32 DBfoundSize; +static u32 DBfoundOffset; +static JKRExpHeap::CMemBlock* DBfoundBlock; +static JKRExpHeap::CMemBlock* DBnewFreeBlock; +static JKRExpHeap::CMemBlock* DBnewUsedBlock; + +JKRExpHeap* JKRExpHeap::createRoot(int heapNum, bool a2) { + JKRExpHeap* heap = nullptr; + + if (!JKRHeap::sRootHeap) { + char* stack_C; + u32 arenaSize; + JKRHeap::initArena(&stack_C, &arenaSize, heapNum); + char* area = stack_C + 0x90; + u32 size = arenaSize - 0x90; + heap = new(stack_C)JKRExpHeap(area, size, nullptr, a2); + JKRHeap::sRootHeap = heap; + } + + heap->mAllocMode = 1; + return heap; +} + +JKRExpHeap* JKRExpHeap::create(u32 size, JKRHeap* pParent, bool errorFlag) { + if (!pParent) { + pParent = JKRHeap::sRootHeap; + } + + if (size == 0xFFFFFFFF) { + size = pParent->getMaxAllocatableSize(0x10); + } + + u32 alignedSize = ALIGN_PREV(size, 0x10); + u32 heapSize = ALIGN_NEXT(sizeof(JKRExpHeap), 0x10); + + if (alignedSize < 0xA0) { + return nullptr; + } + + u8* mem = (u8*)JKRHeap::alloc(alignedSize, 16, pParent); + u8* data = (mem + heapSize); + if (mem == nullptr) { + return nullptr; + } + + JKRExpHeap* heap = new(mem)JKRExpHeap(data, alignedSize - heapSize, pParent, errorFlag); + + if (heap == nullptr) { + JKRHeap::free(mem, nullptr); + return nullptr; + } + + heap->mAllocMode = 0; + return heap; +} + +JKRExpHeap* JKRExpHeap::create(void* ptr, u32 size, JKRHeap* pParent, bool errorFlag) { + JKRHeap* parent; + + if (pParent == nullptr) { + parent = sRootHeap->find(ptr); + + if (parent == nullptr) { + return nullptr; + } + } + else { + parent = pParent; + } + + JKRExpHeap* heap = nullptr; + u32 heapSize = ALIGN_NEXT(sizeof(JKRExpHeap), 0x10); + + if (size < heapSize) { + return nullptr; + } + + void* data = (u8*)ptr + heapSize; + u32 alignSize = ALIGN_PREV((u32)ptr + size - (u32)data, 0x10); + if (ptr != nullptr) { + heap = new(ptr)JKRExpHeap(data, alignSize, parent, errorFlag); + } + + heap->mAllocMode = 1; + heap->_70 = ptr; + heap->_74 = size; + return heap; +} + +void JKRExpHeap::do_destroy() { + if (_6E) { + JKRHeap* heap = mChildTree.getParent()->getObject(); + + if (heap != nullptr) { + this->~JKRExpHeap(); + JKRHeap::free(this, heap); + } + } + else { + this->~JKRExpHeap(); + } +} + +void* JKRExpHeap::do_alloc(u32 size, int align) { + void* ptr; + OSLockMutex(&mMutex); + + if (size < 4) { + size = 4; + } + + if (align >= 0) { + if (align <= 4) { + ptr = allocFromHead(size); + } + else { + ptr = allocFromHead(size, align); + } + } + else { + if (-align <= 4) { + ptr = allocFromTail(size); + } + else { + ptr = allocFromTail(size, -align); + } + } + + if (ptr == nullptr) { + JUTWarningConsole_f(":::cannot alloc memory (0x%x byte).\n", size); + + if (JKRHeap::mErrorFlag == true) { + if (JKRHeap::mErrorHandler) { + (*JKRHeap::mErrorHandler)(this, size, align); + } + } + } + + OSUnlockMutex(&mMutex); + return ptr; +} + +// JKRExpheap::allocFromHead +// JKRExpHeap::allocFromTail + + + +JKRExpHeap::JKRExpHeap(void* data, u32 size, JKRHeap* parent, bool error) + : JKRHeap(data, size, parent, error) { + + CMemBlock* block = (CMemBlock*)data; + + _6A = 0; + _6B = 0xFF; + mHeadFreeList = block; + mTailFreeList = block; + block->initiate(nullptr, nullptr, size - sizeof(CMemBlock), 0, 0); + mHeadUsedList = nullptr; + mTailUsedList = nullptr; +} + +void JKRExpHeap::CMemBlock::initiate(CMemBlock* prev, CMemBlock* next, u32 size, u8 groupID, u8 align) { + mMagic = 'HM'; + mFlags = align; + mGroupId = groupID; + mSize = size; + mPrev = prev; + mNext = next; +} + +JKRExpHeap::CMemBlock* JKRExpHeap::CMemBlock::allocFore(u32 size, u8 group_1, u8 align_1, u8 group_2, u8 align_2) { + CMemBlock* block = nullptr; + mGroupId = group_1; + mFlags = align_1; + + if (mSize >= size + sizeof(CMemBlock)) { + block = (CMemBlock*)((u32)this + size); + block[1].mGroupId = group_2; + block[1].mFlags = align_2; + block[1].mSize = mSize - (size + sizeof(CMemBlock)); + mSize = size; + block++; + } + + return block; +} + +JKRExpHeap::CMemBlock* JKRExpHeap::CMemBlock::allocBack(u32 size, u8 group_1, u8 align_1, u8 group_2, u8 align_2) { + CMemBlock* block = nullptr; + + if (mSize >= size + sizeof(CMemBlock)) { + block = (CMemBlock*)((u32)this + mSize - size); + block->mGroupId = group_2; + block->mFlags = align_2 | 0x80; + block->mSize = size; + mGroupId = group_1; + mFlags = align_1; + mSize -= size + sizeof(CMemBlock); + } + else { + mGroupId = group_2; + mFlags = 0x80; + } + + return block; +} + +JKRExpHeap::CMemBlock* JKRExpHeap::CMemBlock::getHeapBlock(void* ptr) { + if (ptr != nullptr) { + CMemBlock* block = (CMemBlock*)ptr - 1; + + if (block->mMagic == 'HM') { + return block; + } + } + + return nullptr; +} \ No newline at end of file diff --git a/src/JSystem/JKernel/JKRFileFinder.cpp b/src/JSystem/JKernel/JKRFileFinder.cpp new file mode 100644 index 00000000..010ab91d --- /dev/null +++ b/src/JSystem/JKernel/JKRFileFinder.cpp @@ -0,0 +1,47 @@ +#include "JSystem/JKernel/JKRArchive.hpp" +#include "JSystem/JKernel/JKRFileFinder.hpp" + +JKRFileFinder::JKRFileFinder() { + mHasMoreFiles = false; + mFileIsFolder = false; +} + +JKRArcFinder::JKRArcFinder(JKRArchive *pArchive, long firstFileIndex, long nrFiles) { + mArchive = pArchive; + mHasMoreFiles = nrFiles > 0; + mFirstIndex = firstFileIndex; + mLastIndex = firstFileIndex + nrFiles - 1; + mCurrentIndex = firstFileIndex; + + findNextFile(); +} + +#ifdef NON_MATCHING +// Looks identical to base destructor, does not call ~JKRFileFinder() +JKRArcFinder::~JKRArcFinder() { + +} +#endif + +bool JKRArcFinder::findNextFile() { + if (mHasMoreFiles) { + bool moreFiles = mCurrentIndex <= mLastIndex; + mHasMoreFiles = moreFiles; + + // Weird code + if (moreFiles & 0xFF) { + JKRArchive::SDirEntry dir; + mHasMoreFiles = mArchive->getDirEntry(&dir, mCurrentIndex); + + mName = dir.mName; + mDirIndex = mCurrentIndex; + mFileID = dir.mFileID; + mFileFlag = dir.mFileFlag; + mFileIsFolder = ((mFileFlag >> JKRArchive::FILE_FLAG_FOLDER_SHIFT) & 1) != 0; + + mCurrentIndex++; + } + } + + return mHasMoreFiles; +} diff --git a/src/JSystem/JKernel/JKRFileLoader.cpp b/src/JSystem/JKernel/JKRFileLoader.cpp new file mode 100644 index 00000000..179c0ff5 --- /dev/null +++ b/src/JSystem/JKernel/JKRFileLoader.cpp @@ -0,0 +1,75 @@ +#include "JSystem/JKernel/JKRFileLoader.hpp" +#include "revolution.h" + +namespace { + OSMutex gLoaderMutex; // 0x8060CFA8 +} + +JSUList JKRFileLoader::sFileLoaderList = JSUList(); + +JKRFileLoader::JKRFileLoader() : JKRDisposer(), mLoaderLink(this) { + mLoaderName = nullptr; + mLoaderType = 0; + _34 = 0; +} + +JKRFileLoader::~JKRFileLoader() { + if (gCurrentFileLoader == this) { + gCurrentFileLoader = nullptr; + } +} + +void JKRFileLoader::unmount() { + if (_34 == 0) { + return; + } + + if (--_34 != 0) { + return; + } + + delete this; +} + +void *JKRFileLoader::getGlbResource(const char *pName, JKRFileLoader *pLoader) { + void *resource = nullptr; + + if (pLoader != nullptr) { + resource = pLoader->getResource(0, pName); + } + else { + JSUPtrLink *current = sFileLoaderList.mHead; + + while (current != nullptr) { + resource = reinterpret_cast(current->mData)->getResource(0, pName); + + if (resource != nullptr) { + break; + } + + current = current->mNext; + } + } + + return resource; +} + +void JKRFileLoader::initializeVolumeList() { + OSInitMutex(&gLoaderMutex); +} + +void JKRFileLoader::prependVolumeList(JSULink *pLoader) { + OSLockMutex(&gLoaderMutex); + + sFileLoaderList.prepend(pLoader); + + OSUnlockMutex(&gLoaderMutex); +} + +void JKRFileLoader::removeVolumeList(JSULink *pLoader) { + OSLockMutex(&gLoaderMutex); + + sFileLoaderList.remove(pLoader); + + OSUnlockMutex(&gLoaderMutex); +} diff --git a/src/JSystem/JKernel/JKRHeap.cpp b/src/JSystem/JKernel/JKRHeap.cpp new file mode 100644 index 00000000..b6584ec9 --- /dev/null +++ b/src/JSystem/JKernel/JKRHeap.cpp @@ -0,0 +1,371 @@ +#include "JSystem/JKernel/JKRHeap.hpp" +#include "JSystem/JUtility/JUTException.hpp" +#include + +JKRHeap* JKRHeap::sCurrentHeap; +JKRHeap* JKRHeap::sRootHeap; +JKRHeap* JKRHeap::sSystemHeap; + +void* JKRHeap::mCodeStart; +void* JKRHeap::mCodeEnd; +void* JKRHeap::mUserRamStart; +void* JKRHeap::mUserRamEnd; + +JKRErrorHandler JKRHeap::mErrorHandler; + +static bool byte_806B26D8; +static bool byte_806B70B8; + +u32 JKRHeap::mMemorySize; + +u32 JKRHeap::ARALT_AramStartAddr = 0x90000000; + +JKRHeap::JKRHeap(void* data, u32 size, JKRHeap* parent, bool error) : JKRDisposer(), mChildTree(this), mDisposerList() { + OSInitMutex(&mMutex); + mSize = size; + mStart = (u8*)data; + mEnd = (u8*)data + size; + + if (parent == nullptr) { + JKRHeap::sSystemHeap = this; + JKRHeap::sCurrentHeap = this; + } + else { + parent->mChildTree.appendChild(&mChildTree); + + if (JKRHeap::sSystemHeap == JKRHeap::sRootHeap) { + JKRHeap::sSystemHeap = this; + } + + if (JKRHeap::sCurrentHeap == JKRHeap::sRootHeap) { + JKRHeap::sCurrentHeap = this; + } + } + + mErrorFlag = error; + + if (mErrorFlag == true && mErrorHandler == nullptr) { + mErrorHandler = JKRDefaultMemoryErrorRoutine; + } + + _3C = byte_806B26D8; + _3D = byte_806B70B8; + _69 = false; +} + +JKRHeap::~JKRHeap() { + mChildTree.getParent()->removeChild(&mChildTree); + JSUTree* nextRootHeap = sRootHeap->mChildTree.getFirstChild(); + + if (sCurrentHeap == this) + sCurrentHeap = !nextRootHeap ? sRootHeap : nextRootHeap->getObject(); + + if (sSystemHeap == this) + sSystemHeap = !nextRootHeap ? sRootHeap : nextRootHeap->getObject(); +} + + +bool JKRHeap::initArena(char** memory, u32* size, int maxHeaps) { + void* ramStart, *ramEnd, *arenaStart; + + void* arenaLo = OSGetArenaLo(); + void* arenaHi = OSGetArenaHi(); + + OSReport("original arenaLo = %p arenaHi = %p\n", arenaLo, arenaHi); + + if (arenaLo == arenaHi) { + return false; + } + + arenaStart = OSInitAlloc(arenaLo, arenaHi, maxHeaps); + OSBootInfo* code = (OSBootInfo*)OSPhysicalToCached(0); + ramStart = (void*)(((u32)arenaStart + 31) & 0xFFFFFFE0); + ramEnd = (void*)((u32)arenaHi & 0xFFFFFFE0); + + JKRHeap::mCodeStart = code; + JKRHeap::mCodeEnd = ramStart; + JKRHeap::mUserRamStart = ramStart; + JKRHeap::mUserRamEnd = ramEnd; + JKRHeap::mMemorySize = code->memorySize; + + OSSetArenaLo(ramEnd); + OSSetArenaHi(ramEnd); + + *memory = (char*)ramStart; + *size = (u32)ramEnd - (u32)ramStart; + return true; +} + +JKRHeap* JKRHeap::becomeSystemHeap() { + JKRHeap* sys = sSystemHeap; + sSystemHeap = this; + return sys; +} + +JKRHeap* JKRHeap::becomeCurrentHeap() { + JKRHeap* cur = sCurrentHeap; + sCurrentHeap = this; + return cur; +} + +void JKRHeap::destroy(JKRHeap *pHeap) { + pHeap->do_destroy(); +} + +void* JKRHeap::alloc(u32 size, int align, JKRHeap *pHeap) { + if (pHeap != nullptr) { + return pHeap->alloc(size, align); + } + + if (JKRHeap::sCurrentHeap != nullptr) { + return JKRHeap::sCurrentHeap->alloc(size, align); + } + + return nullptr; +} + +void* JKRHeap::alloc(u32 size, int align) { + return do_alloc(size, align); +} + +void JKRHeap::free(void *pData, JKRHeap *pHeap) { + if (!pHeap) { + pHeap = findFromRoot(pData); + + if (!pHeap) { + return; + } + } + + pHeap->do_free(pData); +} + +void JKRHeap::free(void *pData) { + do_free(pData); +} + +void JKRHeap::callAllDisposer() { + while (mDisposerList.mHead != nullptr) { + reinterpret_cast(mDisposerList.mHead->mData)->~JKRDisposer(); + } +} + +void JKRHeap::freeAll() { + do_freeAll(); +} + +void JKRHeap::freeTail() { + do_freeTail(); +} + +s32 JKRHeap::resize(void *pData, u32 size) { + return do_resize(pData, size); +} + +s32 JKRHeap::getFreeSize() { + return do_getFreeSize(); +} + +void* JKRHeap::getMaxFreeBlock() { + return do_getMaxFreeBlock(); +} + +s32 JKRHeap::getTotalFreeSize() { + return do_getTotalFreeSize(); +} + +JKRHeap* JKRHeap::findFromRoot(void *pData) { + JKRHeap* root = sRootHeap; + + if (root == nullptr) { + return nullptr; + } + + if ((void*)root->mStart <= pData && pData < (void*)root->mEnd) { + return root->find(pData); + } + + return root->findAllHeap(pData); +} + +/* functionally equiv but not matching */ +JKRHeap* JKRHeap::find(void *pData) const { + if (mStart <= pData && pData < mEnd) { + const JSUTree& tree = mChildTree; + + if (tree.getNumChildren() != 0) { + for (JSUTreeIterator iterator(mChildTree.getFirstChild()); + iterator != mChildTree.getEndChild(); ++iterator) { + JKRHeap* result = iterator->find(pData); + + if (result) { + return result; + } + } + } + + // this is to avoid returning a const JKRHeap ptr + return const_cast(this); + } + + return nullptr; +} + +/* same here */ +JKRHeap* JKRHeap::findAllHeap(void* ptr) const { + if (mChildTree.getNumChildren() != 0) { + for (JSUTreeIterator iterator(mChildTree.getFirstChild()); iterator != mChildTree.getEndChild(); ++iterator) { + JKRHeap* heap = iterator->findAllHeap(ptr); + + if (heap != nullptr) { + return heap; + } + } + } + + if (mStart <= ptr && ptr < mEnd) { + return const_cast(this); + } + + return nullptr; +} + +void JKRHeap::dispose_subroutine(u32 start, u32 end) { + JSUListIterator last_it; + JSUListIterator next_it; + JSUListIterator it; + + for (it = mDisposerList.getFirst(); it != mDisposerList.getEnd(); it = next_it) { + JKRDisposer* disp = it.getObject(); + + if ((void*)start <= disp && disp < (void*)end) { + disp->~JKRDisposer(); + + if (last_it == nullptr) { + next_it = mDisposerList.getFirst(); + } + else { + next_it = last_it; + next_it++; + } + } + else { + last_it = it; + next_it = it; + next_it++; + } + } +} + +bool JKRHeap::dispose(void* ptr, u32 size) { + u32 begin = (u32)ptr; + u32 end = (u32)ptr + size; + dispose_subroutine(begin, end); + return false; +} + +void JKRHeap::dispose(void* begin, void* end) { + dispose_subroutine((u32)begin, (u32)end); +} + +void JKRHeap::dispose() { + const JSUList& list = mDisposerList; + JSUListIterator iterator; + + while (list.getFirst() != list.getEnd()) { + iterator = list.getFirst(); + iterator->~JKRDisposer(); + } +} + +void JKRHeap::copyMemory(void *pDst, void *pSrc, u32 size) { + u32 count = (size + 3) / 4; + u32* dst_32 = (u32*)pDst; + u32* src_32 = (u32*)pSrc; + + while (count > 0) { + *dst_32 = *src_32; + dst_32++; + src_32++; + count--; + } +} + +void JKRDefaultMemoryErrorRoutine(void* pHeap, u32 size, int alignment) { + JUTException::panic_f(__FILE__, 0x355, "%s", "abort\n"); +} + +JKRErrorHandler JKRHeap::setErrorHandler(JKRErrorHandler errorHandler) { + JKRErrorHandler prev = JKRHeap::mErrorHandler; + + if (!errorHandler) { + errorHandler = JKRDefaultMemoryErrorRoutine; + } + + JKRHeap::mErrorHandler = errorHandler; + return prev; +} + +void* operator new(u32 size) { + return JKRHeap::alloc(size, 4, nullptr); +} + +void* operator new(u32 size, int align) { + return JKRHeap::alloc(size, align, nullptr); +} + +void* operator new(u32 size, JKRHeap *pHeap, int align) { + return JKRHeap::alloc(size, align, pHeap); +} + +void* operator new[](u32 size) { + return JKRHeap::alloc(size, 4, nullptr); +} + +void* operator new[](u32 size, int align) { + return JKRHeap::alloc(size, align, nullptr); +} + +void* operator new[](u32 size, JKRHeap *pHeap, int align) { + return JKRHeap::alloc(size, align, pHeap); +} + +void operator delete(void *pData) { + JKRHeap::free(pData, nullptr); +} + +void operator delete[](void *pData) { + JKRHeap::free(pData, nullptr); +} + +void JKRHeap::state_register(TState *, u32) const { + return; +} + +bool JKRHeap::state_compare(const TState &lhs, const TState &rhs) const { + return lhs._4 == rhs._4; +} + +void JKRHeap::state_dump(const TState &) const { + return; +} + +void JKRHeap::setAltAramStartAdr(u32 addr) { + ARALT_AramStartAddr = addr; +} + +u32 JKRHeap::getAltAramStartAdr() { + return ARALT_AramStartAddr; +} + +s32 JKRHeap::do_changeGroupID(u8) { + return 0; +} + +u8 JKRHeap::do_getCurrentGroupId() { + return 0; +} + +bool JKRHeap::dump_sort() { + return true; +} \ No newline at end of file diff --git a/src/JSystem/JKernel/JKRMemArchive.cpp b/src/JSystem/JKernel/JKRMemArchive.cpp new file mode 100644 index 00000000..a6b10029 --- /dev/null +++ b/src/JSystem/JKernel/JKRMemArchive.cpp @@ -0,0 +1,293 @@ +#include "JSystem/JKernel/JKRAram.hpp" +#include "JSystem/JKernel/JKRDecomp.hpp" +#include "JSystem/JKernel/JKRDvdRipper.hpp" +#include "JSystem/JKernel/JKRMemArchive.hpp" +#include "JSystem/JKernel/JKRHeap.hpp" +#include "JSystem/JUtility/JUTException.hpp" +#include "revolution.h" +#include + +JKRMemArchive::JKRMemArchive() { + +} + +JKRMemArchive::JKRMemArchive(long entryNum, EMountDirection mountDir) : JKRArchive(entryNum, MOUNT_MODE_MEM) { + mIsMounted = false; + mMountDir = mountDir; + + if (!open(entryNum, mountDir)) { + return; + } + + mLoaderType = RARC_MAGIC; + mLoaderName = mStringTable + mDirs->mNameOffset; + + prependVolumeList(&mLoaderLink); + + mIsMounted = true; +} + +JKRMemArchive::~JKRMemArchive() { + if (mIsMounted == true) { + if (_6C && mHeader != nullptr) { + JKRHeap::free(mHeader, mHeap); + } + + removeVolumeList(&mLoaderLink); + mIsMounted = false; + } +} + +void JKRMemArchive::removeResourceAll() { + if (mInfoBlock == nullptr) { + return; + } + + if (mMountMode == MOUNT_MODE_MEM) { + return; + } + + SDIFileEntry *current = mFiles; + + for (s32 i = 0; i < mInfoBlock->mNrFiles; i++) { + if (current->mFileData != nullptr) { + current->mFileData = nullptr; + } + } +} + +bool JKRMemArchive::removeResource(void *pResource) { + SDIFileEntry *file = findPtrResource(pResource); + + if (file == nullptr) { + return false; + } + + file->mFileData = nullptr; + return true; +} + +s32 JKRMemArchive::getExpandedResSize(const void *pResource) const { + SDIFileEntry *file = findPtrResource(pResource); + + if (file == nullptr) { + return -1; + } + + if ((file->mFlag & FILE_FLAG_COMPRESSED) == 0) { + return getResSize(pResource); + } + + return JKRDecompExpandSize(reinterpret_cast(const_cast(pResource))); +} + +void *JKRMemArchive::fetchResource(SDIFileEntry *pFile, unsigned long *pSize) { + if (pFile->mFileData == nullptr) { + pFile->mFileData = mFileDataStart + pFile->mDataOffset; + } + + if (pSize != nullptr) { + *pSize = pFile->mDataSize; + } + + return pFile->mFileData; +} + +void *JKRMemArchive::fetchResource(void *pData, unsigned long dataSize, SDIFileEntry *pFile, unsigned long *pSize) { + u32 size = pFile->mDataSize; + + if (size > dataSize) { + size = dataSize; + } + + if (pFile->mFileData != nullptr) { + memcpy(pData, pFile->mFileData, size); + } + else { + s32 compression; + + if ((pFile->mFlag & FILE_FLAG_COMPRESSED) == 0) { + compression = JKR_COMPRESSION_NONE; + } + else if ((pFile->mFlag & FILE_FLAG_IS_YAZ0) != 0) { + compression = JKR_COMPRESSION_SZS; + } + else { + compression = JKR_COMPRESSION_SZP; + } + + size = fetchResource_subroutine( + mFileDataStart + pFile->mDataOffset, + size, + reinterpret_cast(pData), + dataSize, + compression + ); + } + + if (pSize != nullptr) { + *pSize = size; + } + + return pData; +} + +void JKRMemArchive::fixedInit(long entryNum) { + mIsMounted = false; + mMountMode = MOUNT_MODE_MEM; + _34 = 1; + _58 = 2; + mHeap = JKRHeap::sCurrentHeap; + mEntryNum = entryNum; + + if (gCurrentFileLoader != nullptr) { + return; + } + + gCurrentFileLoader = this; + sCurrentDirIndex = 0; +} + +bool JKRMemArchive::mountFixed(void *a1, JKRMemBreakFlag breakFlag) { + if (check_mount_already(reinterpret_cast(a1)) != nullptr) { + return false; + } + + fixedInit(reinterpret_cast(a1)); + + if (!open(a1, 0xFFFF, breakFlag)) { + return false; + } + + SDIDirEntry *firstDir = mDirs; + char *stringTable = mStringTable; + + mLoaderType = RARC_MAGIC; + mLoaderName = stringTable + firstDir->mNameOffset; + + prependVolumeList(&mLoaderLink); + + mIsMounted = true; + _6C = breakFlag == JKR_MEM_BREAK_FLAG_1; + + return true; +} + +#ifdef NON_MATCHING +// add r3, r5, r3 instead of add r3, r3, r5 +bool JKRMemArchive::open(long entryNum, EMountDirection mountDir) { + mHeader = nullptr; + mInfoBlock = nullptr; + mFileDataStart = nullptr; + mDirs = nullptr; + mFiles = nullptr; + mStringTable = nullptr; + _6C = false; + mMountDir = mountDir; + + if (mountDir == MOUNT_DIRECTION_1) { + u32 size; + + u8 *pData = JKRDvdRipper::loadToMainRAM( + entryNum, + nullptr, + JKR_EXPAND_SWITCH_1, + 0, + mHeap, + JKRDvdRipper::ALLOC_DIRECTION_1, + 0, + reinterpret_cast(&_5C), + &size + ); + + mHeader = reinterpret_cast(pData); + + if (pData != nullptr) { + DCInvalidateRange(pData, size); + } + } + else { + u32 size; + + u8 *pData = JKRDvdRipper::loadToMainRAM( + entryNum, + nullptr, + JKR_EXPAND_SWITCH_1, + 0, + mHeap, + JKRDvdRipper::ALLOC_DIRECTION_2, + 0, + reinterpret_cast(&_5C), + &size + ); + + mHeader = reinterpret_cast(pData); + + if (pData != nullptr) { + DCInvalidateRange(pData, size); + } + } + + if (mHeader == nullptr) { + mMountMode = MOUNT_MODE_0; + } + else { + mInfoBlock = reinterpret_cast(reinterpret_cast(mHeader) + mHeader->mHeaderSize);; + mDirs = reinterpret_cast(reinterpret_cast(mInfoBlock) + mInfoBlock->mDirOffset); + mFiles = reinterpret_cast(reinterpret_cast(mInfoBlock) + mInfoBlock->mFileOffset); + mStringTable = reinterpret_cast(reinterpret_cast(mInfoBlock) + mInfoBlock->mStringTableOffset); + mFileDataStart = reinterpret_cast(mHeader) + mHeader->mFileDataOffset + mHeader->mHeaderSize; + _6C = true; + } + + return mMountMode != MOUNT_MODE_0; +} +#endif + +#ifdef NON_MATCHING +// add r5, r4, r5 instead of add r5, r5, r4 +bool JKRMemArchive::open(void *pData, unsigned long a2, JKRMemBreakFlag breakFlag) { + mHeader = reinterpret_cast(pData); + mInfoBlock = reinterpret_cast(reinterpret_cast(mHeader) + mHeader->mHeaderSize);; + mDirs = reinterpret_cast(reinterpret_cast(mInfoBlock) + mInfoBlock->mDirOffset); + mFiles = reinterpret_cast(reinterpret_cast(mInfoBlock) + mInfoBlock->mFileOffset); + mStringTable = reinterpret_cast(reinterpret_cast(mInfoBlock) + mInfoBlock->mStringTableOffset); + mFileDataStart = reinterpret_cast(mHeader) + mHeader->mFileDataOffset + mHeader->mHeaderSize; + _6C = breakFlag == JKR_MEM_BREAK_FLAG_1; + mHeap = JKRHeap::findFromRoot(pData); + _5C = 0; + + return true; +} +#endif + +#ifdef NON_MATCHING +// Register mismatch +s32 JKRMemArchive::fetchResource_subroutine(unsigned char *pSrc, unsigned long srcSize, unsigned char *pDst, unsigned long dstSize, int compression) { + switch (compression) { + case JKR_COMPRESSION_NONE: + if (srcSize > dstSize) { + srcSize = dstSize; + } + + memcpy(pDst, pSrc, srcSize); + + return srcSize; + case JKR_COMPRESSION_SZP: + case JKR_COMPRESSION_SZS: + srcSize = JKRDecompExpandSize(pSrc);; + + if (srcSize > dstSize) { + srcSize = dstSize; + } + + JKRDecomp::orderSync(pSrc, pDst, srcSize, 0); + return srcSize; + default: + JUTException::panic_f(__FILE__, 723, "%s", "??? bad sequence\n"); + break; + } + + return 0; +} +#endif diff --git a/src/JSystem/JKernel/JKRThread.cpp b/src/JSystem/JKernel/JKRThread.cpp new file mode 100644 index 00000000..ab7c18df --- /dev/null +++ b/src/JSystem/JKernel/JKRThread.cpp @@ -0,0 +1,95 @@ +#include "JSystem/JKernel/JKRThread.hpp" +#include "JSystem/JKernel/JKRHeap.hpp" + +JSUList JKRThread::sThreadList = JSUList(false); +JSUList JKRThread::sTaskList = JSUList(); + +JKRThread::TLoad::TLoad() { + clear(); + + _0 = 0; + _10 = 0; +} + +void JKRThread::TLoad::clear() { + _8 = 0; + _4 = 0; + _C = 0; +} + +JKRThread::~JKRThread() { + sThreadList.remove(&mDisposerList); + + if (_28) { + if (!OSIsThreadTerminated(mThread)) { + OSDetachThread(mThread); + OSCancelThread(mThread); + } + + JKRHeap::free(_58, _28); + JKRHeap::free(mThread, _28); + } + + JKRHeap::free(mMessage, 0); +} + +void JKRThread::setCommon_mesgQueue(JKRHeap *pHeap, int msgCount) { + mMsgCount = msgCount; + mMessage = reinterpret_cast(JKRHeap::alloc(mMsgCount * 4, 0, pHeap)); + OSInitMessageQueue(&mQueue, mMessage, mMsgCount); + sThreadList.append(&mDisposerList); + _74 = 0; + _78 = 0; +} + +/* +void JKRThread::setCommon_heapSpecified(JKRHeap *pHeap, u32 a2, int a3) { + _28 = pHeap; + _5C = (void*)(a3 & 0xFFFFFFE0); + _58 = JKRHeap::alloc(*(u32*)_5C, 32, pHeap); + OSThread* thread = reinterpret_cast(JKRHeap::alloc(0x318, 0x20, _28)); + mThread = thread; + OSCreateThread(thread, JKRThread::start, this, 0, 0, 0, 0); + //OSCreateThread(thread, JKRThread::start, this, (u8*)_5C + _58, _5C, a3, 1); +} +*/ + +s32 JKRThread::start(void *pData) { + return run(); +} + +JKRThread* JKRThread::searchThread(OSThread *pThread) { + for (JSUPtrLink* i = sThreadList.mHead; i; i = i->mNext) { + JKRThread* thread = reinterpret_cast(i->mData); + + if (thread->mThread == pThread) { + return thread; + } + } + + return 0; +} + +#ifdef NON_MATCHING +JKRThread* JKRThreadSwitch::enter(JKRThread *pThread, int a2) { + JKRThread* thread = pThread; + + if (!pThread) { + return 0; + } + + JKRThread* foundThread = JKRThread::searchThread(pThread->mThread); + + if (foundThread) { + thread = foundThread; + } + + JKRThread::TLoad* inf = &thread->_60; + + inf->clear(); + inf->_10 = a2; + inf->_0 = 1; + + return thread; +} +#endif \ No newline at end of file diff --git a/src/JSystem/JMath/JMath.cpp b/src/JSystem/JMath/JMath.cpp new file mode 100644 index 00000000..bcce8818 --- /dev/null +++ b/src/JSystem/JMath/JMath.cpp @@ -0,0 +1,25 @@ +#include "JSystem/JMath/JMath.hpp" + +// this is a different type but it works for now +f32 sLookupTable[1024]; + +#ifdef NON_MATCHING +// some small issues +f32 JMAAcosRadian(f32 val) { + if (val >= 1.0f) { + return 0.0f; + } + + if (val <= -1.0f) { + return 3.1415927f; + } + + if (val >= 0.0f) { + u32 idx = 1023.5f * -val; + return 1.5707964f + sLookupTable[idx]; + } + + u32 idx = 1023.5f * val; + return sLookupTable[idx] - 1.5707964f; +} +#endif \ No newline at end of file diff --git a/src/JSystem/JMath/random.cpp b/src/JSystem/JMath/random.cpp new file mode 100644 index 00000000..d959e966 --- /dev/null +++ b/src/JSystem/JMath/random.cpp @@ -0,0 +1,5 @@ +#include "JSystem/JMath/random.hpp" + +namespace JMath { + TRandom_fast_::TRandom_fast_(u32 seed) : mSeed(seed) {} +}; diff --git a/src/JSystem/JSupport/JSUInputStream.cpp b/src/JSystem/JSupport/JSUInputStream.cpp new file mode 100644 index 00000000..6c57be67 --- /dev/null +++ b/src/JSystem/JSupport/JSUInputStream.cpp @@ -0,0 +1,25 @@ +#include "JSystem/JSupport/JSURandomInputStream.hpp" + +s32 JSUInputStream::read(void *pDest, s32 length) { + s32 read = readData(pDest, length); + if (read != length) { + setState(IO_ERROR); + } + return read; +} + +s32 JSURandomInputStream::skip(s32 amount) { + s32 read = seekPos(amount, SEEK_FROM_POSITION); + if (read != amount) { + setState(IO_ERROR); + } + return read; +} + +#ifdef NON_MATCHING +s32 JSURandomInputStream::seek(s32 offset, JSUStreamSeekFrom whence) { + s32 read = seekPos(offset, whence); + mState = (mState & 0x1) != 0; + return read; +} +#endif diff --git a/src/JSystem/JSupport/JSUList.cpp b/src/JSystem/JSupport/JSUList.cpp new file mode 100644 index 00000000..42cdbe3e --- /dev/null +++ b/src/JSystem/JSupport/JSUList.cpp @@ -0,0 +1,152 @@ +#include "JSystem/JSupport/JSUList.hpp" + +JSUPtrLink::JSUPtrLink(void *pData) { + mData = pData; + mPtrList = 0; + mPrev = 0; + mNext = 0; +} + +JSUPtrLink::~JSUPtrLink() { + if (mPtrList) { + mPtrList->remove(this); + } +} + +JSUPtrList::JSUPtrList(bool doInitialize) { + if (doInitialize) { + initiate(); + } +} + +JSUPtrList::~JSUPtrList() { + JSUPtrLink* curHead = mHead; + + for (int i = 0; i < mNodeCount; i++) { + curHead->mPtrList = 0; + curHead = curHead->mNext; + } +} + +void JSUPtrList::initiate() { + mHead = 0; + mTail = 0; + mNodeCount = 0; +} + +void JSUPtrList::setFirst(JSUPtrLink *pLink) { + pLink->mPtrList = this; + pLink->mPrev = 0; + pLink->mNext = 0; + mTail = pLink; + mHead = pLink; + mNodeCount = 1; +} + +bool JSUPtrList::append(JSUPtrLink *pLink) { + bool validity = (pLink->mPtrList == 0); + + if (!validity) { + validity = pLink->mPtrList->remove(pLink); + } + + if (validity) { + if (!mNodeCount) { + setFirst(pLink); + } + else { + pLink->mPtrList = this; + pLink->mPrev = mTail; + pLink->mNext = 0; + mTail->mNext = pLink; + mTail = pLink; + mNodeCount = mNodeCount + 1; + } + } + + return validity; +} + +bool JSUPtrList::prepend(JSUPtrLink *pLink) { + bool validity = (pLink->mPtrList == 0); + + if (!validity) { + validity = pLink->mPtrList->remove(pLink); + } + + if (validity) { + if (!mNodeCount) { + setFirst(pLink); + } + else { + pLink->mPtrList = this; + pLink->mPrev = 0; + pLink->mNext = mHead; + mHead->mPrev = pLink; + mHead = pLink; + mNodeCount = mNodeCount + 1; + } + } + + return validity; +} + +bool JSUPtrList::insert(JSUPtrLink *pLink_1, JSUPtrLink *pLink_2) { + if (pLink_1 == mHead) { + return prepend(pLink_2); + } + if (!pLink_1) { + return append(pLink_2); + } + if (pLink_1->mPtrList != this) { + return false; + } + + JSUPtrList* link2PtrList = pLink_2->mPtrList; + + bool validity = (link2PtrList == 0); + + if (!validity) { + validity = link2PtrList->remove(pLink_2); + } + + if (validity) { + JSUPtrLink* prev = pLink_1->mPrev; + pLink_2->mPtrList = this; + pLink_2->mPrev = prev; + pLink_2->mNext = pLink_1; + prev->mNext = pLink_2; + pLink_1->mPrev = pLink_2; + mNodeCount++; + } + + return validity; +} + +bool JSUPtrList::remove(JSUPtrLink *pLink) { + bool isSameList = (pLink->mPtrList == this); + + if (isSameList) { + if (mNodeCount == 1) { + mHead = 0; + mTail = 0; + } + else if (pLink == mHead) { + pLink->mNext->mPrev = 0; + mHead = pLink->mNext; + } + else if (pLink == mTail) { + pLink->mPrev->mNext = 0; + mTail = pLink->mPrev; + } + else { + pLink->mPrev->mNext = pLink->mNext; + pLink->mNext->mPrev = pLink->mPrev; + } + + pLink->mPtrList = 0; + mNodeCount--; + } + + return isSameList; +} diff --git a/src/JSystem/JSupport/JSUMemoryStream.cpp b/src/JSystem/JSupport/JSUMemoryStream.cpp new file mode 100644 index 00000000..362b28f5 --- /dev/null +++ b/src/JSystem/JSupport/JSUMemoryStream.cpp @@ -0,0 +1,93 @@ +#include "JSystem/JSupport/JSUMemoryInputStream.hpp" +#include "JSystem/JSupport/JSUMemoryOutputStream.hpp" +#include + +void JSUMemoryInputStream::setBuffer(const void *pBuffer, s32 length) { + mBuffer = pBuffer; + mLength = length; + mPosition = 0; +} + +u32 JSUMemoryInputStream::readData(void *pDest, s32 length) { + if (mPosition + length > mLength) { + length = mLength - mPosition; + } + if (length > 0) { + memcpy(pDest, (void*)((int)mBuffer + mPosition), length); + mPosition += length; + } + return length; +} + +s32 JSUMemoryInputStream::seekPos(s32 offset, JSUStreamSeekFrom whence) { + s32 oldPosition = mPosition; + switch (whence) { + case SEEK_FROM_START: + mPosition = offset; + break; + case SEEK_FROM_END: + mPosition = mLength - offset; + break; + case SEEK_FROM_POSITION: + mPosition += offset; + break; + } + if (mPosition < 0) { + mPosition = 0; + } + if (mPosition > mLength) { + mPosition = mLength; + } + return mPosition - oldPosition; +} + +void JSUMemoryOutputStream::setBuffer(void *pBuffer, s32 length) { + mBuffer = pBuffer; + mLength = length; + mPosition = 0; +} + +s32 JSUMemoryOutputStream::writeData(const void *pSrc, s32 length) { + if (mPosition + length > mLength) { + length = mLength - mPosition; + } + if (length > 0) { + memcpy((void*)((int)mBuffer + mPosition), pSrc, length); + mPosition += length; + } + return length; +} + +s32 JSUMemoryOutputStream::seekPos(s32 offset, JSUStreamSeekFrom whence) { + s32 oldPosition = mPosition; + switch (whence) { + case SEEK_FROM_START: + mPosition = offset; + break; + case SEEK_FROM_END: + mPosition = mLength - offset; + break; + case SEEK_FROM_POSITION: + mPosition += offset; + break; + } + if (mPosition < 0) { + mPosition = 0; + } + if (mPosition > mLength) { + mPosition = mLength; + } + return mPosition - oldPosition; +} + +s32 JSUMemoryOutputStream::getLength() const { + return mLength; +} + +s32 JSUMemoryInputStream::getPosition() const { + return mPosition; +} + +s32 JSUMemoryInputStream::getLength() const { + return mLength; +} \ No newline at end of file diff --git a/src/JSystem/JUtility/JUTConsole.cpp b/src/JSystem/JUtility/JUTConsole.cpp new file mode 100644 index 00000000..573c22ab --- /dev/null +++ b/src/JSystem/JUtility/JUTConsole.cpp @@ -0,0 +1,31 @@ +#include "JSystem/JUtility/JUTConsole.hpp" +#include + +void JUTConsoleManager::drawDirect(bool a1) const { + if (mDirectConsole != nullptr) { + if (a1) { + BOOL en = OSEnableInterrupts(); + u32 startRetraceCount = VIGetRetraceCount(); + u32 curRetraceCount = startRetraceCount; + do { + curRetraceCount = VIGetRetraceCount(); + } while(startRetraceCount == curRetraceCount); + + OSRestoreInterrupts(en); + } + + mDirectConsole->doDraw(JUTConsole::CONSOLE_TYPE_2); + } +} + +void JUTConsoleManager::setDirectConsole(JUTConsole *pConsole) { + if (mDirectConsole != nullptr) { + appendConsole(mDirectConsole); + } + + if (pConsole != nullptr) { + removeConsole(pConsole); + } + + mDirectConsole = pConsole; +} \ No newline at end of file diff --git a/src/JSystem/JUtility/JUTException.cpp b/src/JSystem/JUtility/JUTException.cpp new file mode 100644 index 00000000..dc137f3c --- /dev/null +++ b/src/JSystem/JUtility/JUTException.cpp @@ -0,0 +1,143 @@ +#include "JSystem/JUtility/JUTException.hpp" +#include "JSystem/JUtility/JUTDirectPrint.hpp" +#include +#include + + +struct CallbackObject { + CallbackFunc callback; // 0x0 + u16 error; // 0x4 + u16 pad; // 0x6 + OSContext* context; // 0x8 + int param_3; // 0xC + int param_4; // 0x10 +}; + +static CallbackObject exCallbackObject; +static OSContext context; + +s32 JUTException::run() { + PPCMtmsr(PPCMfmsr() & 0xFFFFF6FF); + OSInitMessageQueue(&sMessageQueue, &sMessageBuffer, 1); + OSMessage msg; + while (true) { + OSReceiveMessage(&sMessageQueue, &msg, 1); + VISetPreRetraceCallback(0); + VISetPostRetraceCallback(0); + CallbackObject* obj = (CallbackObject*)msg; + + CallbackFunc hndlr = obj->callback; + u16 error = obj->error; + OSContext* ctxt = obj->context; + u32 param_3 = obj->param_3; + u32 param_4 = obj->param_4; + + + if (error < 0x11) { + mStackPointer = ctxt->gpr[1]; + } + + void* frameBuf = VIGetCurrentFrameBuffer(); + mFrameMemory = (JUTExternalFB*)frameBuf; + + if (frameBuf == nullptr) { + sErrorManager->createFB(); + } + + sErrorManager->mDirectPrint->changeFrameBuffer(mFrameMemory, sErrorManager->mDirectPrint->mFrameBufferWidth, sErrorManager->mDirectPrint->mFrameBufferHeight); + + if (hndlr != nullptr) { + hndlr(error, ctxt, param_3, param_4); + } + + OSDisableInterrupts(); + void* frameBuffer = VIGetCurrentFrameBuffer(); + mFrameMemory = (JUTExternalFB*)frameBuffer; + sErrorManager->mDirectPrint->changeFrameBuffer(frameBuffer, sErrorManager->mDirectPrint->mFrameBufferWidth, sErrorManager->mDirectPrint->mFrameBufferHeight); + sErrorManager->printContext(error, ctxt, param_3, param_4); + } +} + +void JUTException::errorHandler(u16 err, OSContext *pContext, u32 a3, u32 a4) { + JUTException::msr = PPCMfmsr(); + JUTException::fpscr = pContext->fpscr; + OSFillFPUContext(pContext); + OSSetErrorHandler(err, nullptr); + + if (err == 15) { + OSProtectRange(0, 0, 0, 3); + OSProtectRange(1, 0, 0, 3); + OSProtectRange(2, 0, 0, 3); + OSProtectRange(3, 0, 0, 3); + } + + exCallbackObject.callback = sPreUserCallback; + exCallbackObject.error = err; + exCallbackObject.context = pContext; + exCallbackObject.param_3 = a3; + exCallbackObject.param_4 = a4; + OSSendMessage(&sMessageQueue, &exCallbackObject, 1); + OSEnableScheduler(); + OSYieldThread(); +} + +void JUTException::panic_f_va(const char* file, int line, const char* format, va_list args) { + char buffer[256]; + vsnprintf(buffer, 0xFF, format, args); + + if (sErrorManager == nullptr) { + OSPanic((char*)file, line, buffer); + } + + OSContext* current_context = OSGetCurrentContext(); + memcpy(&context, current_context, sizeof(OSContext)); + sErrorManager->mStackPointer = (u32)OSGetStackPointer(); + + exCallbackObject.callback = sPreUserCallback; + exCallbackObject.error = 0xFF; + exCallbackObject.context = &context; + exCallbackObject.param_3 = 0; + exCallbackObject.param_4 = 0; + + if (sConsole == nullptr || (sConsole && (sConsole->getOutput() & 2) == 0)) { + OSReport("%s in \"%s\" on line %d\n", buffer, file, line); + } + + if (sConsole != nullptr) { + sConsole->print_f("%s in \"%s\" on line %d\n", buffer, file, line); + } + + OSSendMessage(&sMessageQueue, &exCallbackObject, 1); + OSThread* current_thread = OSGetCurrentThread(); + OSSuspendThread(current_thread); +} + +void JUTException::panic_f(const char *file, int line, const char *format, ...) { + va_list args; + va_start(args, format); + panic_f_va(file, line, format, args); + va_end(); +} + +// JUTException::showFloatSub +// JUTException::showFloat +// JUTException::searchPartialModule +// JUTException::showStack +// JUTException::showMainInfo +// JUTException::showGPR +// JUTException::showMapInfo_subroutine +// JUTException::showGPRMap +// JUTException::showSRR0Map +// JUTException::printDebugInfo + +bool JUTException::isEnablePad() const { + if (_84 == 0xFFFFFFFF) { + return true; + } + + if (mGamePadPort >= JUTGamePad::Port_1) { + return 1; + } + + return _84 != 0; +} \ No newline at end of file diff --git a/src/JSystem/JUtility/JUTTexture.cpp b/src/JSystem/JUtility/JUTTexture.cpp new file mode 100644 index 00000000..3f688afa --- /dev/null +++ b/src/JSystem/JUtility/JUTTexture.cpp @@ -0,0 +1,137 @@ +#include "JSystem/JUtility/JUTTexture.hpp" +#include "JSystem/JKernel/JKRHeap.hpp" +#include + +JUTTexture::JUTTexture(const ResTIMG *pImgData, u8 a2) { + _28 = 0; + storeTIMG(pImgData, a2); + _3B &= 2; +} + +JUTTexture::JUTTexture(int width, int height, _GXTexFmt texFmt) { + _3B = _3B & 2 | 1; + u32 bufSize = GXGetTexBufferSize(width, height, texFmt, GX_FALSE, 1); + + ResTIMG* texBuf = reinterpret_cast(new(0x20) u8[bufSize + 0x20]); + _3C = texBuf; + texBuf->mFormat = texFmt; + texBuf->mEnableAlpha = 0; + texBuf->mWidth = width; + texBuf->mHeight = height; + texBuf->mWrapS = 0; + texBuf->mWrapT = 0; + texBuf->mPaletteFormat = 0; + texBuf->_9 = 0; + texBuf->mPaletteCount = 0; + texBuf->mPaletteOffs = 0; + texBuf->_10 = 0; + texBuf->_11 = 0; + texBuf->_12 = 0; + texBuf->_13 = 0; + texBuf->mMagType = 1; + texBuf->mMinType = 1; + texBuf->_16 = 0; + texBuf->_17 = 0; + texBuf->mTotalImgCount = 1; + texBuf->_1A = 0; + texBuf->mImgDataOffs = 0x20; + _28 = 0; + + // cast to u8 solves ambiguity + storeTIMG(texBuf, (u8)0); + DCFlushRange(_24, bufSize); +} + +JUTTexture::~JUTTexture() { + if (_3B & 0x1) { + delete[] _3C; + } + + if (_3B & 0x2) { + delete _28; + } +} + +// JUTTexture::storeTIMG((ResTIMG const *, unsigned char)) + +void JUTTexture::storeTIMG(const ResTIMG *pImg, JUTPalette *pPalette) { + _GXTlut tlut; + + if (!pPalette) { + tlut = GX_TLUT0; + } + else { + tlut = pPalette->_C; + } + + storeTIMG(pImg, pPalette, tlut); +} + +// JUTTexture::storeTIMG((ResTIMG const *, JUTPalette *, _GXTlut)) + +#ifdef NON_MATCHING +void JUTTexture::attachPalette(JUTPalette *pPalette) { + JUTPalette* thing; + if (_20->mPaletteFormat) { + if (pPalette || (thing = _28) == 0) { + mPalette = pPalette; + } + else { + mPalette = thing; + } + + initTexObj(mPalette->_C); + } +} +#endif + +void JUTTexture::init() { + if (!_20->mPaletteCount) { + initTexObj(); + } + else { + if (_28) { + mPalette = _28; + initTexObj(mPalette->_C); + } + } +} + +/*void JUTTexture::initTexObj() { + u32 offs = 0x20; + if (_20->mImgDataOffs) { + offs = _20->mImgDataOffs; + } + + //GXInitTexObj(&mTexObj, reinterpret_cast(_20 + offs), _20->mWidth, _20->mHeight, (_GXTexFmt)_20->mFormat, (_GXTexWrapMode)_20->mWrapS, (_GXTexWrapMode)_20->mWrapT, _20->_10); + //GXInitTexObjLOD(&mTexObj, (GXTexFilter)mMagType, (GXTexFilter)mMinType, _34 * 0.125f, _36 * 0.125f, _38 / 100.0f, _20->_12, _20->_11, (GXAnisotropy)_20->_13); +}*/ + +// JUTTexture::initTexObj((_GXTlut)) + +void JUTTexture::load(_GXTexMapID texMapID) { + if (mPalette) { + mPalette->load(); + } + + GXLoadTexObj(&mTexObj, texMapID); +} + +void JUTTexture::capture(int width, int height, _GXTexFmt texFmt, bool useMipmap, GXBool clear) { + if (_3B & 0x1) { + if (useMipmap) { + GXSetTexCopySrc(width, height, (2 * _20->mWidth), (2 * _20->mHeight)); + } + else { + GXSetTexCopySrc(width, height, _20->mWidth, _20->mHeight); + } + + GXSetTexCopyDst(_20->mWidth, _20->mHeight, texFmt, useMipmap); + GXCopyTex(_24, clear); + GXPixModeSync(); + } +} + +void JUTTexture::setEmbPaletteDelFlag(bool set) { + _3B = _3B & 0x1 | (2 * set); +} \ No newline at end of file