From 476d0fe453cc937f30e9540d23b1b1062eb512d7 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Mon, 18 Dec 2023 13:58:25 -0500 Subject: [PATCH] Bootstrap MxSmack --- 3rdparty/smk/smk.h | 55 +++++++------ CMakeLists.txt | 1 + LEGO1/mxsmack.cpp | 169 +++++++++++++++++++++++++++++++++++++++ LEGO1/mxsmack.h | 34 ++++++++ LEGO1/mxsmkpresenter.cpp | 38 +++------ LEGO1/mxsmkpresenter.h | 27 +------ 6 files changed, 247 insertions(+), 77 deletions(-) create mode 100644 LEGO1/mxsmack.cpp create mode 100644 LEGO1/mxsmack.h diff --git a/3rdparty/smk/smk.h b/3rdparty/smk/smk.h index 0a8624ad..3f2fff80 100644 --- a/3rdparty/smk/smk.h +++ b/3rdparty/smk/smk.h @@ -6,7 +6,7 @@ struct SmackSum { unsigned long m_ms100PerFrame; unsigned long m_totalOpenTime; unsigned long m_totalFrames; - unsigned long m_skippedFrames; + unsigned long m_skippedFrames; unsigned long m_totalBlitTime; unsigned long m_totalReadTime; unsigned long m_totalDecompressTime; @@ -24,31 +24,36 @@ struct SmackSum { unsigned long m_highestExtraUsed; }; +// SIZE 0x390 struct Smack { - unsigned long m_version; - unsigned long m_width; - unsigned long m_height; - unsigned long m_frames; - unsigned long m_msInAFrame; - unsigned long m_smkType; - unsigned long m_audioTrackSize[7]; - unsigned long m_treeSize; - unsigned long m_codeSize; - unsigned long m_abSize; - unsigned long m_detailSize; - unsigned long m_typeSize; - unsigned long m_trackType[7]; - unsigned long m_extra; - unsigned long m_newPalette; - unsigned char m_palette[772]; - unsigned long m_frameNum; - unsigned long m_lastRectX; - unsigned long m_lastRectY; - unsigned long m_lastRectW; - unsigned long m_lastRectH; - unsigned long m_openFlags; - unsigned long m_leftOfs; - unsigned long m_topOfs; + struct Header { + unsigned long m_version; // 0x00 + unsigned long m_width; // 0x04 + unsigned long m_height; // 0x08 + unsigned long m_frames; // 0x0c + unsigned long m_msInAFrame; // 0x10 + unsigned long m_smkType; // 0x14 + unsigned long m_audioTrackSize[7]; // 0x18 + unsigned long m_treeSize; // 0x34 + unsigned long m_codeSize; // 0x38 + unsigned long m_abSize; // 0x3c + unsigned long m_detailSize; // 0x40 + unsigned long m_typeSize; // 0x44 + unsigned long m_trackType[7]; // 0x48 + unsigned long m_extra; // 0x64 + }; + + Header m_header; // 0x00 + unsigned long m_newPalette; // 0x68 + unsigned char m_palette[772]; // 0x6c + unsigned long m_frameNum; // 0x370 + unsigned long m_lastRectX; // 0x374 + unsigned long m_lastRectY; // 0x378 + unsigned long m_lastRectW; // 0x37c + unsigned long m_lastRectH; // 0x380 + unsigned long m_openFlags; // 0x384 + unsigned long m_leftOfs; // 0x388 + unsigned long m_topOfs; // 0x38c }; #endif // SMK_H diff --git a/CMakeLists.txt b/CMakeLists.txt index b549047b..c1ff16aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -168,6 +168,7 @@ add_library(lego1 SHARED LEGO1/mxregionlist.cpp LEGO1/mxscheduler.cpp LEGO1/mxsemaphore.cpp + LEGO1/mxsmack.cpp LEGO1/mxsmkpresenter.cpp LEGO1/mxsoundmanager.cpp LEGO1/mxsoundpresenter.cpp diff --git a/LEGO1/mxsmack.cpp b/LEGO1/mxsmack.cpp new file mode 100644 index 00000000..7982db67 --- /dev/null +++ b/LEGO1/mxsmack.cpp @@ -0,0 +1,169 @@ +#include "mxsmack.h" + +#include + +DECOMP_SIZE_ASSERT(Smack, 0x390); +DECOMP_SIZE_ASSERT(Smack::Header, 0x68); +DECOMP_SIZE_ASSERT(MxSmack, 0x6b8); + +// FUNCTION: LEGO1 0x100c5a90 +MxResult MxSmack::LoadHeaderAndTrees(MxU8* p_data, MxSmack* p_mxSmack) +{ +// Macros for readability +#define HEADER(mxSmack) mxSmack->m_smack.m_header +#define FRAME_COUNT(mxSmack) (HEADER(p_mxSmack).m_frames + (HEADER(p_mxSmack).m_smkType & 1)) + + MxResult result = SUCCESS; + MxU8* frameTypes = NULL; + MxU8* huffmanTrees = NULL; + + if (!p_data || !p_mxSmack) { + result = FAILURE; + } + else { + p_mxSmack->m_frameTypes = NULL; + p_mxSmack->m_frameSizes = NULL; + p_mxSmack->m_huffmanTrees = NULL; + p_mxSmack->m_huffmanTables = NULL; + + memcpy(&HEADER(p_mxSmack), p_data, sizeof(Smack::Header)); + p_data += sizeof(Smack::Header); + + MxU32* frameSizes = new MxU32[FRAME_COUNT(p_mxSmack)]; + + if (!frameSizes) { + result = FAILURE; + } + else { + memcpy(frameSizes, p_data, FRAME_COUNT(p_mxSmack) * sizeof(MxU32)); + + p_data += FRAME_COUNT(p_mxSmack) * sizeof(MxU32); + p_mxSmack->maxFrameSize = 0; + + // TODO + for (MxU32 i = 0; i < FRAME_COUNT(p_mxSmack); i++) { + if (p_mxSmack->maxFrameSize < frameSizes[i]) + p_mxSmack->maxFrameSize = frameSizes[i]; + } + + frameTypes = new MxU8[FRAME_COUNT(p_mxSmack)]; + + if (!frameTypes) { + result = FAILURE; + } + else { + memcpy(frameTypes, p_data, FRAME_COUNT(p_mxSmack)); + p_data += FRAME_COUNT(p_mxSmack); + + MxU32 treeSize = HEADER(p_mxSmack).m_treeSize + 0x1000; + if (treeSize <= 0x2000) + treeSize = 0x2000; + + huffmanTrees = new MxU8[treeSize]; + + if (!huffmanTrees) { + result = FAILURE; + } + else { + memcpy(huffmanTrees + 0x1000, p_data, HEADER(p_mxSmack).m_treeSize); + + p_mxSmack->m_huffmanTables = new MxU8 + [HEADER(p_mxSmack).m_codeSize + HEADER(p_mxSmack).m_abSize + HEADER(p_mxSmack).m_detailSize + + HEADER(p_mxSmack).m_typeSize + FUN_100cd782()]; + + if (!p_mxSmack->m_huffmanTables) { + result = FAILURE; + } + else { + DecodeHuffmanTrees( + huffmanTrees, + p_mxSmack->m_huffmanTables, + HEADER(p_mxSmack).m_codeSize, + HEADER(p_mxSmack).m_abSize, + HEADER(p_mxSmack).m_detailSize, + HEADER(p_mxSmack).m_typeSize + ); + + MxU32 size = FUN_100d052c(HEADER(p_mxSmack).m_width, HEADER(p_mxSmack).m_height) + 32; + p_mxSmack->m_unk0x6b4 = new MxU8[size]; + memset(p_mxSmack->m_unk0x6b4, 0, size); + + MxS32 width = HEADER(p_mxSmack).m_width; + MxU32* data = (MxU32*) p_mxSmack->m_unk0x6b4; + + *data = 1; + data++; + *data = 0; + data++; + *data = HEADER(p_mxSmack).m_width / 4; + data++; + *data = HEADER(p_mxSmack).m_height / 4; + data++; + *data = width - 4; + data++; + *data = width * 3; + data++; + *data = width; + data++; + *data = width * 4 - HEADER(p_mxSmack).m_width; + data++; + data++; + *data = HEADER(p_mxSmack).m_width; + data++; + *data = HEADER(p_mxSmack).m_height; + } + } + } + } + + p_mxSmack->m_frameTypes = frameTypes; + p_mxSmack->m_frameSizes = frameSizes; + p_mxSmack->m_huffmanTrees = huffmanTrees; + } + + return result; + +#undef FRAME_COUNT +#undef HEADER +} + +// FUNCTION: LEGO1 0x100c5d40 +void MxSmack::Destroy(MxSmack* p_mxSmack) +{ + if (p_mxSmack->m_frameSizes) + delete[] p_mxSmack->m_frameSizes; + if (p_mxSmack->m_frameTypes) + delete[] p_mxSmack->m_frameTypes; + if (p_mxSmack->m_huffmanTrees) + delete[] p_mxSmack->m_huffmanTrees; + if (p_mxSmack->m_huffmanTables) + delete[] p_mxSmack->m_huffmanTables; + if (p_mxSmack->m_unk0x6b4) + delete[] p_mxSmack->m_unk0x6b4; +} + +// FUNCTION: LEGO1 0x100cd782 +MxU32 MxSmack::FUN_100cd782() +{ + return 29800; +} + +// STUB: LEGO1 0x100cd7e8 +void MxSmack::DecodeHuffmanTrees( + MxU8* p_huffmanTrees, + MxU8* p_unk0x6ac, + MxULong p_codeSize, + MxULong p_abSize, + MxULong p_detailSize, + MxULong p_typeSize +) +{ + // TODO +} + +// STUB: LEGO1 0x100d052c +MxULong MxSmack::FUN_100d052c(MxULong p_width, MxULong p_height) +{ + // TODO + return 0; +} diff --git a/LEGO1/mxsmack.h b/LEGO1/mxsmack.h new file mode 100644 index 00000000..3eb8f362 --- /dev/null +++ b/LEGO1/mxsmack.h @@ -0,0 +1,34 @@ +#ifndef MXSMACK_H +#define MXSMACK_H + +#include "decomp.h" +#include "mxtypes.h" + +#include + +// SIZE 0x6b8 +struct MxSmack { + Smack m_smack; // 0x00 + undefined m_unk0x3f4[784]; // 0x390 + MxU32* m_frameSizes; // 0x6a0 + MxU8* m_frameTypes; // 0x6a4 + MxU8* m_huffmanTrees; // 0x6a8 + MxU8* m_huffmanTables; // 0x6ac + MxU32 maxFrameSize; // 0x6b0 + MxU8* m_unk0x6b4; // 0x6b4 + + static MxResult LoadHeaderAndTrees(MxU8* p_data, MxSmack* p_mxSmack); + static void Destroy(MxSmack* p_mxSmack); + static MxU32 FUN_100cd782(); + static void DecodeHuffmanTrees( + MxU8* p_huffmanTrees, + MxU8* p_huffmanTables, + MxULong p_codeSize, + MxULong p_abSize, + MxULong p_detailSize, + MxULong p_typeSize + ); + static MxULong FUN_100d052c(MxULong p_width, MxULong p_height); +}; + +#endif // MXSMACK_H diff --git a/LEGO1/mxsmkpresenter.cpp b/LEGO1/mxsmkpresenter.cpp index 1aea3243..c38003d2 100644 --- a/LEGO1/mxsmkpresenter.cpp +++ b/LEGO1/mxsmkpresenter.cpp @@ -31,7 +31,7 @@ void MxSmkPresenter::Destroy(MxBool p_fromDestructor) { m_criticalSection.Enter(); - FUN_100c5d40(&m_mxSmack); + MxSmack::Destroy(&m_mxSmack); Init(); m_criticalSection.Leave(); @@ -41,10 +41,10 @@ void MxSmkPresenter::Destroy(MxBool p_fromDestructor) } } -// STUB: LEGO1 0x100b3940 +// FUNCTION: LEGO1 0x100b3940 void MxSmkPresenter::LoadHeader(MxStreamChunk* p_chunk) { - // TODO + MxSmack::LoadHeaderAndTrees(p_chunk->GetData(), &m_mxSmack); } // FUNCTION: LEGO1 0x100b3960 @@ -54,7 +54,7 @@ void MxSmkPresenter::CreateBitmap() delete m_bitmap; m_bitmap = new MxBitmap; - m_bitmap->SetSize(m_mxSmack.m_smack.m_width, m_mxSmack.m_smack.m_height, NULL, FALSE); + m_bitmap->SetSize(m_mxSmack.m_smack.m_header.m_width, m_mxSmack.m_smack.m_header.m_height, NULL, FALSE); } // STUB: LEGO1 0x100b3a00 @@ -64,23 +64,18 @@ void MxSmkPresenter::LoadFrame(MxStreamChunk* p_chunk) } // FUNCTION: LEGO1 0x100b4260 -MxU32 MxSmkPresenter::VTable0x88() +void MxSmkPresenter::VTable0x88() { - MxU32 result = m_unk0x71c; - if ((m_mxSmack.m_smack.m_smkType & 1) != 0) { - result = m_unk0x71c / m_mxSmack.m_smack.m_frames; - if (1 < m_unk0x71c && (m_unk0x71c % m_mxSmack.m_smack.m_frames) == 1) { + if ((m_mxSmack.m_smack.m_header.m_smkType & 1) != 0) { + MxU32 unk = (m_unk0x71c % m_mxSmack.m_smack.m_header.m_frames); + if (1 < m_unk0x71c && unk == 1) m_unk0x71c = 1; - } - return result; } else { - if (m_mxSmack.m_smack.m_frames == result) { + if (m_mxSmack.m_smack.m_header.m_frames == m_unk0x71c) { m_unk0x71c = 0; - result = 0; memset(m_mxSmack.m_smack.m_palette, 0, sizeof(m_mxSmack.m_smack.m_palette)); } - return result; } } @@ -97,18 +92,3 @@ void MxSmkPresenter::Destroy() { Destroy(FALSE); } - -// FUNCTION: LEGO1 0x100c5d40 -void MxSmkPresenter::FUN_100c5d40(MxSmack* p_mxSmack) -{ - if (p_mxSmack->m_unk0x6a0) - delete p_mxSmack->m_unk0x6a0; - if (p_mxSmack->m_unk0x6a4) - delete p_mxSmack->m_unk0x6a4; - if (p_mxSmack->m_unk0x6a8) - delete p_mxSmack->m_unk0x6a8; - if (p_mxSmack->m_unk0x6ac) - delete p_mxSmack->m_unk0x6ac; - if (p_mxSmack->m_unk0x6b4) - delete p_mxSmack->m_unk0x6b4; -} diff --git a/LEGO1/mxsmkpresenter.h b/LEGO1/mxsmkpresenter.h index 243a4f4e..c70894d7 100644 --- a/LEGO1/mxsmkpresenter.h +++ b/LEGO1/mxsmkpresenter.h @@ -2,10 +2,9 @@ #define MXSMKPRESENTER_H #include "decomp.h" +#include "mxsmack.h" #include "mxvideopresenter.h" -#include - // VTABLE: LEGO1 0x100dc348 // SIZE 0x720 class MxSmkPresenter : public MxVideoPresenter { @@ -31,32 +30,14 @@ class MxSmkPresenter : public MxVideoPresenter { virtual void CreateBitmap() override; // vtable+0x60 virtual void LoadFrame(MxStreamChunk* p_chunk) override; // vtable+0x68 virtual void RealizePalette() override; // vtable+0x70 - virtual MxU32 VTable0x88(); // vtable+0x88 - - struct MxSmack { - Smack m_smack; - - // Unknown for the time being. Not an immediately - // recognizable part of the SMK standard... - - undefined m_unk0x3f4[784]; - undefined4* m_unk0x6a0; - undefined4* m_unk0x6a4; - undefined4* m_unk0x6a8; - undefined4* m_unk0x6ac; - undefined4* m_unk0x6b0; - undefined4* m_unk0x6b4; - }; - - MxSmack m_mxSmack; - undefined4 m_unk0x71c; + virtual void VTable0x88(); // vtable+0x88 private: void Init(); void Destroy(MxBool p_fromDestructor); - // This should most likely be in a separate translation unit - static void FUN_100c5d40(MxSmack* p_mxSmack); + MxSmack m_mxSmack; // 0x64 + undefined4 m_unk0x71c; // 0x71c }; #endif // MXSMKPRESENTER_H