mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-02-13 07:31:04 +00:00
Read whole chunks at a time from Interplay MVE files
This commit is contained in:
parent
80bf62cb3c
commit
fa2cea3e5b
2 changed files with 237 additions and 130 deletions
|
@ -89,8 +89,10 @@ static const int16_t delta_table[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// macro to fetch 16-bit little-endian words from a bytestream
|
// macros to fetch little-endian words from a bytestream
|
||||||
#define LE_16(x) ((*x) | ((*(x+1)) << 8))
|
#define LE_16(x) ((uint16_t)((*(x)) | ((*((x)+1)) << 8)))
|
||||||
|
#define LE_32(x) (LE_16(x) | ((uint32_t)LE_16(x+2) << 16))
|
||||||
|
#define LE_64(x) (LE_32(x) | ((uint64_t)LE_32(x+4) << 32))
|
||||||
|
|
||||||
static bool StreamCallbackFunc(SoundStream* stream, void* buff, int len, void* userdata)
|
static bool StreamCallbackFunc(SoundStream* stream, void* buff, int len, void* userdata)
|
||||||
{
|
{
|
||||||
|
@ -218,71 +220,70 @@ bool InterplayDecoder::RunFrame(uint64_t clock)
|
||||||
chunkSize = LE_16(&chunkPreamble[0]);
|
chunkSize = LE_16(&chunkPreamble[0]);
|
||||||
chunkType = LE_16(&chunkPreamble[2]);
|
chunkType = LE_16(&chunkPreamble[2]);
|
||||||
|
|
||||||
// iterate through individual opcodes
|
ChunkData.resize(chunkSize);
|
||||||
while (chunkSize > 0)
|
if (fr.Read(ChunkData.data(), chunkSize) != chunkSize) {
|
||||||
{
|
|
||||||
if (fr.Read(opcodePreamble, OPCODE_PREAMBLE_SIZE) != OPCODE_PREAMBLE_SIZE)
|
|
||||||
{
|
|
||||||
Printf(TEXTCOLOR_RED "InterplayDecoder: could not read from file (EOF?)\n");
|
Printf(TEXTCOLOR_RED "InterplayDecoder: could not read from file (EOF?)\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
opcodeSize = LE_16(&opcodePreamble[0]);
|
// iterate through individual opcodes
|
||||||
opcodeType = opcodePreamble[2];
|
ChunkPtr = ChunkData.data();
|
||||||
opcodeVersion = opcodePreamble[3];
|
while (chunkSize > 0 && chunkType != CHUNK_BAD)
|
||||||
|
{
|
||||||
|
if (chunkSize < OPCODE_PREAMBLE_SIZE)
|
||||||
|
{
|
||||||
|
Printf(TEXTCOLOR_RED "InterplayDecoder: opcode size too small\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
opcodeSize = LE_16(ChunkPtr);
|
||||||
|
opcodeType = ChunkPtr[2];
|
||||||
|
opcodeVersion = ChunkPtr[3];
|
||||||
|
|
||||||
|
ChunkPtr += OPCODE_PREAMBLE_SIZE;
|
||||||
chunkSize -= OPCODE_PREAMBLE_SIZE;
|
chunkSize -= OPCODE_PREAMBLE_SIZE;
|
||||||
|
if (chunkSize < opcodeSize)
|
||||||
|
{
|
||||||
|
Printf(TEXTCOLOR_RED "InterplayDecoder: opcode size too large for chunk\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
chunkSize -= opcodeSize;
|
chunkSize -= opcodeSize;
|
||||||
|
|
||||||
switch (opcodeType)
|
switch (opcodeType)
|
||||||
{
|
{
|
||||||
case OPCODE_END_OF_STREAM:
|
case OPCODE_END_OF_STREAM:
|
||||||
{
|
{
|
||||||
fr.Seek(opcodeSize, FileReader::SeekCur);
|
ChunkPtr += opcodeSize;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OPCODE_END_OF_CHUNK:
|
case OPCODE_END_OF_CHUNK:
|
||||||
{
|
{
|
||||||
fr.Seek(opcodeSize, FileReader::SeekCur);
|
ChunkPtr += opcodeSize;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OPCODE_CREATE_TIMER:
|
case OPCODE_CREATE_TIMER:
|
||||||
{
|
{
|
||||||
nTimerRate = fr.ReadUInt32();
|
nTimerRate = LE_32(ChunkPtr);
|
||||||
nTimerDiv = fr.ReadUInt16();
|
nTimerDiv = LE_16(ChunkPtr+4);
|
||||||
|
ChunkPtr += 6;
|
||||||
nFrameDuration = ((uint64_t)nTimerRate * nTimerDiv) * 1000;
|
nFrameDuration = ((uint64_t)nTimerRate * nTimerDiv) * 1000;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OPCODE_INIT_AUDIO_BUFFERS:
|
case OPCODE_INIT_AUDIO_BUFFERS:
|
||||||
{
|
{
|
||||||
fr.Seek(2, FileReader::SeekCur);
|
// Skip 2 bytes
|
||||||
uint16_t flags = fr.ReadUInt16();
|
uint16_t flags = LE_16(ChunkPtr+2);
|
||||||
audio.nSampleRate = fr.ReadUInt16();
|
audio.nSampleRate = LE_16(ChunkPtr+4);
|
||||||
|
ChunkPtr += 6;
|
||||||
|
|
||||||
uint32_t nBufferBytes;
|
uint32_t nBufferBytes = (opcodeVersion == 0) ? LE_16(ChunkPtr) : LE_32(ChunkPtr);
|
||||||
|
ChunkPtr += (opcodeVersion == 0) ? 2 : 4;
|
||||||
|
|
||||||
if (opcodeVersion == 0) {
|
audio.nChannels = (flags & 0x1) ? 2 : 1;
|
||||||
nBufferBytes = fr.ReadUInt16();
|
audio.nBitDepth = (flags & 0x2) ? 16 : 8;
|
||||||
}
|
audio.bCompressed = (opcodeVersion > 0 && (flags & 0x4));
|
||||||
else {
|
|
||||||
nBufferBytes = fr.ReadUInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & 0x1) {
|
|
||||||
audio.nChannels = 2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
audio.nChannels = 1;
|
|
||||||
}
|
|
||||||
if (flags & 0x2) {
|
|
||||||
audio.nBitDepth = 16;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
audio.nBitDepth = 8;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,24 +291,37 @@ bool InterplayDecoder::RunFrame(uint64_t clock)
|
||||||
{
|
{
|
||||||
if (!bAudioStarted)
|
if (!bAudioStarted)
|
||||||
{
|
{
|
||||||
|
S_StopMusic(true);
|
||||||
// start audio playback
|
// start audio playback
|
||||||
stream = S_CreateCustomStream(6000, audio.nSampleRate, audio.nChannels, MusicSamples16bit, StreamCallbackFunc, this);
|
stream = S_CreateCustomStream(6000, audio.nSampleRate, audio.nChannels, MusicSamples16bit, StreamCallbackFunc, this);
|
||||||
bAudioStarted = true;
|
bAudioStarted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fr.Seek(opcodeSize, FileReader::SeekCur);
|
ChunkPtr += opcodeSize;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OPCODE_INIT_VIDEO_BUFFERS:
|
case OPCODE_INIT_VIDEO_BUFFERS:
|
||||||
{
|
{
|
||||||
assert(opcodeSize == 8);
|
assert(((opcodeVersion == 0 && opcodeSize >= 4) ||
|
||||||
nWidth = fr.ReadUInt16() * 8;
|
(opcodeVersion == 1 && opcodeSize >= 6) ||
|
||||||
nHeight = fr.ReadUInt16() * 8;
|
(opcodeVersion == 2 && opcodeSize >= 8)) &&
|
||||||
|
opcodeSize <= 8);
|
||||||
|
|
||||||
int count = fr.ReadUInt16();
|
nWidth = LE_16(ChunkPtr) * 8;
|
||||||
int truecolour = fr.ReadUInt16();
|
nHeight = LE_16(ChunkPtr+2) * 8;
|
||||||
|
|
||||||
|
int count, truecolour;
|
||||||
|
if (opcodeVersion > 0)
|
||||||
|
{
|
||||||
|
count = LE_16(ChunkPtr+4);
|
||||||
|
if (opcodeVersion > 1)
|
||||||
|
{
|
||||||
|
truecolour = LE_16(ChunkPtr+6);
|
||||||
assert(truecolour == 0);
|
assert(truecolour == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ChunkPtr += opcodeSize;
|
||||||
|
|
||||||
pVideoBuffers[0] = new uint8_t[nWidth * nHeight];
|
pVideoBuffers[0] = new uint8_t[nWidth * nHeight];
|
||||||
pVideoBuffers[1] = new uint8_t[nWidth * nHeight];
|
pVideoBuffers[1] = new uint8_t[nWidth * nHeight];
|
||||||
|
@ -326,83 +340,143 @@ bool InterplayDecoder::RunFrame(uint64_t clock)
|
||||||
case OPCODE_UNKNOWN_14:
|
case OPCODE_UNKNOWN_14:
|
||||||
case OPCODE_UNKNOWN_15:
|
case OPCODE_UNKNOWN_15:
|
||||||
{
|
{
|
||||||
fr.Seek(opcodeSize, FileReader::SeekCur);
|
ChunkPtr += opcodeSize;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OPCODE_SEND_BUFFER:
|
case OPCODE_SEND_BUFFER:
|
||||||
{
|
{
|
||||||
int nPalStart = fr.ReadUInt16();
|
int nPalStart = LE_16(ChunkPtr);
|
||||||
int nPalCount = fr.ReadUInt16();
|
int nPalCount = LE_16(ChunkPtr+2);
|
||||||
|
ChunkPtr += opcodeSize;
|
||||||
|
|
||||||
animtex.SetFrame(&palette[0].r , GetCurrentFrame());
|
animtex.SetFrame(&palette[0].r , GetCurrentFrame());
|
||||||
|
|
||||||
nFrame++;
|
nFrame++;
|
||||||
SwapFrames();
|
SwapFrames();
|
||||||
|
|
||||||
fr.Seek(opcodeSize-4, FileReader::SeekCur);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OPCODE_AUDIO_FRAME:
|
case OPCODE_AUDIO_FRAME:
|
||||||
{
|
{
|
||||||
int nStart = (int)fr.Tell();
|
auto pStart = ChunkPtr;
|
||||||
uint16_t seqIndex = fr.ReadUInt16();
|
uint16_t seqIndex = LE_16(ChunkPtr);
|
||||||
uint16_t streamMask = fr.ReadUInt16();
|
uint16_t streamMask = LE_16(ChunkPtr+2);
|
||||||
uint16_t nSamples = fr.ReadUInt16(); // number of samples this chunk
|
uint16_t nSamples = LE_16(ChunkPtr+4); // number of samples this chunk(?)
|
||||||
|
ChunkPtr += 6;
|
||||||
|
|
||||||
|
// We only bother with stream 0
|
||||||
|
if (!(streamMask & 1))
|
||||||
|
{
|
||||||
|
ChunkPtr += opcodeSize - 6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nSamples = opcodeSize - 6;
|
||||||
|
if (audio.bCompressed)
|
||||||
|
{
|
||||||
int predictor[2];
|
int predictor[2];
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for (int ch = 0; ch < audio.nChannels; ch++)
|
for (int ch = 0; ch < audio.nChannels; ch++)
|
||||||
{
|
{
|
||||||
predictor[ch] = fr.ReadUInt16();
|
predictor[ch] = (int16_t)LE_16(ChunkPtr);
|
||||||
i++;
|
ChunkPtr += 2;
|
||||||
|
|
||||||
if (predictor[ch] & 0x8000) {
|
|
||||||
predictor[ch] |= 0xFFFF0000; // sign extend
|
|
||||||
}
|
|
||||||
|
|
||||||
audio.samples[audio.nWrite++] = predictor[ch];
|
audio.samples[audio.nWrite++] = predictor[ch];
|
||||||
if (audio.nWrite >= (int)countof(audio.samples)) audio.nWrite = 0;
|
if (audio.nWrite >= (int)countof(audio.samples)) audio.nWrite = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool stereo = audio.nChannels == 2;
|
||||||
|
nSamples -= 2*audio.nChannels;
|
||||||
|
nSamples &= ~(int)stereo;
|
||||||
|
|
||||||
int ch = 0;
|
int ch = 0;
|
||||||
for (; i < (nSamples / 2); i++)
|
for (int i = 0; i < nSamples;)
|
||||||
{
|
{
|
||||||
predictor[ch] += delta_table[fr.ReadUInt8()];
|
int todo = std::min(nSamples-i, (int)std::size(audio.samples)-audio.nWrite);
|
||||||
predictor[ch] = clamp(predictor[ch], -32768, 32768);
|
auto end = ChunkPtr + todo;
|
||||||
|
while(ChunkPtr != end)
|
||||||
|
{
|
||||||
|
predictor[ch] += delta_table[*ChunkPtr++];
|
||||||
|
predictor[ch] = clamp(predictor[ch], -32768, 32767);
|
||||||
|
|
||||||
audio.samples[audio.nWrite++] = predictor[ch];
|
audio.samples[audio.nWrite++] = predictor[ch];
|
||||||
if (audio.nWrite >= (int)countof(audio.samples)) audio.nWrite = 0;
|
|
||||||
|
|
||||||
// toggle channel
|
// toggle channel
|
||||||
ch ^= audio.nChannels - 1;
|
ch ^= stereo;
|
||||||
|
}
|
||||||
|
if (audio.nWrite >= (int)countof(audio.samples)) audio.nWrite = 0;
|
||||||
|
i += todo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (audio.nBitDepth == 8)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < nSamples;)
|
||||||
|
{
|
||||||
|
int todo = std::min(nSamples-i, (int)std::size(audio.samples)-audio.nWrite);
|
||||||
|
auto end = ChunkPtr + todo;
|
||||||
|
while(ChunkPtr != end)
|
||||||
|
audio.samples[audio.nWrite++] = ((*ChunkPtr++)-128) << 8;
|
||||||
|
if (audio.nWrite >= (int)countof(audio.samples)) audio.nWrite = 0;
|
||||||
|
i += todo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nSamples /= 2;
|
||||||
|
for (int i = 0; i < nSamples;)
|
||||||
|
{
|
||||||
|
int todo = std::min(nSamples-i, (int)std::size(audio.samples)-audio.nWrite);
|
||||||
|
auto end = ChunkPtr + todo*2;
|
||||||
|
while(ChunkPtr != end)
|
||||||
|
{
|
||||||
|
audio.samples[audio.nWrite++] = (int16_t)LE_16(ChunkPtr);
|
||||||
|
ChunkPtr += 2;
|
||||||
|
}
|
||||||
|
if (audio.nWrite >= (int)countof(audio.samples)) audio.nWrite = 0;
|
||||||
|
i += todo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int nEnd = (int)fr.Tell();
|
auto pEnd = ChunkPtr;
|
||||||
int nRead = nEnd - nStart;
|
int nRead = (int)(pEnd - pStart);
|
||||||
assert(opcodeSize == nRead);
|
assert(opcodeSize == nRead);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OPCODE_SILENCE_FRAME:
|
case OPCODE_SILENCE_FRAME:
|
||||||
{
|
{
|
||||||
uint16_t seqIndex = fr.ReadUInt16();
|
uint16_t seqIndex = LE_16(ChunkPtr);
|
||||||
uint16_t streamMask = fr.ReadUInt16();
|
uint16_t streamMask = LE_16(ChunkPtr+2);
|
||||||
uint16_t nStreamLen = fr.ReadUInt16();
|
uint16_t nStreamLen = LE_16(ChunkPtr+4);
|
||||||
|
ChunkPtr += 6;
|
||||||
|
|
||||||
|
if (streamMask & 1)
|
||||||
|
{
|
||||||
|
nStreamLen = (opcodeSize-6) * 8 / audio.nBitDepth;
|
||||||
|
|
||||||
|
for (int i = 0; i < nStreamLen;)
|
||||||
|
{
|
||||||
|
int todo = std::min(nStreamLen-i, (int)std::size(audio.samples)-audio.nWrite);
|
||||||
|
memset(&audio.samples[audio.nWrite], 0, todo*2);
|
||||||
|
audio.nWrite += todo;
|
||||||
|
if (audio.nWrite >= (int)countof(audio.samples)) audio.nWrite = 0;
|
||||||
|
i += todo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OPCODE_INIT_VIDEO_MODE:
|
case OPCODE_INIT_VIDEO_MODE:
|
||||||
{
|
{
|
||||||
fr.Seek(opcodeSize, FileReader::SeekCur);
|
ChunkPtr += opcodeSize;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OPCODE_CREATE_GRADIENT:
|
case OPCODE_CREATE_GRADIENT:
|
||||||
{
|
{
|
||||||
fr.Seek(opcodeSize, FileReader::SeekCur);
|
ChunkPtr += opcodeSize;
|
||||||
Printf("InterplayDecoder: Create gradient not supported.\n");
|
Printf("InterplayDecoder: Create gradient not supported.\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -415,20 +489,29 @@ bool InterplayDecoder::RunFrame(uint64_t clock)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nPalStart = fr.ReadUInt16();
|
int nPalStart = LE_16(ChunkPtr);
|
||||||
int nPalCount = fr.ReadUInt16();
|
int nPalEnd = nPalStart + LE_16(ChunkPtr+2) - 1;
|
||||||
for (int i = nPalStart; i <= nPalCount; i++)
|
ChunkPtr += 4;
|
||||||
|
if (nPalStart > 255 || nPalEnd > 255) {
|
||||||
|
Printf("set_palette indices out of range (%d -> %d)\n", nPalStart, nPalEnd);
|
||||||
|
chunkType = CHUNK_BAD;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (int i = nPalStart; i <= nPalEnd; i++)
|
||||||
{
|
{
|
||||||
palette[i].r = fr.ReadUInt8() << 2;
|
palette[i].r = (*ChunkPtr++) << 2;
|
||||||
palette[i].g = fr.ReadUInt8() << 2;
|
palette[i].g = (*ChunkPtr++) << 2;
|
||||||
palette[i].b = fr.ReadUInt8() << 2;
|
palette[i].b = (*ChunkPtr++) << 2;
|
||||||
|
palette[i].r |= palette[i].r >> 6;
|
||||||
|
palette[i].g |= palette[i].g >> 6;
|
||||||
|
palette[i].b |= palette[i].b >> 6;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OPCODE_SET_PALETTE_COMPRESSED:
|
case OPCODE_SET_PALETTE_COMPRESSED:
|
||||||
{
|
{
|
||||||
fr.Seek(opcodeSize, FileReader::SeekCur);
|
ChunkPtr += opcodeSize;
|
||||||
Printf("InterplayDecoder: Set palette compressed not supported.\n");
|
Printf("InterplayDecoder: Set palette compressed not supported.\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -449,17 +532,17 @@ bool InterplayDecoder::RunFrame(uint64_t clock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int nRead = (int)fr.Read(decodeMap.pData, opcodeSize);
|
memcpy(decodeMap.pData, ChunkPtr, opcodeSize);
|
||||||
assert(nRead == opcodeSize);
|
ChunkPtr += opcodeSize;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OPCODE_VIDEO_DATA:
|
case OPCODE_VIDEO_DATA:
|
||||||
{
|
{
|
||||||
int nStart = (int)fr.Tell();
|
auto pStart = ChunkPtr;
|
||||||
|
|
||||||
// need to skip 14 bytes
|
// need to skip 14 bytes
|
||||||
fr.Seek(14, FileReader::SeekCur);
|
ChunkPtr += 14;
|
||||||
|
|
||||||
if (decodeMap.nSize)
|
if (decodeMap.nSize)
|
||||||
{
|
{
|
||||||
|
@ -536,11 +619,11 @@ bool InterplayDecoder::RunFrame(uint64_t clock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int nEnd = (int)fr.Tell();
|
auto pEnd = ChunkPtr;
|
||||||
int nSkipBytes = opcodeSize - (nEnd - nStart); // we can end up with 1 byte left we need to skip
|
int nSkipBytes = opcodeSize - (int)(pEnd - pStart); // we can end up with 1 byte left we need to skip
|
||||||
assert(nSkipBytes <= 1);
|
assert(nSkipBytes <= 1);
|
||||||
|
|
||||||
fr.Seek(nSkipBytes, FileReader::SeekCur);
|
ChunkPtr += nSkipBytes;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,7 +664,7 @@ void InterplayDecoder::DecodeBlock1(int32_t offset)
|
||||||
void InterplayDecoder::DecodeBlock2(int32_t offset)
|
void InterplayDecoder::DecodeBlock2(int32_t offset)
|
||||||
{
|
{
|
||||||
// copy block from 2 frames ago using a motion vector; need 1 more byte
|
// copy block from 2 frames ago using a motion vector; need 1 more byte
|
||||||
uint8_t B = fr.ReadUInt8();
|
uint8_t B = *ChunkPtr++;
|
||||||
|
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
|
@ -603,7 +686,7 @@ void InterplayDecoder::DecodeBlock2(int32_t offset)
|
||||||
void InterplayDecoder::DecodeBlock3(int32_t offset)
|
void InterplayDecoder::DecodeBlock3(int32_t offset)
|
||||||
{
|
{
|
||||||
// copy 8x8 block from current frame from an up/left block
|
// copy 8x8 block from current frame from an up/left block
|
||||||
uint8_t B = fr.ReadUInt8();
|
uint8_t B = *ChunkPtr++;
|
||||||
|
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
|
@ -629,7 +712,7 @@ void InterplayDecoder::DecodeBlock4(int32_t offset)
|
||||||
int x, y;
|
int x, y;
|
||||||
uint8_t B, BL, BH;
|
uint8_t B, BL, BH;
|
||||||
|
|
||||||
B = fr.ReadUInt8();
|
B = *ChunkPtr++;
|
||||||
|
|
||||||
BL = B & 0x0F;
|
BL = B & 0x0F;
|
||||||
BH = (B >> 4) & 0x0F;
|
BH = (B >> 4) & 0x0F;
|
||||||
|
@ -645,8 +728,8 @@ void InterplayDecoder::DecodeBlock4(int32_t offset)
|
||||||
void InterplayDecoder::DecodeBlock5(int32_t offset)
|
void InterplayDecoder::DecodeBlock5(int32_t offset)
|
||||||
{
|
{
|
||||||
// copy a block from the previous frame using an expanded range; need 2 more bytes
|
// copy a block from the previous frame using an expanded range; need 2 more bytes
|
||||||
int8_t x = fr.ReadUInt8();
|
int8_t x = *ChunkPtr++;
|
||||||
int8_t y = fr.ReadUInt8();
|
int8_t y = *ChunkPtr++;
|
||||||
|
|
||||||
uint8_t* pDest = GetCurrentFrame() + (intptr_t)offset;
|
uint8_t* pDest = GetCurrentFrame() + (intptr_t)offset;
|
||||||
uint8_t* pSrc = GetPreviousFrame() + (intptr_t)(int64_t)offset + (int64_t)x + (int64_t(y) * (int64_t)videoStride);
|
uint8_t* pSrc = GetPreviousFrame() + (intptr_t)(int64_t)offset + (int64_t)x + (int64_t(y) * (int64_t)videoStride);
|
||||||
|
@ -662,8 +745,8 @@ void InterplayDecoder::DecodeBlock7(int32_t offset)
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
|
|
||||||
uint8_t P[2];
|
uint8_t P[2];
|
||||||
P[0] = fr.ReadUInt8();
|
P[0] = *ChunkPtr++;
|
||||||
P[1] = fr.ReadUInt8();
|
P[1] = *ChunkPtr++;
|
||||||
|
|
||||||
// 2-color encoding
|
// 2-color encoding
|
||||||
if (P[0] <= P[1])
|
if (P[0] <= P[1])
|
||||||
|
@ -671,7 +754,7 @@ void InterplayDecoder::DecodeBlock7(int32_t offset)
|
||||||
// need 8 more bytes from the stream
|
// need 8 more bytes from the stream
|
||||||
for (int y = 0; y < 8; y++)
|
for (int y = 0; y < 8; y++)
|
||||||
{
|
{
|
||||||
flags = fr.ReadUInt8() | 0x100;
|
flags = (*ChunkPtr++) | 0x100;
|
||||||
for (; flags != 1; flags >>= 1) {
|
for (; flags != 1; flags >>= 1) {
|
||||||
*pBuffer++ = P[flags & 1];
|
*pBuffer++ = P[flags & 1];
|
||||||
}
|
}
|
||||||
|
@ -681,7 +764,8 @@ void InterplayDecoder::DecodeBlock7(int32_t offset)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// need 2 more bytes from the stream
|
// need 2 more bytes from the stream
|
||||||
flags = fr.ReadUInt16();
|
flags = LE_16(ChunkPtr);
|
||||||
|
ChunkPtr += 2;
|
||||||
|
|
||||||
for (int y = 0; y < 8; y += 2)
|
for (int y = 0; y < 8; y += 2)
|
||||||
{
|
{
|
||||||
|
@ -704,8 +788,8 @@ void InterplayDecoder::DecodeBlock8(int32_t offset)
|
||||||
uint8_t P[4];
|
uint8_t P[4];
|
||||||
|
|
||||||
// 2-color encoding for each 4x4 quadrant, or 2-color encoding on either top and bottom or left and right halves
|
// 2-color encoding for each 4x4 quadrant, or 2-color encoding on either top and bottom or left and right halves
|
||||||
P[0] = fr.ReadUInt8();
|
P[0] = *ChunkPtr++;
|
||||||
P[1] = fr.ReadUInt8();
|
P[1] = *ChunkPtr++;
|
||||||
|
|
||||||
if (P[0] <= P[1])
|
if (P[0] <= P[1])
|
||||||
{
|
{
|
||||||
|
@ -715,10 +799,11 @@ void InterplayDecoder::DecodeBlock8(int32_t offset)
|
||||||
if (!(y & 3))
|
if (!(y & 3))
|
||||||
{
|
{
|
||||||
if (y) {
|
if (y) {
|
||||||
P[0] = fr.ReadUInt8();
|
P[0] = *ChunkPtr++;
|
||||||
P[1] = fr.ReadUInt8();
|
P[1] = *ChunkPtr++;
|
||||||
}
|
}
|
||||||
flags = fr.ReadUInt16();
|
flags = LE_16(ChunkPtr);
|
||||||
|
ChunkPtr += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int x = 0; x < 4; x++, flags >>= 1) {
|
for (int x = 0; x < 4; x++, flags >>= 1) {
|
||||||
|
@ -732,9 +817,10 @@ void InterplayDecoder::DecodeBlock8(int32_t offset)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
flags = fr.ReadUInt32();
|
flags = LE_32(ChunkPtr);
|
||||||
P[2] = fr.ReadUInt8();
|
ChunkPtr += 4;
|
||||||
P[3] = fr.ReadUInt8();
|
P[2] = *ChunkPtr++;
|
||||||
|
P[3] = *ChunkPtr++;
|
||||||
|
|
||||||
if (P[2] <= P[3])
|
if (P[2] <= P[3])
|
||||||
{
|
{
|
||||||
|
@ -752,7 +838,8 @@ void InterplayDecoder::DecodeBlock8(int32_t offset)
|
||||||
pBuffer -= 8 * videoStride - 4;
|
pBuffer -= 8 * videoStride - 4;
|
||||||
P[0] = P[2];
|
P[0] = P[2];
|
||||||
P[1] = P[3];
|
P[1] = P[3];
|
||||||
flags = fr.ReadUInt32();
|
flags = LE_32(ChunkPtr);
|
||||||
|
ChunkPtr += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -764,7 +851,8 @@ void InterplayDecoder::DecodeBlock8(int32_t offset)
|
||||||
if (y == 4) {
|
if (y == 4) {
|
||||||
P[0] = P[2];
|
P[0] = P[2];
|
||||||
P[1] = P[3];
|
P[1] = P[3];
|
||||||
flags = fr.ReadUInt32();
|
flags = LE_32(ChunkPtr);
|
||||||
|
ChunkPtr += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int x = 0; x < 8; x++, flags >>= 1)
|
for (int x = 0; x < 8; x++, flags >>= 1)
|
||||||
|
@ -781,7 +869,8 @@ void InterplayDecoder::DecodeBlock9(int32_t offset)
|
||||||
uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset;
|
uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset;
|
||||||
uint8_t P[4];
|
uint8_t P[4];
|
||||||
|
|
||||||
fr.Read(P, 4);
|
memcpy(P, ChunkPtr, 4);
|
||||||
|
ChunkPtr += 4;
|
||||||
|
|
||||||
// 4-color encoding
|
// 4-color encoding
|
||||||
if (P[0] <= P[1])
|
if (P[0] <= P[1])
|
||||||
|
@ -792,7 +881,8 @@ void InterplayDecoder::DecodeBlock9(int32_t offset)
|
||||||
for (int y = 0; y < 8; y++)
|
for (int y = 0; y < 8; y++)
|
||||||
{
|
{
|
||||||
// get the next set of 8 2-bit flags
|
// get the next set of 8 2-bit flags
|
||||||
int flags = fr.ReadUInt16();
|
int flags = LE_16(ChunkPtr);
|
||||||
|
ChunkPtr += 2;
|
||||||
|
|
||||||
for (int x = 0; x < 8; x++, flags >>= 2) {
|
for (int x = 0; x < 8; x++, flags >>= 2) {
|
||||||
*pBuffer++ = P[flags & 0x03];
|
*pBuffer++ = P[flags & 0x03];
|
||||||
|
@ -804,7 +894,8 @@ void InterplayDecoder::DecodeBlock9(int32_t offset)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 1 of 4 colors for each 2x2 block, need 4 more bytes
|
// 1 of 4 colors for each 2x2 block, need 4 more bytes
|
||||||
uint32_t flags = fr.ReadUInt32();
|
uint32_t flags = LE_32(ChunkPtr);
|
||||||
|
ChunkPtr += 4;
|
||||||
|
|
||||||
for (int y = 0; y < 8; y += 2)
|
for (int y = 0; y < 8; y += 2)
|
||||||
{
|
{
|
||||||
|
@ -823,7 +914,8 @@ void InterplayDecoder::DecodeBlock9(int32_t offset)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 1 of 4 colors for each 2x1 or 1x2 block, need 8 more bytes
|
// 1 of 4 colors for each 2x1 or 1x2 block, need 8 more bytes
|
||||||
uint64_t flags = fr.ReadUInt64();
|
uint64_t flags = LE_64(ChunkPtr);
|
||||||
|
ChunkPtr += 8;
|
||||||
|
|
||||||
if (P[2] <= P[3])
|
if (P[2] <= P[3])
|
||||||
{
|
{
|
||||||
|
@ -857,7 +949,8 @@ void InterplayDecoder::DecodeBlock10(int32_t offset)
|
||||||
uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset;
|
uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset;
|
||||||
uint8_t P[8];
|
uint8_t P[8];
|
||||||
|
|
||||||
fr.Read(P, 4);
|
memcpy(P, ChunkPtr, 4);
|
||||||
|
ChunkPtr += 4;
|
||||||
|
|
||||||
// 4-color encoding for each 4x4 quadrant, or 4-color encoding on either top and bottom or left and right halves
|
// 4-color encoding for each 4x4 quadrant, or 4-color encoding on either top and bottom or left and right halves
|
||||||
if (P[0] <= P[1])
|
if (P[0] <= P[1])
|
||||||
|
@ -869,8 +962,12 @@ void InterplayDecoder::DecodeBlock10(int32_t offset)
|
||||||
{
|
{
|
||||||
// new values for each 4x4 block
|
// new values for each 4x4 block
|
||||||
if (!(y & 3)) {
|
if (!(y & 3)) {
|
||||||
if (y) fr.Read(P, 4);
|
if (y) {
|
||||||
flags = fr.ReadUInt32();
|
memcpy(P, ChunkPtr, 4);
|
||||||
|
ChunkPtr += 4;
|
||||||
|
}
|
||||||
|
flags = LE_32(ChunkPtr);
|
||||||
|
ChunkPtr += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int x = 0; x < 4; x++, flags >>= 2) {
|
for (int x = 0; x < 4; x++, flags >>= 2) {
|
||||||
|
@ -886,9 +983,11 @@ void InterplayDecoder::DecodeBlock10(int32_t offset)
|
||||||
{
|
{
|
||||||
// vertical split?
|
// vertical split?
|
||||||
int vert;
|
int vert;
|
||||||
uint64_t flags = fr.ReadUInt64();
|
uint64_t flags = LE_64(ChunkPtr);
|
||||||
|
ChunkPtr += 8;
|
||||||
|
|
||||||
fr.Read(P + 4, 4);
|
memcpy(P + 4, ChunkPtr, 4);
|
||||||
|
ChunkPtr += 4;
|
||||||
vert = P[4] <= P[5];
|
vert = P[4] <= P[5];
|
||||||
|
|
||||||
// 4-color encoding for either left and right or top and bottom halves
|
// 4-color encoding for either left and right or top and bottom halves
|
||||||
|
@ -908,7 +1007,8 @@ void InterplayDecoder::DecodeBlock10(int32_t offset)
|
||||||
// load values for second half
|
// load values for second half
|
||||||
if (y == 7) {
|
if (y == 7) {
|
||||||
memcpy(P, P + 4, 4);
|
memcpy(P, P + 4, 4);
|
||||||
flags = fr.ReadUInt64();
|
flags = LE_64(ChunkPtr);
|
||||||
|
ChunkPtr += 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -921,7 +1021,8 @@ void InterplayDecoder::DecodeBlock11(int32_t offset)
|
||||||
|
|
||||||
for (int y = 0; y < 8; y++)
|
for (int y = 0; y < 8; y++)
|
||||||
{
|
{
|
||||||
fr.Read(pBuffer, 8);
|
memcpy(pBuffer, ChunkPtr, 8);
|
||||||
|
ChunkPtr += 8;
|
||||||
pBuffer += videoStride;
|
pBuffer += videoStride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -938,7 +1039,7 @@ void InterplayDecoder::DecodeBlock12(int32_t offset)
|
||||||
pBuffer[x] =
|
pBuffer[x] =
|
||||||
pBuffer[x + 1] =
|
pBuffer[x + 1] =
|
||||||
pBuffer[x + videoStride] =
|
pBuffer[x + videoStride] =
|
||||||
pBuffer[x + 1 + videoStride] = fr.ReadUInt8();
|
pBuffer[x + 1 + videoStride] = *ChunkPtr++;
|
||||||
}
|
}
|
||||||
pBuffer += videoStride * 2;
|
pBuffer += videoStride * 2;
|
||||||
}
|
}
|
||||||
|
@ -954,8 +1055,8 @@ void InterplayDecoder::DecodeBlock13(int32_t offset)
|
||||||
{
|
{
|
||||||
if (!(y & 3))
|
if (!(y & 3))
|
||||||
{
|
{
|
||||||
P[0] = fr.ReadUInt8();
|
P[0] = *ChunkPtr++;
|
||||||
P[1] = fr.ReadUInt8();
|
P[1] = *ChunkPtr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(pBuffer, P[0], 4);
|
memset(pBuffer, P[0], 4);
|
||||||
|
@ -968,7 +1069,7 @@ void InterplayDecoder::DecodeBlock14(int32_t offset)
|
||||||
{
|
{
|
||||||
// 1-color encoding : the whole block is 1 solid color
|
// 1-color encoding : the whole block is 1 solid color
|
||||||
uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset;
|
uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset;
|
||||||
uint8_t pix = fr.ReadUInt8();
|
uint8_t pix = *ChunkPtr++;
|
||||||
|
|
||||||
for (int y = 0; y < 8; y++)
|
for (int y = 0; y < 8; y++)
|
||||||
{
|
{
|
||||||
|
@ -983,8 +1084,8 @@ void InterplayDecoder::DecodeBlock15(int32_t offset)
|
||||||
uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset;
|
uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset;
|
||||||
uint8_t P[2];
|
uint8_t P[2];
|
||||||
|
|
||||||
P[0] = fr.ReadUInt8();
|
P[0] = *ChunkPtr++;
|
||||||
P[1] = fr.ReadUInt8();
|
P[1] = *ChunkPtr++;
|
||||||
|
|
||||||
for (int y = 0; y < 8; y++)
|
for (int y = 0; y < 8; y++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,6 +44,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "files.h"
|
#include "files.h"
|
||||||
#include "animtexture.h"
|
#include "animtexture.h"
|
||||||
#include "s_music.h"
|
#include "s_music.h"
|
||||||
|
@ -111,6 +113,7 @@ public:
|
||||||
int nChannels;
|
int nChannels;
|
||||||
uint16_t nSampleRate;
|
uint16_t nSampleRate;
|
||||||
uint8_t nBitDepth;
|
uint8_t nBitDepth;
|
||||||
|
bool bCompressed;
|
||||||
|
|
||||||
int16_t samples[6000 * kAudioBlocks]; // must be a multiple of the stream buffer size
|
int16_t samples[6000 * kAudioBlocks]; // must be a multiple of the stream buffer size
|
||||||
int nWrite;
|
int nWrite;
|
||||||
|
@ -165,6 +168,9 @@ private:
|
||||||
double nFps;
|
double nFps;
|
||||||
uint64_t nFrameDuration;
|
uint64_t nFrameDuration;
|
||||||
|
|
||||||
|
std::vector<uint8_t> ChunkData;
|
||||||
|
const uint8_t *ChunkPtr = nullptr;
|
||||||
|
|
||||||
uint8_t* pVideoBuffers[2];
|
uint8_t* pVideoBuffers[2];
|
||||||
uint32_t nCurrentVideoBuffer, nPreviousVideoBuffer;
|
uint32_t nCurrentVideoBuffer, nPreviousVideoBuffer;
|
||||||
int32_t videoStride;
|
int32_t videoStride;
|
||||||
|
|
Loading…
Reference in a new issue