Isle
Loading...
Searching...
No Matches
mxsmk.cpp
Go to the documentation of this file.
1#include "mxsmk.h"
2
3#include "mxbitmap.h"
4
5#include <string.h>
6
9
10// FUNCTION: LEGO1 0x100c5a90
11// FUNCTION: BETA10 0x10151e70
13{
14// Macros for readability
15// If bit0 of SmackerType is set, there is an extra frame ("ring frame")
16// at the end. It is a duplicate of the first frame to simplify looping.
17#define FRAME_COUNT(_tag) (_tag->Frames + (_tag->SmackerType & 1))
18
19 MxResult result = SUCCESS;
20 MxU32* frameSizes = NULL;
21 MxU8* frameTypes = NULL;
22 MxU8* huffmanTrees = NULL;
23 MxU32 sizetables = 0;
24
25 // Forced to declare here because of the gotos.
26 MxU32 i;
27 MxU32 treeSize;
28 MxU32* data;
29 MxU32 size;
30 MxS32 width;
31
32 if (!p_data || !p_mxSmk) {
33 return FAILURE;
34 }
35
36 SmackTag* smackTag = &p_mxSmk->m_smackTag;
37 p_mxSmk->m_frameTypes = NULL;
38 p_mxSmk->m_frameSizes = NULL;
39 p_mxSmk->m_huffmanTrees = NULL;
40 p_mxSmk->m_huffmanTables = NULL;
41
42 memcpy(smackTag, p_data, SmackHeaderSize(smackTag));
43 p_data += SmackHeaderSize(smackTag);
44
45 frameSizes = new MxU32[FRAME_COUNT(smackTag)];
46
47 if (!frameSizes) {
48 result = FAILURE;
49 goto done;
50 }
51
52 memcpy(frameSizes, p_data, FRAME_COUNT(smackTag) * sizeof(MxU32));
53
54 p_data += FRAME_COUNT(smackTag) * sizeof(MxU32);
55 p_mxSmk->m_maxFrameSize = 0;
56
57 for (i = 0; i < FRAME_COUNT(smackTag); i++) {
58 if (p_mxSmk->m_maxFrameSize < frameSizes[i]) {
59 p_mxSmk->m_maxFrameSize = frameSizes[i];
60 }
61 }
62
63 frameTypes = new MxU8[FRAME_COUNT(smackTag)];
64
65 if (!frameTypes) {
66 result = FAILURE;
67 goto done;
68 }
69
70 memcpy(frameTypes, p_data, FRAME_COUNT(smackTag));
71 p_data += FRAME_COUNT(smackTag);
72
73 treeSize = smackTag->tablesize + 0x1000;
74 huffmanTrees = new MxU8[treeSize <= 0x2000 ? 0x2000 : treeSize];
75
76 if (!huffmanTrees) {
77 result = FAILURE;
78 goto done;
79 }
80
81 memcpy(huffmanTrees + 0x1000, p_data, smackTag->tablesize);
82 p_data += smackTag->tablesize;
83
84 sizetables = SmackGetSizeTables();
85 p_mxSmk->m_huffmanTables =
86 new MxU8[smackTag->codesize + smackTag->detailsize + smackTag->typesize + smackTag->absize + sizetables];
87
88 if (!p_mxSmk->m_huffmanTables) {
89 result = FAILURE;
90 goto done;
91 }
92
94 huffmanTrees,
95 p_mxSmk->m_huffmanTables,
96 smackTag->codesize,
97 smackTag->absize,
98 smackTag->detailsize,
99 smackTag->typesize
100 );
101
102 size = SmackGetSizeDeltas(smackTag->Width, smackTag->Height) + 32;
103 p_mxSmk->m_unk0x6b4 = new MxU8[size];
104 memset(p_mxSmk->m_unk0x6b4, 0, size);
105
106 width = p_mxSmk->m_smackTag.Width;
107 data = (MxU32*) p_mxSmk->m_unk0x6b4;
108
109 *data = 1;
110 data++;
111 *data = NULL; // MxU8* bitmapData
112 data++;
113 *data = smackTag->Width / 4;
114 data++;
115 *data = smackTag->Height / 4;
116 data++;
117 *data = width - 4;
118 data++;
119 *data = width * 3;
120 data++;
121 *data = width;
122 data++;
123 *data = width * 3 + (width - smackTag->Width);
124 data++;
125 data++;
126 *data = smackTag->Width;
127 data++;
128 *data = smackTag->Height;
129
130done:
131 p_mxSmk->m_frameTypes = frameTypes;
132 p_mxSmk->m_frameSizes = frameSizes;
133 p_mxSmk->m_huffmanTrees = huffmanTrees;
134 return result;
135
136#undef FRAME_COUNT
137}
138
139// FUNCTION: LEGO1 0x100c5d40
140// FUNCTION: BETA10 0x10152298
141void MxSmk::Destroy(MxSmk* p_mxSmk)
142{
143 if (p_mxSmk->m_frameSizes) {
144 delete[] p_mxSmk->m_frameSizes;
145 }
146 if (p_mxSmk->m_frameTypes) {
147 delete[] p_mxSmk->m_frameTypes;
148 }
149 if (p_mxSmk->m_huffmanTrees) {
150 delete[] p_mxSmk->m_huffmanTrees;
151 }
152 if (p_mxSmk->m_huffmanTables) {
153 delete[] p_mxSmk->m_huffmanTables;
154 }
155 if (p_mxSmk->m_unk0x6b4) {
156 delete[] p_mxSmk->m_unk0x6b4;
157 }
158}
159
160// FUNCTION: LEGO1 0x100c5db0
161// FUNCTION: BETA10 0x10152391
163 MxBITMAPINFO* p_bitmapInfo,
164 MxU8* p_bitmapData,
165 MxSmk* p_mxSmk,
166 MxU8* p_chunkData,
167 MxBool p_paletteChanged,
168 MxRect32List* p_list
169)
170{
171 p_bitmapInfo->m_bmiHeader.biHeight = -MxBitmap::HeightAbs(p_bitmapInfo->m_bmiHeader.biHeight);
172 *(MxU8**) (p_mxSmk->m_unk0x6b4 + 4) = p_bitmapData;
173
174 // Reference: https://wiki.multimedia.cx/index.php/Smacker#Palette_Chunk
175 if (p_paletteChanged) {
176 MxU8 palette[772];
177
178 MxU8* intoChunk = p_chunkData + 1;
179 MxU8* intoPalette = palette;
180 MxU16 paletteIndex = 0;
181 // TODO: struct incorrect, Palette at wrong offset?
182 MxU8* currentPalette = &p_mxSmk->m_smackTag.Palette[4];
183
184 do {
185 if (*intoChunk & 0x80) {
186 MxU8 length = (*intoChunk & 0x7f) + 1;
187 memcpy(intoPalette, &currentPalette[paletteIndex * 3], length * 3);
188 intoPalette += length * 3;
189 paletteIndex += length;
190 intoChunk++;
191 }
192 else {
193 if (*intoChunk & 0x40) {
194 MxU8 length = (*intoChunk & 0x3f) + 1;
195 memcpy(intoPalette, &currentPalette[*(intoChunk + 1) * 3], length * 3);
196 intoPalette += length * 3;
197 paletteIndex += length;
198 intoChunk += 2;
199 }
200 else {
201 *(MxU32*) intoPalette = *(MxU32*) intoChunk;
202 intoPalette += 3;
203 paletteIndex++;
204 intoChunk += 3;
205 }
206 }
207 } while (paletteIndex < 256);
208
209 for (MxU32 i = 0; i < 256; i++) {
210 memcpy(currentPalette, &palette[i * 3], 3);
211 currentPalette += 3;
212 p_bitmapInfo->m_bmiColors[i].rgbBlue = palette[i * 3 + 2] * 4;
213 p_bitmapInfo->m_bmiColors[i].rgbGreen = palette[i * 3 + 1] * 4;
214 p_bitmapInfo->m_bmiColors[i].rgbRed = palette[i * 3] * 4;
215 }
216
217 p_chunkData += *p_chunkData * 4;
218 }
219
220 SmackDoFrameToBuffer(p_chunkData, p_mxSmk->m_huffmanTables, p_mxSmk->m_unk0x6b4);
221
222 MxU16 und = 1;
223 u32 smackRect[4];
224 MxRect32 rect;
225
226 while (GetRect(p_mxSmk->m_unk0x6b4, &und, smackRect, &rect)) {
227 MxRect32* newRect = new MxRect32(rect);
228 p_list->Append(newRect);
229 }
230
231 return SUCCESS;
232}
233
234// FUNCTION: LEGO1 0x100c6050
235// FUNCTION: BETA10 0x10152739
236MxBool MxSmk::GetRect(MxU8* p_unk0x6b4, MxU16* p_und, u32* p_smackRect, MxRect32* p_rect)
237{
238 u32 left, bottom, top, right;
239
240 if (!*p_und) {
241 return FALSE;
242 }
243
244 if (*p_und == 1) {
245 if (!SmackGetRect(p_unk0x6b4, p_smackRect)) {
246 return FALSE;
247 }
248 *p_und = 2;
249 }
250
251 left = p_smackRect[0];
252 top = p_smackRect[1];
253 right = p_smackRect[2] + p_smackRect[0];
254 bottom = p_smackRect[3] + p_smackRect[1];
255
256 while (SmackGetRect(p_unk0x6b4, p_smackRect)) {
257 if (left > p_smackRect[0]) {
258 left = p_smackRect[0];
259 }
260 if (right < p_smackRect[0] + p_smackRect[2]) {
261 right = p_smackRect[0] + p_smackRect[2];
262 }
263
264 bottom = p_smackRect[1] + p_smackRect[3];
265 }
266
267 *p_und = 0;
268 *p_rect = MxRect32(left, top, right, bottom);
269 return TRUE;
270}
static MxLong HeightAbs(MxLong p_value)
[AI] Returns the absolute value of the input height (for DIBs).
Definition: mxbitmap.h:212
void Append(T p_obj)
[AI]
Definition: mxlist.h:100
[AI] List for pointers to MxRect32 rectangles.
Definition: mxgeometry.h:749
[AI] Rectangle using 32-bit signed integer coordinates.
Definition: mxgeometry.h:706
#define TRUE
Definition: d3drmdef.h:28
#define FALSE
Definition: d3drmdef.h:27
#define DECOMP_SIZE_ASSERT(T, S)
Definition: decomp.h:19
#define NULL
[AI] Null pointer value (C/C++ semantics).
Definition: legotypes.h:26
#define FAILURE
[AI] Used to indicate a failed operation in result codes.
Definition: legotypes.h:34
#define SUCCESS
[AI] Used to indicate a successful operation in result codes.
Definition: legotypes.h:30
#define FRAME_COUNT(_tag)
void SmackDoTables(u8 *p_huffmanTrees, u8 *p_huffmanTables, u32 p_codeSize, u32 p_abSize, u32 p_detailSize, u32 p_typeSize)
[AI] Generates Huffman tables required for decoding a Smacker frame.
u32 SmackGetSizeDeltas(u32 p_width, u32 p_height)
[AI] Returns the size required for frame delta data given width and height.
u8 SmackGetRect(u8 *p_unk0x6b4, u32 *p_rect)
[AI] Reads a rectangle from the frame update information.
void SmackDoFrameToBuffer(u8 *p_source, u8 *p_huffmanTables, u8 *p_unk0x6b4)
[AI] Decompress a single Smacker video frame into a provided buffer.
u32 SmackGetSizeTables()
[AI] External functions from SMACK.LIB used for decoding Smacker video data.
MxU8 MxBool
[AI]
Definition: mxtypes.h:124
MxLong MxResult
[AI]
Definition: mxtypes.h:106
unsigned char MxU8
[AI]
Definition: mxtypes.h:8
signed int MxS32
[AI]
Definition: mxtypes.h:38
unsigned short MxU16
[AI]
Definition: mxtypes.h:20
unsigned int MxU32
[AI]
Definition: mxtypes.h:32
#define u32
Definition: rad.h:147
#define SmackHeaderSize(smk)
Definition: smack.h:60
[AI] Represents a bitmap information header plus a 256-color palette, matching the layout for 8-bit D...
Definition: mxbitmap.h:25
RGBQUAD m_bmiColors[256]
[AI] 256-entry color palette for 8bpp images.
Definition: mxbitmap.h:27
BITMAPINFOHEADER m_bmiHeader
[AI] Standard DIB bitmap header (size 0x28 bytes).
Definition: mxbitmap.h:26
[AI] The MxSmk struct encapsulates all data required to decode and display a Smacker (SMK) video stre...
Definition: mxsmk.h:77
MxU32 * m_frameSizes
[AI] Array of frame sizes (in bytes), one entry per video frame (plus ring frame if present).
Definition: mxsmk.h:80
MxU8 * m_huffmanTrees
[AI] Huffman trees used for decompressing video frames.
Definition: mxsmk.h:82
MxU32 m_maxFrameSize
[AI] Maximum size of any frame, used for allocation.
Definition: mxsmk.h:84
static MxResult LoadFrame(MxBITMAPINFO *p_bitmapInfo, MxU8 *p_bitmapData, MxSmk *p_mxSmk, MxU8 *p_chunkData, MxBool p_paletteChanged, MxRect32List *p_list)
[AI] Decompresses and loads a single Smacker frame into a bitmap buffer, updating palette if needed.
Definition: mxsmk.cpp:162
MxU8 * m_unk0x6b4
[AI] Buffer/context for decoding frame delta data; referenced throughout decompression ([AI_SUGGESTED...
Definition: mxsmk.h:85
MxU8 * m_frameTypes
[AI] Array of frame types, one entry per frame.
Definition: mxsmk.h:81
static void Destroy(MxSmk *p_mxSmk)
[AI] Cleans up and deallocates all resources associated with this MxSmk.
Definition: mxsmk.cpp:141
static MxResult LoadHeader(MxU8 *p_data, MxSmk *p_mxSmk)
[AI] Loads the SMK header and initializes decoding structures for a Smacker video.
Definition: mxsmk.cpp:12
MxU8 * m_huffmanTables
[AI] Generated decoding tables for use in SmackDoFrameToBuffer.
Definition: mxsmk.h:83
SmackTag m_smackTag
[AI] Metadata block from the Smacker file header.
Definition: mxsmk.h:78
static MxBool GetRect(MxU8 *p_unk0x6b4, MxU16 *p_und, u32 *p_smackRect, MxRect32 *p_rect)
[AI] Retrieves and merges rectangles describing updated regions of the current frame.
Definition: mxsmk.cpp:236
Definition: smack.h:33
u32 Width
Definition: smack.h:35
u32 absize
Definition: smack.h:43
u32 detailsize
Definition: smack.h:44
u32 Height
Definition: smack.h:36
u8 Palette[772]
Definition: smack.h:49
u32 codesize
Definition: smack.h:42
u32 typesize
Definition: smack.h:45
u32 tablesize
Definition: smack.h:41