Simplify read[LB]E* functions; better frame timing in MveDecoder; misc. fixed

This commit is contained in:
2015-04-28 15:27:06 +02:00
parent 12242de1e1
commit 962bfed0cb
5 changed files with 51 additions and 96 deletions

View File

@@ -64,7 +64,7 @@ std::unique_ptr<IffFile::Object> IffFile::parseObject(char const* base, size_t l
if (!isprint(header.typeID[i])) if (!isprint(header.typeID[i]))
throw FormatException{"Not an IFF chunk"}; throw FormatException{"Not an IFF chunk"};
if (header.length > length-7) if (header.length > length-8)
throw FormatException{"length < size in header"}; throw FormatException{"length < size in header"};
if(memcmp(header.typeID, "FORM", 4) == 0) if(memcmp(header.typeID, "FORM", 4) == 0)

View File

@@ -1,6 +1,6 @@
CXX=g++ CXX=g++
CXXOPTS=-Og -ggdb -Wall -Wextra -pedantic -std=c++14 -flto CXXOPTS=-Og -ggdb -fvar-tracking-assignments -Wall -Wextra -pedantic -std=c++14 -march=native -fstack-protector-strong --param=ssp-buffer-size=4 -flto
LDOPTS= LDOPTS=-Wl,--sort-common,--as-needed
iffexplore_CXXSRCS ::= iffexplore.cc IffFile.cc util.cc exceptions.cc iffexplore_CXXSRCS ::= iffexplore.cc IffFile.cc util.cc exceptions.cc
iffexplore_LIBS ::= iffexplore_LIBS ::=

View File

@@ -6,11 +6,6 @@
#include "IffFile.hh" #include "IffFile.hh"
#include "MveDecoder.hh" #include "MveDecoder.hh"
struct PCChunk {
uint32_t unknown[2];
uint32_t PALTcount;
} __attribute__((__packed__));
MveDecoder::MveDecoder(char const* base, size_t length) MveDecoder::MveDecoder(char const* base, size_t length)
: iff_(base, length), width_(320), height_(165) : iff_(base, length), width_(320), height_(165)
{ {
@@ -89,16 +84,18 @@ MveDecoder::MveDecoder(char const* base, size_t length)
} else if (it->getType() == "INDX") { } else if (it->getType() == "INDX") {
if (haveIndex) if (haveIndex)
throw FormatException{"Multiple INDX"}; throw FormatException{"Multiple INDX"};
if (curSHOT)
throw FormatException{"INDX after SHOT"};
haveIndex = true; haveIndex = true;
for(unsigned i = 0;i < it->getSize()/4;++i) for(unsigned i = 0;i < it->getSize()/4;++i)
branches.push_back(readU32LE(it->begin()+i*4)); branches.push_back(readU32LE(it->begin()+i*4));
branches_.resize(branches.size()); branches_.resize(branches.size());
} else if (it->getType() == "BRCH") { } else if (it->getType() == "BRCH") {
size_t ofs = it->begin()-base; size_t ofs = it->begin()-base-8;
auto idxIt = std::find(branches.begin(), branches.end(), ofs-8); auto idxIt = std::find(branches.begin(), branches.end(), ofs);
if (idxIt == branches.end()) if (idxIt == branches.end())
throw FormatException{"Could not resolve branch " + std::to_string(ofs-8)}; throw FormatException{"Could not resolve branch " + std::to_string(ofs)};
curBRCH = (idxIt-branches.begin()); curBRCH = (idxIt-branches.begin());
} else if (it->getType() == "TEXT") { } else if (it->getType() == "TEXT") {
// Subtitle NYI // Subtitle NYI
@@ -106,7 +103,9 @@ MveDecoder::MveDecoder(char const* base, size_t length)
throw FormatException{"Encountered unexpected chunk: " + it->getType()}; throw FormatException{"Encountered unexpected chunk: " + it->getType()};
} }
#ifdef VIDDEBUG_
unsigned i = 0; unsigned i = 0;
#endif
for (auto& brch : branches_) { for (auto& brch : branches_) {
for (auto& shot : brch) { for (auto& shot : brch) {
#ifdef VIDDEBUG_ #ifdef VIDDEBUG_
@@ -173,9 +172,7 @@ std::vector<char> parseHuff_(char const* data, size_t len)
} else { } else {
if (bytePos >= len) if (bytePos >= len)
throw FormatException{"Huffman stream overrun"}; throw FormatException{"Huffman stream overrun"};
memcpy(&byteBuf, data+bytePos, 1); byteBuf = data[bytePos++];
//printf("Byte: %.2hhx (%s)\n", byteBuf, binify(byteBuf));
++bytePos;
bit = byteBuf&0x1; bit = byteBuf&0x1;
byteBuf >>= 1; byteBuf >>= 1;
byteValid = 7; byteValid = 7;
@@ -183,11 +180,9 @@ std::vector<char> parseHuff_(char const* data, size_t len)
huffIdx = huffTree.at(huffIdx-(bit?1:23)); huffIdx = huffTree.at(huffIdx-(bit?1:23));
//printf("step: %d %.2x\n", bit, huffIdx);
if (huffIdx < 22) { if (huffIdx < 22) {
commands.push_back(huffIdx); commands.push_back(huffIdx);
//printf("out: %.2hhx\n", commands.back());
huffIdx = huffTree.size(); huffIdx = huffTree.size();
} }
} }
@@ -224,8 +219,6 @@ std::vector<uint8_t> parsePixels_(char const* data, size_t len)
uint8_t ofs = *(data+pos++); uint8_t ofs = *(data+pos++);
size = b&0x3; size = b&0x3;
if (pos+size >= len)
throw FormatException{"Pixel data overrun"};
replSize = ((b&0x1c)>>2) + 3; replSize = ((b&0x1c)>>2) + 3;
replOfs = ret.size()-(((b&0x60)<<3)+ofs+1)+size; replOfs = ret.size()-(((b&0x60)<<3)+ofs+1)+size;
@@ -240,8 +233,6 @@ std::vector<uint8_t> parsePixels_(char const* data, size_t len)
uint8_t b2 = *(data+pos++); uint8_t b2 = *(data+pos++);
size = (b1&0xc0)>>6; size = (b1&0xc0)>>6;
if (pos+size >= len)
throw FormatException{"Pixel data overrun"};
replSize = (b&0x3f)+4; replSize = (b&0x3f)+4;
replOfs = ret.size()-(((b1&0x3f)<<8)+b2+1)+size; replOfs = ret.size()-(((b1&0x3f)<<8)+b2+1)+size;
@@ -257,18 +248,20 @@ std::vector<uint8_t> parsePixels_(char const* data, size_t len)
uint8_t b3 = *(data+pos++); uint8_t b3 = *(data+pos++);
size = b&0x3; size = b&0x3;
if (pos+size >= len)
throw FormatException{"Pixel data overrun"};
replSize = b3+5+((b&0xc)<<6); replSize = b3+5+((b&0xc)<<6);
replOfs = ret.size()-(((b&0x10)<<12)+1+(b1<<8)+b2)+size; replOfs = ret.size()-(((b&0x10)<<12)+1+(b1<<8)+b2)+size;
} }
if (pos+size >= len)
throw FormatException{"Pixel data overrun"};
std::copy(data+pos, data+pos+size, std::copy(data+pos, data+pos+size,
std::back_inserter(ret)); std::back_inserter(ret));
pos += size; pos += size;
if (replOfs >= ret.size())
throw FormatException{"Replication offset exceeds buffer"};
for (unsigned i = 0;i < replSize;++i) for (unsigned i = 0;i < replSize;++i)
ret.push_back(ret.at(replOfs+i)); ret.push_back(ret[replOfs+i]);
} else { } else {
#ifdef PIXELDEBUG_ #ifdef PIXELDEBUG_
printf("Code: Copy %.2hhx\n", b); printf("Code: Copy %.2hhx\n", b);
@@ -541,7 +534,9 @@ void MveDecoder::play(unsigned branch) const
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
width_*2, width_*2,
height_*2, // 1.2 scale in height to compensate for non-square pixels in height
// in original MCGA/VGA 320x200 mode
height_*2*1.2,
0); 0);
if (!window) { if (!window) {
@@ -612,9 +607,11 @@ void MveDecoder::play(unsigned branch) const
auto vga = curShot->VGAs.begin(); auto vga = curShot->VGAs.begin();
uint32_t last = 0; uint32_t last = 0;
const double frameTime = 1000/15.0;
double nextFT = frameTime;
Frame frame = parseVGA(**vga++, nullptr); Frame frame = parseVGA(**vga++, nullptr);
std::vector<decltype(last)> frameTimes; decltype(last) minFT = std::numeric_limits<decltype(last)>::max(), maxFT = 0;
bool close = false; bool close = false;
@@ -634,9 +631,19 @@ void MveDecoder::play(unsigned branch) const
} }
auto now = SDL_GetTicks(); auto now = SDL_GetTicks();
if (now-last >= 67) { if (now-last >= nextFT) {
if (last) if (last) {
frameTimes.push_back(now-last); minFT = std::min(minFT, (now-last));
maxFT = std::max(maxFT, (now-last));
if ((now-last)-nextFT <= frameTime)
nextFT = frameTime-((now-last)-nextFT);
else {
printf("NYI: Frame dropping\n");
nextFT = frameTime;
}
}
SDL_Surface *vidSurf = SDL_CreateRGBSurfaceFrom((void*)frame.pixels.data(), width_, height_, 8, width_, 0, 0, 0, 0); SDL_Surface *vidSurf = SDL_CreateRGBSurfaceFrom((void*)frame.pixels.data(), width_, height_, 8, width_, 0, 0, 0, 0);
if (!vidSurf) { if (!vidSurf) {
printf("Could not get video surface: %s\n", SDL_GetError()); printf("Could not get video surface: %s\n", SDL_GetError());
@@ -713,7 +720,8 @@ void MveDecoder::play(unsigned branch) const
} }
} }
frame = parseVGA(**vga++, &frame); frame = parseVGA(**vga++, &frame);
} } else if ((nextFT-(now-last)) >= 10)
SDL_Delay(nextFT-(now-last));
} }
SDL_PauseAudioDevice(audioDev, 1); SDL_PauseAudioDevice(audioDev, 1);
@@ -723,7 +731,6 @@ void MveDecoder::play(unsigned branch) const
SDL_Quit(); SDL_Quit();
printf("Frame times: [%u, %u]\n", printf("Frame times: [%u, %u]\n",
*std::min_element(frameTimes.begin(), frameTimes.end()), minFT, maxFT);
*std::max_element(frameTimes.begin(), frameTimes.end()));
} }

70
util.cc
View File

@@ -92,16 +92,8 @@ uint16_t readU16BE(char const* data)
if(!data) if(!data)
throw std::logic_error("readU16BE() called with nullptr"); throw std::logic_error("readU16BE() called with nullptr");
uint16_t ret; return ((static_cast<uint16_t>(*data)&0xff)<<8) |
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ static_cast<uint8_t>(*(data+1));
ret = ((static_cast<uint16_t>(*data)&0xff)<<8) | static_cast<uint8_t>(*(data+1));
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
memcpy(&ret, data, 2);
#else
#error Unknown endianess
#endif
return ret;
} }
uint32_t readU24BE(char const* data) uint32_t readU24BE(char const* data)
@@ -109,18 +101,9 @@ uint32_t readU24BE(char const* data)
if(!data) if(!data)
throw std::logic_error("readU24BE() called with nullptr"); throw std::logic_error("readU24BE() called with nullptr");
uint32_t ret = 0; return ((static_cast<uint32_t>(*data)&0xff)<<16) |
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
ret = ((static_cast<uint32_t>(*data)&0xff)<<16) |
((static_cast<uint32_t>(*(data+1))&0xff)<<8) | ((static_cast<uint32_t>(*(data+1))&0xff)<<8) |
static_cast<uint8_t>(*(data+2)); static_cast<uint8_t>(*(data+2));
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
memcpy(static_cast<char*>(&ret)+1, data, 3);
#else
#error Unknown endianess
#endif
return ret;
} }
uint32_t readU32BE(char const* data) uint32_t readU32BE(char const* data)
@@ -128,19 +111,10 @@ uint32_t readU32BE(char const* data)
if(!data) if(!data)
throw std::logic_error("readU32BE() called with nullptr"); throw std::logic_error("readU32BE() called with nullptr");
uint32_t ret; return ((static_cast<uint32_t>(*data)&0xff)<<24) |
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
ret = ((static_cast<uint32_t>(*data)&0xff)<<24) |
((static_cast<uint32_t>(*(data+1))&0xff)<<16) | ((static_cast<uint32_t>(*(data+1))&0xff)<<16) |
((static_cast<uint32_t>(*(data+2))&0xff)<<8) | ((static_cast<uint32_t>(*(data+2))&0xff)<<8) |
static_cast<uint8_t>(*(data+3)); static_cast<uint8_t>(*(data+3));
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
memcpy(&ret, data, 4);
#else
#error Unknown endianess
#endif
return ret;
} }
uint16_t readU16LE(char const* data) uint16_t readU16LE(char const* data)
@@ -148,16 +122,8 @@ uint16_t readU16LE(char const* data)
if(!data) if(!data)
throw std::logic_error("readU16LE() called with nullptr"); throw std::logic_error("readU16LE() called with nullptr");
uint16_t ret; return ((static_cast<uint16_t>(*(data+1))&0xff)<<8) |
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ static_cast<uint8_t>(*data);
memcpy(&ret, data, 2);
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
ret = ((static_cast<uint16_t>(*(data+1))&0xff)<<8) | static_cast<uint8_t>(*data);
#else
#error Unknown endianess
#endif
return ret;
} }
uint32_t readU24LE(char const* data) uint32_t readU24LE(char const* data)
@@ -165,18 +131,9 @@ uint32_t readU24LE(char const* data)
if(!data) if(!data)
throw std::logic_error("readU24LE() called with nullptr"); throw std::logic_error("readU24LE() called with nullptr");
uint32_t ret = 0; return ((static_cast<uint32_t>(*(data+2))&0xff)<<16) |
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
memcpy(&ret, data, 3);
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
ret = ((static_cast<uint32_t>(*(data+2))&0xff)<<16) |
((static_cast<uint32_t>(*(data+1))&0xff)<<8) | ((static_cast<uint32_t>(*(data+1))&0xff)<<8) |
static_cast<uint8_t>(*data); static_cast<uint8_t>(*data);
#else
#error Unknown endianess
#endif
return ret;
} }
uint32_t readU32LE(char const* data) uint32_t readU32LE(char const* data)
@@ -184,22 +141,13 @@ uint32_t readU32LE(char const* data)
if(!data) if(!data)
throw std::logic_error("readU32LE() called with nullptr"); throw std::logic_error("readU32LE() called with nullptr");
uint32_t ret; return ((static_cast<uint32_t>(*(data+3))&0xff)<<24) |
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
memcpy(&ret, data, 4);
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
ret = ((static_cast<uint32_t>(*(data+3))&0xff)<<24) |
((static_cast<uint32_t>(*(data+2))&0xff)<<16) | ((static_cast<uint32_t>(*(data+2))&0xff)<<16) |
((static_cast<uint32_t>(*(data+1))&0xff)<<8) | ((static_cast<uint32_t>(*(data+1))&0xff)<<8) |
static_cast<uint8_t>(*data); static_cast<uint8_t>(*data);
#else
#error Unknown endianess
#endif
return ret;
} }
int sextend(unsigned b, int msb) int sextend(unsigned b, unsigned msb)
{ {
if (msb >= sizeof(unsigned)*8) if (msb >= sizeof(unsigned)*8)
throw std::logic_error("sextend: msb out of range"); throw std::logic_error("sextend: msb out of range");

View File

@@ -40,6 +40,6 @@ uint32_t readU24LE(char const* data);
uint32_t readU32LE(char const* data); uint32_t readU32LE(char const* data);
// Sign-extend b starting at msb // Sign-extend b starting at msb
int sextend(unsigned b, int msb); int sextend(unsigned b, unsigned msb);
#endif #endif