Reformat Utilities (Resharper)
This commit is contained in:
parent
68c88a6b7c
commit
c0aabf20a1
97 changed files with 25869 additions and 23038 deletions
|
@ -12,11 +12,13 @@ ArchiveReader::~ArchiveReader()
|
|||
delete[] _buffer;
|
||||
}
|
||||
|
||||
bool ArchiveReader::GetStream(string filename, std::stringstream &stream)
|
||||
bool ArchiveReader::GetStream(string filename, std::stringstream& stream)
|
||||
{
|
||||
if(_initialized) {
|
||||
if (_initialized)
|
||||
{
|
||||
vector<uint8_t> fileData;
|
||||
if(ExtractFile(filename, fileData)) {
|
||||
if (ExtractFile(filename, fileData))
|
||||
{
|
||||
stream.write((char*)fileData.data(), fileData.size());
|
||||
return true;
|
||||
}
|
||||
|
@ -26,17 +28,22 @@ bool ArchiveReader::GetStream(string filename, std::stringstream &stream)
|
|||
|
||||
vector<string> ArchiveReader::GetFileList(std::initializer_list<string> extensions)
|
||||
{
|
||||
if(extensions.size() == 0) {
|
||||
if (extensions.size() == 0)
|
||||
{
|
||||
return InternalGetFileList();
|
||||
}
|
||||
|
||||
vector<string> filenames;
|
||||
for(string filename : InternalGetFileList()) {
|
||||
for (string filename : InternalGetFileList())
|
||||
{
|
||||
string lcFilename = filename;
|
||||
std::transform(lcFilename.begin(), lcFilename.end(), lcFilename.begin(), ::tolower);
|
||||
for(string ext : extensions) {
|
||||
if(lcFilename.size() >= ext.size()) {
|
||||
if(lcFilename.substr(lcFilename.length() - ext.size(), ext.size()).compare(ext) == 0) {
|
||||
for (string ext : extensions)
|
||||
{
|
||||
if (lcFilename.size() >= ext.size())
|
||||
{
|
||||
if (lcFilename.substr(lcFilename.length() - ext.size(), ext.size()).compare(ext) == 0)
|
||||
{
|
||||
filenames.push_back(filename);
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +59,7 @@ bool ArchiveReader::CheckFile(string filename)
|
|||
return std::find(files.begin(), files.end(), filename) != files.end();
|
||||
}
|
||||
|
||||
bool ArchiveReader::LoadArchive(std::istream &in)
|
||||
bool ArchiveReader::LoadArchive(std::istream& in)
|
||||
{
|
||||
in.seekg(0, std::ios::end);
|
||||
std::streampos filesize = in.tellg();
|
||||
|
@ -66,14 +73,15 @@ bool ArchiveReader::LoadArchive(std::istream &in)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool ArchiveReader::LoadArchive(vector<uint8_t> &data)
|
||||
bool ArchiveReader::LoadArchive(vector<uint8_t>& data)
|
||||
{
|
||||
return LoadArchive(data.data(), data.size());
|
||||
}
|
||||
|
||||
bool ArchiveReader::LoadArchive(void* buffer, size_t size)
|
||||
{
|
||||
if(InternalLoadArchive(buffer, size)) {
|
||||
if (InternalLoadArchive(buffer, size))
|
||||
{
|
||||
_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -83,26 +91,31 @@ bool ArchiveReader::LoadArchive(void* buffer, size_t size)
|
|||
bool ArchiveReader::LoadArchive(string filename)
|
||||
{
|
||||
ifstream in(filename, std::ios::binary | std::ios::in);
|
||||
if(in.good()) {
|
||||
if (in.good())
|
||||
{
|
||||
LoadArchive(in);
|
||||
in.close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
shared_ptr<ArchiveReader> ArchiveReader::GetReader(std::istream &in)
|
||||
shared_ptr<ArchiveReader> ArchiveReader::GetReader(std::istream& in)
|
||||
{
|
||||
uint8_t header[2] = { 0,0 };
|
||||
uint8_t header[2] = {0, 0};
|
||||
in.read((char*)header, 2);
|
||||
|
||||
shared_ptr<ArchiveReader> reader;
|
||||
if(memcmp(header, "PK", 2) == 0) {
|
||||
if (memcmp(header, "PK", 2) == 0)
|
||||
{
|
||||
reader.reset(new ZipReader());
|
||||
} else if(memcmp(header, "7z", 2) == 0) {
|
||||
}
|
||||
else if (memcmp(header, "7z", 2) == 0)
|
||||
{
|
||||
reader.reset(new SZReader());
|
||||
}
|
||||
|
||||
if(reader) {
|
||||
if (reader)
|
||||
{
|
||||
reader->LoadArchive(in);
|
||||
}
|
||||
return reader;
|
||||
|
@ -111,7 +124,8 @@ shared_ptr<ArchiveReader> ArchiveReader::GetReader(std::istream &in)
|
|||
shared_ptr<ArchiveReader> ArchiveReader::GetReader(string filepath)
|
||||
{
|
||||
ifstream in(filepath, std::ios::in | std::ios::binary);
|
||||
if(in) {
|
||||
if (in)
|
||||
{
|
||||
return GetReader(in);
|
||||
}
|
||||
return nullptr;
|
||||
|
|
|
@ -14,15 +14,15 @@ public:
|
|||
bool LoadArchive(void* buffer, size_t size);
|
||||
bool LoadArchive(vector<uint8_t>& data);
|
||||
bool LoadArchive(string filename);
|
||||
bool LoadArchive(std::istream &in);
|
||||
bool LoadArchive(std::istream& in);
|
||||
|
||||
bool GetStream(string filename, std::stringstream &stream);
|
||||
bool GetStream(string filename, std::stringstream& stream);
|
||||
|
||||
vector<string> GetFileList(std::initializer_list<string> extensions = {});
|
||||
bool CheckFile(string filename);
|
||||
|
||||
virtual bool ExtractFile(string filename, vector<uint8_t> &output) = 0;
|
||||
virtual bool ExtractFile(string filename, vector<uint8_t>& output) = 0;
|
||||
|
||||
static shared_ptr<ArchiveReader> GetReader(std::istream &in);
|
||||
static shared_ptr<ArchiveReader> GetReader(std::istream& in);
|
||||
static shared_ptr<ArchiveReader> GetReader(string filepath);
|
||||
};
|
|
@ -15,10 +15,13 @@ AutoResetEvent::~AutoResetEvent()
|
|||
void AutoResetEvent::Wait(int timeoutDelay)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
if(timeoutDelay == 0) {
|
||||
if (timeoutDelay == 0)
|
||||
{
|
||||
//Wait until signaled
|
||||
_signal.wait(lock, [this] { return _signaled; });
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
//Wait until signaled or timeout
|
||||
auto timeoutTime = std::chrono::system_clock::now() + std::chrono::duration<int, std::milli>(timeoutDelay);
|
||||
_signal.wait_until(lock, timeoutTime, [this] { return _signaled; });
|
||||
|
|
|
@ -14,19 +14,23 @@ AviRecorder::AviRecorder(VideoCodec codec, uint32_t compressionLevel)
|
|||
|
||||
AviRecorder::~AviRecorder()
|
||||
{
|
||||
if(_recording) {
|
||||
if (_recording)
|
||||
{
|
||||
StopRecording();
|
||||
}
|
||||
|
||||
if(_frameBuffer) {
|
||||
if (_frameBuffer)
|
||||
{
|
||||
delete[] _frameBuffer;
|
||||
_frameBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool AviRecorder::StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate, double fps)
|
||||
bool AviRecorder::StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp,
|
||||
uint32_t audioSampleRate, double fps)
|
||||
{
|
||||
if(!_recording) {
|
||||
if (!_recording)
|
||||
{
|
||||
_outputFile = filename;
|
||||
_sampleRate = audioSampleRate;
|
||||
_width = width;
|
||||
|
@ -36,15 +40,20 @@ bool AviRecorder::StartRecording(string filename, uint32_t width, uint32_t heigh
|
|||
_frameBuffer = new uint8_t[_frameBufferLength];
|
||||
|
||||
_aviWriter.reset(new AviWriter());
|
||||
if(!_aviWriter->StartWrite(filename, _codec, width, height, bpp, (uint32_t)(_fps * 1000000), audioSampleRate, _compressionLevel)) {
|
||||
if (!_aviWriter->StartWrite(filename, _codec, width, height, bpp, (uint32_t)(_fps * 1000000), audioSampleRate,
|
||||
_compressionLevel))
|
||||
{
|
||||
_aviWriter.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
_aviWriterThread = std::thread([=]() {
|
||||
while(!_stopFlag) {
|
||||
_aviWriterThread = std::thread([=]()
|
||||
{
|
||||
while (!_stopFlag)
|
||||
{
|
||||
_waitFrame.Wait();
|
||||
if(_stopFlag) {
|
||||
if (_stopFlag)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -60,7 +69,8 @@ bool AviRecorder::StartRecording(string filename, uint32_t width, uint32_t heigh
|
|||
|
||||
void AviRecorder::StopRecording()
|
||||
{
|
||||
if(_recording) {
|
||||
if (_recording)
|
||||
{
|
||||
_recording = false;
|
||||
|
||||
_stopFlag = true;
|
||||
|
@ -74,10 +84,14 @@ void AviRecorder::StopRecording()
|
|||
|
||||
void AviRecorder::AddFrame(void* frameBuffer, uint32_t width, uint32_t height, double fps)
|
||||
{
|
||||
if(_recording) {
|
||||
if(_width != width || _height != height || _fps != fps) {
|
||||
if (_recording)
|
||||
{
|
||||
if (_width != width || _height != height || _fps != fps)
|
||||
{
|
||||
StopRecording();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
auto lock = _lock.AcquireSafe();
|
||||
memcpy(_frameBuffer, frameBuffer, _frameBufferLength);
|
||||
_waitFrame.Signal();
|
||||
|
@ -87,11 +101,15 @@ void AviRecorder::AddFrame(void* frameBuffer, uint32_t width, uint32_t height, d
|
|||
|
||||
void AviRecorder::AddSound(int16_t* soundBuffer, uint32_t sampleCount, uint32_t sampleRate)
|
||||
{
|
||||
if(_recording) {
|
||||
if(_sampleRate != sampleRate) {
|
||||
if (_recording)
|
||||
{
|
||||
if (_sampleRate != sampleRate)
|
||||
{
|
||||
auto lock = _lock.AcquireSafe();
|
||||
StopRecording();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
_aviWriter->AddSound(soundBuffer, sampleCount);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,8 @@ public:
|
|||
AviRecorder(VideoCodec codec, uint32_t compressionLevel);
|
||||
virtual ~AviRecorder();
|
||||
|
||||
bool StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate, double fps) override;
|
||||
bool StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate,
|
||||
double fps) override;
|
||||
void StopRecording() override;
|
||||
|
||||
void AddFrame(void* frameBuffer, uint32_t width, uint32_t height, double fps) override;
|
||||
|
|
|
@ -28,13 +28,13 @@
|
|||
#include "ZmbvCodec.h"
|
||||
#include "CamstudioCodec.h"
|
||||
|
||||
void AviWriter::WriteAviChunk(const char *tag, uint32_t size, void *data, uint32_t flags)
|
||||
void AviWriter::WriteAviChunk(const char* tag, uint32_t size, void* data, uint32_t flags)
|
||||
{
|
||||
uint8_t chunk[8] = { (uint8_t)tag[0], (uint8_t)tag[1], (uint8_t)tag[2], (uint8_t)tag[3] };
|
||||
uint8_t chunk[8] = {(uint8_t)tag[0], (uint8_t)tag[1], (uint8_t)tag[2], (uint8_t)tag[3]};
|
||||
host_writed(&chunk[4], size);
|
||||
_file.write((char*)chunk, 8);
|
||||
|
||||
uint32_t writesize = (size + 1)&~1;
|
||||
uint32_t writesize = (size + 1) & ~1;
|
||||
_file.write((char*)data, writesize);
|
||||
|
||||
uint32_t pos = _written + 4;
|
||||
|
@ -64,26 +64,33 @@ void AviWriter::host_writed(uint8_t* buffer, uint32_t value)
|
|||
buffer[3] = value >> 24;
|
||||
}
|
||||
|
||||
bool AviWriter::StartWrite(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps, uint32_t audioSampleRate, uint32_t compressionLevel)
|
||||
bool AviWriter::StartWrite(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp,
|
||||
uint32_t fps, uint32_t audioSampleRate, uint32_t compressionLevel)
|
||||
{
|
||||
_codecType = codec;
|
||||
_file.open(filename, std::ios::out | std::ios::binary);
|
||||
if(!_file) {
|
||||
if (!_file)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(_codecType) {
|
||||
default:
|
||||
case VideoCodec::None: _codec.reset(new RawCodec()); break;
|
||||
case VideoCodec::ZMBV: _codec.reset(new ZmbvCodec()); break;
|
||||
case VideoCodec::CSCD: _codec.reset(new CamstudioCodec()); break;
|
||||
switch (_codecType)
|
||||
{
|
||||
default:
|
||||
case VideoCodec::None: _codec.reset(new RawCodec());
|
||||
break;
|
||||
case VideoCodec::ZMBV: _codec.reset(new ZmbvCodec());
|
||||
break;
|
||||
case VideoCodec::CSCD: _codec.reset(new CamstudioCodec());
|
||||
break;
|
||||
}
|
||||
|
||||
if(!_codec->SetupCompress(width, height, compressionLevel)) {
|
||||
if (!_codec->SetupCompress(width, height, compressionLevel))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_frameBuffer = new uint8_t[width*height*bpp];
|
||||
_frameBuffer = new uint8_t[width * height * bpp];
|
||||
|
||||
_aviIndex.clear();
|
||||
_aviIndex.insert(_aviIndex.end(), 8, 0);
|
||||
|
@ -95,7 +102,8 @@ bool AviWriter::StartWrite(string filename, VideoCodec codec, uint32_t width, ui
|
|||
|
||||
_audiorate = audioSampleRate;
|
||||
|
||||
for(int i = 0; i < AviWriter::AviHeaderSize; i++) {
|
||||
for (int i = 0; i < AviWriter::AviHeaderSize; i++)
|
||||
{
|
||||
_file.put(0);
|
||||
}
|
||||
_frames = 0;
|
||||
|
@ -116,100 +124,100 @@ void AviWriter::EndWrite()
|
|||
#define AVIOUTw(_S_) host_writew(&avi_header[header_pos], _S_);header_pos+=2;
|
||||
#define AVIOUTd(_S_) host_writed(&avi_header[header_pos], _S_);header_pos+=4;
|
||||
/* Try and write an avi header */
|
||||
AVIOUT4("RIFF"); // Riff header
|
||||
AVIOUT4("RIFF"); // Riff header
|
||||
AVIOUTd(AviWriter::AviHeaderSize + _written - 8 + (uint32_t)_aviIndex.size());
|
||||
AVIOUT4("AVI ");
|
||||
AVIOUT4("LIST"); // List header
|
||||
AVIOUT4("LIST"); // List header
|
||||
main_list = header_pos;
|
||||
AVIOUTd(0); // TODO size of list
|
||||
AVIOUTd(0); // TODO size of list
|
||||
AVIOUT4("hdrl");
|
||||
|
||||
AVIOUT4("avih");
|
||||
AVIOUTd(56); /* # of bytes to follow */
|
||||
AVIOUTd((uint32_t)(1000000 / _fps)); /* Microseconds per frame */
|
||||
AVIOUTd(56); /* # of bytes to follow */
|
||||
AVIOUTd((uint32_t)(1000000 / _fps)); /* Microseconds per frame */
|
||||
AVIOUTd(0);
|
||||
AVIOUTd(0); /* PaddingGranularity (whatever that might be) */
|
||||
AVIOUTd(0x110); /* Flags,0x10 has index, 0x100 interleaved */
|
||||
AVIOUTd(_frames); /* TotalFrames */
|
||||
AVIOUTd(0); /* InitialFrames */
|
||||
AVIOUTd(2); /* Stream count */
|
||||
AVIOUTd(0); /* SuggestedBufferSize */
|
||||
AVIOUTd(_width); /* Width */
|
||||
AVIOUTd(_height); /* Height */
|
||||
AVIOUTd(0); /* TimeScale: Unit used to measure time */
|
||||
AVIOUTd(0); /* DataRate: Data rate of playback */
|
||||
AVIOUTd(0); /* StartTime: Starting time of AVI data */
|
||||
AVIOUTd(0); /* DataLength: Size of AVI data chunk */
|
||||
AVIOUTd(0); /* PaddingGranularity (whatever that might be) */
|
||||
AVIOUTd(0x110); /* Flags,0x10 has index, 0x100 interleaved */
|
||||
AVIOUTd(_frames); /* TotalFrames */
|
||||
AVIOUTd(0); /* InitialFrames */
|
||||
AVIOUTd(2); /* Stream count */
|
||||
AVIOUTd(0); /* SuggestedBufferSize */
|
||||
AVIOUTd(_width); /* Width */
|
||||
AVIOUTd(_height); /* Height */
|
||||
AVIOUTd(0); /* TimeScale: Unit used to measure time */
|
||||
AVIOUTd(0); /* DataRate: Data rate of playback */
|
||||
AVIOUTd(0); /* StartTime: Starting time of AVI data */
|
||||
AVIOUTd(0); /* DataLength: Size of AVI data chunk */
|
||||
|
||||
/* Video stream list */
|
||||
/* Video stream list */
|
||||
AVIOUT4("LIST");
|
||||
AVIOUTd(4 + 8 + 56 + 8 + 40); /* Size of the list */
|
||||
AVIOUTd(4 + 8 + 56 + 8 + 40); /* Size of the list */
|
||||
AVIOUT4("strl");
|
||||
/* video stream header */
|
||||
AVIOUT4("strh");
|
||||
AVIOUTd(56); /* # of bytes to follow */
|
||||
AVIOUT4("vids"); /* Type */
|
||||
AVIOUT4(_codec->GetFourCC()); /* Handler */
|
||||
AVIOUTd(0); /* Flags */
|
||||
AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */
|
||||
AVIOUTd(0); /* InitialFrames */
|
||||
AVIOUTd(1000000); /* Scale */
|
||||
AVIOUTd(_fps); /* Rate: Rate/Scale == samples/second */
|
||||
AVIOUTd(0); /* Start */
|
||||
AVIOUTd(_frames); /* Length */
|
||||
AVIOUTd(0); /* SuggestedBufferSize */
|
||||
AVIOUTd(~0); /* Quality */
|
||||
AVIOUTd(0); /* SampleSize */
|
||||
AVIOUTd(0); /* Frame */
|
||||
AVIOUTd(0); /* Frame */
|
||||
/* The video stream format */
|
||||
AVIOUTd(56); /* # of bytes to follow */
|
||||
AVIOUT4("vids"); /* Type */
|
||||
AVIOUT4(_codec->GetFourCC()); /* Handler */
|
||||
AVIOUTd(0); /* Flags */
|
||||
AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */
|
||||
AVIOUTd(0); /* InitialFrames */
|
||||
AVIOUTd(1000000); /* Scale */
|
||||
AVIOUTd(_fps); /* Rate: Rate/Scale == samples/second */
|
||||
AVIOUTd(0); /* Start */
|
||||
AVIOUTd(_frames); /* Length */
|
||||
AVIOUTd(0); /* SuggestedBufferSize */
|
||||
AVIOUTd(~0); /* Quality */
|
||||
AVIOUTd(0); /* SampleSize */
|
||||
AVIOUTd(0); /* Frame */
|
||||
AVIOUTd(0); /* Frame */
|
||||
/* The video stream format */
|
||||
AVIOUT4("strf");
|
||||
AVIOUTd(40); /* # of bytes to follow */
|
||||
AVIOUTd(40); /* Size */
|
||||
AVIOUTd(_width); /* Width */
|
||||
AVIOUTd(_height); /* Height */
|
||||
// OUTSHRT(1); OUTSHRT(24); /* Planes, Count */
|
||||
AVIOUTw(1); //number of planes
|
||||
AVIOUTd(40); /* # of bytes to follow */
|
||||
AVIOUTd(40); /* Size */
|
||||
AVIOUTd(_width); /* Width */
|
||||
AVIOUTd(_height); /* Height */
|
||||
// OUTSHRT(1); OUTSHRT(24); /* Planes, Count */
|
||||
AVIOUTw(1); //number of planes
|
||||
AVIOUTw(24); //bits for colors
|
||||
AVIOUT4(_codec->GetFourCC()); /* Compression */
|
||||
AVIOUTd(_width * _height * 4); /* SizeImage (in bytes?) */
|
||||
AVIOUTd(0); /* XPelsPerMeter */
|
||||
AVIOUTd(0); /* YPelsPerMeter */
|
||||
AVIOUTd(0); /* ClrUsed: Number of colors used */
|
||||
AVIOUTd(0); /* ClrImportant: Number of colors important */
|
||||
AVIOUT4(_codec->GetFourCC()); /* Compression */
|
||||
AVIOUTd(_width * _height * 4); /* SizeImage (in bytes?) */
|
||||
AVIOUTd(0); /* XPelsPerMeter */
|
||||
AVIOUTd(0); /* YPelsPerMeter */
|
||||
AVIOUTd(0); /* ClrUsed: Number of colors used */
|
||||
AVIOUTd(0); /* ClrImportant: Number of colors important */
|
||||
|
||||
/* Audio stream list */
|
||||
/* Audio stream list */
|
||||
AVIOUT4("LIST");
|
||||
AVIOUTd(4 + 8 + 56 + 8 + 16); /* Length of list in bytes */
|
||||
AVIOUTd(4 + 8 + 56 + 8 + 16); /* Length of list in bytes */
|
||||
AVIOUT4("strl");
|
||||
/* The audio stream header */
|
||||
AVIOUT4("strh");
|
||||
AVIOUTd(56); /* # of bytes to follow */
|
||||
AVIOUTd(56); /* # of bytes to follow */
|
||||
AVIOUT4("auds");
|
||||
AVIOUTd(0); /* Format (Optionally) */
|
||||
AVIOUTd(0); /* Flags */
|
||||
AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */
|
||||
AVIOUTd(0); /* InitialFrames */
|
||||
AVIOUTd(4); /* Scale */
|
||||
AVIOUTd(_audiorate * 4); /* Rate, actual rate is scale/rate */
|
||||
AVIOUTd(0); /* Start */
|
||||
if(!_audiorate)
|
||||
AVIOUTd(0); /* Format (Optionally) */
|
||||
AVIOUTd(0); /* Flags */
|
||||
AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */
|
||||
AVIOUTd(0); /* InitialFrames */
|
||||
AVIOUTd(4); /* Scale */
|
||||
AVIOUTd(_audiorate * 4); /* Rate, actual rate is scale/rate */
|
||||
AVIOUTd(0); /* Start */
|
||||
if (!_audiorate)
|
||||
_audiorate = 1;
|
||||
AVIOUTd(_audiowritten / 4); /* Length */
|
||||
AVIOUTd(0); /* SuggestedBufferSize */
|
||||
AVIOUTd(~0); /* Quality */
|
||||
AVIOUTd(4); /* SampleSize */
|
||||
AVIOUTd(0); /* Frame */
|
||||
AVIOUTd(0); /* Frame */
|
||||
/* The audio stream format */
|
||||
AVIOUTd(_audiowritten / 4); /* Length */
|
||||
AVIOUTd(0); /* SuggestedBufferSize */
|
||||
AVIOUTd(~0); /* Quality */
|
||||
AVIOUTd(4); /* SampleSize */
|
||||
AVIOUTd(0); /* Frame */
|
||||
AVIOUTd(0); /* Frame */
|
||||
/* The audio stream format */
|
||||
AVIOUT4("strf");
|
||||
AVIOUTd(16); /* # of bytes to follow */
|
||||
AVIOUTw(1); /* Format, WAVE_ZMBV_FORMAT_PCM */
|
||||
AVIOUTw(2); /* Number of channels */
|
||||
AVIOUTd(_audiorate); /* SamplesPerSec */
|
||||
AVIOUTd(_audiorate * 4); /* AvgBytesPerSec*/
|
||||
AVIOUTw(4); /* BlockAlign */
|
||||
AVIOUTw(16); /* BitsPerSample */
|
||||
AVIOUTd(16); /* # of bytes to follow */
|
||||
AVIOUTw(1); /* Format, WAVE_ZMBV_FORMAT_PCM */
|
||||
AVIOUTw(2); /* Number of channels */
|
||||
AVIOUTd(_audiorate); /* SamplesPerSec */
|
||||
AVIOUTd(_audiorate * 4); /* AvgBytesPerSec*/
|
||||
AVIOUTw(4); /* BlockAlign */
|
||||
AVIOUTw(16); /* BitsPerSample */
|
||||
int nmain = header_pos - main_list - 4;
|
||||
/* Finish stream list, i.e. put number of bytes in the list to proper pos */
|
||||
|
||||
|
@ -233,9 +241,10 @@ void AviWriter::EndWrite()
|
|||
_file.close();
|
||||
}
|
||||
|
||||
void AviWriter::AddFrame(uint8_t *frameData)
|
||||
void AviWriter::AddFrame(uint8_t* frameData)
|
||||
{
|
||||
if(!_file) {
|
||||
if (!_file)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -243,17 +252,20 @@ void AviWriter::AddFrame(uint8_t *frameData)
|
|||
|
||||
uint8_t* compressedData = nullptr;
|
||||
int written = _codec->CompressFrame(isKeyFrame, frameData, &compressedData);
|
||||
if(written < 0) {
|
||||
if (written < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(_codecType == VideoCodec::None) {
|
||||
if (_codecType == VideoCodec::None)
|
||||
{
|
||||
isKeyFrame = true;
|
||||
}
|
||||
WriteAviChunk(_codecType == VideoCodec::None ? "00db" : "00dc", written, compressedData, isKeyFrame ? 0x10 : 0);
|
||||
_frames++;
|
||||
|
||||
if(_audioPos) {
|
||||
if (_audioPos)
|
||||
{
|
||||
auto lock = _audioLock.AcquireSafe();
|
||||
WriteAviChunk("01wb", _audioPos, _audiobuf, 0);
|
||||
_audiowritten += _audioPos;
|
||||
|
@ -261,13 +273,14 @@ void AviWriter::AddFrame(uint8_t *frameData)
|
|||
}
|
||||
}
|
||||
|
||||
void AviWriter::AddSound(int16_t *data, uint32_t sampleCount)
|
||||
void AviWriter::AddSound(int16_t* data, uint32_t sampleCount)
|
||||
{
|
||||
if(!_file) {
|
||||
if (!_file)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = _audioLock.AcquireSafe();
|
||||
memcpy(_audiobuf+_audioPos/2, data, sampleCount * 4);
|
||||
memcpy(_audiobuf + _audioPos / 2, data, sampleCount * 4);
|
||||
_audioPos += sampleCount * 4;
|
||||
}
|
|
@ -46,12 +46,13 @@ private:
|
|||
private:
|
||||
void host_writew(uint8_t* buffer, uint16_t value);
|
||||
void host_writed(uint8_t* buffer, uint32_t value);
|
||||
void WriteAviChunk(const char * tag, uint32_t size, void * data, uint32_t flags);
|
||||
void WriteAviChunk(const char* tag, uint32_t size, void* data, uint32_t flags);
|
||||
|
||||
public:
|
||||
void AddFrame(uint8_t* frameData);
|
||||
void AddSound(int16_t * data, uint32_t sampleCount);
|
||||
void AddSound(int16_t* data, uint32_t sampleCount);
|
||||
|
||||
bool StartWrite(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps, uint32_t audioSampleRate, uint32_t compressionLevel);
|
||||
bool StartWrite(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps,
|
||||
uint32_t audioSampleRate, uint32_t compressionLevel);
|
||||
void EndWrite();
|
||||
};
|
|
@ -9,16 +9,19 @@ public:
|
|||
std::string out;
|
||||
|
||||
int val = 0, valb = -6;
|
||||
for(uint8_t c : data) {
|
||||
for (uint8_t c : data)
|
||||
{
|
||||
val = (val << 8) + c;
|
||||
valb += 8;
|
||||
while(valb >= 0) {
|
||||
while (valb >= 0)
|
||||
{
|
||||
out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val >> valb) & 0x3F]);
|
||||
valb -= 6;
|
||||
}
|
||||
}
|
||||
if(valb>-6) out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8)) & 0x3F]);
|
||||
while(out.size() % 4) out.push_back('=');
|
||||
if (valb > -6) out.push_back(
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8)) & 0x3F]);
|
||||
while (out.size() % 4) out.push_back('=');
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -27,14 +30,16 @@ public:
|
|||
vector<uint8_t> out;
|
||||
|
||||
vector<int> T(256, -1);
|
||||
for(int i = 0; i < 64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
|
||||
for (int i = 0; i < 64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
|
||||
|
||||
int val = 0, valb = -8;
|
||||
for(uint8_t c : in) {
|
||||
if(T[c] == -1) break;
|
||||
for (uint8_t c : in)
|
||||
{
|
||||
if (T[c] == -1) break;
|
||||
val = (val << 6) + T[c];
|
||||
valb += 6;
|
||||
if(valb >= 0) {
|
||||
if (valb >= 0)
|
||||
{
|
||||
out.push_back(val >> valb);
|
||||
valb -= 8;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,10 @@ class BaseCodec
|
|||
{
|
||||
public:
|
||||
virtual bool SetupCompress(int width, int height, uint32_t compressionLevel) = 0;
|
||||
virtual int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) = 0;
|
||||
virtual int CompressFrame(bool isKeyFrame, uint8_t* frameData, uint8_t** compressedData) = 0;
|
||||
virtual const char* GetFourCC() = 0;
|
||||
|
||||
virtual ~BaseCodec() { }
|
||||
virtual ~BaseCodec()
|
||||
{
|
||||
}
|
||||
};
|
|
@ -4,19 +4,22 @@
|
|||
#include "BpsPatcher.h"
|
||||
#include "CRC32.h"
|
||||
|
||||
int64_t BpsPatcher::ReadBase128Number(std::istream &file)
|
||||
int64_t BpsPatcher::ReadBase128Number(std::istream& file)
|
||||
{
|
||||
int64_t result = 0;
|
||||
int shift = 0;
|
||||
uint8_t buffer;
|
||||
while(true) {
|
||||
while (true)
|
||||
{
|
||||
file.read((char*)&buffer, 1);
|
||||
if(file.eof()) {
|
||||
if (file.eof())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
result += (buffer & 0x7F) << shift;
|
||||
shift += 7;
|
||||
if(buffer & 0x80) {
|
||||
if (buffer & 0x80)
|
||||
{
|
||||
break;
|
||||
}
|
||||
result += (int64_t)1 << shift;
|
||||
|
@ -25,16 +28,17 @@ int64_t BpsPatcher::ReadBase128Number(std::istream &file)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool BpsPatcher::PatchBuffer(string bpsFilepath, vector<uint8_t> &input, vector<uint8_t> &output)
|
||||
bool BpsPatcher::PatchBuffer(string bpsFilepath, vector<uint8_t>& input, vector<uint8_t>& output)
|
||||
{
|
||||
ifstream bpsFile(bpsFilepath, std::ios::in | std::ios::binary);
|
||||
if(bpsFile) {
|
||||
if (bpsFile)
|
||||
{
|
||||
return PatchBuffer(bpsFile, input, output);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BpsPatcher::PatchBuffer(std::istream &bpsFile, vector<uint8_t> &input, vector<uint8_t> &output)
|
||||
bool BpsPatcher::PatchBuffer(std::istream& bpsFile, vector<uint8_t>& input, vector<uint8_t>& output)
|
||||
{
|
||||
bpsFile.seekg(0, std::ios::end);
|
||||
size_t fileSize = (size_t)bpsFile.tellg();
|
||||
|
@ -42,14 +46,16 @@ bool BpsPatcher::PatchBuffer(std::istream &bpsFile, vector<uint8_t> &input, vect
|
|||
|
||||
char header[4];
|
||||
bpsFile.read((char*)&header, 4);
|
||||
if(memcmp((char*)&header, "BPS1", 4) != 0) {
|
||||
if (memcmp((char*)&header, "BPS1", 4) != 0)
|
||||
{
|
||||
//Invalid BPS file
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t inputFileSize = ReadBase128Number(bpsFile);
|
||||
int64_t outputFileSize = ReadBase128Number(bpsFile);
|
||||
if(inputFileSize == -1 || outputFileSize == -1) {
|
||||
if (inputFileSize == -1 || outputFileSize == -1)
|
||||
{
|
||||
//Invalid file
|
||||
return false;
|
||||
}
|
||||
|
@ -62,49 +68,58 @@ bool BpsPatcher::PatchBuffer(std::istream &bpsFile, vector<uint8_t> &input, vect
|
|||
uint32_t outputOffset = 0;
|
||||
uint32_t inputRelativeOffset = 0;
|
||||
uint32_t outputRelativeOffset = 0;
|
||||
while((size_t)bpsFile.tellg() < fileSize - 12) {
|
||||
while ((size_t)bpsFile.tellg() < fileSize - 12)
|
||||
{
|
||||
int64_t data = ReadBase128Number(bpsFile);
|
||||
if(data == -1) {
|
||||
if (data == -1)
|
||||
{
|
||||
//Invalid file
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t command = data & 0x03;
|
||||
uint64_t length = (data >> 2) + 1;
|
||||
switch(command) {
|
||||
case 0:
|
||||
//SourceRead
|
||||
while(length--) {
|
||||
output[outputOffset] = input[outputOffset];
|
||||
outputOffset++;
|
||||
}
|
||||
break;
|
||||
switch (command)
|
||||
{
|
||||
case 0:
|
||||
//SourceRead
|
||||
while (length--)
|
||||
{
|
||||
output[outputOffset] = input[outputOffset];
|
||||
outputOffset++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
//TargetRead
|
||||
while(length--) {
|
||||
uint8_t value = 0;
|
||||
bpsFile.read((char*)&value, 1);
|
||||
case 1:
|
||||
//TargetRead
|
||||
while (length--)
|
||||
{
|
||||
uint8_t value = 0;
|
||||
bpsFile.read((char*)&value, 1);
|
||||
|
||||
output[outputOffset++] = value;
|
||||
}
|
||||
break;
|
||||
output[outputOffset++] = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: {
|
||||
case 2:
|
||||
{
|
||||
//SourceCopy
|
||||
int32_t data = (int32_t)ReadBase128Number(bpsFile);
|
||||
inputRelativeOffset += (data & 1 ? -1 : +1) * (data >> 1);
|
||||
while(length--) {
|
||||
while (length--)
|
||||
{
|
||||
output[outputOffset++] = input[inputRelativeOffset++];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
case 3:
|
||||
{
|
||||
//TargetCopy
|
||||
int32_t data = (int32_t)ReadBase128Number(bpsFile);
|
||||
outputRelativeOffset += (data & 1 ? -1 : +1) * (data >> 1);
|
||||
while(length--) {
|
||||
while (length--)
|
||||
{
|
||||
output[outputOffset++] = output[outputRelativeOffset++];
|
||||
}
|
||||
break;
|
||||
|
@ -116,12 +131,15 @@ bool BpsPatcher::PatchBuffer(std::istream &bpsFile, vector<uint8_t> &input, vect
|
|||
uint8_t outputChecksum[4];
|
||||
bpsFile.read((char*)inputChecksum, 4);
|
||||
bpsFile.read((char*)outputChecksum, 4);
|
||||
uint32_t patchInputCrc = inputChecksum[0] | (inputChecksum[1] << 8) | (inputChecksum[2] << 16) | (inputChecksum[3] << 24);
|
||||
uint32_t patchOutputCrc = outputChecksum[0] | (outputChecksum[1] << 8) | (outputChecksum[2] << 16) | (outputChecksum[3] << 24);
|
||||
uint32_t patchInputCrc = inputChecksum[0] | (inputChecksum[1] << 8) | (inputChecksum[2] << 16) | (inputChecksum[3] <<
|
||||
24);
|
||||
uint32_t patchOutputCrc = outputChecksum[0] | (outputChecksum[1] << 8) | (outputChecksum[2] << 16) | (outputChecksum[
|
||||
3] << 24);
|
||||
uint32_t inputCrc = CRC32::GetCRC(input.data(), input.size());
|
||||
uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size());
|
||||
|
||||
if(patchInputCrc != inputCrc || patchOutputCrc != outputCrc) {
|
||||
if (patchInputCrc != inputCrc || patchOutputCrc != outputCrc)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
class BpsPatcher
|
||||
{
|
||||
private:
|
||||
static int64_t ReadBase128Number(std::istream &file);
|
||||
static int64_t ReadBase128Number(std::istream& file);
|
||||
|
||||
public:
|
||||
static bool PatchBuffer(std::istream &bpsFile, vector<uint8_t> &input, vector<uint8_t> &output);
|
||||
static bool PatchBuffer(string bpsFilepath, vector<uint8_t> &input, vector<uint8_t> &output);
|
||||
static bool PatchBuffer(std::istream& bpsFile, vector<uint8_t>& input, vector<uint8_t>& output);
|
||||
static bool PatchBuffer(string bpsFilepath, vector<uint8_t>& input, vector<uint8_t>& output);
|
||||
};
|
1107
Utilities/CRC32.cpp
1107
Utilities/CRC32.cpp
File diff suppressed because it is too large
Load diff
|
@ -19,18 +19,21 @@ bool CamstudioCodec::SetupCompress(int width, int height, uint32_t compressionLe
|
|||
_compressionLevel = compressionLevel;
|
||||
_orgWidth = width;
|
||||
|
||||
if(width % 4 != 0) {
|
||||
if (width % 4 != 0)
|
||||
{
|
||||
_rowStride = ((int)((width * 24 + 31) / 32 * 4));
|
||||
} else {
|
||||
_rowStride = width*3;
|
||||
}
|
||||
else
|
||||
{
|
||||
_rowStride = width * 3;
|
||||
}
|
||||
_height = height;
|
||||
|
||||
_prevFrame = new uint8_t[_rowStride*_height]; //24-bit RGB
|
||||
_currentFrame = new uint8_t[_rowStride*_height]; //24-bit RGB
|
||||
_buffer = new uint8_t[_rowStride*_height]; //24-bit RGB
|
||||
_prevFrame = new uint8_t[_rowStride * _height]; //24-bit RGB
|
||||
_currentFrame = new uint8_t[_rowStride * _height]; //24-bit RGB
|
||||
_buffer = new uint8_t[_rowStride * _height]; //24-bit RGB
|
||||
|
||||
_compressBufferLength = compressBound(_rowStride*_height) + 2;
|
||||
_compressBufferLength = compressBound(_rowStride * _height) + 2;
|
||||
_compressBuffer = new uint8_t[_compressBufferLength];
|
||||
|
||||
memset(_prevFrame, 0, _rowStride * _height);
|
||||
|
@ -45,7 +48,8 @@ bool CamstudioCodec::SetupCompress(int width, int height, uint32_t compressionLe
|
|||
|
||||
void CamstudioCodec::LoadRow(uint8_t* inPointer, uint8_t* outPointer)
|
||||
{
|
||||
for(int x = 0; x < _orgWidth; x++) {
|
||||
for (int x = 0; x < _orgWidth; x++)
|
||||
{
|
||||
outPointer[0] = inPointer[0];
|
||||
outPointer[1] = inPointer[1];
|
||||
outPointer[2] = inPointer[2];
|
||||
|
@ -54,7 +58,7 @@ void CamstudioCodec::LoadRow(uint8_t* inPointer, uint8_t* outPointer)
|
|||
}
|
||||
}
|
||||
|
||||
int CamstudioCodec::CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData)
|
||||
int CamstudioCodec::CompressFrame(bool isKeyFrame, uint8_t* frameData, uint8_t** compressedData)
|
||||
{
|
||||
deflateReset(&_compressor);
|
||||
|
||||
|
@ -65,21 +69,26 @@ int CamstudioCodec::CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t**
|
|||
_compressBuffer[1] = 8; //8-bit per color
|
||||
|
||||
uint8_t* rowBuffer = _currentFrame;
|
||||
for(int y = 0; y < _height; y++) {
|
||||
for (int y = 0; y < _height; y++)
|
||||
{
|
||||
LoadRow(frameData + (_height - y - 1) * _orgWidth * 4, rowBuffer);
|
||||
rowBuffer += _rowStride;
|
||||
}
|
||||
|
||||
if(isKeyFrame) {
|
||||
if (isKeyFrame)
|
||||
{
|
||||
_compressor.next_in = _currentFrame;
|
||||
} else {
|
||||
for(int i = 0, len = _rowStride * _height; i < len; i++) {
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0, len = _rowStride * _height; i < len; i++)
|
||||
{
|
||||
_buffer[i] = _currentFrame[i] - _prevFrame[i];
|
||||
}
|
||||
_compressor.next_in = _buffer;
|
||||
}
|
||||
|
||||
memcpy(_prevFrame, _currentFrame, _rowStride*_height);
|
||||
memcpy(_prevFrame, _currentFrame, _rowStride * _height);
|
||||
|
||||
_compressor.avail_in = _height * _rowStride;
|
||||
deflate(&_compressor, MZ_FINISH);
|
||||
|
|
|
@ -25,6 +25,6 @@ public:
|
|||
virtual ~CamstudioCodec();
|
||||
|
||||
virtual bool SetupCompress(int width, int height, uint32_t compressionLevel) override;
|
||||
virtual int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) override;
|
||||
virtual int CompressFrame(bool isKeyFrame, uint8_t* frameData, uint8_t** compressedData) override;
|
||||
virtual const char* GetFourCC() override;
|
||||
};
|
|
@ -2,10 +2,11 @@
|
|||
#include "Equalizer.h"
|
||||
#include "orfanidis_eq.h"
|
||||
|
||||
void Equalizer::ApplyEqualizer(uint32_t sampleCount, int16_t *samples)
|
||||
void Equalizer::ApplyEqualizer(uint32_t sampleCount, int16_t* samples)
|
||||
{
|
||||
double outL, outR;
|
||||
for(uint32_t i = 0; i < sampleCount; i++) {
|
||||
for (uint32_t i = 0; i < sampleCount; i++)
|
||||
{
|
||||
double inL = samples[i * 2];
|
||||
double inR = samples[i * 2 + 1];
|
||||
|
||||
|
@ -19,13 +20,18 @@ void Equalizer::ApplyEqualizer(uint32_t sampleCount, int16_t *samples)
|
|||
|
||||
void Equalizer::UpdateEqualizers(vector<double> bandGains, uint32_t sampleRate)
|
||||
{
|
||||
if(_prevSampleRate != sampleRate || memcmp(bandGains.data(), _prevEqualizerGains.data(), bandGains.size() * sizeof(double)) != 0) {
|
||||
vector<double> bands = { 40, 56, 80, 113, 160, 225, 320, 450, 600, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 10000, 12500, 13000 };
|
||||
if (_prevSampleRate != sampleRate || memcmp(bandGains.data(), _prevEqualizerGains.data(),
|
||||
bandGains.size() * sizeof(double)) != 0)
|
||||
{
|
||||
vector<double> bands = {
|
||||
40, 56, 80, 113, 160, 225, 320, 450, 600, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 10000, 12500, 13000
|
||||
};
|
||||
bands.insert(bands.begin(), bands[0] - (bands[1] - bands[0]));
|
||||
bands.insert(bands.end(), bands[bands.size() - 1] + (bands[bands.size() - 1] - bands[bands.size() - 2]));
|
||||
|
||||
_eqFrequencyGrid.reset(new orfanidis_eq::freq_grid());
|
||||
for(size_t i = 1; i < bands.size() - 1; i++) {
|
||||
for (size_t i = 1; i < bands.size() - 1; i++)
|
||||
{
|
||||
_eqFrequencyGrid->add_band((bands[i] + bands[i - 1]) / 2, bands[i], (bands[i + 1] + bands[i]) / 2);
|
||||
}
|
||||
|
||||
|
@ -34,7 +40,8 @@ void Equalizer::UpdateEqualizers(vector<double> bandGains, uint32_t sampleRate)
|
|||
_equalizerLeft->set_sample_rate(sampleRate);
|
||||
_equalizerRight->set_sample_rate(sampleRate);
|
||||
|
||||
for(unsigned int i = 0; i < _eqFrequencyGrid->get_number_of_bands(); i++) {
|
||||
for (unsigned int i = 0; i < _eqFrequencyGrid->get_number_of_bands(); i++)
|
||||
{
|
||||
_equalizerLeft->change_band_gain_db(i, bandGains[i]);
|
||||
_equalizerRight->change_band_gain_db(i, bandGains[i]);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,6 @@ private:
|
|||
vector<double> _prevEqualizerGains;
|
||||
|
||||
public:
|
||||
void ApplyEqualizer(uint32_t sampleCount, int16_t *samples);
|
||||
void ApplyEqualizer(uint32_t sampleCount, int16_t* samples);
|
||||
void UpdateEqualizers(vector<double> bandGains, uint32_t sampleRate);
|
||||
};
|
|
@ -8,29 +8,38 @@ private:
|
|||
uint16_t _pos = 0;
|
||||
bool _lowerCase = false;
|
||||
|
||||
void WriteAll() {}
|
||||
void WriteAll()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
FastString(bool lowerCase = false) { _lowerCase = lowerCase; }
|
||||
FastString(const char* str, int size) { Write(str, size); }
|
||||
FastString(string &str) { Write(str); }
|
||||
FastString(string& str) { Write(str); }
|
||||
|
||||
void Write(char c)
|
||||
{
|
||||
if(_lowerCase) {
|
||||
if (_lowerCase)
|
||||
{
|
||||
_buffer[_pos++] = ::tolower(c);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffer[_pos++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
void Write(const char* str, int size)
|
||||
{
|
||||
if(_lowerCase) {
|
||||
for(int i = 0; i < size; i++) {
|
||||
if (_lowerCase)
|
||||
{
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
_buffer[_pos + i] = ::tolower(str[i]);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(_buffer + _pos, str, size);
|
||||
}
|
||||
_pos += size;
|
||||
|
@ -38,7 +47,8 @@ public:
|
|||
|
||||
void Delimiter(const char* str)
|
||||
{
|
||||
if(_pos > 0) {
|
||||
if (_pos > 0)
|
||||
{
|
||||
Write(str, (uint16_t)strlen(str));
|
||||
}
|
||||
}
|
||||
|
@ -48,19 +58,23 @@ public:
|
|||
Write(str, (uint16_t)strlen(str));
|
||||
}
|
||||
|
||||
void Write(string &str, bool preserveCase = false)
|
||||
void Write(string& str, bool preserveCase = false)
|
||||
{
|
||||
if(_lowerCase && !preserveCase) {
|
||||
for(size_t i = 0; i < str.size(); i++) {
|
||||
if (_lowerCase && !preserveCase)
|
||||
{
|
||||
for (size_t i = 0; i < str.size(); i++)
|
||||
{
|
||||
_buffer[_pos + i] = ::tolower(str[i]);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(_buffer + _pos, str.c_str(), str.size());
|
||||
}
|
||||
_pos += (uint16_t)str.size();
|
||||
}
|
||||
|
||||
void Write(FastString &str)
|
||||
void Write(FastString& str)
|
||||
{
|
||||
memcpy(_buffer + _pos, str._buffer, str._pos);
|
||||
_pos += str._pos;
|
||||
|
@ -77,8 +91,8 @@ public:
|
|||
return _pos;
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
void WriteAll(T first, Args... args)
|
||||
template <typename T, typename... Args>
|
||||
void WriteAll(T first, Args ... args)
|
||||
{
|
||||
Write(first);
|
||||
WriteAll(args...);
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
#ifndef LIBRETRO
|
||||
#if __has_include(<filesystem>)
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#elif __has_include(<experimental/filesystem>)
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
@ -30,7 +30,8 @@ void FolderUtilities::SetHomeFolder(string homeFolder)
|
|||
|
||||
string FolderUtilities::GetHomeFolder()
|
||||
{
|
||||
if(_homeFolder.size() == 0) {
|
||||
if (_homeFolder.size() == 0)
|
||||
{
|
||||
throw std::runtime_error("Home folder not specified");
|
||||
}
|
||||
return _homeFolder;
|
||||
|
@ -42,15 +43,18 @@ void FolderUtilities::AddKnownGameFolder(string gameFolder)
|
|||
string lowerCaseFolder = gameFolder;
|
||||
std::transform(lowerCaseFolder.begin(), lowerCaseFolder.end(), lowerCaseFolder.begin(), ::tolower);
|
||||
|
||||
for(string folder : _gameFolders) {
|
||||
for (string folder : _gameFolders)
|
||||
{
|
||||
std::transform(folder.begin(), folder.end(), folder.begin(), ::tolower);
|
||||
if(folder.compare(lowerCaseFolder) == 0) {
|
||||
if (folder.compare(lowerCaseFolder) == 0)
|
||||
{
|
||||
alreadyExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!alreadyExists) {
|
||||
if (!alreadyExists)
|
||||
{
|
||||
_gameFolders.push_back(gameFolder);
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +64,8 @@ vector<string> FolderUtilities::GetKnownGameFolders()
|
|||
return _gameFolders;
|
||||
}
|
||||
|
||||
void FolderUtilities::SetFolderOverrides(string saveFolder, string saveStateFolder, string screenshotFolder, string firmwareFolder)
|
||||
void FolderUtilities::SetFolderOverrides(string saveFolder, string saveStateFolder, string screenshotFolder,
|
||||
string firmwareFolder)
|
||||
{
|
||||
_saveFolderOverride = saveFolder;
|
||||
_saveStateFolderOverride = saveStateFolder;
|
||||
|
@ -71,9 +76,12 @@ void FolderUtilities::SetFolderOverrides(string saveFolder, string saveStateFold
|
|||
string FolderUtilities::GetSaveFolder()
|
||||
{
|
||||
string folder;
|
||||
if(_saveFolderOverride.empty()) {
|
||||
if (_saveFolderOverride.empty())
|
||||
{
|
||||
folder = CombinePath(GetHomeFolder(), "Saves");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
folder = _saveFolderOverride;
|
||||
}
|
||||
CreateFolder(folder);
|
||||
|
@ -83,9 +91,12 @@ string FolderUtilities::GetSaveFolder()
|
|||
string FolderUtilities::GetFirmwareFolder()
|
||||
{
|
||||
string folder;
|
||||
if(_firmwareFolderOverride.empty()) {
|
||||
if (_firmwareFolderOverride.empty())
|
||||
{
|
||||
folder = CombinePath(GetHomeFolder(), "Firmware");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
folder = _firmwareFolderOverride;
|
||||
}
|
||||
CreateFolder(folder);
|
||||
|
@ -109,9 +120,12 @@ string FolderUtilities::GetDebuggerFolder()
|
|||
string FolderUtilities::GetSaveStateFolder()
|
||||
{
|
||||
string folder;
|
||||
if(_saveStateFolderOverride.empty()) {
|
||||
if (_saveStateFolderOverride.empty())
|
||||
{
|
||||
folder = CombinePath(GetHomeFolder(), "SaveStates");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
folder = _saveStateFolderOverride;
|
||||
}
|
||||
CreateFolder(folder);
|
||||
|
@ -121,9 +135,12 @@ string FolderUtilities::GetSaveStateFolder()
|
|||
string FolderUtilities::GetScreenshotFolder()
|
||||
{
|
||||
string folder;
|
||||
if(_screenshotFolderOverride.empty()) {
|
||||
if (_screenshotFolderOverride.empty())
|
||||
{
|
||||
folder = CombinePath(GetHomeFolder(), "Screenshots");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
folder = _screenshotFolderOverride;
|
||||
}
|
||||
CreateFolder(folder);
|
||||
|
@ -140,7 +157,8 @@ string FolderUtilities::GetRecentGamesFolder()
|
|||
string FolderUtilities::GetExtension(string filename)
|
||||
{
|
||||
size_t position = filename.find_last_of('.');
|
||||
if(position != string::npos) {
|
||||
if (position != string::npos)
|
||||
{
|
||||
string ext = filename.substr(position, filename.size() - position);
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
|
||||
return ext;
|
||||
|
@ -160,16 +178,22 @@ vector<string> FolderUtilities::GetFolders(string rootFolder)
|
|||
vector<string> folders;
|
||||
|
||||
std::error_code errorCode;
|
||||
if(!fs::is_directory(fs::u8path(rootFolder), errorCode)) {
|
||||
if (!fs::is_directory(fs::u8path(rootFolder), errorCode))
|
||||
{
|
||||
return folders;
|
||||
}
|
||||
|
||||
for(fs::recursive_directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++) {
|
||||
if(i.depth() > 1) {
|
||||
for (fs::recursive_directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++)
|
||||
{
|
||||
if (i.depth() > 1)
|
||||
{
|
||||
//Prevent excessive recursion
|
||||
i.disable_recursion_pending();
|
||||
} else {
|
||||
if(fs::is_directory(i->path(), errorCode)) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fs::is_directory(i->path(), errorCode))
|
||||
{
|
||||
folders.push_back(i->path().u8string());
|
||||
}
|
||||
}
|
||||
|
@ -178,34 +202,46 @@ vector<string> FolderUtilities::GetFolders(string rootFolder)
|
|||
return folders;
|
||||
}
|
||||
|
||||
vector<string> FolderUtilities::GetFilesInFolder(string rootFolder, std::unordered_set<string> extensions, bool recursive)
|
||||
vector<string> FolderUtilities::GetFilesInFolder(string rootFolder, std::unordered_set<string> extensions,
|
||||
bool recursive)
|
||||
{
|
||||
vector<string> files;
|
||||
vector<string> folders = { { rootFolder } };
|
||||
vector<string> folders = {{rootFolder}};
|
||||
|
||||
std::error_code errorCode;
|
||||
if(!fs::is_directory(fs::u8path(rootFolder), errorCode)) {
|
||||
if (!fs::is_directory(fs::u8path(rootFolder), errorCode))
|
||||
{
|
||||
return files;
|
||||
}
|
||||
|
||||
if(recursive) {
|
||||
for(fs::recursive_directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++) {
|
||||
if(i.depth() > 1) {
|
||||
if (recursive)
|
||||
{
|
||||
for (fs::recursive_directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++)
|
||||
{
|
||||
if (i.depth() > 1)
|
||||
{
|
||||
//Prevent excessive recursion
|
||||
i.disable_recursion_pending();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
string extension = i->path().extension().u8string();
|
||||
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
||||
if(extensions.empty() || extensions.find(extension) != extensions.end()) {
|
||||
if (extensions.empty() || extensions.find(extension) != extensions.end())
|
||||
{
|
||||
files.push_back(i->path().u8string());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(fs::directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++) {
|
||||
}
|
||||
else
|
||||
{
|
||||
for (fs::directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++)
|
||||
{
|
||||
string extension = i->path().extension().u8string();
|
||||
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
||||
if(extensions.empty() || extensions.find(extension) != extensions.end()) {
|
||||
if (extensions.empty() || extensions.find(extension) != extensions.end())
|
||||
{
|
||||
files.push_back(i->path().u8string());
|
||||
}
|
||||
}
|
||||
|
@ -217,7 +253,8 @@ vector<string> FolderUtilities::GetFilesInFolder(string rootFolder, std::unorder
|
|||
string FolderUtilities::GetFilename(string filepath, bool includeExtension)
|
||||
{
|
||||
fs::path filename = fs::u8path(filepath).filename();
|
||||
if(!includeExtension) {
|
||||
if (!includeExtension)
|
||||
{
|
||||
filename.replace_extension("");
|
||||
}
|
||||
return filename.u8string();
|
||||
|
@ -231,9 +268,12 @@ string FolderUtilities::GetFolderName(string filepath)
|
|||
string FolderUtilities::CombinePath(string folder, string filename)
|
||||
{
|
||||
//Windows supports forward slashes for paths, too. And fs::u8path is abnormally slow.
|
||||
if(folder[folder.length() - 1] != '/') {
|
||||
if (folder[folder.length() - 1] != '/')
|
||||
{
|
||||
return folder + "/" + filename;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return folder + filename;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,8 @@ public:
|
|||
static void SetHomeFolder(string homeFolder);
|
||||
static string GetHomeFolder();
|
||||
|
||||
static void SetFolderOverrides(string saveFolder, string saveStateFolder, string screenshotFolder, string firmwareFolder);
|
||||
static void SetFolderOverrides(string saveFolder, string saveStateFolder, string screenshotFolder,
|
||||
string firmwareFolder);
|
||||
|
||||
static void AddKnownGameFolder(string gameFolder);
|
||||
static vector<string> GetKnownGameFolders();
|
||||
|
|
|
@ -12,7 +12,8 @@ GifRecorder::~GifRecorder()
|
|||
StopRecording();
|
||||
}
|
||||
|
||||
bool GifRecorder::StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate, double fps)
|
||||
bool GifRecorder::StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp,
|
||||
uint32_t audioSampleRate, double fps)
|
||||
{
|
||||
_outputFile = filename;
|
||||
_recording = GifBegin(_gif.get(), filename.c_str(), width, height, 2, 8, false);
|
||||
|
@ -22,7 +23,8 @@ bool GifRecorder::StartRecording(string filename, uint32_t width, uint32_t heigh
|
|||
|
||||
void GifRecorder::StopRecording()
|
||||
{
|
||||
if(_recording) {
|
||||
if (_recording)
|
||||
{
|
||||
GifEnd(_gif.get());
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +33,8 @@ void GifRecorder::AddFrame(void* frameBuffer, uint32_t width, uint32_t height, d
|
|||
{
|
||||
_frameCounter++;
|
||||
|
||||
if(fps < 55 || (_frameCounter % 6) != 0) {
|
||||
if (fps < 55 || (_frameCounter % 6) != 0)
|
||||
{
|
||||
//At 60 FPS, skip 1 of every 6 frames (max FPS for GIFs is 50fps)
|
||||
GifWriteFrame(_gif.get(), (uint8_t*)frameBuffer, width, height, 2, 8, false);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ public:
|
|||
GifRecorder();
|
||||
virtual ~GifRecorder();
|
||||
|
||||
bool StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate, double fps) override;
|
||||
bool StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate,
|
||||
double fps) override;
|
||||
void StopRecording() override;
|
||||
void AddFrame(void* frameBuffer, uint32_t width, uint32_t height, double fps) override;
|
||||
void AddSound(int16_t* soundBuffer, uint32_t sampleCount, uint32_t sampleRate) override;
|
||||
|
|
|
@ -43,100 +43,103 @@ extern uint32_t RGBtoYUV[16777216];
|
|||
|
||||
static inline uint32_t rgb_to_yuv(uint32_t c)
|
||||
{
|
||||
// Mask against MASK_RGB to discard the alpha channel
|
||||
return RGBtoYUV[MASK_RGB & c];
|
||||
// Mask against MASK_RGB to discard the alpha channel
|
||||
return RGBtoYUV[MASK_RGB & c];
|
||||
}
|
||||
|
||||
/* Test if there is difference in color */
|
||||
static inline int yuv_diff(uint32_t yuv1, uint32_t yuv2) {
|
||||
return (( std::abs((int)((yuv1 & Ymask) - (yuv2 & Ymask))) > trY ) ||
|
||||
( std::abs((int)((yuv1 & Umask) - (yuv2 & Umask))) > trU ) ||
|
||||
( std::abs((int)((yuv1 & Vmask) - (yuv2 & Vmask))) > trV ) );
|
||||
static inline int yuv_diff(uint32_t yuv1, uint32_t yuv2)
|
||||
{
|
||||
return ((std::abs((int)((yuv1 & Ymask) - (yuv2 & Ymask))) > trY) ||
|
||||
(std::abs((int)((yuv1 & Umask) - (yuv2 & Umask))) > trU) ||
|
||||
(std::abs((int)((yuv1 & Vmask) - (yuv2 & Vmask))) > trV));
|
||||
}
|
||||
|
||||
static inline int Diff(uint32_t c1, uint32_t c2)
|
||||
{
|
||||
return yuv_diff(rgb_to_yuv(c1), rgb_to_yuv(c2));
|
||||
return yuv_diff(rgb_to_yuv(c1), rgb_to_yuv(c2));
|
||||
}
|
||||
|
||||
/* Interpolate functions */
|
||||
static inline uint32_t Interpolate_2(uint32_t c1, int w1, uint32_t c2, int w2, int s)
|
||||
{
|
||||
if (c1 == c2) {
|
||||
return c1;
|
||||
}
|
||||
return
|
||||
(((((c1 & MASK_ALPHA) >> 24) * w1 + ((c2 & MASK_ALPHA) >> 24) * w2) << (24-s)) & MASK_ALPHA) +
|
||||
((((c1 & MASK_2) * w1 + (c2 & MASK_2) * w2) >> s) & MASK_2) +
|
||||
((((c1 & MASK_13) * w1 + (c2 & MASK_13) * w2) >> s) & MASK_13);
|
||||
if (c1 == c2)
|
||||
{
|
||||
return c1;
|
||||
}
|
||||
return
|
||||
(((((c1 & MASK_ALPHA) >> 24) * w1 + ((c2 & MASK_ALPHA) >> 24) * w2) << (24 - s)) & MASK_ALPHA) +
|
||||
((((c1 & MASK_2) * w1 + (c2 & MASK_2) * w2) >> s) & MASK_2) +
|
||||
((((c1 & MASK_13) * w1 + (c2 & MASK_13) * w2) >> s) & MASK_13);
|
||||
}
|
||||
|
||||
static inline uint32_t Interpolate_3(uint32_t c1, int w1, uint32_t c2, int w2, uint32_t c3, int w3, int s)
|
||||
{
|
||||
return
|
||||
(((((c1 & MASK_ALPHA) >> 24) * w1 + ((c2 & MASK_ALPHA) >> 24) * w2 + ((c3 & MASK_ALPHA) >> 24) * w3) << (24-s)) & MASK_ALPHA) +
|
||||
((((c1 & MASK_2) * w1 + (c2 & MASK_2) * w2 + (c3 & MASK_2) * w3) >> s) & MASK_2) +
|
||||
((((c1 & MASK_13) * w1 + (c2 & MASK_13) * w2 + (c3 & MASK_13) * w3) >> s) & MASK_13);
|
||||
return
|
||||
(((((c1 & MASK_ALPHA) >> 24) * w1 + ((c2 & MASK_ALPHA) >> 24) * w2 + ((c3 & MASK_ALPHA) >> 24) * w3) << (24 - s))
|
||||
& MASK_ALPHA) +
|
||||
((((c1 & MASK_2) * w1 + (c2 & MASK_2) * w2 + (c3 & MASK_2) * w3) >> s) & MASK_2) +
|
||||
((((c1 & MASK_13) * w1 + (c2 & MASK_13) * w2 + (c3 & MASK_13) * w3) >> s) & MASK_13);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp1(uint32_t c1, uint32_t c2)
|
||||
{
|
||||
//(c1*3+c2) >> 2;
|
||||
return Interpolate_2(c1, 3, c2, 1, 2);
|
||||
//(c1*3+c2) >> 2;
|
||||
return Interpolate_2(c1, 3, c2, 1, 2);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp2(uint32_t c1, uint32_t c2, uint32_t c3)
|
||||
{
|
||||
//(c1*2+c2+c3) >> 2;
|
||||
return Interpolate_3(c1, 2, c2, 1, c3, 1, 2);
|
||||
//(c1*2+c2+c3) >> 2;
|
||||
return Interpolate_3(c1, 2, c2, 1, c3, 1, 2);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp3(uint32_t c1, uint32_t c2)
|
||||
{
|
||||
//(c1*7+c2)/8;
|
||||
return Interpolate_2(c1, 7, c2, 1, 3);
|
||||
//(c1*7+c2)/8;
|
||||
return Interpolate_2(c1, 7, c2, 1, 3);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp4(uint32_t c1, uint32_t c2, uint32_t c3)
|
||||
{
|
||||
//(c1*2+(c2+c3)*7)/16;
|
||||
return Interpolate_3(c1, 2, c2, 7, c3, 7, 4);
|
||||
//(c1*2+(c2+c3)*7)/16;
|
||||
return Interpolate_3(c1, 2, c2, 7, c3, 7, 4);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp5(uint32_t c1, uint32_t c2)
|
||||
{
|
||||
//(c1+c2) >> 1;
|
||||
return Interpolate_2(c1, 1, c2, 1, 1);
|
||||
//(c1+c2) >> 1;
|
||||
return Interpolate_2(c1, 1, c2, 1, 1);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp6(uint32_t c1, uint32_t c2, uint32_t c3)
|
||||
{
|
||||
//(c1*5+c2*2+c3)/8;
|
||||
return Interpolate_3(c1, 5, c2, 2, c3, 1, 3);
|
||||
//(c1*5+c2*2+c3)/8;
|
||||
return Interpolate_3(c1, 5, c2, 2, c3, 1, 3);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp7(uint32_t c1, uint32_t c2, uint32_t c3)
|
||||
{
|
||||
//(c1*6+c2+c3)/8;
|
||||
return Interpolate_3(c1, 6, c2, 1, c3, 1, 3);
|
||||
//(c1*6+c2+c3)/8;
|
||||
return Interpolate_3(c1, 6, c2, 1, c3, 1, 3);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp8(uint32_t c1, uint32_t c2)
|
||||
{
|
||||
//(c1*5+c2*3)/8;
|
||||
return Interpolate_2(c1, 5, c2, 3, 3);
|
||||
//(c1*5+c2*3)/8;
|
||||
return Interpolate_2(c1, 5, c2, 3, 3);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp9(uint32_t c1, uint32_t c2, uint32_t c3)
|
||||
{
|
||||
//(c1*2+(c2+c3)*3)/8;
|
||||
return Interpolate_3(c1, 2, c2, 3, c3, 3, 3);
|
||||
//(c1*2+(c2+c3)*3)/8;
|
||||
return Interpolate_3(c1, 2, c2, 3, c3, 3, 3);
|
||||
}
|
||||
|
||||
static inline uint32_t Interp10(uint32_t c1, uint32_t c2, uint32_t c3)
|
||||
{
|
||||
//(c1*14+c2+c3)/16;
|
||||
return Interpolate_3(c1, 14, c2, 1, c3, 1, 4);
|
||||
//(c1*14+c2+c3)/16;
|
||||
return Interpolate_3(c1, 14, c2, 1, c3, 1, 4);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
10104
Utilities/HQX/hq4x.cpp
10104
Utilities/HQX/hq4x.cpp
File diff suppressed because it is too large
Load diff
|
@ -24,34 +24,37 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#if defined( __GNUC__ )
|
||||
#ifdef __MINGW32__
|
||||
#ifdef __MINGW32__
|
||||
#define HQX_CALLCONV __stdcall
|
||||
#else
|
||||
#define HQX_CALLCONV
|
||||
#endif
|
||||
#else
|
||||
#define HQX_CALLCONV
|
||||
#define HQX_CALLCONV
|
||||
#endif
|
||||
#else
|
||||
#define HQX_CALLCONV
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#ifdef DLL_EXPORT
|
||||
#ifdef DLL_EXPORT
|
||||
#define HQX_API __declspec(dllexport)
|
||||
#else
|
||||
#define HQX_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define HQX_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define HQX_API
|
||||
#endif
|
||||
|
||||
void HQX_CALLCONV hqxInit(void);
|
||||
void HQX_CALLCONV hqx(uint32_t scale, uint32_t * src, uint32_t * dest, int width, int height);
|
||||
void HQX_CALLCONV hqx(uint32_t scale, uint32_t* src, uint32_t* dest, int width, int height);
|
||||
|
||||
void HQX_CALLCONV hq2x_32( uint32_t * src, uint32_t * dest, int width, int height );
|
||||
void HQX_CALLCONV hq3x_32( uint32_t * src, uint32_t * dest, int width, int height );
|
||||
void HQX_CALLCONV hq4x_32( uint32_t * src, uint32_t * dest, int width, int height );
|
||||
void HQX_CALLCONV hq2x_32(uint32_t* src, uint32_t* dest, int width, int height);
|
||||
void HQX_CALLCONV hq3x_32(uint32_t* src, uint32_t* dest, int width, int height);
|
||||
void HQX_CALLCONV hq4x_32(uint32_t* src, uint32_t* dest, int width, int height);
|
||||
|
||||
void HQX_CALLCONV hq2x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height );
|
||||
void HQX_CALLCONV hq3x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height );
|
||||
void HQX_CALLCONV hq4x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height );
|
||||
void HQX_CALLCONV hq2x_32_rb(uint32_t* src, uint32_t src_rowBytes, uint32_t* dest, uint32_t dest_rowBytes, int width,
|
||||
int height);
|
||||
void HQX_CALLCONV hq3x_32_rb(uint32_t* src, uint32_t src_rowBytes, uint32_t* dest, uint32_t dest_rowBytes, int width,
|
||||
int height);
|
||||
void HQX_CALLCONV hq4x_32_rb(uint32_t* src, uint32_t src_rowBytes, uint32_t* dest, uint32_t dest_rowBytes, int width,
|
||||
int height);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,29 +20,34 @@
|
|||
#include <stdint.h>
|
||||
#include "hqx.h"
|
||||
|
||||
uint32_t RGBtoYUV[16777216];
|
||||
uint32_t YUV1, YUV2;
|
||||
uint32_t RGBtoYUV[16777216];
|
||||
uint32_t YUV1, YUV2;
|
||||
|
||||
void HQX_CALLCONV hqxInit(void)
|
||||
{
|
||||
/* Initalize RGB to YUV lookup table */
|
||||
uint32_t c, r, g, b, y, u, v;
|
||||
for (c = 0; c < 16777215; c++) {
|
||||
r = (c & 0xFF0000) >> 16;
|
||||
g = (c & 0x00FF00) >> 8;
|
||||
b = c & 0x0000FF;
|
||||
y = (uint32_t)(0.299*r + 0.587*g + 0.114*b);
|
||||
u = (uint32_t)(-0.169*r - 0.331*g + 0.5*b) + 128;
|
||||
v = (uint32_t)(0.5*r - 0.419*g - 0.081*b) + 128;
|
||||
RGBtoYUV[c] = (y << 16) + (u << 8) + v;
|
||||
}
|
||||
}
|
||||
|
||||
void HQX_CALLCONV hqx(uint32_t scale, uint32_t * src, uint32_t * dest, int width, int height)
|
||||
{
|
||||
switch(scale) {
|
||||
case 2: hq2x_32(src, dest, width, height); break;
|
||||
case 3: hq3x_32(src, dest, width, height); break;
|
||||
case 4: hq4x_32(src, dest, width, height); break;
|
||||
/* Initalize RGB to YUV lookup table */
|
||||
uint32_t c, r, g, b, y, u, v;
|
||||
for (c = 0; c < 16777215; c++)
|
||||
{
|
||||
r = (c & 0xFF0000) >> 16;
|
||||
g = (c & 0x00FF00) >> 8;
|
||||
b = c & 0x0000FF;
|
||||
y = (uint32_t)(0.299 * r + 0.587 * g + 0.114 * b);
|
||||
u = (uint32_t)(-0.169 * r - 0.331 * g + 0.5 * b) + 128;
|
||||
v = (uint32_t)(0.5 * r - 0.419 * g - 0.081 * b) + 128;
|
||||
RGBtoYUV[c] = (y << 16) + (u << 8) + v;
|
||||
}
|
||||
}
|
||||
|
||||
void HQX_CALLCONV hqx(uint32_t scale, uint32_t* src, uint32_t* dest, int width, int height)
|
||||
{
|
||||
switch (scale)
|
||||
{
|
||||
case 2: hq2x_32(src, dest, width, height);
|
||||
break;
|
||||
case 3: hq3x_32(src, dest, width, height);
|
||||
break;
|
||||
case 4: hq4x_32(src, dest, width, height);
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -36,7 +36,8 @@ void HermiteResampler::PushSample(double prevValues[4], int16_t sample)
|
|||
|
||||
void HermiteResampler::Reset()
|
||||
{
|
||||
for(int i = 0; i < 4; i++) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
_prevLeft[i] = 0.0;
|
||||
_prevRight[i] = 0.0;
|
||||
}
|
||||
|
@ -50,15 +51,18 @@ void HermiteResampler::SetSampleRates(double srcRate, double dstRate)
|
|||
|
||||
uint32_t HermiteResampler::Resample(int16_t* in, uint32_t inSampleCount, int16_t* out)
|
||||
{
|
||||
if(_rateRatio == 1.0) {
|
||||
if (_rateRatio == 1.0)
|
||||
{
|
||||
memcpy(out, in, inSampleCount * 2 * sizeof(int16_t));
|
||||
return inSampleCount;
|
||||
}
|
||||
|
||||
uint32_t outPos = 0;
|
||||
|
||||
for(uint32_t i = 0; i < inSampleCount * 2; i += 2) {
|
||||
while(_fraction <= 1.0) {
|
||||
for (uint32_t i = 0; i < inSampleCount * 2; i += 2)
|
||||
{
|
||||
while (_fraction <= 1.0)
|
||||
{
|
||||
//Generate interpolated samples until we have enough samples for the current source sample
|
||||
out[outPos] = HermiteInterpolate(_prevLeft, _fraction);
|
||||
out[outPos + 1] = HermiteInterpolate(_prevRight, _fraction);
|
||||
|
|
|
@ -1,26 +1,8 @@
|
|||
#include "stdafx.h"
|
||||
#include "HexUtilities.h"
|
||||
|
||||
const vector<string> HexUtilities::_hexCache = { {
|
||||
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
|
||||
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
|
||||
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
|
||||
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
|
||||
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
|
||||
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
|
||||
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
|
||||
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
|
||||
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
|
||||
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
|
||||
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
|
||||
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
|
||||
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
|
||||
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
|
||||
"E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
|
||||
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
|
||||
} };
|
||||
|
||||
constexpr const char* _hexCharCache[256] = {
|
||||
const vector<string> HexUtilities::_hexCache = {
|
||||
{
|
||||
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
|
||||
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
|
||||
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
|
||||
|
@ -37,19 +19,45 @@ constexpr const char* _hexCharCache[256] = {
|
|||
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
|
||||
"E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
|
||||
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
|
||||
}
|
||||
};
|
||||
|
||||
constexpr const char* _hexCharCache[256] = {
|
||||
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
|
||||
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
|
||||
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
|
||||
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
|
||||
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
|
||||
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
|
||||
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
|
||||
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
|
||||
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
|
||||
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
|
||||
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
|
||||
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
|
||||
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
|
||||
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
|
||||
"E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
|
||||
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
|
||||
};
|
||||
|
||||
|
||||
int HexUtilities::FromHex(string hex)
|
||||
{
|
||||
int value = 0;
|
||||
for(size_t i = 0, len = hex.size(); i < len; i++) {
|
||||
for (size_t i = 0, len = hex.size(); i < len; i++)
|
||||
{
|
||||
value <<= 4;
|
||||
if(hex[i] >= '0' && hex[i] <= '9') {
|
||||
if (hex[i] >= '0' && hex[i] <= '9')
|
||||
{
|
||||
value |= hex[i] - '0';
|
||||
} else if(hex[i] >= 'A' && hex[i] <= 'F') {
|
||||
}
|
||||
else if (hex[i] >= 'A' && hex[i] <= 'F')
|
||||
{
|
||||
value |= hex[i] - 'A' + 10;
|
||||
} else if(hex[i] >= 'a' && hex[i] <= 'f') {
|
||||
}
|
||||
else if (hex[i] >= 'a' && hex[i] <= 'f')
|
||||
{
|
||||
value |= hex[i] - 'a' + 10;
|
||||
}
|
||||
}
|
||||
|
@ -83,22 +91,31 @@ string HexUtilities::ToHex24(int32_t value)
|
|||
|
||||
string HexUtilities::ToHex(uint32_t value, bool fullSize)
|
||||
{
|
||||
if(fullSize || value > 0xFFFFFF) {
|
||||
return _hexCache[value >> 24] + _hexCache[(value >> 16) & 0xFF] + _hexCache[(value >> 8) & 0xFF] + _hexCache[value & 0xFF];
|
||||
} else if(value <= 0xFF) {
|
||||
if (fullSize || value > 0xFFFFFF)
|
||||
{
|
||||
return _hexCache[value >> 24] + _hexCache[(value >> 16) & 0xFF] + _hexCache[(value >> 8) & 0xFF] + _hexCache[value
|
||||
& 0xFF];
|
||||
}
|
||||
else if (value <= 0xFF)
|
||||
{
|
||||
return ToHex((uint8_t)value);
|
||||
} else if(value <= 0xFFFF) {
|
||||
}
|
||||
else if (value <= 0xFFFF)
|
||||
{
|
||||
return ToHex((uint16_t)value);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return _hexCache[(value >> 16) & 0xFF] + _hexCache[(value >> 8) & 0xFF] + _hexCache[value & 0xFF];
|
||||
}
|
||||
}
|
||||
|
||||
string HexUtilities::ToHex(vector<uint8_t> &data)
|
||||
string HexUtilities::ToHex(vector<uint8_t>& data)
|
||||
{
|
||||
string result;
|
||||
result.reserve(data.size() * 2);
|
||||
for(uint8_t value : data) {
|
||||
for (uint8_t value : data)
|
||||
{
|
||||
result += HexUtilities::ToHex(value);
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -13,7 +13,7 @@ public:
|
|||
static string ToHex(uint32_t value, bool fullSize = false);
|
||||
static string ToHex(int32_t value, bool fullSize = false);
|
||||
static string ToHex24(int32_t value);
|
||||
static string ToHex(vector<uint8_t> &data);
|
||||
static string ToHex(vector<uint8_t>& data);
|
||||
|
||||
static int FromHex(string hex);
|
||||
};
|
|
@ -5,6 +5,5 @@ class Serializer;
|
|||
class ISerializable
|
||||
{
|
||||
public:
|
||||
virtual void Serialize(Serializer &s) = 0;
|
||||
virtual void Serialize(Serializer& s) = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
class IVideoRecorder
|
||||
{
|
||||
public:
|
||||
virtual bool StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate, double fps) = 0;
|
||||
virtual bool StartRecording(string filename, uint32_t width, uint32_t height, uint32_t bpp, uint32_t audioSampleRate,
|
||||
double fps) = 0;
|
||||
virtual void StopRecording() = 0;
|
||||
|
||||
virtual void AddFrame(void* frameBuffer, uint32_t width, uint32_t height, double fps) = 0;
|
||||
|
|
|
@ -15,26 +15,32 @@ public:
|
|||
uint16_t RepeatCount = 0;
|
||||
uint8_t Value = 0;
|
||||
|
||||
bool ReadRecord(std::istream &ipsFile)
|
||||
bool ReadRecord(std::istream& ipsFile)
|
||||
{
|
||||
uint8_t buffer[3];
|
||||
|
||||
ipsFile.read((char*)buffer, 3);
|
||||
if(memcmp(buffer, "EOF", 3) == 0) {
|
||||
if (memcmp(buffer, "EOF", 3) == 0)
|
||||
{
|
||||
//EOF reached
|
||||
return false;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Address = buffer[2] | (buffer[1] << 8) | (buffer[0] << 16);
|
||||
|
||||
ipsFile.read((char*)buffer, 2);
|
||||
Length = buffer[1] | (buffer[0] << 8);
|
||||
|
||||
if(Length == 0) {
|
||||
if (Length == 0)
|
||||
{
|
||||
//RLE record
|
||||
ipsFile.read((char*)buffer, 3);
|
||||
RepeatCount = buffer[1] | (buffer[0] << 8);
|
||||
Value = buffer[2];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Replacement.resize(Length);
|
||||
ipsFile.read((char*)Replacement.data(), Length);
|
||||
}
|
||||
|
@ -42,7 +48,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void WriteRecord(vector<uint8_t> &output)
|
||||
void WriteRecord(vector<uint8_t>& output)
|
||||
{
|
||||
output.push_back((Address >> 16) & 0xFF);
|
||||
output.push_back((Address >> 8) & 0xFF);
|
||||
|
@ -51,37 +57,42 @@ public:
|
|||
output.push_back((Length >> 8) & 0xFF);
|
||||
output.push_back(Length & 0xFF);
|
||||
|
||||
if(Length == 0) {
|
||||
if (Length == 0)
|
||||
{
|
||||
output.push_back((RepeatCount >> 8) & 0xFF);
|
||||
output.push_back(RepeatCount & 0xFF);
|
||||
output.push_back(Value);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
output.insert(output.end(), Replacement.data(), Replacement.data() + Replacement.size());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool IpsPatcher::PatchBuffer(string ipsFilepath, vector<uint8_t> &input, vector<uint8_t> &output)
|
||||
bool IpsPatcher::PatchBuffer(string ipsFilepath, vector<uint8_t>& input, vector<uint8_t>& output)
|
||||
{
|
||||
ifstream ipsFile(ipsFilepath, std::ios::in | std::ios::binary);
|
||||
if(ipsFile) {
|
||||
if (ipsFile)
|
||||
{
|
||||
return PatchBuffer(ipsFile, input, output);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IpsPatcher::PatchBuffer(vector<uint8_t> &ipsData, vector<uint8_t> &input, vector<uint8_t> &output)
|
||||
bool IpsPatcher::PatchBuffer(vector<uint8_t>& ipsData, vector<uint8_t>& input, vector<uint8_t>& output)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss.write((char*)ipsData.data(), ipsData.size());
|
||||
return PatchBuffer(ss, input, output);
|
||||
}
|
||||
|
||||
bool IpsPatcher::PatchBuffer(std::istream &ipsFile, vector<uint8_t> &input, vector<uint8_t> &output)
|
||||
bool IpsPatcher::PatchBuffer(std::istream& ipsFile, vector<uint8_t>& input, vector<uint8_t>& output)
|
||||
{
|
||||
char header[5];
|
||||
ipsFile.read((char*)&header, 5);
|
||||
if(memcmp((char*)&header, "PATCH", 5) != 0) {
|
||||
if (memcmp((char*)&header, "PATCH", 5) != 0)
|
||||
{
|
||||
//Invalid ips file
|
||||
return false;
|
||||
}
|
||||
|
@ -89,18 +100,24 @@ bool IpsPatcher::PatchBuffer(std::istream &ipsFile, vector<uint8_t> &input, vect
|
|||
vector<IpsRecord> records;
|
||||
int32_t truncateOffset = -1;
|
||||
size_t maxOutputSize = input.size();
|
||||
while(!ipsFile.eof()) {
|
||||
while (!ipsFile.eof())
|
||||
{
|
||||
IpsRecord record;
|
||||
if(record.ReadRecord(ipsFile)) {
|
||||
if(record.Address + record.Length + record.RepeatCount > maxOutputSize) {
|
||||
if (record.ReadRecord(ipsFile))
|
||||
{
|
||||
if (record.Address + record.Length + record.RepeatCount > maxOutputSize)
|
||||
{
|
||||
maxOutputSize = record.Address + record.Length + record.RepeatCount;
|
||||
}
|
||||
records.push_back(record);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
//EOF, try to read truncate offset record if it exists
|
||||
uint8_t buffer[3];
|
||||
ipsFile.read((char*)buffer, 3);
|
||||
if(!ipsFile.eof()) {
|
||||
if (!ipsFile.eof())
|
||||
{
|
||||
truncateOffset = buffer[2] | (buffer[1] << 8) | (buffer[0] << 16);
|
||||
}
|
||||
break;
|
||||
|
@ -110,15 +127,20 @@ bool IpsPatcher::PatchBuffer(std::istream &ipsFile, vector<uint8_t> &input, vect
|
|||
output.resize(maxOutputSize);
|
||||
std::copy(input.begin(), input.end(), output.begin());
|
||||
|
||||
for(IpsRecord record : records) {
|
||||
if(record.Length == 0) {
|
||||
std::fill(&output[record.Address], &output[record.Address]+record.RepeatCount, record.Value);
|
||||
} else {
|
||||
std::copy(record.Replacement.begin(), record.Replacement.end(), output.begin()+record.Address);
|
||||
for (IpsRecord record : records)
|
||||
{
|
||||
if (record.Length == 0)
|
||||
{
|
||||
std::fill(&output[record.Address], &output[record.Address] + record.RepeatCount, record.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::copy(record.Replacement.begin(), record.Replacement.end(), output.begin() + record.Address);
|
||||
}
|
||||
}
|
||||
|
||||
if(truncateOffset != -1 && (int32_t)output.size() > truncateOffset) {
|
||||
if (truncateOffset != -1 && (int32_t)output.size() > truncateOffset)
|
||||
{
|
||||
output.resize(truncateOffset);
|
||||
}
|
||||
|
||||
|
@ -128,31 +150,41 @@ bool IpsPatcher::PatchBuffer(std::istream &ipsFile, vector<uint8_t> &input, vect
|
|||
vector<uint8_t> IpsPatcher::CreatePatch(vector<uint8_t> originalData, vector<uint8_t> newData)
|
||||
{
|
||||
vector<uint8_t> patchFile;
|
||||
if(originalData.size() != newData.size()) {
|
||||
if (originalData.size() != newData.size())
|
||||
{
|
||||
return patchFile;
|
||||
}
|
||||
|
||||
uint8_t header[5] = { 'P', 'A', 'T', 'C', 'H' };
|
||||
uint8_t header[5] = {'P', 'A', 'T', 'C', 'H'};
|
||||
patchFile.insert(patchFile.end(), header, header + sizeof(header));
|
||||
|
||||
size_t i = 0, len = originalData.size();
|
||||
while(i < len) {
|
||||
while(i < len && originalData[i] == newData[i]) {
|
||||
while (i < len)
|
||||
{
|
||||
while (i < len && originalData[i] == newData[i])
|
||||
{
|
||||
i++;
|
||||
}
|
||||
if(i < len) {
|
||||
if (i < len)
|
||||
{
|
||||
IpsRecord patchRecord;
|
||||
uint8_t rleByte = newData[i];
|
||||
uint8_t rleCount = 0;
|
||||
bool createRleRecord = false;
|
||||
patchRecord.Address = (uint32_t)i;
|
||||
patchRecord.Length = 0;
|
||||
while(i < len && patchRecord.Length < 65535 && originalData[i] != newData[i]) {
|
||||
if(newData[i] == rleByte) {
|
||||
while (i < len && patchRecord.Length < 65535 && originalData[i] != newData[i])
|
||||
{
|
||||
if (newData[i] == rleByte)
|
||||
{
|
||||
rleCount++;
|
||||
} else if(createRleRecord) {
|
||||
}
|
||||
else if (createRleRecord)
|
||||
{
|
||||
break;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
rleByte = newData[i];
|
||||
rleCount = 1;
|
||||
}
|
||||
|
@ -160,30 +192,38 @@ vector<uint8_t> IpsPatcher::CreatePatch(vector<uint8_t> originalData, vector<uin
|
|||
patchRecord.Length++;
|
||||
i++;
|
||||
|
||||
if((patchRecord.Length == rleCount && rleCount > 3) || rleCount > 13) {
|
||||
if ((patchRecord.Length == rleCount && rleCount > 3) || rleCount > 13)
|
||||
{
|
||||
//Making a RLE entry would probably save space, so write the current entry and create a RLE entry after it
|
||||
if(patchRecord.Length == rleCount) {
|
||||
if (patchRecord.Length == rleCount)
|
||||
{
|
||||
//Same character since the start of this entry, make the RLE entry now
|
||||
createRleRecord = true;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
patchRecord.Length -= rleCount;
|
||||
i -= rleCount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(createRleRecord) {
|
||||
if (createRleRecord)
|
||||
{
|
||||
patchRecord.Length = 0;
|
||||
patchRecord.RepeatCount = rleCount;
|
||||
patchRecord.Value = rleByte;
|
||||
} else {
|
||||
patchRecord.Replacement = vector<uint8_t>(&newData[patchRecord.Address], &newData[patchRecord.Address + patchRecord.Length]);
|
||||
}
|
||||
else
|
||||
{
|
||||
patchRecord.Replacement = vector<uint8_t>(&newData[patchRecord.Address],
|
||||
&newData[patchRecord.Address + patchRecord.Length]);
|
||||
}
|
||||
patchRecord.WriteRecord(patchFile);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t endOfFile[3] = { 'E', 'O', 'F' };
|
||||
uint8_t endOfFile[3] = {'E', 'O', 'F'};
|
||||
patchFile.insert(patchFile.end(), endOfFile, endOfFile + sizeof(endOfFile));
|
||||
|
||||
return patchFile;
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
class IpsPatcher
|
||||
{
|
||||
public:
|
||||
static bool PatchBuffer(string ipsFilepath, vector<uint8_t> &input, vector<uint8_t> &output);
|
||||
static bool PatchBuffer(string ipsFilepath, vector<uint8_t>& input, vector<uint8_t>& output);
|
||||
static bool PatchBuffer(vector<uint8_t>& ipsData, vector<uint8_t>& input, vector<uint8_t>& output);
|
||||
static bool PatchBuffer(std::istream &ipsFile, vector<uint8_t> &input, vector<uint8_t> &output);
|
||||
static bool PatchBuffer(std::istream& ipsFile, vector<uint8_t>& input, vector<uint8_t>& output);
|
||||
static vector<uint8_t> CreatePatch(vector<uint8_t> originalData, vector<uint8_t> newData);
|
||||
};
|
|
@ -40,8 +40,7 @@
|
|||
typename_t colorL = *(in + nextline + nextcolumn2); \
|
||||
typename_t colorM = *(in + nextline2 - prevcolumn); \
|
||||
typename_t colorN = *(in + nextline2 + 0); \
|
||||
typename_t colorO = *(in + nextline2 + nextcolumn); \
|
||||
|
||||
typename_t colorO = *(in + nextline2 + nextcolumn);
|
||||
#ifndef twoxsai_function
|
||||
#define twoxsai_function(result_cb, interpolate_cb, interpolate2_cb) \
|
||||
if (colorA == colorD && colorB != colorC) \
|
||||
|
@ -130,20 +129,23 @@
|
|||
out += 2
|
||||
#endif
|
||||
|
||||
void twoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride)
|
||||
void twoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t* src, unsigned src_stride, uint32_t* dst,
|
||||
unsigned dst_stride)
|
||||
{
|
||||
unsigned finish;
|
||||
unsigned finish;
|
||||
int y = 0;
|
||||
int x = 0;
|
||||
for(; height; height--) {
|
||||
uint32_t *in = (uint32_t*)src;
|
||||
uint32_t *out = (uint32_t*)dst;
|
||||
for (; height; height--)
|
||||
{
|
||||
uint32_t* in = (uint32_t*)src;
|
||||
uint32_t* out = (uint32_t*)dst;
|
||||
|
||||
int prevline = (y > 0 ? src_stride : 0);
|
||||
int nextline = (height > 1 ? src_stride : 0);
|
||||
int nextline2 = (height > 2 ? src_stride * 2 : nextline);
|
||||
|
||||
for(finish = width; finish; finish -= 1) {
|
||||
for (finish = width; finish; finish -= 1)
|
||||
{
|
||||
int prevcolumn = (x > 0 ? 1 : 0);
|
||||
int nextcolumn = (finish > 1 ? 1 : 0);
|
||||
int nextcolumn2 = (finish > 2 ? 2 : nextcolumn);
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#pragma once
|
||||
#include "../stdafx.h"
|
||||
|
||||
extern void supertwoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride);
|
||||
extern void twoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride);
|
||||
extern void supereagle_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride);
|
||||
|
||||
extern void supertwoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t* src, unsigned src_stride,
|
||||
uint32_t* dst, unsigned dst_stride);
|
||||
extern void twoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t* src, unsigned src_stride, uint32_t* dst,
|
||||
unsigned dst_stride);
|
||||
extern void supereagle_generic_xrgb8888(unsigned width, unsigned height, uint32_t* src, unsigned src_stride,
|
||||
uint32_t* dst, unsigned dst_stride);
|
||||
|
|
|
@ -108,20 +108,23 @@
|
|||
out += 2
|
||||
#endif
|
||||
|
||||
void supertwoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride)
|
||||
void supertwoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t* src, unsigned src_stride, uint32_t* dst,
|
||||
unsigned dst_stride)
|
||||
{
|
||||
unsigned finish;
|
||||
int y = 0;
|
||||
int x = 0;
|
||||
for(; height; height--) {
|
||||
uint32_t *in = (uint32_t*)src;
|
||||
uint32_t *out = (uint32_t*)dst;
|
||||
for (; height; height--)
|
||||
{
|
||||
uint32_t* in = (uint32_t*)src;
|
||||
uint32_t* out = (uint32_t*)dst;
|
||||
|
||||
int prevline = (y > 0 ? src_stride : 0);
|
||||
int nextline = (height > 1 ? src_stride : 0);
|
||||
int nextline2 = (height > 2 ? src_stride * 2 : nextline);
|
||||
|
||||
for(finish = width; finish; finish -= 1) {
|
||||
for (finish = width; finish; finish -= 1)
|
||||
{
|
||||
int prevcolumn = (x > 0 ? 1 : 0);
|
||||
int nextcolumn = (finish > 1 ? 1 : 0);
|
||||
int nextcolumn2 = (finish > 2 ? 2 : nextcolumn);
|
||||
|
@ -133,7 +136,8 @@ void supertwoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *sr
|
|||
// A1 A2
|
||||
//--------------------------------------
|
||||
|
||||
supertwoxsai_function(supertwoxsai_result, supertwoxsai_interpolate_xrgb8888, supertwoxsai_interpolate2_xrgb8888);
|
||||
supertwoxsai_function(supertwoxsai_result, supertwoxsai_interpolate_xrgb8888,
|
||||
supertwoxsai_interpolate2_xrgb8888);
|
||||
x++;
|
||||
}
|
||||
|
||||
|
|
|
@ -125,20 +125,23 @@
|
|||
out += 2
|
||||
#endif
|
||||
|
||||
void supereagle_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride)
|
||||
void supereagle_generic_xrgb8888(unsigned width, unsigned height, uint32_t* src, unsigned src_stride, uint32_t* dst,
|
||||
unsigned dst_stride)
|
||||
{
|
||||
unsigned finish;
|
||||
unsigned finish;
|
||||
int y = 0;
|
||||
int x = 0;
|
||||
for(; height; height--) {
|
||||
uint32_t *in = (uint32_t*)src;
|
||||
uint32_t *out = (uint32_t*)dst;
|
||||
for (; height; height--)
|
||||
{
|
||||
uint32_t* in = (uint32_t*)src;
|
||||
uint32_t* out = (uint32_t*)dst;
|
||||
|
||||
int prevline = (y > 0 ? src_stride : 0);
|
||||
int nextline = (height > 1 ? src_stride : 0);
|
||||
int nextline2 = (height > 2 ? src_stride * 2 : nextline);
|
||||
|
||||
for(finish = width; finish; finish -= 1) {
|
||||
for (finish = width; finish; finish -= 1)
|
||||
{
|
||||
int prevcolumn = (x > 0 ? 1 : 0);
|
||||
int nextcolumn = (finish > 1 ? 1 : 0);
|
||||
int nextcolumn2 = (finish > 2 ? 2 : nextcolumn);
|
||||
|
|
|
@ -7,29 +7,34 @@ class LowPassFilter
|
|||
{
|
||||
private:
|
||||
uint8_t _prevSampleCounter = 0;
|
||||
int16_t _prevSamplesLeft[10] = { 0,0,0,0,0,0,0,0,0,0 };
|
||||
int16_t _prevSamplesRight[10] = { 0,0,0,0,0,0,0,0,0,0 };
|
||||
int16_t _prevSamplesLeft[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
int16_t _prevSamplesRight[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
void UpdateSample(int16_t *buffer, size_t index, int strength, double volume, int16_t *_prevSamples)
|
||||
void UpdateSample(int16_t* buffer, size_t index, int strength, double volume, int16_t* _prevSamples)
|
||||
{
|
||||
if(strength > 0) {
|
||||
if (strength > 0)
|
||||
{
|
||||
int32_t sum = std::accumulate(_prevSamples, _prevSamples + strength, 0);
|
||||
buffer[index] = (int16_t)((sum + buffer[index]) / (strength + 1) * volume);
|
||||
_prevSamples[_prevSampleCounter] = buffer[index];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[index] = (int16_t)(buffer[index] * volume);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void ApplyFilter(int16_t *buffer, size_t sampleCount, int strength, double volume = 1.0f)
|
||||
void ApplyFilter(int16_t* buffer, size_t sampleCount, int strength, double volume = 1.0f)
|
||||
{
|
||||
assert(strength <= 10);
|
||||
|
||||
for(size_t i = 0; i < sampleCount*2; i+=2) {
|
||||
for (size_t i = 0; i < sampleCount * 2; i += 2)
|
||||
{
|
||||
UpdateSample(buffer, i, strength, volume, _prevSamplesLeft);
|
||||
UpdateSample(buffer, i+1, strength, volume, _prevSamplesRight);
|
||||
if(strength > 0) {
|
||||
UpdateSample(buffer, i + 1, strength, volume, _prevSamplesRight);
|
||||
if (strength > 0)
|
||||
{
|
||||
_prevSampleCounter = (_prevSampleCounter + 1) % strength;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,11 +4,13 @@
|
|||
class PNGHelper
|
||||
{
|
||||
private:
|
||||
static int DecodePNG(vector<unsigned char>& out_image, unsigned long& image_width, unsigned long& image_height, const unsigned char* in_png, size_t in_size, bool convert_to_rgba32 = true);
|
||||
static int DecodePNG(vector<unsigned char>& out_image, unsigned long& image_width, unsigned long& image_height,
|
||||
const unsigned char* in_png, size_t in_size, bool convert_to_rgba32 = true);
|
||||
|
||||
public:
|
||||
static bool WritePNG(std::stringstream &stream, uint32_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel = 32);
|
||||
static bool WritePNG(std::stringstream& stream, uint32_t* buffer, uint32_t xSize, uint32_t ySize,
|
||||
uint32_t bitsPerPixel = 32);
|
||||
static bool WritePNG(string filename, uint32_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel = 32);
|
||||
static bool ReadPNG(string filename, vector<uint8_t> &pngData, uint32_t &pngWidth, uint32_t &pngHeight);
|
||||
static bool ReadPNG(vector<uint8_t> input, vector<uint8_t> &output, uint32_t &pngWidth, uint32_t &pngHeight);
|
||||
static bool ReadPNG(string filename, vector<uint8_t>& pngData, uint32_t& pngWidth, uint32_t& pngHeight);
|
||||
static bool ReadPNG(vector<uint8_t> input, vector<uint8_t>& output, uint32_t& pngWidth, uint32_t& pngHeight);
|
||||
};
|
|
@ -11,35 +11,37 @@ void PlatformUtilities::DisableScreensaver()
|
|||
{
|
||||
//Prevent screensaver/etc from starting while using the emulator
|
||||
//DirectInput devices apparently do not always count as user input
|
||||
#if !defined(LIBRETRO) && defined(_WIN32)
|
||||
#if !defined(LIBRETRO) && defined(_WIN32)
|
||||
SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED | ES_CONTINUOUS);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void PlatformUtilities::EnableScreensaver()
|
||||
{
|
||||
#if !defined(LIBRETRO) && defined(_WIN32)
|
||||
#if !defined(LIBRETRO) && defined(_WIN32)
|
||||
SetThreadExecutionState(ES_CONTINUOUS);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void PlatformUtilities::EnableHighResolutionTimer()
|
||||
{
|
||||
#if !defined(LIBRETRO) && defined(_WIN32)
|
||||
//Request a 1ms timer resolution on Windows while a game is running
|
||||
if(!_highResTimerEnabled) {
|
||||
if (!_highResTimerEnabled)
|
||||
{
|
||||
timeBeginPeriod(1);
|
||||
_highResTimerEnabled = true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void PlatformUtilities::RestoreTimerResolution()
|
||||
{
|
||||
#if !defined(LIBRETRO) && defined(_WIN32)
|
||||
if(_highResTimerEnabled) {
|
||||
#if !defined(LIBRETRO) && defined(_WIN32)
|
||||
if (_highResTimerEnabled)
|
||||
{
|
||||
timeEndPeriod(1);
|
||||
_highResTimerEnabled = false;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
|
@ -24,15 +24,17 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) override
|
||||
virtual int CompressFrame(bool isKeyFrame, uint8_t* frameData, uint8_t** compressedData) override
|
||||
{
|
||||
*compressedData = _buffer;
|
||||
|
||||
//Convert raw frame to BMP/DIB format (row order is reversed)
|
||||
uint8_t* buffer = _buffer;
|
||||
frameData += (_height - 1) * _width * 4;
|
||||
for(int y = 0; y < _height; y++) {
|
||||
for(int x = 0; x < _width; x++) {
|
||||
for (int y = 0; y < _height; y++)
|
||||
{
|
||||
for (int x = 0; x < _width; x++)
|
||||
{
|
||||
buffer[0] = frameData[0];
|
||||
buffer[1] = frameData[1];
|
||||
buffer[2] = frameData[2];
|
||||
|
|
|
@ -16,13 +16,14 @@ SZReader::~SZReader()
|
|||
|
||||
bool SZReader::InternalLoadArchive(void* buffer, size_t size)
|
||||
{
|
||||
if(_initialized) {
|
||||
if (_initialized)
|
||||
{
|
||||
SzArEx_Free(&_archive, &_allocImp);
|
||||
_initialized = false;
|
||||
}
|
||||
|
||||
ISzAlloc allocImp{ SzAlloc, SzFree };
|
||||
ISzAlloc allocTempImp{ SzAllocTemp, SzFreeTemp };
|
||||
ISzAlloc allocImp{SzAlloc, SzFree};
|
||||
ISzAlloc allocTempImp{SzAllocTemp, SzFreeTemp};
|
||||
|
||||
MemBufferInit(&_memBufferStream, &_lookStream, buffer, size);
|
||||
CrcGenerateTable();
|
||||
|
@ -31,30 +32,36 @@ bool SZReader::InternalLoadArchive(void* buffer, size_t size)
|
|||
return !SzArEx_Open(&_archive, &_lookStream.s, &allocImp, &allocTempImp);
|
||||
}
|
||||
|
||||
bool SZReader::ExtractFile(string filename, vector<uint8_t> &output)
|
||||
bool SZReader::ExtractFile(string filename, vector<uint8_t>& output)
|
||||
{
|
||||
bool result = false;
|
||||
if(_initialized) {
|
||||
char16_t *utf16Filename = (char16_t*)SzAlloc(nullptr, 2000);
|
||||
if (_initialized)
|
||||
{
|
||||
char16_t* utf16Filename = (char16_t*)SzAlloc(nullptr, 2000);
|
||||
|
||||
uint32_t blockIndex = 0xFFFFFFFF;
|
||||
uint8_t *outBuffer = 0;
|
||||
uint8_t* outBuffer = 0;
|
||||
size_t outBufferSize = 0;
|
||||
|
||||
for(uint32_t i = 0; i < _archive.NumFiles; i++) {
|
||||
for (uint32_t i = 0; i < _archive.NumFiles; i++)
|
||||
{
|
||||
size_t offset = 0;
|
||||
size_t outSizeProcessed = 0;
|
||||
unsigned isDir = SzArEx_IsDir(&_archive, i);
|
||||
if(isDir) {
|
||||
if (isDir)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
SzArEx_GetFileNameUtf16(&_archive, i, (uint16_t*)utf16Filename);
|
||||
string entryName = utf8::utf8::encode(std::u16string(utf16Filename));
|
||||
if(filename == entryName) {
|
||||
WRes res = SzArEx_Extract(&_archive, &_lookStream.s, i, &blockIndex, &outBuffer, &outBufferSize, &offset, &outSizeProcessed, &_allocImp, &_allocTempImp);
|
||||
if(res == SZ_OK) {
|
||||
output = vector<uint8_t>(outBuffer+offset, outBuffer+offset+outSizeProcessed);
|
||||
if (filename == entryName)
|
||||
{
|
||||
WRes res = SzArEx_Extract(&_archive, &_lookStream.s, i, &blockIndex, &outBuffer, &outBufferSize, &offset,
|
||||
&outSizeProcessed, &_allocImp, &_allocTempImp);
|
||||
if (res == SZ_OK)
|
||||
{
|
||||
output = vector<uint8_t>(outBuffer + offset, outBuffer + offset + outSizeProcessed);
|
||||
result = true;
|
||||
}
|
||||
IAlloc_Free(&_allocImp, outBuffer);
|
||||
|
@ -70,12 +77,15 @@ bool SZReader::ExtractFile(string filename, vector<uint8_t> &output)
|
|||
vector<string> SZReader::InternalGetFileList()
|
||||
{
|
||||
vector<string> filenames;
|
||||
char16_t *utf16Filename = (char16_t*)SzAlloc(nullptr, 2000);
|
||||
char16_t* utf16Filename = (char16_t*)SzAlloc(nullptr, 2000);
|
||||
|
||||
if(_initialized) {
|
||||
for(uint32_t i = 0; i < _archive.NumFiles; i++) {
|
||||
if (_initialized)
|
||||
{
|
||||
for (uint32_t i = 0; i < _archive.NumFiles; i++)
|
||||
{
|
||||
unsigned isDir = SzArEx_IsDir(&_archive, i);
|
||||
if(isDir) {
|
||||
if (isDir)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@ private:
|
|||
CMemBufferInStream _memBufferStream;
|
||||
CLookToRead _lookStream;
|
||||
CSzArEx _archive;
|
||||
ISzAlloc _allocImp{ SzAlloc, SzFree };
|
||||
ISzAlloc _allocTempImp{ SzAllocTemp, SzFreeTemp };
|
||||
ISzAlloc _allocImp{SzAlloc, SzFree};
|
||||
ISzAlloc _allocTempImp{SzAllocTemp, SzFreeTemp};
|
||||
|
||||
protected:
|
||||
bool InternalLoadArchive(void* buffer, size_t size);
|
||||
|
@ -24,5 +24,5 @@ public:
|
|||
SZReader();
|
||||
virtual ~SZReader();
|
||||
|
||||
bool ExtractFile(string filename, vector<uint8_t> &output);
|
||||
bool ExtractFile(string filename, vector<uint8_t>& output);
|
||||
};
|
|
@ -44,15 +44,19 @@
|
|||
*/
|
||||
/* #define USE_SCALE_RANDOMWRITE */
|
||||
|
||||
static inline void scale2x_8_def_border(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
|
||||
static inline void scale2x_8_def_border(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1,
|
||||
const scale2x_uint8* src2, unsigned count)
|
||||
{
|
||||
assert(count >= 2);
|
||||
|
||||
/* first pixel */
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1]) {
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1])
|
||||
{
|
||||
dst[0] = src1[0] == src0[0] ? src0[0] : src1[0];
|
||||
dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
@ -63,11 +67,15 @@ static inline void scale2x_8_def_border(scale2x_uint8* dst, const scale2x_uint8*
|
|||
|
||||
/* central pixels */
|
||||
count -= 2;
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
while (count)
|
||||
{
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1])
|
||||
{
|
||||
dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
|
||||
dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
@ -80,24 +88,33 @@ static inline void scale2x_8_def_border(scale2x_uint8* dst, const scale2x_uint8*
|
|||
}
|
||||
|
||||
/* last pixel */
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0]) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0])
|
||||
{
|
||||
dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
|
||||
dst[1] = src1[0] == src0[0] ? src0[0] : src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale2x_8_def_center(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
|
||||
static inline void scale2x_8_def_center(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1,
|
||||
const scale2x_uint8* src2, unsigned count)
|
||||
{
|
||||
assert(count >= 2);
|
||||
|
||||
/* first pixel */
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1]) {
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1])
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
|
||||
} else {
|
||||
dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1])
|
||||
? src1[1]
|
||||
: src1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
@ -108,11 +125,19 @@ static inline void scale2x_8_def_center(scale2x_uint8* dst, const scale2x_uint8*
|
|||
|
||||
/* central pixels */
|
||||
count -= 2;
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
|
||||
dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
|
||||
} else {
|
||||
while (count)
|
||||
{
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1])
|
||||
{
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1])
|
||||
? src1[-1]
|
||||
: src1[0];
|
||||
dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1])
|
||||
? src1[1]
|
||||
: src1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
@ -125,24 +150,33 @@ static inline void scale2x_8_def_center(scale2x_uint8* dst, const scale2x_uint8*
|
|||
}
|
||||
|
||||
/* last pixel */
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0]) {
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0])
|
||||
{
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1])
|
||||
? src1[-1]
|
||||
: src1[0];
|
||||
dst[1] = src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale2x_16_def_border(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
|
||||
static inline void scale2x_16_def_border(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1,
|
||||
const scale2x_uint16* src2, unsigned count)
|
||||
{
|
||||
assert(count >= 2);
|
||||
|
||||
/* first pixel */
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1]) {
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1])
|
||||
{
|
||||
dst[0] = src1[0] == src0[0] ? src0[0] : src1[0];
|
||||
dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
@ -153,11 +187,15 @@ static inline void scale2x_16_def_border(scale2x_uint16* dst, const scale2x_uint
|
|||
|
||||
/* central pixels */
|
||||
count -= 2;
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
while (count)
|
||||
{
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1])
|
||||
{
|
||||
dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
|
||||
dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
@ -170,24 +208,33 @@ static inline void scale2x_16_def_border(scale2x_uint16* dst, const scale2x_uint
|
|||
}
|
||||
|
||||
/* last pixel */
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0]) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0])
|
||||
{
|
||||
dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
|
||||
dst[1] = src1[0] == src0[0] ? src0[0] : src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale2x_16_def_center(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
|
||||
static inline void scale2x_16_def_center(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1,
|
||||
const scale2x_uint16* src2, unsigned count)
|
||||
{
|
||||
assert(count >= 2);
|
||||
|
||||
/* first pixel */
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1]) {
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1])
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
|
||||
} else {
|
||||
dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1])
|
||||
? src1[1]
|
||||
: src1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
@ -198,11 +245,19 @@ static inline void scale2x_16_def_center(scale2x_uint16* dst, const scale2x_uint
|
|||
|
||||
/* central pixels */
|
||||
count -= 2;
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
|
||||
dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
|
||||
} else {
|
||||
while (count)
|
||||
{
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1])
|
||||
{
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1])
|
||||
? src1[-1]
|
||||
: src1[0];
|
||||
dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1])
|
||||
? src1[1]
|
||||
: src1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
@ -215,24 +270,33 @@ static inline void scale2x_16_def_center(scale2x_uint16* dst, const scale2x_uint
|
|||
}
|
||||
|
||||
/* last pixel */
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0]) {
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0])
|
||||
{
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1])
|
||||
? src1[-1]
|
||||
: src1[0];
|
||||
dst[1] = src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale2x_32_def_border(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
|
||||
static inline void scale2x_32_def_border(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1,
|
||||
const scale2x_uint32* src2, unsigned count)
|
||||
{
|
||||
assert(count >= 2);
|
||||
|
||||
/* first pixel */
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1]) {
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1])
|
||||
{
|
||||
dst[0] = src1[0] == src0[0] ? src0[0] : src1[0];
|
||||
dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
@ -243,11 +307,15 @@ static inline void scale2x_32_def_border(scale2x_uint32* dst, const scale2x_uint
|
|||
|
||||
/* central pixels */
|
||||
count -= 2;
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
while (count)
|
||||
{
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1])
|
||||
{
|
||||
dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
|
||||
dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
@ -260,24 +328,33 @@ static inline void scale2x_32_def_border(scale2x_uint32* dst, const scale2x_uint
|
|||
}
|
||||
|
||||
/* last pixel */
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0]) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0])
|
||||
{
|
||||
dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
|
||||
dst[1] = src1[0] == src0[0] ? src0[0] : src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale2x_32_def_center(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
|
||||
static inline void scale2x_32_def_center(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1,
|
||||
const scale2x_uint32* src2, unsigned count)
|
||||
{
|
||||
assert(count >= 2);
|
||||
|
||||
/* first pixel */
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1]) {
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1])
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
|
||||
} else {
|
||||
dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1])
|
||||
? src1[1]
|
||||
: src1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
@ -288,11 +365,19 @@ static inline void scale2x_32_def_center(scale2x_uint32* dst, const scale2x_uint
|
|||
|
||||
/* central pixels */
|
||||
count -= 2;
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
|
||||
dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
|
||||
} else {
|
||||
while (count)
|
||||
{
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1])
|
||||
{
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1])
|
||||
? src1[-1]
|
||||
: src1[0];
|
||||
dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1])
|
||||
? src1[1]
|
||||
: src1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
@ -305,10 +390,15 @@ static inline void scale2x_32_def_center(scale2x_uint32* dst, const scale2x_uint
|
|||
}
|
||||
|
||||
/* last pixel */
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0]) {
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0])
|
||||
{
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1])
|
||||
? src1[-1]
|
||||
: src1[0];
|
||||
dst[1] = src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
}
|
||||
|
@ -329,7 +419,8 @@ static inline void scale2x_32_def_center(scale2x_uint32* dst, const scale2x_uint
|
|||
* \param dst0 First destination row, double length in pixels.
|
||||
* \param dst1 Second destination row, double length in pixels.
|
||||
*/
|
||||
void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
|
||||
void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1,
|
||||
const scale2x_uint8* src2, unsigned count)
|
||||
{
|
||||
#ifdef USE_SCALE_RANDOMWRITE
|
||||
scale2x_8_def_whole(dst0, dst1, src0, src1, src2, count);
|
||||
|
@ -350,7 +441,8 @@ void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8
|
|||
* \param dst0 First destination row, double length in pixels.
|
||||
* \param dst1 Second destination row, double length in pixels.
|
||||
*/
|
||||
void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
|
||||
void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1,
|
||||
const scale2x_uint16* src2, unsigned count)
|
||||
{
|
||||
#ifdef USE_SCALE_RANDOMWRITE
|
||||
scale2x_16_def_whole(dst0, dst1, src0, src1, src2, count);
|
||||
|
@ -371,7 +463,8 @@ void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_ui
|
|||
* \param dst0 First destination row, double length in pixels.
|
||||
* \param dst1 Second destination row, double length in pixels.
|
||||
*/
|
||||
void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
|
||||
void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1,
|
||||
const scale2x_uint32* src2, unsigned count)
|
||||
{
|
||||
#ifdef USE_SCALE_RANDOMWRITE
|
||||
scale2x_32_def_whole(dst0, dst1, src0, src1, src2, count);
|
||||
|
@ -385,7 +478,8 @@ void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_ui
|
|||
* Scale by a factor of 2x3 a row of pixels of 8 bits.
|
||||
* \note Like scale2x_8_def();
|
||||
*/
|
||||
void scale2x3_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
|
||||
void scale2x3_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, const scale2x_uint8* src0,
|
||||
const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
|
||||
{
|
||||
#ifdef USE_SCALE_RANDOMWRITE
|
||||
scale2x_8_def_whole(dst0, dst2, src0, src1, src2, count);
|
||||
|
@ -401,7 +495,8 @@ void scale2x3_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst
|
|||
* Scale by a factor of 2x3 a row of pixels of 16 bits.
|
||||
* \note Like scale2x_16_def();
|
||||
*/
|
||||
void scale2x3_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
|
||||
void scale2x3_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, const scale2x_uint16* src0,
|
||||
const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
|
||||
{
|
||||
#ifdef USE_SCALE_RANDOMWRITE
|
||||
scale2x_16_def_whole(dst0, dst2, src0, src1, src2, count);
|
||||
|
@ -417,7 +512,8 @@ void scale2x3_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16*
|
|||
* Scale by a factor of 2x3 a row of pixels of 32 bits.
|
||||
* \note Like scale2x_32_def();
|
||||
*/
|
||||
void scale2x3_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
|
||||
void scale2x3_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, const scale2x_uint32* src0,
|
||||
const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
|
||||
{
|
||||
#ifdef USE_SCALE_RANDOMWRITE
|
||||
scale2x_32_def_whole(dst0, dst2, src0, src1, src2, count);
|
||||
|
@ -433,7 +529,8 @@ void scale2x3_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32*
|
|||
* Scale by a factor of 2x4 a row of pixels of 8 bits.
|
||||
* \note Like scale2x_8_def();
|
||||
*/
|
||||
void scale2x4_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, scale2x_uint8* dst3, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
|
||||
void scale2x4_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, scale2x_uint8* dst3,
|
||||
const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
|
||||
{
|
||||
#ifdef USE_SCALE_RANDOMWRITE
|
||||
scale2x_8_def_whole(dst0, dst3, src0, src1, src2, count);
|
||||
|
@ -451,7 +548,8 @@ void scale2x4_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst
|
|||
* Scale by a factor of 2x4 a row of pixels of 16 bits.
|
||||
* \note Like scale2x_16_def();
|
||||
*/
|
||||
void scale2x4_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, scale2x_uint16* dst3, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
|
||||
void scale2x4_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, scale2x_uint16* dst3,
|
||||
const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
|
||||
{
|
||||
#ifdef USE_SCALE_RANDOMWRITE
|
||||
scale2x_16_def_whole(dst0, dst3, src0, src1, src2, count);
|
||||
|
@ -469,7 +567,8 @@ void scale2x4_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16*
|
|||
* Scale by a factor of 2x4 a row of pixels of 32 bits.
|
||||
* \note Like scale2x_32_def();
|
||||
*/
|
||||
void scale2x4_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, scale2x_uint32* dst3, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
|
||||
void scale2x4_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, scale2x_uint32* dst3,
|
||||
const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
|
||||
{
|
||||
#ifdef USE_SCALE_RANDOMWRITE
|
||||
scale2x_32_def_whole(dst0, dst3, src0, src1, src2, count);
|
||||
|
|
|
@ -21,17 +21,27 @@ typedef unsigned char scale2x_uint8;
|
|||
typedef unsigned short scale2x_uint16;
|
||||
typedef unsigned scale2x_uint32;
|
||||
|
||||
void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count);
|
||||
void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count);
|
||||
void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count);
|
||||
void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1,
|
||||
const scale2x_uint8* src2, unsigned count);
|
||||
void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1,
|
||||
const scale2x_uint16* src2, unsigned count);
|
||||
void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1,
|
||||
const scale2x_uint32* src2, unsigned count);
|
||||
|
||||
void scale2x3_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count);
|
||||
void scale2x3_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count);
|
||||
void scale2x3_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count);
|
||||
void scale2x3_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, const scale2x_uint8* src0,
|
||||
const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count);
|
||||
void scale2x3_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, const scale2x_uint16* src0,
|
||||
const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count);
|
||||
void scale2x3_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, const scale2x_uint32* src0,
|
||||
const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count);
|
||||
|
||||
void scale2x4_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, scale2x_uint8* dst3, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count);
|
||||
void scale2x4_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, scale2x_uint16* dst3, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count);
|
||||
void scale2x4_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, scale2x_uint32* dst3, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count);
|
||||
void scale2x4_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, scale2x_uint8* dst3,
|
||||
const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count);
|
||||
void scale2x4_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, scale2x_uint16* dst3,
|
||||
const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2,
|
||||
unsigned count);
|
||||
void scale2x4_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, scale2x_uint32* dst3,
|
||||
const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2,
|
||||
unsigned count);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -44,16 +44,22 @@
|
|||
*/
|
||||
/* #define USE_SCALE_RANDOMWRITE */
|
||||
|
||||
static inline void scale3x_8_def_border(scale3x_uint8* dst, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count)
|
||||
static inline void scale3x_8_def_border(scale3x_uint8* dst, const scale3x_uint8* src0, const scale3x_uint8* src1,
|
||||
const scale3x_uint8* src2, unsigned count)
|
||||
{
|
||||
assert(count >= 2);
|
||||
|
||||
/* first pixel */
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1]) {
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1])
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
|
||||
dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0])
|
||||
? src0[0]
|
||||
: src1[0];
|
||||
dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
|
@ -65,12 +71,18 @@ static inline void scale3x_8_def_border(scale3x_uint8* dst, const scale3x_uint8*
|
|||
|
||||
/* central pixels */
|
||||
count -= 2;
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
while (count)
|
||||
{
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1])
|
||||
{
|
||||
dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
|
||||
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
|
||||
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1])
|
||||
? src0[0]
|
||||
: src1[0];
|
||||
dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
|
@ -84,27 +96,40 @@ static inline void scale3x_8_def_border(scale3x_uint8* dst, const scale3x_uint8*
|
|||
}
|
||||
|
||||
/* last pixel */
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0]) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0])
|
||||
{
|
||||
dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
|
||||
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
|
||||
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1])
|
||||
? src0[0]
|
||||
: src1[0];
|
||||
dst[2] = src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale3x_8_def_center(scale3x_uint8* dst, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count)
|
||||
static inline void scale3x_8_def_center(scale3x_uint8* dst, const scale3x_uint8* src0, const scale3x_uint8* src1,
|
||||
const scale3x_uint8* src2, unsigned count)
|
||||
{
|
||||
assert(count >= 2);
|
||||
|
||||
/* first pixel */
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1]) {
|
||||
dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1])
|
||||
{
|
||||
dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0])
|
||||
? src1[0]
|
||||
: src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
|
||||
} else {
|
||||
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1])
|
||||
? src1[1]
|
||||
: src1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
|
@ -116,12 +141,20 @@ static inline void scale3x_8_def_center(scale3x_uint8* dst, const scale3x_uint8*
|
|||
|
||||
/* central pixels */
|
||||
count -= 2;
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
|
||||
while (count)
|
||||
{
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1])
|
||||
{
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1])
|
||||
? src1[-1]
|
||||
: src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
|
||||
} else {
|
||||
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1])
|
||||
? src1[1]
|
||||
: src1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
|
@ -135,27 +168,40 @@ static inline void scale3x_8_def_center(scale3x_uint8* dst, const scale3x_uint8*
|
|||
}
|
||||
|
||||
/* last pixel */
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0]) {
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0])
|
||||
{
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1])
|
||||
? src1[-1]
|
||||
: src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
|
||||
} else {
|
||||
dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0])
|
||||
? src1[0]
|
||||
: src1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale3x_16_def_border(scale3x_uint16* dst, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count)
|
||||
static inline void scale3x_16_def_border(scale3x_uint16* dst, const scale3x_uint16* src0, const scale3x_uint16* src1,
|
||||
const scale3x_uint16* src2, unsigned count)
|
||||
{
|
||||
assert(count >= 2);
|
||||
|
||||
/* first pixel */
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1]) {
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1])
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
|
||||
dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0])
|
||||
? src0[0]
|
||||
: src1[0];
|
||||
dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
|
@ -167,12 +213,18 @@ static inline void scale3x_16_def_border(scale3x_uint16* dst, const scale3x_uint
|
|||
|
||||
/* central pixels */
|
||||
count -= 2;
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
while (count)
|
||||
{
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1])
|
||||
{
|
||||
dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
|
||||
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
|
||||
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1])
|
||||
? src0[0]
|
||||
: src1[0];
|
||||
dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
|
@ -186,27 +238,40 @@ static inline void scale3x_16_def_border(scale3x_uint16* dst, const scale3x_uint
|
|||
}
|
||||
|
||||
/* last pixel */
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0]) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0])
|
||||
{
|
||||
dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
|
||||
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
|
||||
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1])
|
||||
? src0[0]
|
||||
: src1[0];
|
||||
dst[2] = src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale3x_16_def_center(scale3x_uint16* dst, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count)
|
||||
static inline void scale3x_16_def_center(scale3x_uint16* dst, const scale3x_uint16* src0, const scale3x_uint16* src1,
|
||||
const scale3x_uint16* src2, unsigned count)
|
||||
{
|
||||
assert(count >= 2);
|
||||
|
||||
/* first pixel */
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1]) {
|
||||
dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1])
|
||||
{
|
||||
dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0])
|
||||
? src1[0]
|
||||
: src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
|
||||
} else {
|
||||
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1])
|
||||
? src1[1]
|
||||
: src1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
|
@ -218,12 +283,20 @@ static inline void scale3x_16_def_center(scale3x_uint16* dst, const scale3x_uint
|
|||
|
||||
/* central pixels */
|
||||
count -= 2;
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
|
||||
while (count)
|
||||
{
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1])
|
||||
{
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1])
|
||||
? src1[-1]
|
||||
: src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
|
||||
} else {
|
||||
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1])
|
||||
? src1[1]
|
||||
: src1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
|
@ -237,27 +310,40 @@ static inline void scale3x_16_def_center(scale3x_uint16* dst, const scale3x_uint
|
|||
}
|
||||
|
||||
/* last pixel */
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0]) {
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0])
|
||||
{
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1])
|
||||
? src1[-1]
|
||||
: src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
|
||||
} else {
|
||||
dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0])
|
||||
? src1[0]
|
||||
: src1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale3x_32_def_border(scale3x_uint32* dst, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count)
|
||||
static inline void scale3x_32_def_border(scale3x_uint32* dst, const scale3x_uint32* src0, const scale3x_uint32* src1,
|
||||
const scale3x_uint32* src2, unsigned count)
|
||||
{
|
||||
assert(count >= 2);
|
||||
|
||||
/* first pixel */
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1]) {
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1])
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
|
||||
dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0])
|
||||
? src0[0]
|
||||
: src1[0];
|
||||
dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
|
@ -269,12 +355,18 @@ static inline void scale3x_32_def_border(scale3x_uint32* dst, const scale3x_uint
|
|||
|
||||
/* central pixels */
|
||||
count -= 2;
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
while (count)
|
||||
{
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1])
|
||||
{
|
||||
dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
|
||||
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
|
||||
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1])
|
||||
? src0[0]
|
||||
: src1[0];
|
||||
dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
|
@ -288,27 +380,40 @@ static inline void scale3x_32_def_border(scale3x_uint32* dst, const scale3x_uint
|
|||
}
|
||||
|
||||
/* last pixel */
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0]) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0])
|
||||
{
|
||||
dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
|
||||
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
|
||||
dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1])
|
||||
? src0[0]
|
||||
: src1[0];
|
||||
dst[2] = src1[0];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void scale3x_32_def_center(scale3x_uint32* dst, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count)
|
||||
static inline void scale3x_32_def_center(scale3x_uint32* dst, const scale3x_uint32* src0, const scale3x_uint32* src1,
|
||||
const scale3x_uint32* src2, unsigned count)
|
||||
{
|
||||
assert(count >= 2);
|
||||
|
||||
/* first pixel */
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1]) {
|
||||
dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
|
||||
if (src0[0] != src2[0] && src1[0] != src1[1])
|
||||
{
|
||||
dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0])
|
||||
? src1[0]
|
||||
: src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
|
||||
} else {
|
||||
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1])
|
||||
? src1[1]
|
||||
: src1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
|
@ -320,12 +425,20 @@ static inline void scale3x_32_def_center(scale3x_uint32* dst, const scale3x_uint
|
|||
|
||||
/* central pixels */
|
||||
count -= 2;
|
||||
while (count) {
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1]) {
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
|
||||
while (count)
|
||||
{
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[1])
|
||||
{
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1])
|
||||
? src1[-1]
|
||||
: src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
|
||||
} else {
|
||||
dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1])
|
||||
? src1[1]
|
||||
: src1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
|
@ -339,11 +452,18 @@ static inline void scale3x_32_def_center(scale3x_uint32* dst, const scale3x_uint
|
|||
}
|
||||
|
||||
/* last pixel */
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0]) {
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
|
||||
if (src0[0] != src2[0] && src1[-1] != src1[0])
|
||||
{
|
||||
dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1])
|
||||
? src1[-1]
|
||||
: src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
|
||||
} else {
|
||||
dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0])
|
||||
? src1[0]
|
||||
: src1[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src1[0];
|
||||
dst[1] = src1[0];
|
||||
dst[2] = src1[0];
|
||||
|
@ -364,7 +484,8 @@ static inline void scale3x_32_def_center(scale3x_uint32* dst, const scale3x_uint
|
|||
* \param dst1 Second destination row, triple length in pixels.
|
||||
* \param dst2 Third destination row, triple length in pixels.
|
||||
*/
|
||||
void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count)
|
||||
void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0,
|
||||
const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count)
|
||||
{
|
||||
#ifdef USE_SCALE_RANDOMWRITE
|
||||
scale3x_8_def_whole(dst0, dst1, dst2, src0, src1, src2, count);
|
||||
|
@ -387,7 +508,8 @@ void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2
|
|||
* \param dst1 Second destination row, triple length in pixels.
|
||||
* \param dst2 Third destination row, triple length in pixels.
|
||||
*/
|
||||
void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count)
|
||||
void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0,
|
||||
const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count)
|
||||
{
|
||||
#ifdef USE_SCALE_RANDOMWRITE
|
||||
scale3x_16_def_whole(dst0, dst1, dst2, src0, src1, src2, count);
|
||||
|
@ -410,7 +532,8 @@ void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16*
|
|||
* \param dst1 Second destination row, triple length in pixels.
|
||||
* \param dst2 Third destination row, triple length in pixels.
|
||||
*/
|
||||
void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count)
|
||||
void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0,
|
||||
const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count)
|
||||
{
|
||||
#ifdef USE_SCALE_RANDOMWRITE
|
||||
scale3x_32_def_whole(dst0, dst1, dst2, src0, src1, src2, count);
|
||||
|
@ -420,4 +543,3 @@ void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32*
|
|||
scale3x_32_def_border(dst2, src2, src1, src0, count);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -21,9 +21,11 @@ typedef unsigned char scale3x_uint8;
|
|||
typedef unsigned short scale3x_uint16;
|
||||
typedef unsigned scale3x_uint32;
|
||||
|
||||
void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count);
|
||||
void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count);
|
||||
void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count);
|
||||
void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0,
|
||||
const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count);
|
||||
void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0,
|
||||
const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count);
|
||||
void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0,
|
||||
const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -49,55 +49,83 @@
|
|||
/**
|
||||
* Apply the Scale2x effect on a group of rows. Used internally.
|
||||
*/
|
||||
static inline void stage_scale2x(void* dst0, void* dst1, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row)
|
||||
static inline void stage_scale2x(void* dst0, void* dst1, const void* src0, const void* src1, const void* src2,
|
||||
unsigned pixel, unsigned pixel_per_row)
|
||||
{
|
||||
switch (pixel) {
|
||||
case 1 : scale2x_8_def(SSDST(8,0), SSDST(8,1), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break;
|
||||
case 2 : scale2x_16_def(SSDST(16,0), SSDST(16,1), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break;
|
||||
case 4 : scale2x_32_def(SSDST(32,0), SSDST(32,1), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break;
|
||||
switch (pixel)
|
||||
{
|
||||
case 1: scale2x_8_def(SSDST(8, 0), SSDST(8, 1), SSSRC(8, 0), SSSRC(8, 1), SSSRC(8, 2), pixel_per_row);
|
||||
break;
|
||||
case 2: scale2x_16_def(SSDST(16, 0), SSDST(16, 1), SSSRC(16, 0), SSSRC(16, 1), SSSRC(16, 2), pixel_per_row);
|
||||
break;
|
||||
case 4: scale2x_32_def(SSDST(32, 0), SSDST(32, 1), SSSRC(32, 0), SSSRC(32, 1), SSSRC(32, 2), pixel_per_row);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the Scale2x3 effect on a group of rows. Used internally.
|
||||
*/
|
||||
static inline void stage_scale2x3(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row)
|
||||
static inline void stage_scale2x3(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1,
|
||||
const void* src2, unsigned pixel, unsigned pixel_per_row)
|
||||
{
|
||||
switch (pixel) {
|
||||
case 1 : scale2x3_8_def(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break;
|
||||
case 2 : scale2x3_16_def(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break;
|
||||
case 4 : scale2x3_32_def(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break;
|
||||
switch (pixel)
|
||||
{
|
||||
case 1: scale2x3_8_def(SSDST(8, 0), SSDST(8, 1), SSDST(8, 2), SSSRC(8, 0), SSSRC(8, 1), SSSRC(8, 2), pixel_per_row);
|
||||
break;
|
||||
case 2: scale2x3_16_def(SSDST(16, 0), SSDST(16, 1), SSDST(16, 2), SSSRC(16, 0), SSSRC(16, 1), SSSRC(16, 2),
|
||||
pixel_per_row);
|
||||
break;
|
||||
case 4: scale2x3_32_def(SSDST(32, 0), SSDST(32, 1), SSDST(32, 2), SSSRC(32, 0), SSSRC(32, 1), SSSRC(32, 2),
|
||||
pixel_per_row);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the Scale2x4 effect on a group of rows. Used internally.
|
||||
*/
|
||||
static inline void stage_scale2x4(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row)
|
||||
static inline void stage_scale2x4(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1,
|
||||
const void* src2, unsigned pixel, unsigned pixel_per_row)
|
||||
{
|
||||
switch (pixel) {
|
||||
case 1 : scale2x4_8_def(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSDST(8,3), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break;
|
||||
case 2 : scale2x4_16_def(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSDST(16,3), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break;
|
||||
case 4 : scale2x4_32_def(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSDST(32,3), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break;
|
||||
switch (pixel)
|
||||
{
|
||||
case 1: scale2x4_8_def(SSDST(8, 0), SSDST(8, 1), SSDST(8, 2), SSDST(8, 3), SSSRC(8, 0), SSSRC(8, 1), SSSRC(8, 2),
|
||||
pixel_per_row);
|
||||
break;
|
||||
case 2: scale2x4_16_def(SSDST(16, 0), SSDST(16, 1), SSDST(16, 2), SSDST(16, 3), SSSRC(16, 0), SSSRC(16, 1),
|
||||
SSSRC(16, 2), pixel_per_row);
|
||||
break;
|
||||
case 4: scale2x4_32_def(SSDST(32, 0), SSDST(32, 1), SSDST(32, 2), SSDST(32, 3), SSSRC(32, 0), SSSRC(32, 1),
|
||||
SSSRC(32, 2), pixel_per_row);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the Scale3x effect on a group of rows. Used internally.
|
||||
*/
|
||||
static inline void stage_scale3x(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row)
|
||||
static inline void stage_scale3x(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1,
|
||||
const void* src2, unsigned pixel, unsigned pixel_per_row)
|
||||
{
|
||||
switch (pixel) {
|
||||
case 1 : scale3x_8_def(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break;
|
||||
case 2 : scale3x_16_def(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break;
|
||||
case 4 : scale3x_32_def(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break;
|
||||
switch (pixel)
|
||||
{
|
||||
case 1: scale3x_8_def(SSDST(8, 0), SSDST(8, 1), SSDST(8, 2), SSSRC(8, 0), SSSRC(8, 1), SSSRC(8, 2), pixel_per_row);
|
||||
break;
|
||||
case 2: scale3x_16_def(SSDST(16, 0), SSDST(16, 1), SSDST(16, 2), SSSRC(16, 0), SSSRC(16, 1), SSSRC(16, 2),
|
||||
pixel_per_row);
|
||||
break;
|
||||
case 4: scale3x_32_def(SSDST(32, 0), SSDST(32, 1), SSDST(32, 2), SSSRC(32, 0), SSSRC(32, 1), SSSRC(32, 2),
|
||||
pixel_per_row);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the Scale4x effect on a group of rows. Used internally.
|
||||
*/
|
||||
static inline void stage_scale4x(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1, const void* src2, const void* src3, unsigned pixel, unsigned pixel_per_row)
|
||||
static inline void stage_scale4x(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1,
|
||||
const void* src2, const void* src3, unsigned pixel, unsigned pixel_per_row)
|
||||
{
|
||||
stage_scale2x(dst0, dst1, src0, src1, src2, pixel, 2 * pixel_per_row);
|
||||
stage_scale2x(dst2, dst3, src1, src2, src3, pixel, 2 * pixel_per_row);
|
||||
|
@ -121,7 +149,8 @@ static inline void stage_scale4x(void* dst0, void* dst1, void* dst2, void* dst3,
|
|||
* \param width Horizontal size in pixels of the source bitmap.
|
||||
* \param height Vertical size in pixels of the source bitmap.
|
||||
*/
|
||||
static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
|
||||
static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel,
|
||||
unsigned width, unsigned height)
|
||||
{
|
||||
unsigned char* dst = (unsigned char*)void_dst;
|
||||
const unsigned char* src = (const unsigned char*)void_src;
|
||||
|
@ -136,7 +165,8 @@ static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, un
|
|||
dst = SCDST(2);
|
||||
|
||||
count -= 2;
|
||||
while (count) {
|
||||
while (count)
|
||||
{
|
||||
stage_scale2x(SCDST(0), SCDST(1), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
|
||||
|
||||
dst = SCDST(2);
|
||||
|
@ -162,7 +192,8 @@ static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, un
|
|||
* \param width Horizontal size in pixels of the source bitmap.
|
||||
* \param height Vertical size in pixels of the source bitmap.
|
||||
*/
|
||||
static void scale2x3(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
|
||||
static void scale2x3(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel,
|
||||
unsigned width, unsigned height)
|
||||
{
|
||||
unsigned char* dst = (unsigned char*)void_dst;
|
||||
const unsigned char* src = (const unsigned char*)void_src;
|
||||
|
@ -177,7 +208,8 @@ static void scale2x3(void* void_dst, unsigned dst_slice, const void* void_src, u
|
|||
dst = SCDST(3);
|
||||
|
||||
count -= 2;
|
||||
while (count) {
|
||||
while (count)
|
||||
{
|
||||
stage_scale2x3(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
|
||||
|
||||
dst = SCDST(3);
|
||||
|
@ -203,7 +235,8 @@ static void scale2x3(void* void_dst, unsigned dst_slice, const void* void_src, u
|
|||
* \param width Horizontal size in pixels of the source bitmap.
|
||||
* \param height Vertical size in pixels of the source bitmap.
|
||||
*/
|
||||
static void scale2x4(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
|
||||
static void scale2x4(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel,
|
||||
unsigned width, unsigned height)
|
||||
{
|
||||
unsigned char* dst = (unsigned char*)void_dst;
|
||||
const unsigned char* src = (const unsigned char*)void_src;
|
||||
|
@ -218,7 +251,8 @@ static void scale2x4(void* void_dst, unsigned dst_slice, const void* void_src, u
|
|||
dst = SCDST(4);
|
||||
|
||||
count -= 2;
|
||||
while (count) {
|
||||
while (count)
|
||||
{
|
||||
stage_scale2x4(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
|
||||
|
||||
dst = SCDST(4);
|
||||
|
@ -244,7 +278,8 @@ static void scale2x4(void* void_dst, unsigned dst_slice, const void* void_src, u
|
|||
* \param width Horizontal size in pixels of the source bitmap.
|
||||
* \param height Vertical size in pixels of the source bitmap.
|
||||
*/
|
||||
static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
|
||||
static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel,
|
||||
unsigned width, unsigned height)
|
||||
{
|
||||
unsigned char* dst = (unsigned char*)void_dst;
|
||||
const unsigned char* src = (const unsigned char*)void_src;
|
||||
|
@ -259,7 +294,8 @@ static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, un
|
|||
dst = SCDST(3);
|
||||
|
||||
count -= 2;
|
||||
while (count) {
|
||||
while (count)
|
||||
{
|
||||
stage_scale3x(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
|
||||
|
||||
dst = SCDST(3);
|
||||
|
@ -292,7 +328,8 @@ static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, un
|
|||
* \param width Horizontal size in pixels of the source bitmap.
|
||||
* \param height Vertical size in pixels of the source bitmap.
|
||||
*/
|
||||
static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsigned mid_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
|
||||
static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsigned mid_slice, const void* void_src,
|
||||
unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
|
||||
{
|
||||
unsigned char* dst = (unsigned char*)void_dst;
|
||||
const unsigned char* src = (const unsigned char*)void_src;
|
||||
|
@ -323,7 +360,8 @@ static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsi
|
|||
dst = SCDST(4);
|
||||
|
||||
count -= 4;
|
||||
while (count) {
|
||||
while (count)
|
||||
{
|
||||
unsigned char* tmp;
|
||||
|
||||
stage_scale2x(SCMID(4), SCMID(5), SCSRC(2), SCSRC(3), SCSRC(4), pixel, width);
|
||||
|
@ -368,7 +406,8 @@ static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsi
|
|||
* \param width Horizontal size in pixels of the source bitmap.
|
||||
* \param height Vertical size in pixels of the source bitmap.
|
||||
*/
|
||||
static void scale4x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
|
||||
static void scale4x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel,
|
||||
unsigned width, unsigned height)
|
||||
{
|
||||
unsigned mid_slice;
|
||||
void* mid;
|
||||
|
@ -410,18 +449,19 @@ int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned
|
|||
if (pixel != 1 && pixel != 2 && pixel != 4)
|
||||
return -1;
|
||||
|
||||
switch (scale) {
|
||||
case 202 :
|
||||
case 203 :
|
||||
case 204 :
|
||||
case 2 :
|
||||
case 303 :
|
||||
case 3 :
|
||||
switch (scale)
|
||||
{
|
||||
case 202:
|
||||
case 203:
|
||||
case 204:
|
||||
case 2:
|
||||
case 303:
|
||||
case 3:
|
||||
if (height < 2)
|
||||
return -1;
|
||||
break;
|
||||
case 404 :
|
||||
case 4 :
|
||||
case 404:
|
||||
case 4:
|
||||
if (height < 4)
|
||||
return -1;
|
||||
break;
|
||||
|
@ -447,27 +487,28 @@ int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned
|
|||
* \param width Horizontal size in pixels of the source bitmap.
|
||||
* \param height Vertical size in pixels of the source bitmap.
|
||||
*/
|
||||
void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
|
||||
void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel,
|
||||
unsigned width, unsigned height)
|
||||
{
|
||||
switch (scale) {
|
||||
case 202 :
|
||||
case 2 :
|
||||
switch (scale)
|
||||
{
|
||||
case 202:
|
||||
case 2:
|
||||
scale2x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
|
||||
break;
|
||||
case 203 :
|
||||
case 203:
|
||||
scale2x3(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
|
||||
break;
|
||||
case 204 :
|
||||
case 204:
|
||||
scale2x4(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
|
||||
break;
|
||||
case 303 :
|
||||
case 3 :
|
||||
case 303:
|
||||
case 3:
|
||||
scale3x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
|
||||
break;
|
||||
case 404 :
|
||||
case 4 :
|
||||
case 404:
|
||||
case 4:
|
||||
scale4x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#define __SCALEBIT_H
|
||||
|
||||
int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned height);
|
||||
void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height);
|
||||
void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel,
|
||||
unsigned width, unsigned height);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ Serializer::Serializer(uint32_t version)
|
|||
_saving = true;
|
||||
}
|
||||
|
||||
Serializer::Serializer(istream &file, uint32_t version, bool compressed)
|
||||
Serializer::Serializer(istream& file, uint32_t version, bool compressed)
|
||||
{
|
||||
_version = version;
|
||||
|
||||
|
@ -22,7 +22,8 @@ Serializer::Serializer(istream &file, uint32_t version, bool compressed)
|
|||
_block->Position = 0;
|
||||
_saving = false;
|
||||
|
||||
if(compressed) {
|
||||
if (compressed)
|
||||
{
|
||||
uint32_t decompressedSize;
|
||||
file.read((char*)&decompressedSize, sizeof(decompressedSize));
|
||||
|
||||
|
@ -36,7 +37,9 @@ Serializer::Serializer(istream &file, uint32_t version, bool compressed)
|
|||
|
||||
unsigned long decompSize = decompressedSize;
|
||||
uncompress(_block->Data.data(), &decompSize, compressedData.data(), (unsigned long)compressedData.size());
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
file.seekg(0, std::ios::end);
|
||||
uint32_t size = (uint32_t)file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
@ -50,14 +53,16 @@ void Serializer::EnsureCapacity(uint32_t typeSize)
|
|||
{
|
||||
//Make sure the current block/stream is large enough to fit the next write
|
||||
uint32_t oldSize = (uint32_t)_block->Data.size();
|
||||
if(oldSize == 0) {
|
||||
if (oldSize == 0)
|
||||
{
|
||||
oldSize = typeSize * 2;
|
||||
}
|
||||
|
||||
uint32_t sizeRequired = _block->Position + typeSize;
|
||||
|
||||
uint32_t newSize = oldSize;
|
||||
while(newSize < sizeRequired) {
|
||||
while (newSize < sizeRequired)
|
||||
{
|
||||
newSize *= 2;
|
||||
}
|
||||
|
||||
|
@ -73,10 +78,13 @@ void Serializer::StreamStartBlock()
|
|||
unique_ptr<BlockData> block(new BlockData());
|
||||
block->Position = 0;
|
||||
|
||||
if(!_saving) {
|
||||
VectorInfo<uint8_t> vectorInfo = { &block->Data };
|
||||
if (!_saving)
|
||||
{
|
||||
VectorInfo<uint8_t> vectorInfo = {&block->Data};
|
||||
InternalStream(vectorInfo);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
block->Data = vector<uint8_t>(0x100);
|
||||
}
|
||||
|
||||
|
@ -86,7 +94,8 @@ void Serializer::StreamStartBlock()
|
|||
|
||||
void Serializer::StreamEndBlock()
|
||||
{
|
||||
if(_blocks.empty()) {
|
||||
if (_blocks.empty())
|
||||
{
|
||||
throw std::runtime_error("Invalid call to end block");
|
||||
}
|
||||
|
||||
|
@ -95,20 +104,25 @@ void Serializer::StreamEndBlock()
|
|||
_block = std::move(_blocks.back());
|
||||
_blocks.pop_back();
|
||||
|
||||
if(_saving) {
|
||||
ArrayInfo<uint8_t> arrayInfo { block->Data.data(), block->Position };
|
||||
if (_saving)
|
||||
{
|
||||
ArrayInfo<uint8_t> arrayInfo{block->Data.data(), block->Position};
|
||||
InternalStream(arrayInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void Serializer::Save(ostream& file, int compressionLevel)
|
||||
{
|
||||
if(compressionLevel == 0) {
|
||||
if (compressionLevel == 0)
|
||||
{
|
||||
file.write((char*)_block->Data.data(), _block->Position);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned long compressedSize = compressBound((unsigned long)_block->Position);
|
||||
uint8_t* compressedData = new uint8_t[compressedSize];
|
||||
compress2(compressedData, &compressedSize, (unsigned char*)_block->Data.data(), (unsigned long)_block->Position, compressionLevel);
|
||||
compress2(compressedData, &compressedSize, (unsigned char*)_block->Data.data(), (unsigned long)_block->Position,
|
||||
compressionLevel);
|
||||
|
||||
uint32_t size = (uint32_t)compressedSize;
|
||||
file.write((char*)&_block->Position, sizeof(uint32_t));
|
||||
|
@ -131,27 +145,31 @@ void Serializer::SkipBlock(istream* file)
|
|||
file->seekg(blockSize, std::ios::cur);
|
||||
}
|
||||
|
||||
void Serializer::Stream(ISerializable &obj)
|
||||
void Serializer::Stream(ISerializable& obj)
|
||||
{
|
||||
StreamStartBlock();
|
||||
obj.Serialize(*this);
|
||||
StreamEndBlock();
|
||||
}
|
||||
void Serializer::Stream(ISerializable *obj)
|
||||
|
||||
void Serializer::Stream(ISerializable* obj)
|
||||
{
|
||||
StreamStartBlock();
|
||||
obj->Serialize(*this);
|
||||
StreamEndBlock();
|
||||
}
|
||||
|
||||
void Serializer::InternalStream(string &str)
|
||||
void Serializer::InternalStream(string& str)
|
||||
{
|
||||
if(_saving) {
|
||||
if (_saving)
|
||||
{
|
||||
vector<uint8_t> stringData;
|
||||
stringData.resize(str.size());
|
||||
memcpy(stringData.data(), str.data(), str.size());
|
||||
StreamVector(stringData);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
vector<uint8_t> stringData;
|
||||
StreamVector(stringData);
|
||||
str = string(stringData.begin(), stringData.end());
|
||||
|
|
|
@ -5,20 +5,20 @@
|
|||
class Serializer;
|
||||
class ISerializable;
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
struct ArrayInfo
|
||||
{
|
||||
T* Array;
|
||||
uint32_t ElementCount;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
struct VectorInfo
|
||||
{
|
||||
vector<T>* Vector;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
struct ValueInfo
|
||||
{
|
||||
T* Value;
|
||||
|
@ -43,69 +43,86 @@ private:
|
|||
private:
|
||||
void EnsureCapacity(uint32_t typeSize);
|
||||
|
||||
template<typename T> void StreamElement(T &value, T defaultValue = T());
|
||||
template <typename T>
|
||||
void StreamElement(T& value, T defaultValue = T());
|
||||
|
||||
template<typename T> void InternalStream(ArrayInfo<T> &info);
|
||||
template<typename T> void InternalStream(VectorInfo<T> &info);
|
||||
template<typename T> void InternalStream(ValueInfo<T> &info);
|
||||
template<typename T> void InternalStream(T &value);
|
||||
void InternalStream(string &str);
|
||||
template <typename T>
|
||||
void InternalStream(ArrayInfo<T>& info);
|
||||
template <typename T>
|
||||
void InternalStream(VectorInfo<T>& info);
|
||||
template <typename T>
|
||||
void InternalStream(ValueInfo<T>& info);
|
||||
template <typename T>
|
||||
void InternalStream(T& value);
|
||||
void InternalStream(string& str);
|
||||
void RecursiveStream();
|
||||
|
||||
template<typename T, typename... T2> void RecursiveStream(T &value, T2&... args);
|
||||
template <typename T, typename... T2>
|
||||
void RecursiveStream(T& value, T2&... args);
|
||||
|
||||
void StreamStartBlock();
|
||||
void StreamEndBlock();
|
||||
|
||||
public:
|
||||
Serializer(uint32_t version);
|
||||
Serializer(istream &file, uint32_t version, bool compressed = true);
|
||||
Serializer(istream& file, uint32_t version, bool compressed = true);
|
||||
|
||||
uint32_t GetVersion() { return _version; }
|
||||
bool IsSaving() { return _saving; }
|
||||
|
||||
template<typename... T> void Stream(T&... args);
|
||||
template<typename T> void StreamArray(T *array, uint32_t size);
|
||||
template<typename T> void StreamVector(vector<T> &list);
|
||||
template <typename... T>
|
||||
void Stream(T&... args);
|
||||
template <typename T>
|
||||
void StreamArray(T* array, uint32_t size);
|
||||
template <typename T>
|
||||
void StreamVector(vector<T>& list);
|
||||
|
||||
void Save(ostream &file, int compressionLevel = 1);
|
||||
void Save(ostream& file, int compressionLevel = 1);
|
||||
|
||||
void Stream(ISerializable &obj);
|
||||
void Stream(ISerializable *obj);
|
||||
void Stream(ISerializable& obj);
|
||||
void Stream(ISerializable* obj);
|
||||
|
||||
void WriteEmptyBlock(ostream* file);
|
||||
void SkipBlock(istream* file);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void Serializer::StreamElement(T &value, T defaultValue)
|
||||
template <typename T>
|
||||
void Serializer::StreamElement(T& value, T defaultValue)
|
||||
{
|
||||
if(_saving) {
|
||||
if (_saving)
|
||||
{
|
||||
uint8_t* bytes = (uint8_t*)&value;
|
||||
int typeSize = sizeof(T);
|
||||
|
||||
EnsureCapacity(typeSize);
|
||||
for(int i = 0; i < typeSize; i++) {
|
||||
for (int i = 0; i < typeSize; i++)
|
||||
{
|
||||
_block->Data[_block->Position++] = bytes[i];
|
||||
}
|
||||
} else {
|
||||
if(_block->Position + sizeof(T) <= _block->Data.size()) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_block->Position + sizeof(T) <= _block->Data.size())
|
||||
{
|
||||
memcpy(&value, _block->Data.data() + _block->Position, sizeof(T));
|
||||
_block->Position += sizeof(T);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
value = defaultValue;
|
||||
_block->Position = (uint32_t)_block->Data.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Serializer::InternalStream(ArrayInfo<T> &info)
|
||||
template <typename T>
|
||||
void Serializer::InternalStream(ArrayInfo<T>& info)
|
||||
{
|
||||
uint32_t count = info.ElementCount;
|
||||
StreamElement<uint32_t>(count);
|
||||
|
||||
if(!_saving) {
|
||||
if (!_saving)
|
||||
{
|
||||
//Reset array to 0 before loading from file
|
||||
memset(info.Array, 0, info.ElementCount * sizeof(T));
|
||||
}
|
||||
|
@ -113,58 +130,64 @@ void Serializer::InternalStream(ArrayInfo<T> &info)
|
|||
//Load the number of elements requested, or the maximum possible (based on what is present in the save state)
|
||||
EnsureCapacity(info.ElementCount * sizeof(T));
|
||||
|
||||
if(_saving) {
|
||||
if (_saving)
|
||||
{
|
||||
memcpy(_block->Data.data() + _block->Position, info.Array, info.ElementCount * sizeof(T));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(info.Array, _block->Data.data() + _block->Position, info.ElementCount * sizeof(T));
|
||||
}
|
||||
_block->Position += info.ElementCount * sizeof(T);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Serializer::InternalStream(VectorInfo<T> &info)
|
||||
template <typename T>
|
||||
void Serializer::InternalStream(VectorInfo<T>& info)
|
||||
{
|
||||
vector<T> *vector = info.Vector;
|
||||
vector<T>* vector = info.Vector;
|
||||
|
||||
uint32_t count = (uint32_t)vector->size();
|
||||
StreamElement<uint32_t>(count);
|
||||
|
||||
if(!_saving) {
|
||||
if(count > 0xFFFFFF) {
|
||||
if (!_saving)
|
||||
{
|
||||
if (count > 0xFFFFFF)
|
||||
{
|
||||
throw std::runtime_error("Invalid save state");
|
||||
}
|
||||
vector->resize(count);
|
||||
memset(vector->data(), 0, sizeof(T)*count);
|
||||
memset(vector->data(), 0, sizeof(T) * count);
|
||||
}
|
||||
|
||||
//Load the number of elements requested
|
||||
T* pointer = vector->data();
|
||||
for(uint32_t i = 0; i < count; i++) {
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
{
|
||||
StreamElement<T>(*pointer);
|
||||
pointer++;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Serializer::InternalStream(ValueInfo<T> &info)
|
||||
template <typename T>
|
||||
void Serializer::InternalStream(ValueInfo<T>& info)
|
||||
{
|
||||
StreamElement<T>(*info.Value, info.DefaultValue);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Serializer::InternalStream(T &value)
|
||||
template <typename T>
|
||||
void Serializer::InternalStream(T& value)
|
||||
{
|
||||
StreamElement<T>(value);
|
||||
}
|
||||
|
||||
template<typename T, typename... T2>
|
||||
void Serializer::RecursiveStream(T &value, T2&... args)
|
||||
template <typename T, typename... T2>
|
||||
void Serializer::RecursiveStream(T& value, T2&... args)
|
||||
{
|
||||
InternalStream(value);
|
||||
RecursiveStream(args...);
|
||||
}
|
||||
|
||||
template<typename... T>
|
||||
template <typename... T>
|
||||
void Serializer::Stream(T&... args)
|
||||
{
|
||||
StreamStartBlock();
|
||||
|
@ -172,8 +195,8 @@ void Serializer::Stream(T&... args)
|
|||
StreamEndBlock();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Serializer::StreamArray(T *array, uint32_t size)
|
||||
template <typename T>
|
||||
void Serializer::StreamArray(T* array, uint32_t size)
|
||||
{
|
||||
ArrayInfo<T> info;
|
||||
info.Array = array;
|
||||
|
@ -181,8 +204,8 @@ void Serializer::StreamArray(T *array, uint32_t size)
|
|||
InternalStream(info);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Serializer::StreamVector(vector<T> &list)
|
||||
template <typename T>
|
||||
void Serializer::StreamVector(vector<T>& list)
|
||||
{
|
||||
VectorInfo<T> info;
|
||||
info.Vector = &list;
|
||||
|
|
|
@ -22,11 +22,14 @@ LockHandler SimpleLock::AcquireSafe()
|
|||
|
||||
void SimpleLock::Acquire()
|
||||
{
|
||||
if(_lockCount == 0 || _holderThreadID != _threadID) {
|
||||
while(_lock.test_and_set());
|
||||
if (_lockCount == 0 || _holderThreadID != _threadID)
|
||||
{
|
||||
while (_lock.test_and_set());
|
||||
_holderThreadID = _threadID;
|
||||
_lockCount = 1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
//Same thread can acquire the same lock multiple times
|
||||
_lockCount++;
|
||||
}
|
||||
|
@ -46,19 +49,23 @@ void SimpleLock::WaitForRelease()
|
|||
|
||||
void SimpleLock::Release()
|
||||
{
|
||||
if(_lockCount > 0 && _holderThreadID == _threadID) {
|
||||
if (_lockCount > 0 && _holderThreadID == _threadID)
|
||||
{
|
||||
_lockCount--;
|
||||
if(_lockCount == 0) {
|
||||
if (_lockCount == 0)
|
||||
{
|
||||
_holderThreadID = std::thread::id();
|
||||
_lock.clear();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LockHandler::LockHandler(SimpleLock *lock)
|
||||
LockHandler::LockHandler(SimpleLock* lock)
|
||||
{
|
||||
_lock = lock;
|
||||
_lock->Acquire();
|
||||
|
|
|
@ -7,9 +7,9 @@ class SimpleLock;
|
|||
class LockHandler
|
||||
{
|
||||
private:
|
||||
SimpleLock *_lock;
|
||||
SimpleLock* _lock;
|
||||
public:
|
||||
LockHandler(SimpleLock *lock);
|
||||
LockHandler(SimpleLock* lock);
|
||||
~LockHandler();
|
||||
};
|
||||
|
||||
|
@ -33,4 +33,3 @@ public:
|
|||
void WaitForRelease();
|
||||
void Release();
|
||||
};
|
||||
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
using namespace std;
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma comment(lib,"ws2_32.lib") //Winsock Library
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <Ws2tcpip.h>
|
||||
#include <Windows.h>
|
||||
#pragma comment(lib,"ws2_32.lib") //Winsock Library
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <Ws2tcpip.h>
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
@ -38,21 +38,25 @@ using namespace std;
|
|||
|
||||
Socket::Socket()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaDat;
|
||||
if(WSAStartup(MAKEWORD(2, 2), &wsaDat) != 0) {
|
||||
std::cout << "WSAStartup failed." << std::endl;
|
||||
SetConnectionErrorFlag();
|
||||
return;
|
||||
}
|
||||
_cleanupWSA = true;
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaDat;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaDat) != 0)
|
||||
{
|
||||
std::cout << "WSAStartup failed." << std::endl;
|
||||
SetConnectionErrorFlag();
|
||||
return;
|
||||
}
|
||||
_cleanupWSA = true;
|
||||
#endif
|
||||
|
||||
_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if(_socket == INVALID_SOCKET) {
|
||||
if (_socket == INVALID_SOCKET)
|
||||
{
|
||||
std::cout << "Socket creation failed." << std::endl;
|
||||
SetConnectionErrorFlag();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
SetSocketOptions();
|
||||
}
|
||||
}
|
||||
|
@ -61,28 +65,34 @@ Socket::Socket(uintptr_t socket)
|
|||
{
|
||||
_socket = socket;
|
||||
|
||||
if(socket == INVALID_SOCKET) {
|
||||
if (socket == INVALID_SOCKET)
|
||||
{
|
||||
SetConnectionErrorFlag();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
SetSocketOptions();
|
||||
}
|
||||
}
|
||||
|
||||
Socket::~Socket()
|
||||
{
|
||||
if(_UPnPPort != -1) {
|
||||
if (_UPnPPort != -1)
|
||||
{
|
||||
UPnPPortMapper::RemoveNATPortMapping(_UPnPPort, IPProtocol::TCP);
|
||||
}
|
||||
|
||||
if(_socket != INVALID_SOCKET) {
|
||||
if (_socket != INVALID_SOCKET)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if(_cleanupWSA) {
|
||||
WSACleanup();
|
||||
}
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
if (_cleanupWSA)
|
||||
{
|
||||
WSACleanup();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Socket::SetSocketOptions()
|
||||
|
@ -126,11 +136,13 @@ void Socket::Bind(uint16_t port)
|
|||
serverInf.sin_addr.s_addr = INADDR_ANY;
|
||||
serverInf.sin_port = htons(port);
|
||||
|
||||
if(UPnPPortMapper::AddNATPortMapping(port, port, IPProtocol::TCP)) {
|
||||
if (UPnPPortMapper::AddNATPortMapping(port, port, IPProtocol::TCP))
|
||||
{
|
||||
_UPnPPort = port;
|
||||
}
|
||||
|
||||
if(::bind(_socket, (SOCKADDR*)(&serverInf), sizeof(serverInf)) == SOCKET_ERROR) {
|
||||
if (::bind(_socket, (SOCKADDR*)(&serverInf), sizeof(serverInf)) == SOCKET_ERROR)
|
||||
{
|
||||
std::cout << "Unable to bind socket." << std::endl;
|
||||
SetConnectionErrorFlag();
|
||||
}
|
||||
|
@ -145,12 +157,15 @@ bool Socket::Connect(const char* hostname, uint16_t port)
|
|||
hint.ai_family = AF_INET;
|
||||
hint.ai_protocol = IPPROTO_TCP;
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
addrinfo *addrInfo;
|
||||
addrinfo* addrInfo;
|
||||
|
||||
if(getaddrinfo(hostname, std::to_string(port).c_str(), &hint, &addrInfo) != 0) {
|
||||
if (getaddrinfo(hostname, std::to_string(port).c_str(), &hint, &addrInfo) != 0)
|
||||
{
|
||||
std::cout << "Failed to resolve hostname." << std::endl;
|
||||
SetConnectionErrorFlag();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
//Set socket in non-blocking mode
|
||||
u_long iMode = 1;
|
||||
ioctlsocket(_socket, FIONBIO, &iMode);
|
||||
|
@ -159,13 +174,13 @@ bool Socket::Connect(const char* hostname, uint16_t port)
|
|||
connect(_socket, addrInfo->ai_addr, (int)addrInfo->ai_addrlen);
|
||||
|
||||
fd_set writeSockets;
|
||||
#ifdef _WIN32
|
||||
writeSockets.fd_count = 1;
|
||||
writeSockets.fd_array[0] = _socket;
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
writeSockets.fd_count = 1;
|
||||
writeSockets.fd_array[0] = _socket;
|
||||
#else
|
||||
FD_ZERO(&writeSockets);
|
||||
FD_SET(_socket, &writeSockets);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//Timeout after 3 seconds
|
||||
TIMEVAL timeout;
|
||||
|
@ -173,12 +188,16 @@ bool Socket::Connect(const char* hostname, uint16_t port)
|
|||
timeout.tv_usec = 0;
|
||||
|
||||
// check if the socket is ready
|
||||
int returnVal = select((int)_socket+1, nullptr, &writeSockets, nullptr, &timeout);
|
||||
if(returnVal > 0) {
|
||||
int returnVal = select((int)_socket + 1, nullptr, &writeSockets, nullptr, &timeout);
|
||||
if (returnVal > 0)
|
||||
{
|
||||
result = true;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
//Could not connect
|
||||
if(returnVal == SOCKET_ERROR) {
|
||||
if (returnVal == SOCKET_ERROR)
|
||||
{
|
||||
//int nError = WSAGetLastError();
|
||||
//std::cout << "select failed: nError " << std::to_string(nError) << " returnVal" << std::to_string(returnVal) << std::endl;
|
||||
}
|
||||
|
@ -193,7 +212,8 @@ bool Socket::Connect(const char* hostname, uint16_t port)
|
|||
|
||||
void Socket::Listen(int backlog)
|
||||
{
|
||||
if(listen(_socket, backlog) == SOCKET_ERROR) {
|
||||
if (listen(_socket, backlog) == SOCKET_ERROR)
|
||||
{
|
||||
std::cout << "listen failed." << std::endl;
|
||||
SetConnectionErrorFlag();
|
||||
}
|
||||
|
@ -210,27 +230,36 @@ bool WouldBlock(int nError)
|
|||
return nError == WSAEWOULDBLOCK || nError == EAGAIN;
|
||||
}
|
||||
|
||||
int Socket::Send(char *buf, int len, int flags)
|
||||
int Socket::Send(char* buf, int len, int flags)
|
||||
{
|
||||
int retryCount = 15;
|
||||
int nError = 0;
|
||||
int returnVal;
|
||||
do {
|
||||
do
|
||||
{
|
||||
//Loop until everything has been sent (shouldn't loop at all in the vast majority of cases)
|
||||
returnVal = send(_socket, buf, len, flags);
|
||||
|
||||
if(returnVal > 0) {
|
||||
if (returnVal > 0)
|
||||
{
|
||||
//Sent partial data, adjust pointer & length
|
||||
buf += returnVal;
|
||||
len -= returnVal;
|
||||
} else if(returnVal == SOCKET_ERROR) {
|
||||
}
|
||||
else if (returnVal == SOCKET_ERROR)
|
||||
{
|
||||
nError = WSAGetLastError();
|
||||
if(nError != 0) {
|
||||
if(!WouldBlock(nError)) {
|
||||
if (nError != 0)
|
||||
{
|
||||
if (!WouldBlock(nError))
|
||||
{
|
||||
SetConnectionErrorFlag();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
retryCount--;
|
||||
if(retryCount == 0) {
|
||||
if (retryCount == 0)
|
||||
{
|
||||
//Connection seems dead, close it.
|
||||
std::cout << "Unable to send data, closing socket." << std::endl;
|
||||
Close();
|
||||
|
@ -241,22 +270,28 @@ int Socket::Send(char *buf, int len, int flags)
|
|||
}
|
||||
}
|
||||
}
|
||||
} while(WouldBlock(nError) && len > 0);
|
||||
}
|
||||
while (WouldBlock(nError) && len > 0);
|
||||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
int Socket::Recv(char *buf, int len, int flags)
|
||||
int Socket::Recv(char* buf, int len, int flags)
|
||||
{
|
||||
int returnVal = recv(_socket, buf, len, flags);
|
||||
|
||||
if(returnVal == SOCKET_ERROR) {
|
||||
if (returnVal == SOCKET_ERROR)
|
||||
{
|
||||
int nError = WSAGetLastError();
|
||||
if(nError && !WouldBlock(nError)) {
|
||||
std::cout << "recv failed: nError " << std::to_string(nError) << " returnVal" << std::to_string(returnVal) << std::endl;
|
||||
if (nError && !WouldBlock(nError))
|
||||
{
|
||||
std::cout << "recv failed: nError " << std::to_string(nError) << " returnVal" << std::to_string(returnVal) <<
|
||||
std::endl;
|
||||
SetConnectionErrorFlag();
|
||||
}
|
||||
} else if(returnVal == 0) {
|
||||
}
|
||||
else if (returnVal == 0)
|
||||
{
|
||||
//Socket closed
|
||||
std::cout << "Socket closed by peer." << std::endl;
|
||||
Close();
|
||||
|
|
|
@ -6,9 +6,9 @@ class Socket
|
|||
{
|
||||
private:
|
||||
#ifndef LIBRETRO
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
bool _cleanupWSA = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
uintptr_t _socket = ~0;
|
||||
bool _connectionError = false;
|
||||
|
@ -31,8 +31,8 @@ public:
|
|||
void Listen(int backlog);
|
||||
shared_ptr<Socket> Accept();
|
||||
|
||||
int Send(char *buf, int len, int flags);
|
||||
void BufferedSend(char *buf, int len);
|
||||
int Send(char* buf, int len, int flags);
|
||||
void BufferedSend(char* buf, int len);
|
||||
void SendBuffer();
|
||||
int Recv(char *buf, int len, int flags);
|
||||
int Recv(char* buf, int len, int flags);
|
||||
};
|
||||
|
|
|
@ -9,7 +9,8 @@ public:
|
|||
vector<string> result;
|
||||
size_t index = 0;
|
||||
size_t lastIndex = 0;
|
||||
while((index = input.find(delimiter, index)) != string::npos) {
|
||||
while ((index = input.find(delimiter, index)) != string::npos)
|
||||
{
|
||||
result.push_back(input.substr(lastIndex, index - lastIndex));
|
||||
index++;
|
||||
lastIndex = index;
|
||||
|
|
|
@ -25,9 +25,11 @@ double Timer::GetElapsedMS()
|
|||
|
||||
void Timer::WaitUntil(double targetMillisecond)
|
||||
{
|
||||
if(targetMillisecond > 0) {
|
||||
if (targetMillisecond > 0)
|
||||
{
|
||||
double elapsedTime = GetElapsedMS();
|
||||
if(targetMillisecond - elapsedTime > 1) {
|
||||
if (targetMillisecond - elapsedTime > 1)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>((int)(targetMillisecond - elapsedTime)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,12 @@ using namespace std::chrono;
|
|||
|
||||
class Timer
|
||||
{
|
||||
private:
|
||||
high_resolution_clock::time_point _start;
|
||||
private:
|
||||
high_resolution_clock::time_point _start;
|
||||
|
||||
public:
|
||||
Timer();
|
||||
void Reset();
|
||||
double GetElapsedMS();
|
||||
void WaitUntil(double targetMillisecond);
|
||||
Timer();
|
||||
void Reset();
|
||||
double GetElapsedMS();
|
||||
void WaitUntil(double targetMillisecond);
|
||||
};
|
|
@ -12,52 +12,66 @@ bool UPnPPortMapper::AddNATPortMapping(uint16_t internalPort, uint16_t externalP
|
|||
|
||||
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||
|
||||
IUPnPNAT *nat = nullptr;
|
||||
IUPnPNAT* nat = nullptr;
|
||||
HRESULT hResult = CoCreateInstance(__uuidof(UPnPNAT), nullptr, CLSCTX_ALL, __uuidof(IUPnPNAT), (void**)&nat);
|
||||
|
||||
BSTR proto = SysAllocString((protocol == IPProtocol::TCP) ? L"TCP" : L"UDP");
|
||||
|
||||
if(SUCCEEDED(hResult) && nat) {
|
||||
IStaticPortMappingCollection *spmc = nullptr;
|
||||
if (SUCCEEDED(hResult) && nat)
|
||||
{
|
||||
IStaticPortMappingCollection* spmc = nullptr;
|
||||
hResult = nat->get_StaticPortMappingCollection(&spmc);
|
||||
if(SUCCEEDED(hResult) && spmc) {
|
||||
IStaticPortMapping *spm = nullptr;
|
||||
if (SUCCEEDED(hResult) && spmc)
|
||||
{
|
||||
IStaticPortMapping* spm = nullptr;
|
||||
hResult = spmc->get_Item(externalPort, proto, &spm);
|
||||
if(spm != nullptr) {
|
||||
if (spm != nullptr)
|
||||
{
|
||||
//An identical mapping already exists, remove it
|
||||
if(RemoveNATPortMapping(externalPort, protocol)) {
|
||||
if (RemoveNATPortMapping(externalPort, protocol))
|
||||
{
|
||||
std::cout << "Removed existing UPnP mapping." << std::endl;
|
||||
spm->Release();
|
||||
spm = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if(!SUCCEEDED(hResult) || spm == nullptr) {
|
||||
if (!SUCCEEDED(hResult) || spm == nullptr)
|
||||
{
|
||||
std::cout << "Attempting to automatically forward port via UPnP..." << std::endl;
|
||||
|
||||
vector<wstring> localIPs = GetLocalIPs();
|
||||
BSTR desc = SysAllocString(L"Mesen NetPlay");
|
||||
spm = nullptr;
|
||||
|
||||
for(size_t i = 0, len = localIPs.size(); i < len; i++) {
|
||||
for (size_t i = 0, len = localIPs.size(); i < len; i++)
|
||||
{
|
||||
BSTR clientStr = SysAllocString(localIPs[i].c_str());
|
||||
hResult = spmc->Add(externalPort, proto, internalPort, clientStr, true, desc, &spm);
|
||||
SysFreeString(clientStr);
|
||||
SysFreeString(desc);
|
||||
|
||||
if(SUCCEEDED(hResult) && spm) {
|
||||
if (SUCCEEDED(hResult) && spm)
|
||||
{
|
||||
//Successfully added a new port mapping
|
||||
std::cout << std::dec << "Forwarded port " << externalPort << " to IP " << utf8::utf8::encode(localIPs[i]) << std::endl;
|
||||
std::cout << std::dec << "Forwarded port " << externalPort << " to IP " <<
|
||||
utf8::utf8::encode(localIPs[i]) << std::endl;
|
||||
result = true;
|
||||
} else {
|
||||
std::cout << "Unable to add UPnP port mapping. IP: " << utf8::utf8::encode(localIPs[i]) << " HRESULT: 0x" << std::hex << hResult << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Unable to add UPnP port mapping. IP: " << utf8::utf8::encode(localIPs[i]) <<
|
||||
" HRESULT: 0x" << std::hex << hResult << std::endl;
|
||||
}
|
||||
|
||||
if(spm) {
|
||||
if (spm)
|
||||
{
|
||||
spm->Release();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Unable to add UPnP port mapping." << std::endl;
|
||||
}
|
||||
spmc->Release();
|
||||
|
@ -74,8 +88,8 @@ bool UPnPPortMapper::AddNATPortMapping(uint16_t internalPort, uint16_t externalP
|
|||
|
||||
bool UPnPPortMapper::RemoveNATPortMapping(uint16_t externalPort, IPProtocol protocol)
|
||||
{
|
||||
IUPnPNAT *nat = nullptr;
|
||||
IStaticPortMappingCollection *spmc;
|
||||
IUPnPNAT* nat = nullptr;
|
||||
IStaticPortMappingCollection* spmc;
|
||||
bool result = false;
|
||||
|
||||
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||
|
@ -84,9 +98,11 @@ bool UPnPPortMapper::RemoveNATPortMapping(uint16_t externalPort, IPProtocol prot
|
|||
|
||||
BSTR proto = SysAllocString((protocol == IPProtocol::TCP) ? L"TCP" : L"UDP");
|
||||
|
||||
if(SUCCEEDED(hResult) && nat) {
|
||||
if (SUCCEEDED(hResult) && nat)
|
||||
{
|
||||
hResult = nat->get_StaticPortMappingCollection(&spmc);
|
||||
if(SUCCEEDED(hResult) && spmc) {
|
||||
if (SUCCEEDED(hResult) && spmc)
|
||||
{
|
||||
spmc->Remove(externalPort, proto);
|
||||
spmc->Release();
|
||||
result = true;
|
||||
|
@ -104,8 +120,8 @@ bool UPnPPortMapper::RemoveNATPortMapping(uint16_t externalPort, IPProtocol prot
|
|||
vector<wstring> UPnPPortMapper::GetLocalIPs()
|
||||
{
|
||||
vector<wstring> localIPs;
|
||||
ADDRINFOW *result = nullptr;
|
||||
ADDRINFOW *current = nullptr;
|
||||
ADDRINFOW* result = nullptr;
|
||||
ADDRINFOW* current = nullptr;
|
||||
ADDRINFOW hints;
|
||||
|
||||
ZeroMemory(&hints, sizeof(hints));
|
||||
|
@ -117,14 +133,18 @@ vector<wstring> UPnPPortMapper::GetLocalIPs()
|
|||
DWORD hostSize = 255;
|
||||
GetComputerName(hostName, &hostSize);
|
||||
|
||||
if(GetAddrInfoW(hostName, nullptr, &hints, &result) == 0) {
|
||||
if (GetAddrInfoW(hostName, nullptr, &hints, &result) == 0)
|
||||
{
|
||||
current = result;
|
||||
while(current != nullptr) {
|
||||
while (current != nullptr)
|
||||
{
|
||||
wchar_t ipAddr[255];
|
||||
DWORD ipSize = 255;
|
||||
|
||||
if(WSAAddressToString(current->ai_addr, (DWORD)current->ai_addrlen, nullptr, ipAddr, &ipSize) == 0) {
|
||||
if(std::find(localIPs.begin(), localIPs.end(), ipAddr) == localIPs.end()) {
|
||||
if (WSAAddressToString(current->ai_addr, (DWORD)current->ai_addrlen, nullptr, ipAddr, &ipSize) == 0)
|
||||
{
|
||||
if (std::find(localIPs.begin(), localIPs.end(), ipAddr) == localIPs.end())
|
||||
{
|
||||
localIPs.push_back(ipAddr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,27 +5,27 @@
|
|||
|
||||
namespace utf8
|
||||
{
|
||||
std::wstring utf8::decode(const std::string &str)
|
||||
std::wstring utf8::decode(const std::string& str)
|
||||
{
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
|
||||
return conv.from_bytes(str);
|
||||
}
|
||||
|
||||
std::string utf8::encode(const std::wstring &wstr)
|
||||
std::string utf8::encode(const std::wstring& wstr)
|
||||
{
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
|
||||
return conv.to_bytes(wstr);
|
||||
return conv.to_bytes(wstr);
|
||||
}
|
||||
|
||||
std::string utf8::encode(const std::u16string &wstr)
|
||||
std::string utf8::encode(const std::u16string& wstr)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<int16_t>, int16_t> conv;
|
||||
auto p = reinterpret_cast<const int16_t *>(wstr.data());
|
||||
return conv.to_bytes(p, p + wstr.size());
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<int16_t>, int16_t> conv;
|
||||
auto p = reinterpret_cast<const int16_t*>(wstr.data());
|
||||
return conv.to_bytes(p, p + wstr.size());
|
||||
#else
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> conv;
|
||||
return conv.to_bytes(wstr);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -2,30 +2,51 @@
|
|||
|
||||
#include <fstream>
|
||||
|
||||
namespace utf8 {
|
||||
namespace utf8
|
||||
{
|
||||
class utf8
|
||||
{
|
||||
public:
|
||||
static std::wstring decode(const std::string &str);
|
||||
static std::string encode(const std::wstring &wstr);
|
||||
static std::string encode(const std::u16string &wstr);
|
||||
static std::wstring decode(const std::string& str);
|
||||
static std::string encode(const std::wstring& wstr);
|
||||
static std::string encode(const std::u16string& wstr);
|
||||
};
|
||||
|
||||
#if defined(_WIN32) && !defined(LIBRETRO)
|
||||
class ifstream : public std::ifstream
|
||||
{
|
||||
public:
|
||||
ifstream(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot) : std::ifstream(utf8::decode(_Str), _Mode, _Prot) { }
|
||||
ifstream() : std::ifstream() { }
|
||||
void open(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot) { std::ifstream::open(utf8::decode(_Str), _Mode, _Prot); }
|
||||
ifstream(const std::string& _Str, ios_base::openmode _Mode = ios_base::in,
|
||||
int _Prot = (int)ios_base::_Openprot) : std::ifstream(utf8::decode(_Str), _Mode, _Prot)
|
||||
{
|
||||
}
|
||||
|
||||
ifstream() : std::ifstream()
|
||||
{
|
||||
}
|
||||
|
||||
void open(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot)
|
||||
{
|
||||
std::ifstream::open(utf8::decode(_Str), _Mode, _Prot);
|
||||
}
|
||||
};
|
||||
|
||||
class ofstream : public std::ofstream
|
||||
{
|
||||
public:
|
||||
ofstream(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot) : std::ofstream(utf8::decode(_Str), _Mode, _Prot) { }
|
||||
ofstream() : std::ofstream() { }
|
||||
void open(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot) { std::ofstream::open(utf8::decode(_Str), _Mode, _Prot); }
|
||||
ofstream(const std::string& _Str, ios_base::openmode _Mode = ios_base::in,
|
||||
int _Prot = (int)ios_base::_Openprot) : std::ofstream(utf8::decode(_Str), _Mode, _Prot)
|
||||
{
|
||||
}
|
||||
|
||||
ofstream() : std::ofstream()
|
||||
{
|
||||
}
|
||||
|
||||
void open(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot)
|
||||
{
|
||||
std::ofstream::open(utf8::decode(_Str), _Mode, _Prot);
|
||||
}
|
||||
};
|
||||
#else
|
||||
using std::ifstream;
|
||||
|
|
|
@ -4,19 +4,22 @@
|
|||
#include "UpsPatcher.h"
|
||||
#include "CRC32.h"
|
||||
|
||||
int64_t UpsPatcher::ReadBase128Number(std::istream &file)
|
||||
int64_t UpsPatcher::ReadBase128Number(std::istream& file)
|
||||
{
|
||||
int64_t result = 0;
|
||||
int shift = 0;
|
||||
uint8_t buffer;
|
||||
while(true) {
|
||||
while (true)
|
||||
{
|
||||
file.read((char*)&buffer, 1);
|
||||
if(file.eof()) {
|
||||
if (file.eof())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
result += (buffer & 0x7F) << shift;
|
||||
shift += 7;
|
||||
if(buffer & 0x80) {
|
||||
if (buffer & 0x80)
|
||||
{
|
||||
break;
|
||||
}
|
||||
result += (int64_t)1 << shift;
|
||||
|
@ -25,16 +28,17 @@ int64_t UpsPatcher::ReadBase128Number(std::istream &file)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool UpsPatcher::PatchBuffer(string upsFilepath, vector<uint8_t> &input, vector<uint8_t> &output)
|
||||
bool UpsPatcher::PatchBuffer(string upsFilepath, vector<uint8_t>& input, vector<uint8_t>& output)
|
||||
{
|
||||
ifstream upsFile(upsFilepath, std::ios::in | std::ios::binary);
|
||||
if(upsFile) {
|
||||
if (upsFile)
|
||||
{
|
||||
return PatchBuffer(upsFile, input, output);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UpsPatcher::PatchBuffer(std::istream &upsFile, vector<uint8_t> &input, vector<uint8_t> &output)
|
||||
bool UpsPatcher::PatchBuffer(std::istream& upsFile, vector<uint8_t>& input, vector<uint8_t>& output)
|
||||
{
|
||||
upsFile.seekg(0, std::ios::end);
|
||||
size_t fileSize = (size_t)upsFile.tellg();
|
||||
|
@ -42,14 +46,16 @@ bool UpsPatcher::PatchBuffer(std::istream &upsFile, vector<uint8_t> &input, vect
|
|||
|
||||
char header[4];
|
||||
upsFile.read((char*)&header, 4);
|
||||
if(memcmp((char*)&header, "UPS1", 4) != 0) {
|
||||
if (memcmp((char*)&header, "UPS1", 4) != 0)
|
||||
{
|
||||
//Invalid UPS file
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t inputFileSize = ReadBase128Number(upsFile);
|
||||
int64_t outputFileSize = ReadBase128Number(upsFile);
|
||||
if(inputFileSize == -1 || outputFileSize == -1) {
|
||||
if (inputFileSize == -1 || outputFileSize == -1)
|
||||
{
|
||||
//Invalid file
|
||||
return false;
|
||||
}
|
||||
|
@ -58,19 +64,23 @@ bool UpsPatcher::PatchBuffer(std::istream &upsFile, vector<uint8_t> &input, vect
|
|||
std::copy(input.begin(), input.end(), output.begin());
|
||||
|
||||
uint32_t pos = 0;
|
||||
while((size_t)upsFile.tellg() < fileSize - 12) {
|
||||
while ((size_t)upsFile.tellg() < fileSize - 12)
|
||||
{
|
||||
int32_t offset = (int32_t)ReadBase128Number(upsFile);
|
||||
if(offset == -1) {
|
||||
if (offset == -1)
|
||||
{
|
||||
//Invalid file
|
||||
return false;
|
||||
}
|
||||
|
||||
pos += offset;
|
||||
|
||||
while(true) {
|
||||
while (true)
|
||||
{
|
||||
uint8_t xorValue = 0;
|
||||
upsFile.read((char*)&xorValue, 1);
|
||||
if((size_t)upsFile.tellg() > fileSize - 12) {
|
||||
if ((size_t)upsFile.tellg() > fileSize - 12)
|
||||
{
|
||||
//Invalid file
|
||||
return false;
|
||||
}
|
||||
|
@ -78,7 +88,8 @@ bool UpsPatcher::PatchBuffer(std::istream &upsFile, vector<uint8_t> &input, vect
|
|||
output[pos] ^= xorValue;
|
||||
pos++;
|
||||
|
||||
if(!xorValue) {
|
||||
if (!xorValue)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -88,12 +99,15 @@ bool UpsPatcher::PatchBuffer(std::istream &upsFile, vector<uint8_t> &input, vect
|
|||
uint8_t outputChecksum[4];
|
||||
upsFile.read((char*)inputChecksum, 4);
|
||||
upsFile.read((char*)outputChecksum, 4);
|
||||
uint32_t patchInputCrc = inputChecksum[0] | (inputChecksum[1] << 8) | (inputChecksum[2] << 16) | (inputChecksum[3] << 24);
|
||||
uint32_t patchOutputCrc = outputChecksum[0] | (outputChecksum[1] << 8) | (outputChecksum[2] << 16) | (outputChecksum[3] << 24);
|
||||
uint32_t patchInputCrc = inputChecksum[0] | (inputChecksum[1] << 8) | (inputChecksum[2] << 16) | (inputChecksum[3] <<
|
||||
24);
|
||||
uint32_t patchOutputCrc = outputChecksum[0] | (outputChecksum[1] << 8) | (outputChecksum[2] << 16) | (outputChecksum[
|
||||
3] << 24);
|
||||
uint32_t inputCrc = CRC32::GetCRC(input.data(), input.size());
|
||||
uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size());
|
||||
|
||||
if(patchInputCrc != inputCrc || patchOutputCrc != outputCrc) {
|
||||
if (patchInputCrc != inputCrc || patchOutputCrc != outputCrc)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
class UpsPatcher
|
||||
{
|
||||
private:
|
||||
static int64_t ReadBase128Number(std::istream &file);
|
||||
static int64_t ReadBase128Number(std::istream& file);
|
||||
|
||||
public:
|
||||
static bool PatchBuffer(std::istream &upsFile, vector<uint8_t> &input, vector<uint8_t> &output);
|
||||
static bool PatchBuffer(string upsFilepath, vector<uint8_t> &input, vector<uint8_t> &output);
|
||||
static bool PatchBuffer(std::istream& upsFile, vector<uint8_t>& input, vector<uint8_t>& output);
|
||||
static bool PatchBuffer(string upsFilepath, vector<uint8_t>& input, vector<uint8_t>& output);
|
||||
};
|
|
@ -10,7 +10,7 @@
|
|||
#include "../Utilities/IpsPatcher.h"
|
||||
#include "../Utilities/UpsPatcher.h"
|
||||
|
||||
const std::initializer_list<string> VirtualFile::RomExtensions = { ".sfc", ".smc", ".swc", ".fig", ".bs", ".gb", ".gbc" };
|
||||
const std::initializer_list<string> VirtualFile::RomExtensions = {".sfc", ".smc", ".swc", ".fig", ".bs", ".gb", ".gbc"};
|
||||
|
||||
VirtualFile::VirtualFile()
|
||||
{
|
||||
|
@ -26,12 +26,18 @@ VirtualFile::VirtualFile(const string& file)
|
|||
{
|
||||
vector<string> tokens = StringUtilities::Split(file, '\x1');
|
||||
_path = tokens[0];
|
||||
if(tokens.size() > 1) {
|
||||
if (tokens.size() > 1)
|
||||
{
|
||||
_innerFile = tokens[1];
|
||||
if(tokens.size() > 2) {
|
||||
try {
|
||||
if (tokens.size() > 2)
|
||||
{
|
||||
try
|
||||
{
|
||||
_innerFileIndex = std::stoi(tokens[2]);
|
||||
} catch(std::exception&) {}
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,14 +58,22 @@ VirtualFile::VirtualFile(std::istream& input, string filePath)
|
|||
|
||||
VirtualFile::operator std::string() const
|
||||
{
|
||||
if(_innerFile.empty()) {
|
||||
if (_innerFile.empty())
|
||||
{
|
||||
return _path;
|
||||
} else if(_path.empty()) {
|
||||
}
|
||||
else if (_path.empty())
|
||||
{
|
||||
throw std::runtime_error("Cannot convert to string");
|
||||
} else {
|
||||
if(_innerFileIndex >= 0) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_innerFileIndex >= 0)
|
||||
{
|
||||
return _path + "\x1" + _innerFile + "\x1" + std::to_string(_innerFileIndex);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return _path + "\x1" + _innerFile;
|
||||
}
|
||||
}
|
||||
|
@ -77,22 +91,32 @@ void VirtualFile::FromStream(std::istream& input, vector<uint8_t>& output)
|
|||
|
||||
void VirtualFile::LoadFile()
|
||||
{
|
||||
if(_data.size() == 0) {
|
||||
if(!_innerFile.empty()) {
|
||||
if (_data.size() == 0)
|
||||
{
|
||||
if (!_innerFile.empty())
|
||||
{
|
||||
shared_ptr<ArchiveReader> reader = ArchiveReader::GetReader(_path);
|
||||
if(reader) {
|
||||
if(_innerFileIndex >= 0) {
|
||||
if (reader)
|
||||
{
|
||||
if (_innerFileIndex >= 0)
|
||||
{
|
||||
vector<string> filelist = reader->GetFileList(VirtualFile::RomExtensions);
|
||||
if((int32_t)filelist.size() > _innerFileIndex) {
|
||||
if ((int32_t)filelist.size() > _innerFileIndex)
|
||||
{
|
||||
reader->ExtractFile(filelist[_innerFileIndex], _data);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
reader->ExtractFile(_innerFile, _data);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ifstream input(_path, std::ios::in | std::ios::binary);
|
||||
if(input.good()) {
|
||||
if (input.good())
|
||||
{
|
||||
FromStream(input, _data);
|
||||
}
|
||||
}
|
||||
|
@ -101,25 +125,35 @@ void VirtualFile::LoadFile()
|
|||
|
||||
bool VirtualFile::IsValid()
|
||||
{
|
||||
if(_data.size() > 0) {
|
||||
if (_data.size() > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!_innerFile.empty()) {
|
||||
if (!_innerFile.empty())
|
||||
{
|
||||
shared_ptr<ArchiveReader> reader = ArchiveReader::GetReader(_path);
|
||||
if(reader) {
|
||||
if (reader)
|
||||
{
|
||||
vector<string> filelist = reader->GetFileList();
|
||||
if(_innerFileIndex >= 0) {
|
||||
if((int32_t)filelist.size() > _innerFileIndex) {
|
||||
if (_innerFileIndex >= 0)
|
||||
{
|
||||
if ((int32_t)filelist.size() > _innerFileIndex)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::find(filelist.begin(), filelist.end(), _innerFile) != filelist.end();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ifstream input(_path, std::ios::in | std::ios::binary);
|
||||
if(input) {
|
||||
if (input)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +190,8 @@ size_t VirtualFile::GetSize()
|
|||
bool VirtualFile::ReadFile(vector<uint8_t>& out)
|
||||
{
|
||||
LoadFile();
|
||||
if(_data.size() > 0) {
|
||||
if (_data.size() > 0)
|
||||
{
|
||||
out.resize(_data.size(), 0);
|
||||
std::copy(_data.begin(), _data.end(), out.begin());
|
||||
return true;
|
||||
|
@ -167,7 +202,8 @@ bool VirtualFile::ReadFile(vector<uint8_t>& out)
|
|||
bool VirtualFile::ReadFile(std::stringstream& out)
|
||||
{
|
||||
LoadFile();
|
||||
if(_data.size() > 0) {
|
||||
if (_data.size() > 0)
|
||||
{
|
||||
out.write((char*)_data.data(), _data.size());
|
||||
return true;
|
||||
}
|
||||
|
@ -177,7 +213,8 @@ bool VirtualFile::ReadFile(std::stringstream& out)
|
|||
bool VirtualFile::ReadFile(uint8_t* out, uint32_t expectedSize)
|
||||
{
|
||||
LoadFile();
|
||||
if(_data.size() == expectedSize) {
|
||||
if (_data.size() == expectedSize)
|
||||
{
|
||||
memcpy(out, _data.data(), _data.size());
|
||||
return true;
|
||||
}
|
||||
|
@ -188,22 +225,30 @@ bool VirtualFile::ApplyPatch(VirtualFile& patch)
|
|||
{
|
||||
//Apply patch file
|
||||
bool result = false;
|
||||
if(IsValid() && patch.IsValid()) {
|
||||
if (IsValid() && patch.IsValid())
|
||||
{
|
||||
patch.LoadFile();
|
||||
LoadFile();
|
||||
if(patch._data.size() >= 5) {
|
||||
if (patch._data.size() >= 5)
|
||||
{
|
||||
vector<uint8_t> patchedData;
|
||||
std::stringstream ss;
|
||||
patch.ReadFile(ss);
|
||||
|
||||
if(memcmp(patch._data.data(), "PATCH", 5) == 0) {
|
||||
if (memcmp(patch._data.data(), "PATCH", 5) == 0)
|
||||
{
|
||||
result = IpsPatcher::PatchBuffer(ss, _data, patchedData);
|
||||
} else if(memcmp(patch._data.data(), "UPS1", 4) == 0) {
|
||||
}
|
||||
else if (memcmp(patch._data.data(), "UPS1", 4) == 0)
|
||||
{
|
||||
result = UpsPatcher::PatchBuffer(ss, _data, patchedData);
|
||||
} else if(memcmp(patch._data.data(), "BPS1", 4) == 0) {
|
||||
}
|
||||
else if (memcmp(patch._data.data(), "BPS1", 4) == 0)
|
||||
{
|
||||
result = BpsPatcher::PatchBuffer(ss, _data, patchedData);
|
||||
}
|
||||
if(result) {
|
||||
if (result)
|
||||
{
|
||||
_data = patchedData;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ private:
|
|||
int32_t _innerFileIndex = -1;
|
||||
vector<uint8_t> _data;
|
||||
|
||||
void FromStream(std::istream &input, vector<uint8_t> &output);
|
||||
void FromStream(std::istream& input, vector<uint8_t>& output);
|
||||
|
||||
void LoadFile();
|
||||
|
||||
|
@ -18,10 +18,10 @@ public:
|
|||
static const std::initializer_list<string> RomExtensions;
|
||||
|
||||
VirtualFile();
|
||||
VirtualFile(const string &archivePath, const string innerFile);
|
||||
VirtualFile(const string &file);
|
||||
VirtualFile(const void *buffer, size_t bufferSize, string fileName = "noname");
|
||||
VirtualFile(std::istream &input, string filePath);
|
||||
VirtualFile(const string& archivePath, const string innerFile);
|
||||
VirtualFile(const string& file);
|
||||
VirtualFile(const void* buffer, size_t bufferSize, string fileName = "noname");
|
||||
VirtualFile(std::istream& input, string filePath);
|
||||
|
||||
operator std::string() const;
|
||||
|
||||
|
@ -33,9 +33,9 @@ public:
|
|||
|
||||
size_t GetSize();
|
||||
|
||||
bool ReadFile(vector<uint8_t> &out);
|
||||
bool ReadFile(std::stringstream &out);
|
||||
bool ReadFile(vector<uint8_t>& out);
|
||||
bool ReadFile(std::stringstream& out);
|
||||
bool ReadFile(uint8_t* out, uint32_t expectedSize);
|
||||
|
||||
bool ApplyPatch(VirtualFile &patch);
|
||||
bool ApplyPatch(VirtualFile& patch);
|
||||
};
|
|
@ -10,14 +10,16 @@ ZipReader::ZipReader()
|
|||
|
||||
ZipReader::~ZipReader()
|
||||
{
|
||||
if(_initialized) {
|
||||
if (_initialized)
|
||||
{
|
||||
mz_zip_reader_end(&_zipArchive);
|
||||
}
|
||||
}
|
||||
|
||||
bool ZipReader::InternalLoadArchive(void* buffer, size_t size)
|
||||
{
|
||||
if(_initialized) {
|
||||
if (_initialized)
|
||||
{
|
||||
mz_zip_reader_end(&_zipArchive);
|
||||
memset(&_zipArchive, 0, sizeof(mz_zip_archive));
|
||||
_initialized = false;
|
||||
|
@ -29,10 +31,13 @@ bool ZipReader::InternalLoadArchive(void* buffer, size_t size)
|
|||
vector<string> ZipReader::InternalGetFileList()
|
||||
{
|
||||
vector<string> fileList;
|
||||
if(_initialized) {
|
||||
for(int i = 0, len = (int)mz_zip_reader_get_num_files(&_zipArchive); i < len; i++) {
|
||||
if (_initialized)
|
||||
{
|
||||
for (int i = 0, len = (int)mz_zip_reader_get_num_files(&_zipArchive); i < len; i++)
|
||||
{
|
||||
mz_zip_archive_file_stat file_stat;
|
||||
if(!mz_zip_reader_file_stat(&_zipArchive, i, &file_stat)) {
|
||||
if (!mz_zip_reader_file_stat(&_zipArchive, i, &file_stat))
|
||||
{
|
||||
std::cout << "mz_zip_reader_file_stat() failed!" << std::endl;
|
||||
}
|
||||
|
||||
|
@ -42,12 +47,14 @@ vector<string> ZipReader::InternalGetFileList()
|
|||
return fileList;
|
||||
}
|
||||
|
||||
bool ZipReader::ExtractFile(string filename, vector<uint8_t> &output)
|
||||
bool ZipReader::ExtractFile(string filename, vector<uint8_t>& output)
|
||||
{
|
||||
if(_initialized) {
|
||||
if (_initialized)
|
||||
{
|
||||
size_t uncompSize;
|
||||
void *p = mz_zip_reader_extract_file_to_heap(&_zipArchive, filename.c_str(), &uncompSize, 0);
|
||||
if(!p) {
|
||||
void* p = mz_zip_reader_extract_file_to_heap(&_zipArchive, filename.c_str(), &uncompSize, 0);
|
||||
if (!p)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
std::cout << "mz_zip_reader_extract_file_to_heap() failed!" << std::endl;
|
||||
#endif
|
||||
|
|
|
@ -16,5 +16,5 @@ public:
|
|||
ZipReader();
|
||||
virtual ~ZipReader();
|
||||
|
||||
bool ExtractFile(string filename, vector<uint8_t> &output);
|
||||
bool ExtractFile(string filename, vector<uint8_t>& output);
|
||||
};
|
|
@ -29,19 +29,21 @@ bool ZipWriter::Save()
|
|||
|
||||
void ZipWriter::AddFile(string filepath, string zipFilename)
|
||||
{
|
||||
if(!mz_zip_writer_add_file(&_zipArchive, zipFilename.c_str(), filepath.c_str(), "", 0, MZ_BEST_COMPRESSION)) {
|
||||
if (!mz_zip_writer_add_file(&_zipArchive, zipFilename.c_str(), filepath.c_str(), "", 0, MZ_BEST_COMPRESSION))
|
||||
{
|
||||
std::cout << "mz_zip_writer_add_file() failed!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ZipWriter::AddFile(vector<uint8_t> &fileData, string zipFilename)
|
||||
void ZipWriter::AddFile(vector<uint8_t>& fileData, string zipFilename)
|
||||
{
|
||||
if(!mz_zip_writer_add_mem(&_zipArchive, zipFilename.c_str(), fileData.data(), fileData.size(), MZ_BEST_COMPRESSION)) {
|
||||
if (!mz_zip_writer_add_mem(&_zipArchive, zipFilename.c_str(), fileData.data(), fileData.size(), MZ_BEST_COMPRESSION))
|
||||
{
|
||||
std::cout << "mz_zip_writer_add_file() failed!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ZipWriter::AddFile(std::stringstream &filestream, string zipFilename)
|
||||
void ZipWriter::AddFile(std::stringstream& filestream, string zipFilename)
|
||||
{
|
||||
filestream.seekg(0, std::ios::end);
|
||||
size_t bufferSize = (size_t)filestream.tellg();
|
||||
|
|
|
@ -16,6 +16,6 @@ public:
|
|||
bool Save();
|
||||
|
||||
void AddFile(string filepath, string zipFilename);
|
||||
void AddFile(vector<uint8_t> &fileData, string zipFilename);
|
||||
void AddFile(std::stringstream &filestream, string zipFilename);
|
||||
void AddFile(vector<uint8_t>& fileData, string zipFilename);
|
||||
void AddFile(std::stringstream& filestream, string zipFilename);
|
||||
};
|
|
@ -39,24 +39,32 @@
|
|||
#define Mask_KeyFrame 0x01
|
||||
#define Mask_DeltaPalette 0x02
|
||||
|
||||
int ZmbvCodec::NeededSize( int _width, int _height, zmbv_format_t _format) {
|
||||
int ZmbvCodec::NeededSize(int _width, int _height, zmbv_format_t _format)
|
||||
{
|
||||
int f;
|
||||
switch (_format) {
|
||||
case ZMBV_FORMAT_8BPP:f = 1;break;
|
||||
case ZMBV_FORMAT_15BPP:f = 2;break;
|
||||
case ZMBV_FORMAT_16BPP:f = 2;break;
|
||||
case ZMBV_FORMAT_32BPP:f = 4;break;
|
||||
switch (_format)
|
||||
{
|
||||
case ZMBV_FORMAT_8BPP: f = 1;
|
||||
break;
|
||||
case ZMBV_FORMAT_15BPP: f = 2;
|
||||
break;
|
||||
case ZMBV_FORMAT_16BPP: f = 2;
|
||||
break;
|
||||
case ZMBV_FORMAT_32BPP: f = 4;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
f = f*_width*_height + 2*(1+(_width/8)) * (1+(_height/8))+1024;
|
||||
return f + f/1000;
|
||||
f = f * _width * _height + 2 * (1 + (_width / 8)) * (1 + (_height / 8)) + 1024;
|
||||
return f + f / 1000;
|
||||
}
|
||||
|
||||
bool ZmbvCodec::SetupBuffers(zmbv_format_t _format, int blockwidth, int blockheight) {
|
||||
bool ZmbvCodec::SetupBuffers(zmbv_format_t _format, int blockwidth, int blockheight)
|
||||
{
|
||||
FreeBuffers();
|
||||
palsize = 0;
|
||||
switch (_format) {
|
||||
switch (_format)
|
||||
{
|
||||
case ZMBV_FORMAT_8BPP:
|
||||
pixelsize = 1;
|
||||
palsize = 256;
|
||||
|
@ -73,50 +81,59 @@ bool ZmbvCodec::SetupBuffers(zmbv_format_t _format, int blockwidth, int blockhei
|
|||
default:
|
||||
return false;
|
||||
};
|
||||
bufsize = (height+2*MAX_VECTOR)*pitch*pixelsize+2048;
|
||||
bufsize = (height + 2 * MAX_VECTOR) * pitch * pixelsize + 2048;
|
||||
|
||||
buf1 = new unsigned char[bufsize];
|
||||
buf2 = new unsigned char[bufsize];
|
||||
work = new unsigned char[bufsize];
|
||||
|
||||
int xblocks = (width/blockwidth);
|
||||
int xblocks = (width / blockwidth);
|
||||
int xleft = width % blockwidth;
|
||||
if (xleft) xblocks++;
|
||||
int yblocks = (height/blockheight);
|
||||
int yblocks = (height / blockheight);
|
||||
int yleft = height % blockheight;
|
||||
if (yleft) yblocks++;
|
||||
blockcount=yblocks*xblocks;
|
||||
blocks=new FrameBlock[blockcount];
|
||||
blockcount = yblocks * xblocks;
|
||||
blocks = new FrameBlock[blockcount];
|
||||
|
||||
if (!buf1 || !buf2 || !work || !blocks) {
|
||||
if (!buf1 || !buf2 || !work || !blocks)
|
||||
{
|
||||
FreeBuffers();
|
||||
return false;
|
||||
}
|
||||
int y,x,i;
|
||||
i=0;
|
||||
for (y=0;y<yblocks;y++) {
|
||||
for (x=0;x<xblocks;x++) {
|
||||
blocks[i].start=((y*blockheight)+MAX_VECTOR)*pitch+
|
||||
(x*blockwidth)+MAX_VECTOR;
|
||||
if (xleft && x==(xblocks-1)) {
|
||||
blocks[i].dx=xleft;
|
||||
} else {
|
||||
blocks[i].dx=blockwidth;
|
||||
int y, x, i;
|
||||
i = 0;
|
||||
for (y = 0; y < yblocks; y++)
|
||||
{
|
||||
for (x = 0; x < xblocks; x++)
|
||||
{
|
||||
blocks[i].start = ((y * blockheight) + MAX_VECTOR) * pitch +
|
||||
(x * blockwidth) + MAX_VECTOR;
|
||||
if (xleft && x == (xblocks - 1))
|
||||
{
|
||||
blocks[i].dx = xleft;
|
||||
}
|
||||
if (yleft && y==(yblocks-1)) {
|
||||
blocks[i].dy=yleft;
|
||||
} else {
|
||||
blocks[i].dy=blockheight;
|
||||
else
|
||||
{
|
||||
blocks[i].dx = blockwidth;
|
||||
}
|
||||
if (yleft && y == (yblocks - 1))
|
||||
{
|
||||
blocks[i].dy = yleft;
|
||||
}
|
||||
else
|
||||
{
|
||||
blocks[i].dy = blockheight;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
memset(buf1,0,bufsize);
|
||||
memset(buf2,0,bufsize);
|
||||
memset(work,0,bufsize);
|
||||
oldframe=buf1;
|
||||
newframe=buf2;
|
||||
memset(buf1, 0, bufsize);
|
||||
memset(buf2, 0, bufsize);
|
||||
memset(work, 0, bufsize);
|
||||
oldframe = buf1;
|
||||
newframe = buf2;
|
||||
format = _format;
|
||||
|
||||
_bufSize = NeededSize(width, height, format);
|
||||
|
@ -125,141 +142,165 @@ bool ZmbvCodec::SetupBuffers(zmbv_format_t _format, int blockwidth, int blockhei
|
|||
return true;
|
||||
}
|
||||
|
||||
void ZmbvCodec::CreateVectorTable(void) {
|
||||
int x,y,s;
|
||||
VectorCount=1;
|
||||
void ZmbvCodec::CreateVectorTable(void)
|
||||
{
|
||||
int x, y, s;
|
||||
VectorCount = 1;
|
||||
|
||||
VectorTable[0].x=VectorTable[0].y=0;
|
||||
for (s=1;s<=10;s++) {
|
||||
for (y=0-s;y<=0+s;y++) for (x=0-s;x<=0+s;x++) {
|
||||
if (abs(x)==s || abs(y)==s) {
|
||||
VectorTable[VectorCount].x=x;
|
||||
VectorTable[VectorCount].y=y;
|
||||
VectorCount++;
|
||||
VectorTable[0].x = VectorTable[0].y = 0;
|
||||
for (s = 1; s <= 10; s++)
|
||||
{
|
||||
for (y = 0 - s; y <= 0 + s; y++)
|
||||
for (x = 0 - s; x <= 0 + s; x++)
|
||||
{
|
||||
if (abs(x) == s || abs(y) == s)
|
||||
{
|
||||
VectorTable[VectorCount].x = x;
|
||||
VectorTable[VectorCount].y = y;
|
||||
VectorCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class P>
|
||||
INLINE int ZmbvCodec::PossibleBlock(int vx,int vy,FrameBlock * block) {
|
||||
int ret=0;
|
||||
P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx;
|
||||
P * pnew=((P*)newframe)+block->start;;
|
||||
for (int y=0;y<block->dy;y+=4) {
|
||||
for (int x=0;x<block->dx;x+=4) {
|
||||
int test=0-((pold[x]-pnew[x])&0x00ffffff);
|
||||
ret-=(test>>31);
|
||||
template <class P>
|
||||
INLINE int ZmbvCodec::PossibleBlock(int vx, int vy, FrameBlock* block)
|
||||
{
|
||||
int ret = 0;
|
||||
P* pold = ((P*)oldframe) + block->start + (vy * pitch) + vx;
|
||||
P* pnew = ((P*)newframe) + block->start;;
|
||||
for (int y = 0; y < block->dy; y += 4)
|
||||
{
|
||||
for (int x = 0; x < block->dx; x += 4)
|
||||
{
|
||||
int test = 0 - ((pold[x] - pnew[x]) & 0x00ffffff);
|
||||
ret -= (test >> 31);
|
||||
}
|
||||
pold+=pitch*4;
|
||||
pnew+=pitch*4;
|
||||
pold += pitch * 4;
|
||||
pnew += pitch * 4;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<class P>
|
||||
INLINE int ZmbvCodec::CompareBlock(int vx,int vy,FrameBlock * block) {
|
||||
int ret=0;
|
||||
P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx;
|
||||
P * pnew=((P*)newframe)+block->start;;
|
||||
for (int y=0;y<block->dy;y++) {
|
||||
for (int x=0;x<block->dx;x++) {
|
||||
int test=0-((pold[x]-pnew[x])&0x00ffffff);
|
||||
ret-=(test>>31);
|
||||
template <class P>
|
||||
INLINE int ZmbvCodec::CompareBlock(int vx, int vy, FrameBlock* block)
|
||||
{
|
||||
int ret = 0;
|
||||
P* pold = ((P*)oldframe) + block->start + (vy * pitch) + vx;
|
||||
P* pnew = ((P*)newframe) + block->start;;
|
||||
for (int y = 0; y < block->dy; y++)
|
||||
{
|
||||
for (int x = 0; x < block->dx; x++)
|
||||
{
|
||||
int test = 0 - ((pold[x] - pnew[x]) & 0x00ffffff);
|
||||
ret -= (test >> 31);
|
||||
}
|
||||
pold+=pitch;
|
||||
pnew+=pitch;
|
||||
pold += pitch;
|
||||
pnew += pitch;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<class P>
|
||||
INLINE void ZmbvCodec::AddXorBlock(int vx,int vy,FrameBlock * block) {
|
||||
P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx;
|
||||
P * pnew=((P*)newframe)+block->start;
|
||||
for (int y=0;y<block->dy;y++) {
|
||||
for (int x=0;x<block->dx;x++) {
|
||||
*((P*)&work[workUsed])=pnew[x] ^ pold[x];
|
||||
workUsed+=sizeof(P);
|
||||
template <class P>
|
||||
INLINE void ZmbvCodec::AddXorBlock(int vx, int vy, FrameBlock* block)
|
||||
{
|
||||
P* pold = ((P*)oldframe) + block->start + (vy * pitch) + vx;
|
||||
P* pnew = ((P*)newframe) + block->start;
|
||||
for (int y = 0; y < block->dy; y++)
|
||||
{
|
||||
for (int x = 0; x < block->dx; x++)
|
||||
{
|
||||
*((P*)&work[workUsed]) = pnew[x] ^ pold[x];
|
||||
workUsed += sizeof(P);
|
||||
}
|
||||
pold+=pitch;
|
||||
pnew+=pitch;
|
||||
pold += pitch;
|
||||
pnew += pitch;
|
||||
}
|
||||
}
|
||||
|
||||
template<class P>
|
||||
void ZmbvCodec::AddXorFrame(void) {
|
||||
signed char * vectors=(signed char*)&work[workUsed];
|
||||
template <class P>
|
||||
void ZmbvCodec::AddXorFrame(void)
|
||||
{
|
||||
signed char* vectors = (signed char*)&work[workUsed];
|
||||
/* Align the following xor data on 4 byte boundary*/
|
||||
workUsed=(workUsed + blockcount*2 +3) & ~3;
|
||||
for (int b=0;b<blockcount;b++) {
|
||||
FrameBlock * block=&blocks[b];
|
||||
workUsed = (workUsed + blockcount * 2 + 3) & ~3;
|
||||
for (int b = 0; b < blockcount; b++)
|
||||
{
|
||||
FrameBlock* block = &blocks[b];
|
||||
int bestvx = 0;
|
||||
int bestvy = 0;
|
||||
int bestchange=CompareBlock<P>(0,0, block);
|
||||
int possibles=64;
|
||||
for (int v=0;v<VectorCount && possibles;v++) {
|
||||
if (bestchange<4) break;
|
||||
int bestchange = CompareBlock<P>(0, 0, block);
|
||||
int possibles = 64;
|
||||
for (int v = 0; v < VectorCount && possibles; v++)
|
||||
{
|
||||
if (bestchange < 4) break;
|
||||
int vx = VectorTable[v].x;
|
||||
int vy = VectorTable[v].y;
|
||||
if (PossibleBlock<P>(vx, vy, block) < 4) {
|
||||
if (PossibleBlock<P>(vx, vy, block) < 4)
|
||||
{
|
||||
possibles--;
|
||||
int testchange=CompareBlock<P>(vx,vy, block);
|
||||
if (testchange<bestchange) {
|
||||
bestchange=testchange;
|
||||
int testchange = CompareBlock<P>(vx, vy, block);
|
||||
if (testchange < bestchange)
|
||||
{
|
||||
bestchange = testchange;
|
||||
bestvx = vx;
|
||||
bestvy = vy;
|
||||
}
|
||||
}
|
||||
}
|
||||
vectors[b*2+0]=(bestvx << 1);
|
||||
vectors[b*2+1]=(bestvy << 1);
|
||||
if (bestchange) {
|
||||
vectors[b*2+0]|=1;
|
||||
vectors[b * 2 + 0] = (bestvx << 1);
|
||||
vectors[b * 2 + 1] = (bestvy << 1);
|
||||
if (bestchange)
|
||||
{
|
||||
vectors[b * 2 + 0] |= 1;
|
||||
AddXorBlock<P>(bestvx, bestvy, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ZmbvCodec::SetupCompress( int _width, int _height, uint32_t compressionLevel ) {
|
||||
bool ZmbvCodec::SetupCompress(int _width, int _height, uint32_t compressionLevel)
|
||||
{
|
||||
width = _width;
|
||||
height = _height;
|
||||
pitch = _width + 2*MAX_VECTOR;
|
||||
pitch = _width + 2 * MAX_VECTOR;
|
||||
format = ZMBV_FORMAT_NONE;
|
||||
if (deflateInit (&zstream, compressionLevel) != Z_OK)
|
||||
if (deflateInit(&zstream, compressionLevel) != Z_OK)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZmbvCodec::PrepareCompressFrame(int flags, zmbv_format_t _format, char * pal)
|
||||
bool ZmbvCodec::PrepareCompressFrame(int flags, zmbv_format_t _format, char* pal)
|
||||
{
|
||||
int i;
|
||||
unsigned char *firstByte;
|
||||
unsigned char* firstByte;
|
||||
|
||||
if (_format != format) {
|
||||
if (!SetupBuffers( _format, 16, 16))
|
||||
if (_format != format)
|
||||
{
|
||||
if (!SetupBuffers(_format, 16, 16))
|
||||
return false;
|
||||
flags|=1; //Force a keyframe
|
||||
flags |= 1; //Force a keyframe
|
||||
}
|
||||
/* replace oldframe with new frame */
|
||||
unsigned char *copyFrame = newframe;
|
||||
unsigned char* copyFrame = newframe;
|
||||
newframe = oldframe;
|
||||
oldframe = copyFrame;
|
||||
|
||||
compressInfo.linesDone = 0;
|
||||
compressInfo.writeSize = _bufSize;
|
||||
compressInfo.writeDone = 1;
|
||||
compressInfo.writeBuf = (unsigned char *)_buf;
|
||||
compressInfo.writeBuf = (unsigned char*)_buf;
|
||||
/* Set a pointer to the first byte which will contain info about this frame */
|
||||
firstByte = compressInfo.writeBuf;
|
||||
*firstByte = 0;
|
||||
//Reset the work buffer
|
||||
workUsed = 0;workPos = 0;
|
||||
if (flags & 1) {
|
||||
workUsed = 0;
|
||||
workPos = 0;
|
||||
if (flags & 1)
|
||||
{
|
||||
/* Make a keyframe */
|
||||
*firstByte |= Mask_KeyFrame;
|
||||
KeyframeHeader * header = (KeyframeHeader *)(compressInfo.writeBuf + compressInfo.writeDone);
|
||||
KeyframeHeader* header = (KeyframeHeader*)(compressInfo.writeBuf + compressInfo.writeDone);
|
||||
header->high_version = DBZV_VERSION_HIGH;
|
||||
header->low_version = DBZV_VERSION_LOW;
|
||||
header->compression = COMPRESSION_ZLIB;
|
||||
|
@ -268,82 +309,95 @@ bool ZmbvCodec::PrepareCompressFrame(int flags, zmbv_format_t _format, char * pa
|
|||
header->blockheight = 16;
|
||||
compressInfo.writeDone += sizeof(KeyframeHeader);
|
||||
/* Copy the new frame directly over */
|
||||
if (palsize) {
|
||||
if (palsize)
|
||||
{
|
||||
if (pal)
|
||||
memcpy(&palette, pal, sizeof(palette));
|
||||
else
|
||||
memset(&palette,0, sizeof(palette));
|
||||
memset(&palette, 0, sizeof(palette));
|
||||
/* keyframes get the full palette */
|
||||
for (i=0;i<palsize;i++) {
|
||||
work[workUsed++] = palette[i*4+0];
|
||||
work[workUsed++] = palette[i*4+1];
|
||||
work[workUsed++] = palette[i*4+2];
|
||||
for (i = 0; i < palsize; i++)
|
||||
{
|
||||
work[workUsed++] = palette[i * 4 + 0];
|
||||
work[workUsed++] = palette[i * 4 + 1];
|
||||
work[workUsed++] = palette[i * 4 + 2];
|
||||
}
|
||||
}
|
||||
/* Restart deflate */
|
||||
deflateReset(&zstream);
|
||||
} else {
|
||||
if (palsize && pal && memcmp(pal, palette, palsize * 4)) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (palsize && pal && memcmp(pal, palette, palsize * 4))
|
||||
{
|
||||
*firstByte |= Mask_DeltaPalette;
|
||||
for(i=0;i<palsize;i++) {
|
||||
work[workUsed++]=palette[i*4+0] ^ pal[i*4+0];
|
||||
work[workUsed++]=palette[i*4+1] ^ pal[i*4+1];
|
||||
work[workUsed++]=palette[i*4+2] ^ pal[i*4+2];
|
||||
for (i = 0; i < palsize; i++)
|
||||
{
|
||||
work[workUsed++] = palette[i * 4 + 0] ^ pal[i * 4 + 0];
|
||||
work[workUsed++] = palette[i * 4 + 1] ^ pal[i * 4 + 1];
|
||||
work[workUsed++] = palette[i * 4 + 2] ^ pal[i * 4 + 2];
|
||||
}
|
||||
memcpy(&palette,pal, palsize * 4);
|
||||
memcpy(&palette, pal, palsize * 4);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZmbvCodec::CompressLines(int lineCount, void *lineData[])
|
||||
void ZmbvCodec::CompressLines(int lineCount, void* lineData[])
|
||||
{
|
||||
int linePitch = pitch * pixelsize;
|
||||
int lineWidth = width * pixelsize;
|
||||
int i = 0;
|
||||
unsigned char *destStart = newframe + pixelsize*(MAX_VECTOR+(compressInfo.linesDone+MAX_VECTOR)*pitch);
|
||||
while ( i < lineCount && (compressInfo.linesDone < height)) {
|
||||
memcpy(destStart, lineData[i], lineWidth );
|
||||
unsigned char* destStart = newframe + pixelsize * (MAX_VECTOR + (compressInfo.linesDone + MAX_VECTOR) * pitch);
|
||||
while (i < lineCount && (compressInfo.linesDone < height))
|
||||
{
|
||||
memcpy(destStart, lineData[i], lineWidth);
|
||||
destStart += linePitch;
|
||||
i++; compressInfo.linesDone++;
|
||||
i++;
|
||||
compressInfo.linesDone++;
|
||||
}
|
||||
}
|
||||
|
||||
int ZmbvCodec::FinishCompressFrame(uint8_t** compressedData)
|
||||
{
|
||||
unsigned char firstByte = *compressInfo.writeBuf;
|
||||
if (firstByte & Mask_KeyFrame) {
|
||||
if (firstByte & Mask_KeyFrame)
|
||||
{
|
||||
int i;
|
||||
/* Add the full frame data */
|
||||
unsigned char * readFrame = newframe + pixelsize*(MAX_VECTOR+MAX_VECTOR*pitch);
|
||||
for (i=0;i<height;i++) {
|
||||
memcpy(&work[workUsed], readFrame, width*pixelsize);
|
||||
readFrame += pitch*pixelsize;
|
||||
workUsed += width*pixelsize;
|
||||
unsigned char* readFrame = newframe + pixelsize * (MAX_VECTOR + MAX_VECTOR * pitch);
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
memcpy(&work[workUsed], readFrame, width * pixelsize);
|
||||
readFrame += pitch * pixelsize;
|
||||
workUsed += width * pixelsize;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Add the delta frame data */
|
||||
switch (format) {
|
||||
case ZMBV_FORMAT_8BPP:
|
||||
AddXorFrame<int8_t>();
|
||||
break;
|
||||
case ZMBV_FORMAT_15BPP:
|
||||
case ZMBV_FORMAT_16BPP:
|
||||
AddXorFrame<int16_t>();
|
||||
break;
|
||||
switch (format)
|
||||
{
|
||||
case ZMBV_FORMAT_8BPP:
|
||||
AddXorFrame<int8_t>();
|
||||
break;
|
||||
case ZMBV_FORMAT_15BPP:
|
||||
case ZMBV_FORMAT_16BPP:
|
||||
AddXorFrame<int16_t>();
|
||||
break;
|
||||
|
||||
default:
|
||||
case ZMBV_FORMAT_32BPP:
|
||||
AddXorFrame<int32_t>();
|
||||
break;
|
||||
default:
|
||||
case ZMBV_FORMAT_32BPP:
|
||||
AddXorFrame<int32_t>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Create the actual frame with compression */
|
||||
zstream.next_in = (Bytef *)work;
|
||||
zstream.next_in = (Bytef*)work;
|
||||
zstream.avail_in = workUsed;
|
||||
zstream.total_in = 0;
|
||||
|
||||
zstream.next_out = (Bytef *)(compressInfo.writeBuf + compressInfo.writeDone);
|
||||
zstream.next_out = (Bytef*)(compressInfo.writeBuf + compressInfo.writeDone);
|
||||
zstream.avail_out = compressInfo.writeSize - compressInfo.writeDone;
|
||||
zstream.total_out = 0;
|
||||
|
||||
|
@ -375,17 +429,19 @@ ZmbvCodec::ZmbvCodec()
|
|||
buf1 = nullptr;
|
||||
buf2 = nullptr;
|
||||
work = nullptr;
|
||||
memset( &zstream, 0, sizeof(zstream));
|
||||
memset(&zstream, 0, sizeof(zstream));
|
||||
}
|
||||
|
||||
int ZmbvCodec::CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData)
|
||||
int ZmbvCodec::CompressFrame(bool isKeyFrame, uint8_t* frameData, uint8_t** compressedData)
|
||||
{
|
||||
if(!PrepareCompressFrame(isKeyFrame ? 1 : 0, ZMBV_FORMAT_32BPP, nullptr)) {
|
||||
if (!PrepareCompressFrame(isKeyFrame ? 1 : 0, ZMBV_FORMAT_32BPP, nullptr))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(int i = 0; i < height; i++) {
|
||||
void * rowPointer = frameData + i*width*4;
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
void* rowPointer = frameData + i * width * 4;
|
||||
CompressLines(1, &rowPointer);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,58 +30,65 @@
|
|||
#define INLINE inline
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
ZMBV_FORMAT_NONE = 0x00,
|
||||
ZMBV_FORMAT_1BPP = 0x01,
|
||||
ZMBV_FORMAT_2BPP = 0x02,
|
||||
ZMBV_FORMAT_4BPP = 0x03,
|
||||
ZMBV_FORMAT_8BPP = 0x04,
|
||||
ZMBV_FORMAT_15BPP = 0x05,
|
||||
ZMBV_FORMAT_16BPP = 0x06,
|
||||
ZMBV_FORMAT_24BPP = 0x07,
|
||||
ZMBV_FORMAT_32BPP = 0x08
|
||||
typedef enum
|
||||
{
|
||||
ZMBV_FORMAT_NONE = 0x00,
|
||||
ZMBV_FORMAT_1BPP = 0x01,
|
||||
ZMBV_FORMAT_2BPP = 0x02,
|
||||
ZMBV_FORMAT_4BPP = 0x03,
|
||||
ZMBV_FORMAT_8BPP = 0x04,
|
||||
ZMBV_FORMAT_15BPP = 0x05,
|
||||
ZMBV_FORMAT_16BPP = 0x06,
|
||||
ZMBV_FORMAT_24BPP = 0x07,
|
||||
ZMBV_FORMAT_32BPP = 0x08
|
||||
} zmbv_format_t;
|
||||
|
||||
class ZmbvCodec : public BaseCodec
|
||||
{
|
||||
private:
|
||||
struct FrameBlock {
|
||||
struct FrameBlock
|
||||
{
|
||||
int start = 0;
|
||||
int dx = 0,dy = 0;
|
||||
int dx = 0, dy = 0;
|
||||
};
|
||||
struct CodecVector {
|
||||
int x = 0,y = 0;
|
||||
|
||||
struct CodecVector
|
||||
{
|
||||
int x = 0, y = 0;
|
||||
int slot = 0;
|
||||
};
|
||||
struct KeyframeHeader {
|
||||
|
||||
struct KeyframeHeader
|
||||
{
|
||||
unsigned char high_version = 0;
|
||||
unsigned char low_version = 0;
|
||||
unsigned char compression = 0;
|
||||
unsigned char format = 0;
|
||||
unsigned char blockwidth = 0,blockheight = 0;
|
||||
unsigned char blockwidth = 0, blockheight = 0;
|
||||
};
|
||||
|
||||
struct {
|
||||
int linesDone = 0;
|
||||
int writeSize = 0;
|
||||
int writeDone = 0;
|
||||
unsigned char *writeBuf = nullptr;
|
||||
struct
|
||||
{
|
||||
int linesDone = 0;
|
||||
int writeSize = 0;
|
||||
int writeDone = 0;
|
||||
unsigned char* writeBuf = nullptr;
|
||||
} compressInfo;
|
||||
|
||||
CodecVector VectorTable[512] = {};
|
||||
int VectorCount = 0;
|
||||
|
||||
unsigned char *oldframe=nullptr, *newframe=nullptr;
|
||||
unsigned char *buf1=nullptr, *buf2=nullptr, *work=nullptr;
|
||||
unsigned char *oldframe = nullptr, *newframe = nullptr;
|
||||
unsigned char *buf1 = nullptr, *buf2 = nullptr, *work = nullptr;
|
||||
int bufsize = 0;
|
||||
|
||||
int blockcount = 0;
|
||||
FrameBlock * blocks = nullptr;
|
||||
FrameBlock* blocks = nullptr;
|
||||
|
||||
int workUsed = 0, workPos = 0;
|
||||
|
||||
int palsize = 0;
|
||||
char palette[256*4] = {};
|
||||
char palette[256 * 4] = {};
|
||||
int height = 0, width = 0, pitch = 0;
|
||||
zmbv_format_t format = zmbv_format_t::ZMBV_FORMAT_NONE;
|
||||
int pixelsize = 0;
|
||||
|
@ -96,20 +103,24 @@ private:
|
|||
void CreateVectorTable(void);
|
||||
bool SetupBuffers(zmbv_format_t format, int blockwidth, int blockheight);
|
||||
|
||||
template<class P> void AddXorFrame(void);
|
||||
template<class P> INLINE int PossibleBlock(int vx,int vy,FrameBlock * block);
|
||||
template<class P> INLINE int CompareBlock(int vx,int vy,FrameBlock * block);
|
||||
template<class P> INLINE void AddXorBlock(int vx,int vy,FrameBlock * block);
|
||||
template <class P>
|
||||
void AddXorFrame(void);
|
||||
template <class P>
|
||||
INLINE int PossibleBlock(int vx, int vy, FrameBlock* block);
|
||||
template <class P>
|
||||
INLINE int CompareBlock(int vx, int vy, FrameBlock* block);
|
||||
template <class P>
|
||||
INLINE void AddXorBlock(int vx, int vy, FrameBlock* block);
|
||||
|
||||
int NeededSize(int _width, int _height, zmbv_format_t _format);
|
||||
|
||||
void CompressLines(int lineCount, void *lineData[]);
|
||||
bool PrepareCompressFrame(int flags, zmbv_format_t _format, char * pal);
|
||||
void CompressLines(int lineCount, void* lineData[]);
|
||||
bool PrepareCompressFrame(int flags, zmbv_format_t _format, char* pal);
|
||||
int FinishCompressFrame(uint8_t** compressedData);
|
||||
|
||||
public:
|
||||
ZmbvCodec();
|
||||
bool SetupCompress(int _width, int _height, uint32_t compressionLevel) override;
|
||||
int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) override;
|
||||
int CompressFrame(bool isKeyFrame, uint8_t* frameData, uint8_t** compressedData) override;
|
||||
const char* GetFourCC() override;
|
||||
};
|
||||
|
|
|
@ -30,8 +30,9 @@ Avoids constants that don't fit in 32 bits. */
|
|||
enum { pre_shift = 32 };
|
||||
|
||||
#elif defined(ULLONG_MAX)
|
||||
typedef unsigned long long fixed_t;
|
||||
enum { pre_shift = 32 };
|
||||
typedef unsigned long long fixed_t;
|
||||
|
||||
enum { pre_shift = 32 };
|
||||
|
||||
#else
|
||||
typedef unsigned fixed_t;
|
||||
|
@ -41,17 +42,23 @@ Avoids constants that don't fit in 32 bits. */
|
|||
|
||||
enum { time_bits = pre_shift + 20 };
|
||||
|
||||
static fixed_t const time_unit = (fixed_t) 1 << time_bits;
|
||||
static fixed_t const time_unit = (fixed_t)1 << time_bits;
|
||||
|
||||
enum { bass_shift = 9 }; /* affects high-pass filter breakpoint frequency */
|
||||
enum { bass_shift = 9 }; /* affects high-pass filter breakpoint frequency */
|
||||
enum { end_frame_extra = 2 }; /* allows deltas slightly after frame length */
|
||||
|
||||
enum { half_width = 8 };
|
||||
enum { buf_extra = half_width*2 + end_frame_extra };
|
||||
enum { phase_bits = 5 };
|
||||
enum { half_width = 8 };
|
||||
|
||||
enum { buf_extra = half_width * 2 + end_frame_extra };
|
||||
|
||||
enum { phase_bits = 5 };
|
||||
|
||||
enum { phase_count = 1 << phase_bits };
|
||||
enum { delta_bits = 15 };
|
||||
enum { delta_unit = 1 << delta_bits };
|
||||
|
||||
enum { delta_bits = 15 };
|
||||
|
||||
enum { delta_unit = 1 << delta_bits };
|
||||
|
||||
enum { frac_bits = time_bits - pre_shift };
|
||||
|
||||
/* We could eliminate avail and encode whole samples in offset, but that would
|
||||
|
@ -80,6 +87,7 @@ typedef int buf_t;
|
|||
((n) >> (shift))
|
||||
|
||||
enum { max_sample = +32767 };
|
||||
|
||||
enum { min_sample = -32768 };
|
||||
|
||||
#define CLAMP( n ) \
|
||||
|
@ -88,72 +96,72 @@ enum { min_sample = -32768 };
|
|||
n = ARITH_SHIFT( n, 16 ) ^ max_sample;\
|
||||
}
|
||||
|
||||
static void check_assumptions( void )
|
||||
static void check_assumptions(void)
|
||||
{
|
||||
int n;
|
||||
|
||||
#if INT_MAX < 0x7FFFFFFF || UINT_MAX < 0xFFFFFFFF
|
||||
#if INT_MAX < 0x7FFFFFFF || UINT_MAX < 0xFFFFFFFF
|
||||
#error "int must be at least 32 bits"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
assert( (-3 >> 1) == -2 ); /* right shift must preserve sign */
|
||||
assert((-3 >> 1) == -2); /* right shift must preserve sign */
|
||||
|
||||
n = max_sample * 2;
|
||||
CLAMP( n );
|
||||
assert( n == max_sample );
|
||||
CLAMP(n);
|
||||
assert(n == max_sample);
|
||||
|
||||
n = min_sample * 2;
|
||||
CLAMP( n );
|
||||
assert( n == min_sample );
|
||||
CLAMP(n);
|
||||
assert(n == min_sample);
|
||||
|
||||
assert( blip_max_ratio <= time_unit );
|
||||
assert( blip_max_frame <= (fixed_t) -1 >> time_bits );
|
||||
assert(blip_max_ratio <= time_unit);
|
||||
assert(blip_max_frame <= (fixed_t) -1 >> time_bits);
|
||||
}
|
||||
|
||||
blip_t* blip_new( int size )
|
||||
blip_t* blip_new(int size)
|
||||
{
|
||||
blip_t* m;
|
||||
assert( size >= 0 );
|
||||
assert(size >= 0);
|
||||
|
||||
m = (blip_t*) malloc( sizeof *m + (size + buf_extra) * sizeof (buf_t) );
|
||||
if ( m )
|
||||
m = (blip_t*)malloc(sizeof *m + (size + buf_extra) * sizeof(buf_t));
|
||||
if (m)
|
||||
{
|
||||
m->factor = time_unit / blip_max_ratio;
|
||||
m->size = size;
|
||||
blip_clear( m );
|
||||
m->size = size;
|
||||
blip_clear(m);
|
||||
check_assumptions();
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
void blip_delete( blip_t* m )
|
||||
void blip_delete(blip_t* m)
|
||||
{
|
||||
if ( m != NULL )
|
||||
if (m != NULL)
|
||||
{
|
||||
/* Clear fields in case user tries to use after freeing */
|
||||
memset( m, 0, sizeof *m );
|
||||
free( m );
|
||||
memset(m, 0, sizeof *m);
|
||||
free(m);
|
||||
}
|
||||
}
|
||||
|
||||
void blip_set_rates( blip_t* m, double clock_rate, double sample_rate )
|
||||
void blip_set_rates(blip_t* m, double clock_rate, double sample_rate)
|
||||
{
|
||||
double factor = time_unit * sample_rate / clock_rate;
|
||||
m->factor = (fixed_t) factor;
|
||||
m->factor = (fixed_t)factor;
|
||||
|
||||
/* Fails if clock_rate exceeds maximum, relative to sample_rate */
|
||||
assert( 0 <= factor - m->factor && factor - m->factor < 1 );
|
||||
assert(0 <= factor - m->factor && factor - m->factor < 1);
|
||||
|
||||
/* Avoid requiring math.h. Equivalent to
|
||||
m->factor = (int) ceil( factor ) */
|
||||
if ( m->factor < factor )
|
||||
if (m->factor < factor)
|
||||
m->factor++;
|
||||
|
||||
/* At this point, factor is most likely rounded up, but could still
|
||||
have been rounded down in the floating-point calculation. */
|
||||
}
|
||||
|
||||
void blip_clear( blip_t* m )
|
||||
void blip_clear(blip_t* m)
|
||||
{
|
||||
/* We could set offset to 0, factor/2, or factor-1. 0 is suitable if
|
||||
factor is rounded up. factor-1 is suitable if factor is rounded down.
|
||||
|
@ -161,72 +169,72 @@ void blip_clear( blip_t* m )
|
|||
with the slight loss of showing an error in half the time. Since for
|
||||
a 64-bit factor this is years, the halving isn't a problem. */
|
||||
|
||||
m->offset = m->factor / 2;
|
||||
m->avail = 0;
|
||||
m->offset = m->factor / 2;
|
||||
m->avail = 0;
|
||||
m->integrator = 0;
|
||||
memset( SAMPLES( m ), 0, (m->size + buf_extra) * sizeof (buf_t) );
|
||||
memset(SAMPLES(m), 0, (m->size + buf_extra) * sizeof(buf_t));
|
||||
}
|
||||
|
||||
int blip_clocks_needed( const blip_t* m, int samples )
|
||||
int blip_clocks_needed(const blip_t* m, int samples)
|
||||
{
|
||||
fixed_t needed;
|
||||
|
||||
/* Fails if buffer can't hold that many more samples */
|
||||
assert( samples >= 0 && m->avail + samples <= m->size );
|
||||
assert(samples >= 0 && m->avail + samples <= m->size);
|
||||
|
||||
needed = (fixed_t) samples * time_unit;
|
||||
if ( needed < m->offset )
|
||||
needed = (fixed_t)samples * time_unit;
|
||||
if (needed < m->offset)
|
||||
return 0;
|
||||
|
||||
return (int)((needed - m->offset + m->factor - 1) / m->factor);
|
||||
}
|
||||
|
||||
void blip_end_frame( blip_t* m, unsigned t )
|
||||
void blip_end_frame(blip_t* m, unsigned t)
|
||||
{
|
||||
fixed_t off = t * m->factor + m->offset;
|
||||
m->avail += off >> time_bits;
|
||||
m->offset = off & (time_unit - 1);
|
||||
|
||||
/* Fails if buffer size was exceeded */
|
||||
assert( m->avail <= m->size );
|
||||
assert(m->avail <= m->size);
|
||||
}
|
||||
|
||||
int blip_samples_avail( const blip_t* m )
|
||||
int blip_samples_avail(const blip_t* m)
|
||||
{
|
||||
return m->avail;
|
||||
}
|
||||
|
||||
static void remove_samples( blip_t* m, int count )
|
||||
static void remove_samples(blip_t* m, int count)
|
||||
{
|
||||
buf_t* buf = SAMPLES( m );
|
||||
buf_t* buf = SAMPLES(m);
|
||||
int remain = m->avail + buf_extra - count;
|
||||
m->avail -= count;
|
||||
|
||||
memmove( &buf [0], &buf [count], remain * sizeof buf [0] );
|
||||
memset( &buf [remain], 0, count * sizeof buf [0] );
|
||||
memmove(&buf[0], &buf[count], remain * sizeof buf[0]);
|
||||
memset(&buf[remain], 0, count * sizeof buf[0]);
|
||||
}
|
||||
|
||||
int blip_read_samples( blip_t* m, short out [], int count, int stereo )
|
||||
int blip_read_samples(blip_t* m, short out[], int count, int stereo)
|
||||
{
|
||||
assert( count >= 0 );
|
||||
assert(count >= 0);
|
||||
|
||||
if ( count > m->avail )
|
||||
if (count > m->avail)
|
||||
count = m->avail;
|
||||
|
||||
if ( count )
|
||||
if (count)
|
||||
{
|
||||
int const step = stereo ? 2 : 1;
|
||||
buf_t const* in = SAMPLES( m );
|
||||
buf_t const* in = SAMPLES(m);
|
||||
buf_t const* end = in + count;
|
||||
int sum = m->integrator;
|
||||
do
|
||||
{
|
||||
/* Eliminate fraction */
|
||||
int s = ARITH_SHIFT( sum, delta_bits );
|
||||
int s = ARITH_SHIFT(sum, delta_bits);
|
||||
|
||||
sum += *in++;
|
||||
|
||||
CLAMP( s );
|
||||
CLAMP(s);
|
||||
|
||||
*out = s;
|
||||
out += step;
|
||||
|
@ -234,10 +242,10 @@ int blip_read_samples( blip_t* m, short out [], int count, int stereo )
|
|||
/* High-pass filter */
|
||||
sum -= s << (delta_bits - bass_shift);
|
||||
}
|
||||
while ( in != end );
|
||||
while (in != end);
|
||||
m->integrator = sum;
|
||||
|
||||
remove_samples( m, count );
|
||||
remove_samples(m, count);
|
||||
}
|
||||
|
||||
return count;
|
||||
|
@ -250,41 +258,41 @@ int blip_read_samples( blip_t* m, short out [], int count, int stereo )
|
|||
*/
|
||||
|
||||
/* Sinc_Generator( 0.9, 0.55, 4.5 ) */
|
||||
static short const bl_step [phase_count + 1] [half_width] =
|
||||
static short const bl_step[phase_count + 1][half_width] =
|
||||
{
|
||||
{ 43, -115, 350, -488, 1136, -914, 5861,21022},
|
||||
{ 44, -118, 348, -473, 1076, -799, 5274,21001},
|
||||
{ 45, -121, 344, -454, 1011, -677, 4706,20936},
|
||||
{ 46, -122, 336, -431, 942, -549, 4156,20829},
|
||||
{ 47, -123, 327, -404, 868, -418, 3629,20679},
|
||||
{ 47, -122, 316, -375, 792, -285, 3124,20488},
|
||||
{ 47, -120, 303, -344, 714, -151, 2644,20256},
|
||||
{ 46, -117, 289, -310, 634, -17, 2188,19985},
|
||||
{ 46, -114, 273, -275, 553, 117, 1758,19675},
|
||||
{ 44, -108, 255, -237, 471, 247, 1356,19327},
|
||||
{ 43, -103, 237, -199, 390, 373, 981,18944},
|
||||
{ 42, -98, 218, -160, 310, 495, 633,18527},
|
||||
{ 40, -91, 198, -121, 231, 611, 314,18078},
|
||||
{ 38, -84, 178, -81, 153, 722, 22,17599},
|
||||
{ 36, -76, 157, -43, 80, 824, -241,17092},
|
||||
{ 34, -68, 135, -3, 8, 919, -476,16558},
|
||||
{ 32, -61, 115, 34, -60, 1006, -683,16001},
|
||||
{ 29, -52, 94, 70, -123, 1083, -862,15422},
|
||||
{ 27, -44, 73, 106, -184, 1152,-1015,14824},
|
||||
{ 25, -36, 53, 139, -239, 1211,-1142,14210},
|
||||
{ 22, -27, 34, 170, -290, 1261,-1244,13582},
|
||||
{ 20, -20, 16, 199, -335, 1301,-1322,12942},
|
||||
{ 18, -12, -3, 226, -375, 1331,-1376,12293},
|
||||
{ 15, -4, -19, 250, -410, 1351,-1408,11638},
|
||||
{ 13, 3, -35, 272, -439, 1361,-1419,10979},
|
||||
{ 11, 9, -49, 292, -464, 1362,-1410,10319},
|
||||
{ 9, 16, -63, 309, -483, 1354,-1383, 9660},
|
||||
{ 7, 22, -75, 322, -496, 1337,-1339, 9005},
|
||||
{ 6, 26, -85, 333, -504, 1312,-1280, 8355},
|
||||
{ 4, 31, -94, 341, -507, 1278,-1205, 7713},
|
||||
{ 3, 35, -102, 347, -506, 1238,-1119, 7082},
|
||||
{ 1, 40, -110, 350, -499, 1190,-1021, 6464},
|
||||
{ 0, 43, -115, 350, -488, 1136, -914, 5861}
|
||||
{43, -115, 350, -488, 1136, -914, 5861, 21022},
|
||||
{44, -118, 348, -473, 1076, -799, 5274, 21001},
|
||||
{45, -121, 344, -454, 1011, -677, 4706, 20936},
|
||||
{46, -122, 336, -431, 942, -549, 4156, 20829},
|
||||
{47, -123, 327, -404, 868, -418, 3629, 20679},
|
||||
{47, -122, 316, -375, 792, -285, 3124, 20488},
|
||||
{47, -120, 303, -344, 714, -151, 2644, 20256},
|
||||
{46, -117, 289, -310, 634, -17, 2188, 19985},
|
||||
{46, -114, 273, -275, 553, 117, 1758, 19675},
|
||||
{44, -108, 255, -237, 471, 247, 1356, 19327},
|
||||
{43, -103, 237, -199, 390, 373, 981, 18944},
|
||||
{42, -98, 218, -160, 310, 495, 633, 18527},
|
||||
{40, -91, 198, -121, 231, 611, 314, 18078},
|
||||
{38, -84, 178, -81, 153, 722, 22, 17599},
|
||||
{36, -76, 157, -43, 80, 824, -241, 17092},
|
||||
{34, -68, 135, -3, 8, 919, -476, 16558},
|
||||
{32, -61, 115, 34, -60, 1006, -683, 16001},
|
||||
{29, -52, 94, 70, -123, 1083, -862, 15422},
|
||||
{27, -44, 73, 106, -184, 1152, -1015, 14824},
|
||||
{25, -36, 53, 139, -239, 1211, -1142, 14210},
|
||||
{22, -27, 34, 170, -290, 1261, -1244, 13582},
|
||||
{20, -20, 16, 199, -335, 1301, -1322, 12942},
|
||||
{18, -12, -3, 226, -375, 1331, -1376, 12293},
|
||||
{15, -4, -19, 250, -410, 1351, -1408, 11638},
|
||||
{13, 3, -35, 272, -439, 1361, -1419, 10979},
|
||||
{11, 9, -49, 292, -464, 1362, -1410, 10319},
|
||||
{9, 16, -63, 309, -483, 1354, -1383, 9660},
|
||||
{7, 22, -75, 322, -496, 1337, -1339, 9005},
|
||||
{6, 26, -85, 333, -504, 1312, -1280, 8355},
|
||||
{4, 31, -94, 341, -507, 1278, -1205, 7713},
|
||||
{3, 35, -102, 347, -506, 1238, -1119, 7082},
|
||||
{1, 40, -110, 350, -499, 1190, -1021, 6464},
|
||||
{0, 43, -115, 350, -488, 1136, -914, 5861}
|
||||
};
|
||||
|
||||
/* Shifting by pre_shift allows calculation using unsigned int rather than
|
||||
|
@ -292,54 +300,54 @@ possibly-wider fixed_t. On 32-bit platforms, this is likely more efficient.
|
|||
And by having pre_shift 32, a 32-bit platform can easily do the shift by
|
||||
simply ignoring the low half. */
|
||||
|
||||
void blip_add_delta( blip_t* m, unsigned time, int delta )
|
||||
void blip_add_delta(blip_t* m, unsigned time, int delta)
|
||||
{
|
||||
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
|
||||
buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits);
|
||||
unsigned fixed = (unsigned)((time * m->factor + m->offset) >> pre_shift);
|
||||
buf_t* out = SAMPLES(m) + m->avail + (fixed >> frac_bits);
|
||||
|
||||
int const phase_shift = frac_bits - phase_bits;
|
||||
int phase = fixed >> phase_shift & (phase_count - 1);
|
||||
short const* in = bl_step [phase];
|
||||
short const* rev = bl_step [phase_count - phase];
|
||||
short const* in = bl_step[phase];
|
||||
short const* rev = bl_step[phase_count - phase];
|
||||
|
||||
int interp = fixed >> (phase_shift - delta_bits) & (delta_unit - 1);
|
||||
int delta2 = (delta * interp) >> delta_bits;
|
||||
delta -= delta2;
|
||||
|
||||
/* Fails if buffer size was exceeded */
|
||||
assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
|
||||
assert(out <= &SAMPLES( m ) [m->size + end_frame_extra]);
|
||||
|
||||
out [0] += in[0]*delta + in[half_width+0]*delta2;
|
||||
out [1] += in[1]*delta + in[half_width+1]*delta2;
|
||||
out [2] += in[2]*delta + in[half_width+2]*delta2;
|
||||
out [3] += in[3]*delta + in[half_width+3]*delta2;
|
||||
out [4] += in[4]*delta + in[half_width+4]*delta2;
|
||||
out [5] += in[5]*delta + in[half_width+5]*delta2;
|
||||
out [6] += in[6]*delta + in[half_width+6]*delta2;
|
||||
out [7] += in[7]*delta + in[half_width+7]*delta2;
|
||||
out[0] += in[0] * delta + in[half_width + 0] * delta2;
|
||||
out[1] += in[1] * delta + in[half_width + 1] * delta2;
|
||||
out[2] += in[2] * delta + in[half_width + 2] * delta2;
|
||||
out[3] += in[3] * delta + in[half_width + 3] * delta2;
|
||||
out[4] += in[4] * delta + in[half_width + 4] * delta2;
|
||||
out[5] += in[5] * delta + in[half_width + 5] * delta2;
|
||||
out[6] += in[6] * delta + in[half_width + 6] * delta2;
|
||||
out[7] += in[7] * delta + in[half_width + 7] * delta2;
|
||||
|
||||
in = rev;
|
||||
out [ 8] += in[7]*delta + in[7-half_width]*delta2;
|
||||
out [ 9] += in[6]*delta + in[6-half_width]*delta2;
|
||||
out [10] += in[5]*delta + in[5-half_width]*delta2;
|
||||
out [11] += in[4]*delta + in[4-half_width]*delta2;
|
||||
out [12] += in[3]*delta + in[3-half_width]*delta2;
|
||||
out [13] += in[2]*delta + in[2-half_width]*delta2;
|
||||
out [14] += in[1]*delta + in[1-half_width]*delta2;
|
||||
out [15] += in[0]*delta + in[0-half_width]*delta2;
|
||||
out[8] += in[7] * delta + in[7 - half_width] * delta2;
|
||||
out[9] += in[6] * delta + in[6 - half_width] * delta2;
|
||||
out[10] += in[5] * delta + in[5 - half_width] * delta2;
|
||||
out[11] += in[4] * delta + in[4 - half_width] * delta2;
|
||||
out[12] += in[3] * delta + in[3 - half_width] * delta2;
|
||||
out[13] += in[2] * delta + in[2 - half_width] * delta2;
|
||||
out[14] += in[1] * delta + in[1 - half_width] * delta2;
|
||||
out[15] += in[0] * delta + in[0 - half_width] * delta2;
|
||||
}
|
||||
|
||||
void blip_add_delta_fast( blip_t* m, unsigned time, int delta )
|
||||
void blip_add_delta_fast(blip_t* m, unsigned time, int delta)
|
||||
{
|
||||
unsigned fixed = (unsigned) ((time * m->factor + m->offset) >> pre_shift);
|
||||
buf_t* out = SAMPLES( m ) + m->avail + (fixed >> frac_bits);
|
||||
unsigned fixed = (unsigned)((time * m->factor + m->offset) >> pre_shift);
|
||||
buf_t* out = SAMPLES(m) + m->avail + (fixed >> frac_bits);
|
||||
|
||||
int interp = fixed >> (frac_bits - delta_bits) & (delta_unit - 1);
|
||||
int delta2 = delta * interp;
|
||||
|
||||
/* Fails if buffer size was exceeded */
|
||||
assert( out <= &SAMPLES( m ) [m->size + end_frame_extra] );
|
||||
assert(out <= &SAMPLES( m ) [m->size + end_frame_extra]);
|
||||
|
||||
out [7] += delta * delta_unit - delta2;
|
||||
out [8] += delta2;
|
||||
out[7] += delta * delta_unit - delta2;
|
||||
out[8] += delta2;
|
||||
}
|
||||
|
|
|
@ -9,13 +9,13 @@ Sample buffer that resamples from input clock rate to output sample rate */
|
|||
#define BLIP_BUF_H
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define EXPORT __declspec(dllexport)
|
||||
#define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** First parameter of most functions is blip_t*, or const blip_t* if nothing
|
||||
|
@ -25,57 +25,63 @@ typedef struct blip_t blip_t;
|
|||
/** Creates new buffer that can hold at most sample_count samples. Sets rates
|
||||
so that there are blip_max_ratio clocks per sample. Returns pointer to new
|
||||
buffer, or NULL if insufficient memory. */
|
||||
EXPORT blip_t* blip_new( int sample_count );
|
||||
EXPORT blip_t* blip_new(int sample_count);
|
||||
|
||||
/** Sets approximate input clock rate and output sample rate. For every
|
||||
clock_rate input clocks, approximately sample_rate samples are generated. */
|
||||
EXPORT void blip_set_rates( blip_t*, double clock_rate, double sample_rate );
|
||||
EXPORT void blip_set_rates(blip_t*, double clock_rate, double sample_rate);
|
||||
|
||||
enum { /** Maximum clock_rate/sample_rate ratio. For a given sample_rate,
|
||||
clock_rate must not be greater than sample_rate*blip_max_ratio. */
|
||||
blip_max_ratio = 1 << 20 };
|
||||
enum
|
||||
{
|
||||
/** Maximum clock_rate/sample_rate ratio. For a given sample_rate,
|
||||
clock_rate must not be greater than sample_rate*blip_max_ratio. */
|
||||
blip_max_ratio = 1 << 20
|
||||
};
|
||||
|
||||
/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */
|
||||
EXPORT void blip_clear( blip_t* );
|
||||
EXPORT void blip_clear(blip_t*);
|
||||
|
||||
/** Adds positive/negative delta into buffer at specified clock time. */
|
||||
EXPORT void blip_add_delta( blip_t*, unsigned int clock_time, int delta );
|
||||
EXPORT void blip_add_delta(blip_t*, unsigned int clock_time, int delta);
|
||||
|
||||
/** Same as blip_add_delta(), but uses faster, lower-quality synthesis. */
|
||||
void blip_add_delta_fast( blip_t*, unsigned int clock_time, int delta );
|
||||
void blip_add_delta_fast(blip_t*, unsigned int clock_time, int delta);
|
||||
|
||||
/** Length of time frame, in clocks, needed to make sample_count additional
|
||||
samples available. */
|
||||
int blip_clocks_needed( const blip_t*, int sample_count );
|
||||
int blip_clocks_needed(const blip_t*, int sample_count);
|
||||
|
||||
enum { /** Maximum number of samples that can be generated from one time frame. */
|
||||
blip_max_frame = 4000 };
|
||||
enum
|
||||
{
|
||||
/** Maximum number of samples that can be generated from one time frame. */
|
||||
blip_max_frame = 4000
|
||||
};
|
||||
|
||||
/** Makes input clocks before clock_duration available for reading as output
|
||||
samples. Also begins new time frame at clock_duration, so that clock time 0 in
|
||||
the new time frame specifies the same clock as clock_duration in the old time
|
||||
frame specified. Deltas can have been added slightly past clock_duration (up to
|
||||
however many clocks there are in two output samples). */
|
||||
EXPORT void blip_end_frame( blip_t*, unsigned int clock_duration );
|
||||
EXPORT void blip_end_frame(blip_t*, unsigned int clock_duration);
|
||||
|
||||
/** Number of buffered samples available for reading. */
|
||||
int blip_samples_avail( const blip_t* );
|
||||
int blip_samples_avail(const blip_t*);
|
||||
|
||||
/** Reads and removes at most 'count' samples and writes them to 'out'. If
|
||||
'stereo' is true, writes output to every other element of 'out', allowing easy
|
||||
interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed
|
||||
samples. Returns number of samples actually read. */
|
||||
EXPORT int blip_read_samples( blip_t*, short out [], int count, int stereo );
|
||||
EXPORT int blip_read_samples(blip_t*, short out[], int count, int stereo);
|
||||
|
||||
/** Frees buffer. No effect if NULL is passed. */
|
||||
EXPORT void blip_delete( blip_t* );
|
||||
EXPORT void blip_delete(blip_t*);
|
||||
|
||||
|
||||
/* Deprecated */
|
||||
typedef blip_t blip_buffer_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
1117
Utilities/gif.h
1117
Utilities/gif.h
File diff suppressed because it is too large
Load diff
|
@ -90,26 +90,27 @@
|
|||
* This processes one or more 64-byte data blocks, but does NOT update
|
||||
* the bit counters. There are no alignment requirements.
|
||||
*/
|
||||
static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
|
||||
static const void* body(MD5_CTX* ctx, const void* data, unsigned long size)
|
||||
{
|
||||
const unsigned char *ptr;
|
||||
const unsigned char* ptr;
|
||||
MD5_u32plus a, b, c, d;
|
||||
MD5_u32plus saved_a, saved_b, saved_c, saved_d;
|
||||
|
||||
ptr = (const unsigned char *)data;
|
||||
ptr = (const unsigned char*)data;
|
||||
|
||||
a = ctx->a;
|
||||
b = ctx->b;
|
||||
c = ctx->c;
|
||||
d = ctx->d;
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
saved_a = a;
|
||||
saved_b = b;
|
||||
saved_c = c;
|
||||
saved_d = d;
|
||||
|
||||
/* Round 1 */
|
||||
/* Round 1 */
|
||||
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
|
||||
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
|
||||
STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
|
||||
|
@ -127,7 +128,7 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
|
|||
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
|
||||
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
|
||||
|
||||
/* Round 2 */
|
||||
/* Round 2 */
|
||||
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
|
||||
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
|
||||
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
|
||||
|
@ -145,7 +146,7 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
|
|||
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
|
||||
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
|
||||
|
||||
/* Round 3 */
|
||||
/* Round 3 */
|
||||
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
|
||||
STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
|
||||
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
|
||||
|
@ -163,7 +164,7 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
|
|||
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
|
||||
STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
|
||||
|
||||
/* Round 4 */
|
||||
/* Round 4 */
|
||||
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
|
||||
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
|
||||
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
|
||||
|
@ -187,7 +188,8 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
|
|||
d += saved_d;
|
||||
|
||||
ptr += 64;
|
||||
} while (size -= 64);
|
||||
}
|
||||
while (size -= 64);
|
||||
|
||||
ctx->a = a;
|
||||
ctx->b = b;
|
||||
|
@ -197,7 +199,7 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
|
|||
return ptr;
|
||||
}
|
||||
|
||||
void MD5_Init(MD5_CTX *ctx)
|
||||
void MD5_Init(MD5_CTX* ctx)
|
||||
{
|
||||
ctx->a = 0x67452301;
|
||||
ctx->b = 0xefcdab89;
|
||||
|
@ -208,7 +210,7 @@ void MD5_Init(MD5_CTX *ctx)
|
|||
ctx->hi = 0;
|
||||
}
|
||||
|
||||
void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
|
||||
void MD5_Update(MD5_CTX* ctx, const void* data, unsigned long size)
|
||||
{
|
||||
MD5_u32plus saved_lo;
|
||||
unsigned long used, available;
|
||||
|
@ -220,21 +222,24 @@ void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
|
|||
|
||||
used = saved_lo & 0x3f;
|
||||
|
||||
if (used) {
|
||||
if (used)
|
||||
{
|
||||
available = 64 - used;
|
||||
|
||||
if (size < available) {
|
||||
if (size < available)
|
||||
{
|
||||
memcpy(&ctx->buffer[used], data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&ctx->buffer[used], data, available);
|
||||
data = (const unsigned char *)data + available;
|
||||
data = (const unsigned char*)data + available;
|
||||
size -= available;
|
||||
body(ctx, ctx->buffer, 64);
|
||||
}
|
||||
|
||||
if (size >= 64) {
|
||||
if (size >= 64)
|
||||
{
|
||||
data = body(ctx, data, size & ~(unsigned long)0x3f);
|
||||
size &= 0x3f;
|
||||
}
|
||||
|
@ -242,7 +247,7 @@ void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
|
|||
memcpy(ctx->buffer, data, size);
|
||||
}
|
||||
|
||||
void MD5_Final(unsigned char *result, MD5_CTX *ctx)
|
||||
void MD5_Final(unsigned char* result, MD5_CTX* ctx)
|
||||
{
|
||||
unsigned long used, available;
|
||||
|
||||
|
@ -252,7 +257,8 @@ void MD5_Final(unsigned char *result, MD5_CTX *ctx)
|
|||
|
||||
available = 64 - used;
|
||||
|
||||
if (available < 8) {
|
||||
if (available < 8)
|
||||
{
|
||||
memset(&ctx->buffer[used], 0, available);
|
||||
body(ctx, ctx->buffer, 64);
|
||||
used = 0;
|
||||
|
@ -308,7 +314,8 @@ string GetMd5Sum(void* buffer, size_t size)
|
|||
|
||||
std::stringstream ss;
|
||||
ss << std::hex << std::uppercase << std::setfill('0');
|
||||
for(int i = 0; i < 16; i++) {
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
ss << std::setw(2) << (int)result[i];
|
||||
}
|
||||
return ss.str();
|
||||
|
|
|
@ -28,15 +28,16 @@
|
|||
/* Any 32-bit or wider unsigned integer data type will do */
|
||||
typedef unsigned int MD5_u32plus;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
MD5_u32plus lo, hi;
|
||||
MD5_u32plus a, b, c, d;
|
||||
unsigned char buffer[64];
|
||||
MD5_u32plus block[16];
|
||||
} MD5_CTX;
|
||||
|
||||
extern void MD5_Init(MD5_CTX *ctx);
|
||||
extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
|
||||
extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
|
||||
extern void GetMd5Sum(unsigned char *result, void* buffer, unsigned long size);
|
||||
extern void MD5_Init(MD5_CTX* ctx);
|
||||
extern void MD5_Update(MD5_CTX* ctx, const void* data, unsigned long size);
|
||||
extern void MD5_Final(unsigned char* result, MD5_CTX* ctx);
|
||||
extern void GetMd5Sum(unsigned char* result, void* buffer, unsigned long size);
|
||||
extern string GetMd5Sum(void* buffer, size_t size);
|
||||
|
|
6513
Utilities/miniz.cpp
6513
Utilities/miniz.cpp
File diff suppressed because it is too large
Load diff
|
@ -199,7 +199,7 @@
|
|||
#endif
|
||||
|
||||
#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)
|
||||
#include <time.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__)
|
||||
|
@ -232,15 +232,15 @@ extern "C" {
|
|||
typedef unsigned long mz_ulong;
|
||||
|
||||
// mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap.
|
||||
void mz_free(void *p);
|
||||
void mz_free(void* p);
|
||||
|
||||
#define MZ_ADLER32_INIT (1)
|
||||
// mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL.
|
||||
mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len);
|
||||
mz_ulong mz_adler32(mz_ulong adler, const unsigned char* ptr, size_t buf_len);
|
||||
|
||||
#define MZ_CRC32_INIT (0)
|
||||
// mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL.
|
||||
mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len);
|
||||
mz_ulong mz_crc32(mz_ulong crc, const unsigned char* ptr, size_t buf_len);
|
||||
|
||||
// Compression strategies.
|
||||
enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 };
|
||||
|
@ -252,9 +252,9 @@ enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3
|
|||
|
||||
// Heap allocation callbacks.
|
||||
// Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long.
|
||||
typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size);
|
||||
typedef void (*mz_free_func)(void *opaque, void *address);
|
||||
typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size);
|
||||
typedef void*(*mz_alloc_func)(void* opaque, size_t items, size_t size);
|
||||
typedef void (*mz_free_func)(void* opaque, void* address);
|
||||
typedef void*(*mz_realloc_func)(void* opaque, void* address, size_t items, size_t size);
|
||||
|
||||
#define MZ_VERSION "9.1.15"
|
||||
#define MZ_VERNUM 0x91F0
|
||||
|
@ -267,10 +267,30 @@ typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size
|
|||
enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 };
|
||||
|
||||
// Return status codes. MZ_PARAM_ERROR is non-standard.
|
||||
enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 };
|
||||
enum
|
||||
{
|
||||
MZ_OK = 0,
|
||||
MZ_STREAM_END = 1,
|
||||
MZ_NEED_DICT = 2,
|
||||
MZ_ERRNO = -1,
|
||||
MZ_STREAM_ERROR = -2,
|
||||
MZ_DATA_ERROR = -3,
|
||||
MZ_MEM_ERROR = -4,
|
||||
MZ_BUF_ERROR = -5,
|
||||
MZ_VERSION_ERROR = -6,
|
||||
MZ_PARAM_ERROR = -10000
|
||||
};
|
||||
|
||||
// Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL.
|
||||
enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 };
|
||||
enum
|
||||
{
|
||||
MZ_NO_COMPRESSION = 0,
|
||||
MZ_BEST_SPEED = 1,
|
||||
MZ_BEST_COMPRESSION = 9,
|
||||
MZ_UBER_COMPRESSION = 10,
|
||||
MZ_DEFAULT_LEVEL = 6,
|
||||
MZ_DEFAULT_COMPRESSION = -1
|
||||
};
|
||||
|
||||
// Window bits
|
||||
#define MZ_DEFAULT_WINDOW_BITS 15
|
||||
|
@ -280,30 +300,30 @@ struct mz_internal_state;
|
|||
// Compression/decompression stream struct.
|
||||
typedef struct mz_stream_s
|
||||
{
|
||||
const unsigned char *next_in; // pointer to next byte to read
|
||||
unsigned int avail_in; // number of bytes available at next_in
|
||||
mz_ulong total_in; // total number of bytes consumed so far
|
||||
const unsigned char* next_in; // pointer to next byte to read
|
||||
unsigned int avail_in; // number of bytes available at next_in
|
||||
mz_ulong total_in; // total number of bytes consumed so far
|
||||
|
||||
unsigned char *next_out; // pointer to next byte to write
|
||||
unsigned int avail_out; // number of bytes that can be written to next_out
|
||||
mz_ulong total_out; // total number of bytes produced so far
|
||||
unsigned char* next_out; // pointer to next byte to write
|
||||
unsigned int avail_out; // number of bytes that can be written to next_out
|
||||
mz_ulong total_out; // total number of bytes produced so far
|
||||
|
||||
char *msg; // error msg (unused)
|
||||
struct mz_internal_state *state; // internal state, allocated by zalloc/zfree
|
||||
char* msg; // error msg (unused)
|
||||
struct mz_internal_state* state; // internal state, allocated by zalloc/zfree
|
||||
|
||||
mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc)
|
||||
mz_free_func zfree; // optional heap free function (defaults to free)
|
||||
void *opaque; // heap alloc function user pointer
|
||||
mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc)
|
||||
mz_free_func zfree; // optional heap free function (defaults to free)
|
||||
void* opaque; // heap alloc function user pointer
|
||||
|
||||
int data_type; // data_type (unused)
|
||||
mz_ulong adler; // adler32 of the source or uncompressed data
|
||||
mz_ulong reserved; // not used
|
||||
int data_type; // data_type (unused)
|
||||
mz_ulong adler; // adler32 of the source or uncompressed data
|
||||
mz_ulong reserved; // not used
|
||||
} mz_stream;
|
||||
|
||||
typedef mz_stream *mz_streamp;
|
||||
typedef mz_stream* mz_streamp;
|
||||
|
||||
// Returns the version string of miniz.c.
|
||||
const char *mz_version(void);
|
||||
const char* mz_version(void);
|
||||
|
||||
// mz_deflateInit() initializes a compressor with default options:
|
||||
// Parameters:
|
||||
|
@ -351,8 +371,9 @@ mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len);
|
|||
|
||||
// Single-call compression functions mz_compress() and mz_compress2():
|
||||
// Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure.
|
||||
int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);
|
||||
int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level);
|
||||
int mz_compress(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len);
|
||||
int mz_compress2(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len,
|
||||
int level);
|
||||
|
||||
// mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress().
|
||||
mz_ulong mz_compressBound(mz_ulong source_len);
|
||||
|
@ -385,84 +406,84 @@ int mz_inflateEnd(mz_streamp pStream);
|
|||
|
||||
// Single-call decompression.
|
||||
// Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure.
|
||||
int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);
|
||||
int mz_uncompress(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len);
|
||||
|
||||
// Returns a string description of the specified error code, or NULL if the error code is invalid.
|
||||
const char *mz_error(int err);
|
||||
const char* mz_error(int err);
|
||||
|
||||
// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports.
|
||||
// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project.
|
||||
#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
|
||||
typedef unsigned char Byte;
|
||||
typedef unsigned int uInt;
|
||||
typedef mz_ulong uLong;
|
||||
typedef Byte Bytef;
|
||||
typedef uInt uIntf;
|
||||
typedef char charf;
|
||||
typedef int intf;
|
||||
typedef void *voidpf;
|
||||
typedef uLong uLongf;
|
||||
typedef void *voidp;
|
||||
typedef void *const voidpc;
|
||||
#define Z_NULL 0
|
||||
#define Z_NO_FLUSH MZ_NO_FLUSH
|
||||
#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH
|
||||
#define Z_SYNC_FLUSH MZ_SYNC_FLUSH
|
||||
#define Z_FULL_FLUSH MZ_FULL_FLUSH
|
||||
#define Z_FINISH MZ_FINISH
|
||||
#define Z_BLOCK MZ_BLOCK
|
||||
#define Z_OK MZ_OK
|
||||
#define Z_STREAM_END MZ_STREAM_END
|
||||
#define Z_NEED_DICT MZ_NEED_DICT
|
||||
#define Z_ERRNO MZ_ERRNO
|
||||
#define Z_STREAM_ERROR MZ_STREAM_ERROR
|
||||
#define Z_DATA_ERROR MZ_DATA_ERROR
|
||||
#define Z_MEM_ERROR MZ_MEM_ERROR
|
||||
#define Z_BUF_ERROR MZ_BUF_ERROR
|
||||
#define Z_VERSION_ERROR MZ_VERSION_ERROR
|
||||
#define Z_PARAM_ERROR MZ_PARAM_ERROR
|
||||
#define Z_NO_COMPRESSION MZ_NO_COMPRESSION
|
||||
#define Z_BEST_SPEED MZ_BEST_SPEED
|
||||
#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION
|
||||
#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION
|
||||
#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY
|
||||
#define Z_FILTERED MZ_FILTERED
|
||||
#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY
|
||||
#define Z_RLE MZ_RLE
|
||||
#define Z_FIXED MZ_FIXED
|
||||
#define Z_DEFLATED MZ_DEFLATED
|
||||
#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS
|
||||
#define alloc_func mz_alloc_func
|
||||
#define free_func mz_free_func
|
||||
#define internal_state mz_internal_state
|
||||
#define z_stream mz_stream
|
||||
#define deflateInit mz_deflateInit
|
||||
#define deflateInit2 mz_deflateInit2
|
||||
#define deflateReset mz_deflateReset
|
||||
#define deflate mz_deflate
|
||||
#define deflateEnd mz_deflateEnd
|
||||
#define deflateBound mz_deflateBound
|
||||
#define compress mz_compress
|
||||
#define compress2 mz_compress2
|
||||
#define compressBound mz_compressBound
|
||||
#define inflateInit mz_inflateInit
|
||||
#define inflateInit2 mz_inflateInit2
|
||||
#define inflate mz_inflate
|
||||
#define inflateEnd mz_inflateEnd
|
||||
#define uncompress mz_uncompress
|
||||
#define crc32 mz_crc32
|
||||
#define adler32 mz_adler32
|
||||
#define MAX_WBITS 15
|
||||
#define MAX_MEM_LEVEL 9
|
||||
#define zError mz_error
|
||||
#define ZLIB_VERSION MZ_VERSION
|
||||
#define ZLIB_VERNUM MZ_VERNUM
|
||||
#define ZLIB_VER_MAJOR MZ_VER_MAJOR
|
||||
#define ZLIB_VER_MINOR MZ_VER_MINOR
|
||||
#define ZLIB_VER_REVISION MZ_VER_REVISION
|
||||
#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION
|
||||
#define zlibVersion mz_version
|
||||
#define zlib_version mz_version()
|
||||
typedef unsigned char Byte;
|
||||
typedef unsigned int uInt;
|
||||
typedef mz_ulong uLong;
|
||||
typedef Byte Bytef;
|
||||
typedef uInt uIntf;
|
||||
typedef char charf;
|
||||
typedef int intf;
|
||||
typedef void* voidpf;
|
||||
typedef uLong uLongf;
|
||||
typedef void* voidp;
|
||||
typedef void* const voidpc;
|
||||
#define Z_NULL 0
|
||||
#define Z_NO_FLUSH MZ_NO_FLUSH
|
||||
#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH
|
||||
#define Z_SYNC_FLUSH MZ_SYNC_FLUSH
|
||||
#define Z_FULL_FLUSH MZ_FULL_FLUSH
|
||||
#define Z_FINISH MZ_FINISH
|
||||
#define Z_BLOCK MZ_BLOCK
|
||||
#define Z_OK MZ_OK
|
||||
#define Z_STREAM_END MZ_STREAM_END
|
||||
#define Z_NEED_DICT MZ_NEED_DICT
|
||||
#define Z_ERRNO MZ_ERRNO
|
||||
#define Z_STREAM_ERROR MZ_STREAM_ERROR
|
||||
#define Z_DATA_ERROR MZ_DATA_ERROR
|
||||
#define Z_MEM_ERROR MZ_MEM_ERROR
|
||||
#define Z_BUF_ERROR MZ_BUF_ERROR
|
||||
#define Z_VERSION_ERROR MZ_VERSION_ERROR
|
||||
#define Z_PARAM_ERROR MZ_PARAM_ERROR
|
||||
#define Z_NO_COMPRESSION MZ_NO_COMPRESSION
|
||||
#define Z_BEST_SPEED MZ_BEST_SPEED
|
||||
#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION
|
||||
#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION
|
||||
#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY
|
||||
#define Z_FILTERED MZ_FILTERED
|
||||
#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY
|
||||
#define Z_RLE MZ_RLE
|
||||
#define Z_FIXED MZ_FIXED
|
||||
#define Z_DEFLATED MZ_DEFLATED
|
||||
#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS
|
||||
#define alloc_func mz_alloc_func
|
||||
#define free_func mz_free_func
|
||||
#define internal_state mz_internal_state
|
||||
#define z_stream mz_stream
|
||||
#define deflateInit mz_deflateInit
|
||||
#define deflateInit2 mz_deflateInit2
|
||||
#define deflateReset mz_deflateReset
|
||||
#define deflate mz_deflate
|
||||
#define deflateEnd mz_deflateEnd
|
||||
#define deflateBound mz_deflateBound
|
||||
#define compress mz_compress
|
||||
#define compress2 mz_compress2
|
||||
#define compressBound mz_compressBound
|
||||
#define inflateInit mz_inflateInit
|
||||
#define inflateInit2 mz_inflateInit2
|
||||
#define inflate mz_inflate
|
||||
#define inflateEnd mz_inflateEnd
|
||||
#define uncompress mz_uncompress
|
||||
#define crc32 mz_crc32
|
||||
#define adler32 mz_adler32
|
||||
#define MAX_WBITS 15
|
||||
#define MAX_MEM_LEVEL 9
|
||||
#define zError mz_error
|
||||
#define ZLIB_VERSION MZ_VERSION
|
||||
#define ZLIB_VERNUM MZ_VERNUM
|
||||
#define ZLIB_VER_MAJOR MZ_VER_MAJOR
|
||||
#define ZLIB_VER_MINOR MZ_VER_MINOR
|
||||
#define ZLIB_VER_REVISION MZ_VER_REVISION
|
||||
#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION
|
||||
#define zlibVersion mz_version
|
||||
#define zlib_version mz_version()
|
||||
#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
|
||||
|
||||
#endif // MINIZ_NO_ZLIB_APIS
|
||||
|
@ -483,7 +504,7 @@ typedef int mz_bool;
|
|||
|
||||
// An attempt to work around MSVC's spammy "warning C4127: conditional expression is constant" message.
|
||||
#ifdef _MSC_VER
|
||||
#define MZ_MACRO_END while (0, 0)
|
||||
#define MZ_MACRO_END while (0, 0)
|
||||
#else
|
||||
#define MZ_MACRO_END while (0)
|
||||
#endif
|
||||
|
@ -494,143 +515,153 @@ typedef int mz_bool;
|
|||
|
||||
enum
|
||||
{
|
||||
MZ_ZIP_MAX_IO_BUF_SIZE = 64*1024,
|
||||
MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260,
|
||||
MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256
|
||||
MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024,
|
||||
MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260,
|
||||
MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mz_uint32 m_file_index;
|
||||
mz_uint32 m_central_dir_ofs;
|
||||
mz_uint16 m_version_made_by;
|
||||
mz_uint16 m_version_needed;
|
||||
mz_uint16 m_bit_flag;
|
||||
mz_uint16 m_method;
|
||||
mz_uint32 m_file_index;
|
||||
mz_uint32 m_central_dir_ofs;
|
||||
mz_uint16 m_version_made_by;
|
||||
mz_uint16 m_version_needed;
|
||||
mz_uint16 m_bit_flag;
|
||||
mz_uint16 m_method;
|
||||
#ifndef MINIZ_NO_TIME
|
||||
time_t m_time;
|
||||
time_t m_time;
|
||||
#endif
|
||||
mz_uint32 m_crc32;
|
||||
mz_uint64 m_comp_size;
|
||||
mz_uint64 m_uncomp_size;
|
||||
mz_uint16 m_internal_attr;
|
||||
mz_uint32 m_external_attr;
|
||||
mz_uint64 m_local_header_ofs;
|
||||
mz_uint32 m_comment_size;
|
||||
char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
|
||||
char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];
|
||||
mz_uint32 m_crc32;
|
||||
mz_uint64 m_comp_size;
|
||||
mz_uint64 m_uncomp_size;
|
||||
mz_uint16 m_internal_attr;
|
||||
mz_uint32 m_external_attr;
|
||||
mz_uint64 m_local_header_ofs;
|
||||
mz_uint32 m_comment_size;
|
||||
char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
|
||||
char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];
|
||||
} mz_zip_archive_file_stat;
|
||||
|
||||
typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n);
|
||||
typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n);
|
||||
typedef size_t (*mz_file_read_func)(void* pOpaque, mz_uint64 file_ofs, void* pBuf, size_t n);
|
||||
typedef size_t (*mz_file_write_func)(void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n);
|
||||
|
||||
struct mz_zip_internal_state_tag;
|
||||
typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MZ_ZIP_MODE_INVALID = 0,
|
||||
MZ_ZIP_MODE_READING = 1,
|
||||
MZ_ZIP_MODE_WRITING = 2,
|
||||
MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
|
||||
MZ_ZIP_MODE_INVALID = 0,
|
||||
MZ_ZIP_MODE_READING = 1,
|
||||
MZ_ZIP_MODE_WRITING = 2,
|
||||
MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
|
||||
} mz_zip_mode;
|
||||
|
||||
typedef struct mz_zip_archive_tag
|
||||
{
|
||||
mz_uint64 m_archive_size;
|
||||
mz_uint64 m_central_directory_file_ofs;
|
||||
mz_uint m_total_files;
|
||||
mz_zip_mode m_zip_mode;
|
||||
mz_uint64 m_archive_size;
|
||||
mz_uint64 m_central_directory_file_ofs;
|
||||
mz_uint m_total_files;
|
||||
mz_zip_mode m_zip_mode;
|
||||
|
||||
mz_uint m_file_offset_alignment;
|
||||
mz_uint m_file_offset_alignment;
|
||||
|
||||
mz_alloc_func m_pAlloc;
|
||||
mz_free_func m_pFree;
|
||||
mz_realloc_func m_pRealloc;
|
||||
void *m_pAlloc_opaque;
|
||||
mz_alloc_func m_pAlloc;
|
||||
mz_free_func m_pFree;
|
||||
mz_realloc_func m_pRealloc;
|
||||
void* m_pAlloc_opaque;
|
||||
|
||||
mz_file_read_func m_pRead;
|
||||
mz_file_write_func m_pWrite;
|
||||
void *m_pIO_opaque;
|
||||
|
||||
mz_zip_internal_state *m_pState;
|
||||
mz_file_read_func m_pRead;
|
||||
mz_file_write_func m_pWrite;
|
||||
void* m_pIO_opaque;
|
||||
|
||||
mz_zip_internal_state* m_pState;
|
||||
} mz_zip_archive;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
|
||||
MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,
|
||||
MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,
|
||||
MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800
|
||||
MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
|
||||
MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,
|
||||
MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,
|
||||
MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800
|
||||
} mz_zip_flags;
|
||||
|
||||
// ZIP archive reading
|
||||
|
||||
// Inits a ZIP archive reader.
|
||||
// These functions read and validate the archive's central directory.
|
||||
mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags);
|
||||
mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags);
|
||||
mz_bool mz_zip_reader_init(mz_zip_archive* pZip, mz_uint64 size, mz_uint32 flags);
|
||||
mz_bool mz_zip_reader_init_mem(mz_zip_archive* pZip, const void* pMem, size_t size, mz_uint32 flags);
|
||||
|
||||
#ifndef MINIZ_NO_STDIO
|
||||
mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags);
|
||||
mz_bool mz_zip_reader_init_file(mz_zip_archive* pZip, const char* pFilename, mz_uint32 flags);
|
||||
#endif
|
||||
|
||||
// Returns the total number of files in the archive.
|
||||
mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip);
|
||||
mz_uint mz_zip_reader_get_num_files(mz_zip_archive* pZip);
|
||||
|
||||
// Returns detailed information about an archive file entry.
|
||||
mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat);
|
||||
mz_bool mz_zip_reader_file_stat(mz_zip_archive* pZip, mz_uint file_index, mz_zip_archive_file_stat* pStat);
|
||||
|
||||
// Determines if an archive file entry is a directory entry.
|
||||
mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index);
|
||||
mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index);
|
||||
mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive* pZip, mz_uint file_index);
|
||||
mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive* pZip, mz_uint file_index);
|
||||
|
||||
// Retrieves the filename of an archive file entry.
|
||||
// Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename.
|
||||
mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size);
|
||||
mz_uint mz_zip_reader_get_filename(mz_zip_archive* pZip, mz_uint file_index, char* pFilename,
|
||||
mz_uint filename_buf_size);
|
||||
|
||||
// Attempts to locates a file in the archive's central directory.
|
||||
// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH
|
||||
// Returns -1 if the file cannot be found.
|
||||
int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);
|
||||
int mz_zip_reader_locate_file(mz_zip_archive* pZip, const char* pName, const char* pComment, mz_uint flags);
|
||||
|
||||
// Extracts a archive file to a memory buffer using no memory allocation.
|
||||
mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
|
||||
mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
|
||||
mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive* pZip, mz_uint file_index, void* pBuf, size_t buf_size,
|
||||
mz_uint flags, void* pUser_read_buf, size_t user_read_buf_size);
|
||||
mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive* pZip, const char* pFilename, void* pBuf,
|
||||
size_t buf_size, mz_uint flags, void* pUser_read_buf,
|
||||
size_t user_read_buf_size);
|
||||
|
||||
// Extracts a archive file to a memory buffer.
|
||||
mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags);
|
||||
mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags);
|
||||
mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive* pZip, mz_uint file_index, void* pBuf, size_t buf_size,
|
||||
mz_uint flags);
|
||||
mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive* pZip, const char* pFilename, void* pBuf, size_t buf_size,
|
||||
mz_uint flags);
|
||||
|
||||
// Extracts a archive file to a dynamically allocated heap buffer.
|
||||
void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags);
|
||||
void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags);
|
||||
void* mz_zip_reader_extract_to_heap(mz_zip_archive* pZip, mz_uint file_index, size_t* pSize, mz_uint flags);
|
||||
void* mz_zip_reader_extract_file_to_heap(mz_zip_archive* pZip, const char* pFilename, size_t* pSize, mz_uint flags);
|
||||
|
||||
// Extracts a archive file using a callback function to output the file's data.
|
||||
mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags);
|
||||
mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags);
|
||||
mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive* pZip, mz_uint file_index, mz_file_write_func pCallback,
|
||||
void* pOpaque, mz_uint flags);
|
||||
mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive* pZip, const char* pFilename,
|
||||
mz_file_write_func pCallback, void* pOpaque, mz_uint flags);
|
||||
|
||||
#ifndef MINIZ_NO_STDIO
|
||||
// Extracts a archive file to a disk file and sets its last accessed and modified times.
|
||||
// This function only extracts files, not archive directory records.
|
||||
mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags);
|
||||
mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags);
|
||||
mz_bool mz_zip_reader_extract_to_file(mz_zip_archive* pZip, mz_uint file_index, const char* pDst_filename,
|
||||
mz_uint flags);
|
||||
mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive* pZip, const char* pArchive_filename,
|
||||
const char* pDst_filename, mz_uint flags);
|
||||
#endif
|
||||
|
||||
// Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used.
|
||||
mz_bool mz_zip_reader_end(mz_zip_archive *pZip);
|
||||
mz_bool mz_zip_reader_end(mz_zip_archive* pZip);
|
||||
|
||||
// ZIP archive writing
|
||||
|
||||
#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
|
||||
|
||||
// Inits a ZIP archive writer.
|
||||
mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size);
|
||||
mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size);
|
||||
mz_bool mz_zip_writer_init(mz_zip_archive* pZip, mz_uint64 existing_size);
|
||||
mz_bool mz_zip_writer_init_heap(mz_zip_archive* pZip, size_t size_to_reserve_at_beginning,
|
||||
size_t initial_allocation_size);
|
||||
|
||||
#ifndef MINIZ_NO_STDIO
|
||||
mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning);
|
||||
mz_bool mz_zip_writer_init_file(mz_zip_archive* pZip, const char* pFilename, mz_uint64 size_to_reserve_at_beginning);
|
||||
#endif
|
||||
|
||||
// Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive.
|
||||
|
@ -639,43 +670,50 @@ mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_
|
|||
// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL.
|
||||
// Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before
|
||||
// the archive is finalized the file's central directory will be hosed.
|
||||
mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename);
|
||||
mz_bool mz_zip_writer_init_from_reader(mz_zip_archive* pZip, const char* pFilename);
|
||||
|
||||
// Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive.
|
||||
// To add a directory entry, call this method with an archive name ending in a forwardslash with empty buffer.
|
||||
// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION.
|
||||
mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags);
|
||||
mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32);
|
||||
mz_bool mz_zip_writer_add_mem(mz_zip_archive* pZip, const char* pArchive_name, const void* pBuf, size_t buf_size,
|
||||
mz_uint level_and_flags);
|
||||
mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive* pZip, const char* pArchive_name, const void* pBuf, size_t buf_size,
|
||||
const void* pComment, mz_uint16 comment_size, mz_uint level_and_flags,
|
||||
mz_uint64 uncomp_size, mz_uint32 uncomp_crc32);
|
||||
|
||||
#ifndef MINIZ_NO_STDIO
|
||||
// Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive.
|
||||
// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION.
|
||||
mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);
|
||||
mz_bool mz_zip_writer_add_file(mz_zip_archive* pZip, const char* pArchive_name, const char* pSrc_filename,
|
||||
const void* pComment, mz_uint16 comment_size, mz_uint level_and_flags);
|
||||
#endif
|
||||
|
||||
// Adds a file to an archive by fully cloning the data from another archive.
|
||||
// This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data, and comment fields.
|
||||
mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index);
|
||||
mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive* pZip, mz_zip_archive* pSource_zip, mz_uint file_index);
|
||||
|
||||
// Finalizes the archive by writing the central directory records followed by the end of central directory record.
|
||||
// After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end().
|
||||
// An archive must be manually finalized by calling this function for it to be valid.
|
||||
mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip);
|
||||
mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize);
|
||||
mz_bool mz_zip_writer_finalize_archive(mz_zip_archive* pZip);
|
||||
mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive* pZip, void** pBuf, size_t* pSize);
|
||||
|
||||
// Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used.
|
||||
// Note for the archive to be valid, it must have been finalized before ending.
|
||||
mz_bool mz_zip_writer_end(mz_zip_archive *pZip);
|
||||
mz_bool mz_zip_writer_end(mz_zip_archive* pZip);
|
||||
|
||||
// Misc. high-level helper functions:
|
||||
|
||||
// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive.
|
||||
// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION.
|
||||
mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);
|
||||
mz_bool mz_zip_add_mem_to_archive_file_in_place(const char* pZip_filename, const char* pArchive_name, const void* pBuf,
|
||||
size_t buf_size, const void* pComment, mz_uint16 comment_size,
|
||||
mz_uint level_and_flags);
|
||||
|
||||
// Reads a single file from an archive into a heap block.
|
||||
// Returns NULL on failure.
|
||||
void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags);
|
||||
void* mz_zip_extract_archive_file_to_heap(const char* pZip_filename, const char* pArchive_name, size_t* pSize,
|
||||
mz_uint zip_flags);
|
||||
|
||||
#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
|
||||
|
||||
|
@ -690,10 +728,10 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char
|
|||
// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes.
|
||||
enum
|
||||
{
|
||||
TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
|
||||
TINFL_FLAG_HAS_MORE_INPUT = 2,
|
||||
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
|
||||
TINFL_FLAG_COMPUTE_ADLER32 = 8
|
||||
TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
|
||||
TINFL_FLAG_HAS_MORE_INPUT = 2,
|
||||
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
|
||||
TINFL_FLAG_COMPUTE_ADLER32 = 8
|
||||
};
|
||||
|
||||
// High level decompression functions:
|
||||
|
@ -704,19 +742,22 @@ enum
|
|||
// Function returns a pointer to the decompressed data, or NULL on failure.
|
||||
// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data.
|
||||
// The caller must call mz_free() on the returned block when it's no longer needed.
|
||||
void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
|
||||
void* tinfl_decompress_mem_to_heap(const void* pSrc_buf, size_t src_buf_len, size_t* pOut_len, int flags);
|
||||
|
||||
// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory.
|
||||
// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success.
|
||||
#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
|
||||
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
|
||||
size_t tinfl_decompress_mem_to_mem(void* pOut_buf, size_t out_buf_len, const void* pSrc_buf, size_t src_buf_len,
|
||||
int flags);
|
||||
|
||||
// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer.
|
||||
// Returns 1 on success or 0 on failure.
|
||||
typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
|
||||
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
|
||||
typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void* pUser);
|
||||
int tinfl_decompress_mem_to_callback(const void* pIn_buf, size_t* pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func,
|
||||
void* pPut_buf_user, int flags);
|
||||
|
||||
struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor;
|
||||
struct tinfl_decompressor_tag;
|
||||
typedef struct tinfl_decompressor_tag tinfl_decompressor;
|
||||
|
||||
// Max size of LZ dictionary.
|
||||
#define TINFL_LZ_DICT_SIZE 32768
|
||||
|
@ -724,12 +765,12 @@ struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decom
|
|||
// Return status.
|
||||
typedef enum
|
||||
{
|
||||
TINFL_STATUS_BAD_PARAM = -3,
|
||||
TINFL_STATUS_ADLER32_MISMATCH = -2,
|
||||
TINFL_STATUS_FAILED = -1,
|
||||
TINFL_STATUS_DONE = 0,
|
||||
TINFL_STATUS_NEEDS_MORE_INPUT = 1,
|
||||
TINFL_STATUS_HAS_MORE_OUTPUT = 2
|
||||
TINFL_STATUS_BAD_PARAM = -3,
|
||||
TINFL_STATUS_ADLER32_MISMATCH = -2,
|
||||
TINFL_STATUS_FAILED = -1,
|
||||
TINFL_STATUS_DONE = 0,
|
||||
TINFL_STATUS_NEEDS_MORE_INPUT = 1,
|
||||
TINFL_STATUS_HAS_MORE_OUTPUT = 2
|
||||
} tinfl_status;
|
||||
|
||||
// Initializes the decompressor to its initial state.
|
||||
|
@ -738,28 +779,34 @@ typedef enum
|
|||
|
||||
// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability.
|
||||
// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output.
|
||||
tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);
|
||||
tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_next, size_t* pIn_buf_size,
|
||||
mz_uint8* pOut_buf_start, mz_uint8* pOut_buf_next, size_t* pOut_buf_size,
|
||||
const mz_uint32 decomp_flags);
|
||||
|
||||
// Internal/private bits follow.
|
||||
enum
|
||||
{
|
||||
TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19,
|
||||
TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
|
||||
TINFL_MAX_HUFF_TABLES = 3,
|
||||
TINFL_MAX_HUFF_SYMBOLS_0 = 288,
|
||||
TINFL_MAX_HUFF_SYMBOLS_1 = 32,
|
||||
TINFL_MAX_HUFF_SYMBOLS_2 = 19,
|
||||
TINFL_FAST_LOOKUP_BITS = 10,
|
||||
TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
|
||||
mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
|
||||
mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
|
||||
mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
|
||||
} tinfl_huff_table;
|
||||
|
||||
#if MINIZ_HAS_64BIT_REGISTERS
|
||||
#define TINFL_USE_64BIT_BITBUF 1
|
||||
#define TINFL_USE_64BIT_BITBUF 1
|
||||
#endif
|
||||
|
||||
#if TINFL_USE_64BIT_BITBUF
|
||||
typedef mz_uint64 tinfl_bit_buf_t;
|
||||
#define TINFL_BITBUF_SIZE (64)
|
||||
typedef mz_uint64 tinfl_bit_buf_t;
|
||||
#define TINFL_BITBUF_SIZE (64)
|
||||
#else
|
||||
typedef mz_uint32 tinfl_bit_buf_t;
|
||||
#define TINFL_BITBUF_SIZE (32)
|
||||
|
@ -767,11 +814,12 @@ typedef struct
|
|||
|
||||
struct tinfl_decompressor_tag
|
||||
{
|
||||
mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
|
||||
tinfl_bit_buf_t m_bit_buf;
|
||||
size_t m_dist_from_out_buf_start;
|
||||
tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
|
||||
mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
|
||||
mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter,
|
||||
m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
|
||||
tinfl_bit_buf_t m_bit_buf;
|
||||
size_t m_dist_from_out_buf_start;
|
||||
tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
|
||||
mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
|
||||
};
|
||||
|
||||
// ------------------- Low-level Compression API Definitions
|
||||
|
@ -783,7 +831,9 @@ struct tinfl_decompressor_tag
|
|||
// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression).
|
||||
enum
|
||||
{
|
||||
TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF
|
||||
TDEFL_HUFFMAN_ONLY = 0,
|
||||
TDEFL_DEFAULT_MAX_PROBES = 128,
|
||||
TDEFL_MAX_PROBES_MASK = 0xFFF
|
||||
};
|
||||
|
||||
// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data.
|
||||
|
@ -797,14 +847,14 @@ enum
|
|||
// The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK).
|
||||
enum
|
||||
{
|
||||
TDEFL_WRITE_ZLIB_HEADER = 0x01000,
|
||||
TDEFL_COMPUTE_ADLER32 = 0x02000,
|
||||
TDEFL_GREEDY_PARSING_FLAG = 0x04000,
|
||||
TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,
|
||||
TDEFL_RLE_MATCHES = 0x10000,
|
||||
TDEFL_FILTER_MATCHES = 0x20000,
|
||||
TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
|
||||
TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
|
||||
TDEFL_WRITE_ZLIB_HEADER = 0x01000,
|
||||
TDEFL_COMPUTE_ADLER32 = 0x02000,
|
||||
TDEFL_GREEDY_PARSING_FLAG = 0x04000,
|
||||
TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,
|
||||
TDEFL_RLE_MATCHES = 0x10000,
|
||||
TDEFL_FILTER_MATCHES = 0x20000,
|
||||
TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
|
||||
TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
|
||||
};
|
||||
|
||||
// High level compression functions:
|
||||
|
@ -816,11 +866,12 @@ enum
|
|||
// Function returns a pointer to the compressed data, or NULL on failure.
|
||||
// *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data.
|
||||
// The caller must free() the returned block when it's no longer needed.
|
||||
void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
|
||||
void* tdefl_compress_mem_to_heap(const void* pSrc_buf, size_t src_buf_len, size_t* pOut_len, int flags);
|
||||
|
||||
// tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory.
|
||||
// Returns 0 on failure.
|
||||
size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
|
||||
size_t tdefl_compress_mem_to_mem(void* pOut_buf, size_t out_buf_len, const void* pSrc_buf, size_t src_buf_len,
|
||||
int flags);
|
||||
|
||||
// Compresses an image to a compressed PNG file in memory.
|
||||
// On entry:
|
||||
|
@ -832,68 +883,90 @@ size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void
|
|||
// Function returns a pointer to the compressed data, or NULL on failure.
|
||||
// *pLen_out will be set to the size of the PNG image file.
|
||||
// The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed.
|
||||
void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip);
|
||||
void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out);
|
||||
void* tdefl_write_image_to_png_file_in_memory_ex(const void* pImage, int w, int h, int num_chans, size_t* pLen_out,
|
||||
mz_uint level, mz_bool flip);
|
||||
void* tdefl_write_image_to_png_file_in_memory(const void* pImage, int w, int h, int num_chans, size_t* pLen_out);
|
||||
|
||||
// Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time.
|
||||
typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
|
||||
typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void* pUser);
|
||||
|
||||
// tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally.
|
||||
mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
|
||||
mz_bool tdefl_compress_mem_to_output(const void* pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func,
|
||||
void* pPut_buf_user, int flags);
|
||||
|
||||
enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 };
|
||||
enum
|
||||
{
|
||||
TDEFL_MAX_HUFF_TABLES = 3,
|
||||
TDEFL_MAX_HUFF_SYMBOLS_0 = 288,
|
||||
TDEFL_MAX_HUFF_SYMBOLS_1 = 32,
|
||||
TDEFL_MAX_HUFF_SYMBOLS_2 = 19,
|
||||
TDEFL_LZ_DICT_SIZE = 32768,
|
||||
TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1,
|
||||
TDEFL_MIN_MATCH_LEN = 3,
|
||||
TDEFL_MAX_MATCH_LEN = 258
|
||||
};
|
||||
|
||||
// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes).
|
||||
#if TDEFL_LESS_MEMORY
|
||||
enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS };
|
||||
#else
|
||||
enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS };
|
||||
enum
|
||||
{
|
||||
TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024,
|
||||
TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
|
||||
TDEFL_MAX_HUFF_SYMBOLS = 288,
|
||||
TDEFL_LZ_HASH_BITS = 15,
|
||||
TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
|
||||
TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
|
||||
TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
|
||||
};
|
||||
#endif
|
||||
|
||||
// The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions.
|
||||
typedef enum
|
||||
{
|
||||
TDEFL_STATUS_BAD_PARAM = -2,
|
||||
TDEFL_STATUS_PUT_BUF_FAILED = -1,
|
||||
TDEFL_STATUS_OKAY = 0,
|
||||
TDEFL_STATUS_DONE = 1,
|
||||
TDEFL_STATUS_BAD_PARAM = -2,
|
||||
TDEFL_STATUS_PUT_BUF_FAILED = -1,
|
||||
TDEFL_STATUS_OKAY = 0,
|
||||
TDEFL_STATUS_DONE = 1,
|
||||
} tdefl_status;
|
||||
|
||||
// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums
|
||||
typedef enum
|
||||
{
|
||||
TDEFL_NO_FLUSH = 0,
|
||||
TDEFL_SYNC_FLUSH = 2,
|
||||
TDEFL_FULL_FLUSH = 3,
|
||||
TDEFL_FINISH = 4
|
||||
TDEFL_NO_FLUSH = 0,
|
||||
TDEFL_SYNC_FLUSH = 2,
|
||||
TDEFL_FULL_FLUSH = 3,
|
||||
TDEFL_FINISH = 4
|
||||
} tdefl_flush;
|
||||
|
||||
// tdefl's compression state structure.
|
||||
typedef struct
|
||||
{
|
||||
tdefl_put_buf_func_ptr m_pPut_buf_func;
|
||||
void *m_pPut_buf_user;
|
||||
mz_uint m_flags, m_max_probes[2];
|
||||
int m_greedy_parsing;
|
||||
mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
|
||||
mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
|
||||
mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer;
|
||||
mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish;
|
||||
tdefl_status m_prev_return_status;
|
||||
const void *m_pIn_buf;
|
||||
void *m_pOut_buf;
|
||||
size_t *m_pIn_buf_size, *m_pOut_buf_size;
|
||||
tdefl_flush m_flush;
|
||||
const mz_uint8 *m_pSrc;
|
||||
size_t m_src_buf_left, m_out_buf_ofs;
|
||||
mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];
|
||||
mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
|
||||
mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
|
||||
mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
|
||||
mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];
|
||||
mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];
|
||||
mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];
|
||||
mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];
|
||||
tdefl_put_buf_func_ptr m_pPut_buf_func;
|
||||
void* m_pPut_buf_user;
|
||||
mz_uint m_flags, m_max_probes[2];
|
||||
int m_greedy_parsing;
|
||||
mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
|
||||
mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
|
||||
mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer;
|
||||
mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished,
|
||||
m_block_index, m_wants_to_finish;
|
||||
tdefl_status m_prev_return_status;
|
||||
const void* m_pIn_buf;
|
||||
void* m_pOut_buf;
|
||||
size_t *m_pIn_buf_size, *m_pOut_buf_size;
|
||||
tdefl_flush m_flush;
|
||||
const mz_uint8* m_pSrc;
|
||||
size_t m_src_buf_left, m_out_buf_ofs;
|
||||
mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];
|
||||
mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
|
||||
mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
|
||||
mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
|
||||
mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];
|
||||
mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];
|
||||
mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];
|
||||
mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];
|
||||
} tdefl_compressor;
|
||||
|
||||
// Initializes the compressor.
|
||||
|
@ -901,17 +974,18 @@ typedef struct
|
|||
// pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression.
|
||||
// If pBut_buf_func is NULL the user should always call the tdefl_compress() API.
|
||||
// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.)
|
||||
tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
|
||||
tdefl_status tdefl_init(tdefl_compressor* d, tdefl_put_buf_func_ptr pPut_buf_func, void* pPut_buf_user, int flags);
|
||||
|
||||
// Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible.
|
||||
tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush);
|
||||
tdefl_status tdefl_compress(tdefl_compressor* d, const void* pIn_buf, size_t* pIn_buf_size, void* pOut_buf,
|
||||
size_t* pOut_buf_size, tdefl_flush flush);
|
||||
|
||||
// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr.
|
||||
// tdefl_compress_buffer() always consumes the entire input buffer.
|
||||
tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush);
|
||||
tdefl_status tdefl_compress_buffer(tdefl_compressor* d, const void* pIn_buf, size_t in_buf_size, tdefl_flush flush);
|
||||
|
||||
tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d);
|
||||
mz_uint32 tdefl_get_adler32(tdefl_compressor *d);
|
||||
tdefl_status tdefl_get_prev_return_status(tdefl_compressor* d);
|
||||
mz_uint32 tdefl_get_adler32(tdefl_compressor* d);
|
||||
|
||||
// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros.
|
||||
#ifndef MINIZ_NO_ZLIB_APIS
|
||||
|
@ -927,4 +1001,3 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int
|
|||
#endif
|
||||
|
||||
#endif // MINIZ_HEADER_INCLUDED
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -24,11 +24,11 @@
|
|||
#include <fstream>
|
||||
|
||||
|
||||
static const size_t BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */
|
||||
static const size_t BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */
|
||||
static const size_t BLOCK_BYTES = BLOCK_INTS * 4;
|
||||
|
||||
|
||||
static void reset(uint32_t digest[], std::string &buffer, uint64_t &transforms)
|
||||
static void reset(uint32_t digest[], std::string& buffer, uint64_t& transforms)
|
||||
{
|
||||
/* SHA1 initialization constants */
|
||||
digest[0] = 0x67452301;
|
||||
|
@ -59,41 +59,46 @@ static uint32_t blk(const uint32_t block[BLOCK_INTS], const size_t i)
|
|||
* (R0+R1), R2, R3, R4 are the different operations used in SHA1
|
||||
*/
|
||||
|
||||
static void R0(const uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
|
||||
static void R0(const uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t& w, const uint32_t x, const uint32_t y,
|
||||
uint32_t& z, const size_t i)
|
||||
{
|
||||
z += ((w&(x^y)) ^ y) + block[i] + 0x5a827999 + rol(v, 5);
|
||||
z += ((w & (x ^ y)) ^ y) + block[i] + 0x5a827999 + rol(v, 5);
|
||||
w = rol(w, 30);
|
||||
}
|
||||
|
||||
|
||||
static void R1(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
|
||||
static void R1(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t& w, const uint32_t x, const uint32_t y,
|
||||
uint32_t& z, const size_t i)
|
||||
{
|
||||
block[i] = blk(block, i);
|
||||
z += ((w&(x^y)) ^ y) + block[i] + 0x5a827999 + rol(v, 5);
|
||||
z += ((w & (x ^ y)) ^ y) + block[i] + 0x5a827999 + rol(v, 5);
|
||||
w = rol(w, 30);
|
||||
}
|
||||
|
||||
|
||||
static void R2(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
|
||||
static void R2(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t& w, const uint32_t x, const uint32_t y,
|
||||
uint32_t& z, const size_t i)
|
||||
{
|
||||
block[i] = blk(block, i);
|
||||
z += (w^x^y) + block[i] + 0x6ed9eba1 + rol(v, 5);
|
||||
z += (w ^ x ^ y) + block[i] + 0x6ed9eba1 + rol(v, 5);
|
||||
w = rol(w, 30);
|
||||
}
|
||||
|
||||
|
||||
static void R3(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
|
||||
static void R3(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t& w, const uint32_t x, const uint32_t y,
|
||||
uint32_t& z, const size_t i)
|
||||
{
|
||||
block[i] = blk(block, i);
|
||||
z += (((w | x)&y) | (w&x)) + block[i] + 0x8f1bbcdc + rol(v, 5);
|
||||
z += (((w | x) & y) | (w & x)) + block[i] + 0x8f1bbcdc + rol(v, 5);
|
||||
w = rol(w, 30);
|
||||
}
|
||||
|
||||
|
||||
static void R4(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i)
|
||||
static void R4(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t& w, const uint32_t x, const uint32_t y,
|
||||
uint32_t& z, const size_t i)
|
||||
{
|
||||
block[i] = blk(block, i);
|
||||
z += (w^x^y) + block[i] + 0xca62c1d6 + rol(v, 5);
|
||||
z += (w ^ x ^ y) + block[i] + 0xca62c1d6 + rol(v, 5);
|
||||
w = rol(w, 30);
|
||||
}
|
||||
|
||||
|
@ -102,7 +107,7 @@ static void R4(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const
|
|||
* Hash a single 512-bit block. This is the core of the algorithm.
|
||||
*/
|
||||
|
||||
static void transform(uint32_t digest[], uint32_t block[BLOCK_INTS], uint64_t &transforms)
|
||||
static void transform(uint32_t digest[], uint32_t block[BLOCK_INTS], uint64_t& transforms)
|
||||
{
|
||||
/* Copy digest[] to working vars */
|
||||
uint32_t a = digest[0];
|
||||
|
@ -205,10 +210,11 @@ static void transform(uint32_t digest[], uint32_t block[BLOCK_INTS], uint64_t &t
|
|||
}
|
||||
|
||||
|
||||
static void buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_INTS])
|
||||
static void buffer_to_block(const std::string& buffer, uint32_t block[BLOCK_INTS])
|
||||
{
|
||||
/* Convert the std::string (byte buffer) to a uint32_t array (MSB) */
|
||||
for(size_t i = 0; i < BLOCK_INTS; i++) {
|
||||
for (size_t i = 0; i < BLOCK_INTS; i++)
|
||||
{
|
||||
block[i] = (buffer[4 * i + 3] & 0xff)
|
||||
| (buffer[4 * i + 2] & 0xff) << 8
|
||||
| (buffer[4 * i + 1] & 0xff) << 16
|
||||
|
@ -223,22 +229,24 @@ SHA1::SHA1()
|
|||
}
|
||||
|
||||
|
||||
void SHA1::update(const std::string &s)
|
||||
void SHA1::update(const std::string& s)
|
||||
{
|
||||
std::istringstream is(s);
|
||||
update(is);
|
||||
}
|
||||
|
||||
|
||||
void SHA1::update(std::istream &is)
|
||||
void SHA1::update(std::istream& is)
|
||||
{
|
||||
char sbuf[BLOCK_BYTES];
|
||||
uint32_t block[BLOCK_INTS];
|
||||
|
||||
while(true) {
|
||||
while (true)
|
||||
{
|
||||
is.read(sbuf, BLOCK_BYTES - buffer.size());
|
||||
buffer.append(sbuf, (size_t)is.gcount());
|
||||
if(buffer.size() != BLOCK_BYTES) {
|
||||
if (buffer.size() != BLOCK_BYTES)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -256,21 +264,24 @@ void SHA1::update(std::istream &is)
|
|||
std::string SHA1::final()
|
||||
{
|
||||
/* Total number of hashed bits */
|
||||
uint64_t total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8;
|
||||
uint64_t total_bits = (transforms * BLOCK_BYTES + buffer.size()) * 8;
|
||||
|
||||
/* Padding */
|
||||
buffer += (char)0x80;
|
||||
size_t orig_size = buffer.size();
|
||||
while(buffer.size() < BLOCK_BYTES) {
|
||||
while (buffer.size() < BLOCK_BYTES)
|
||||
{
|
||||
buffer += (char)0x00;
|
||||
}
|
||||
|
||||
uint32_t block[BLOCK_INTS];
|
||||
buffer_to_block(buffer, block);
|
||||
|
||||
if(orig_size > BLOCK_BYTES - 8) {
|
||||
if (orig_size > BLOCK_BYTES - 8)
|
||||
{
|
||||
transform(digest, block, transforms);
|
||||
for(size_t i = 0; i < BLOCK_INTS - 2; i++) {
|
||||
for (size_t i = 0; i < BLOCK_INTS - 2; i++)
|
||||
{
|
||||
block[i] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -282,7 +293,8 @@ std::string SHA1::final()
|
|||
|
||||
/* Hex std::string */
|
||||
std::ostringstream result;
|
||||
for(size_t i = 0; i < sizeof(digest) / sizeof(digest[0]); i++) {
|
||||
for (size_t i = 0; i < sizeof(digest) / sizeof(digest[0]); i++)
|
||||
{
|
||||
result << std::uppercase << std::hex << std::setfill('0') << std::setw(8);
|
||||
result << digest[i];
|
||||
}
|
||||
|
@ -293,7 +305,7 @@ std::string SHA1::final()
|
|||
return result.str();
|
||||
}
|
||||
|
||||
std::string SHA1::GetHash(vector<uint8_t> &data)
|
||||
std::string SHA1::GetHash(vector<uint8_t>& data)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss.write((char*)data.data(), data.size());
|
||||
|
@ -313,14 +325,14 @@ std::string SHA1::GetHash(uint8_t* data, size_t size)
|
|||
return checksum.final();
|
||||
}
|
||||
|
||||
std::string SHA1::GetHash(std::istream &stream)
|
||||
std::string SHA1::GetHash(std::istream& stream)
|
||||
{
|
||||
SHA1 checksum;
|
||||
checksum.update(stream);
|
||||
return checksum.final();
|
||||
}
|
||||
|
||||
std::string SHA1::GetHash(const std::string &filename)
|
||||
std::string SHA1::GetHash(const std::string& filename)
|
||||
{
|
||||
std::ifstream stream(filename.c_str(), std::ios::binary);
|
||||
SHA1 checksum;
|
||||
|
|
|
@ -26,17 +26,17 @@
|
|||
class SHA1
|
||||
{
|
||||
public:
|
||||
SHA1();
|
||||
void update(const std::string &s);
|
||||
void update(std::istream &is);
|
||||
std::string final();
|
||||
static std::string GetHash(const std::string &filename);
|
||||
static std::string GetHash(std::istream &stream);
|
||||
static std::string GetHash(vector<uint8_t> &data);
|
||||
static std::string GetHash(uint8_t* data, size_t size);
|
||||
SHA1();
|
||||
void update(const std::string& s);
|
||||
void update(std::istream& is);
|
||||
std::string final();
|
||||
static std::string GetHash(const std::string& filename);
|
||||
static std::string GetHash(std::istream& stream);
|
||||
static std::string GetHash(vector<uint8_t>& data);
|
||||
static std::string GetHash(uint8_t* data, size_t size);
|
||||
|
||||
private:
|
||||
uint32_t digest[5];
|
||||
std::string buffer;
|
||||
uint64_t transforms;
|
||||
uint32_t digest[5];
|
||||
std::string buffer;
|
||||
uint64_t transforms;
|
||||
};
|
||||
|
|
|
@ -14,10 +14,10 @@ details. You should have received a copy of the GNU Lesser General Public
|
|||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
snes_ntsc_setup_t const snes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 1, 0, 0 };
|
||||
snes_ntsc_setup_t const snes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
|
||||
snes_ntsc_setup_t const snes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 1, 0, 0 };
|
||||
snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 1, 0, 0 };
|
||||
snes_ntsc_setup_t const snes_ntsc_monochrome = {0, -1, 0, 0, .2, 0, .2, -.2, -.2, -1, 1, 0, 0};
|
||||
snes_ntsc_setup_t const snes_ntsc_composite = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0};
|
||||
snes_ntsc_setup_t const snes_ntsc_svideo = {0, 0, 0, 0, .2, 0, .2, -1, -1, 0, 1, 0, 0};
|
||||
snes_ntsc_setup_t const snes_ntsc_rgb = {0, 0, 0, 0, .2, 0, .7, -1, -1, -1, 1, 0, 0};
|
||||
|
||||
#define alignment_count 3
|
||||
#define burst_count 3
|
||||
|
@ -34,62 +34,62 @@ snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1
|
|||
#include "snes_ntsc_impl.h"
|
||||
|
||||
/* 3 input pixels -> 8 composite samples */
|
||||
pixel_info_t const snes_ntsc_pixels [alignment_count] = {
|
||||
{ PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } },
|
||||
{ PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } },
|
||||
{ PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } },
|
||||
pixel_info_t const snes_ntsc_pixels[alignment_count] = {
|
||||
{PIXEL_OFFSET(-4, -9), {1, 1, .6667f, 0}},
|
||||
{PIXEL_OFFSET(-2, -7), {.3333f, 1, 1, .3333f}},
|
||||
{PIXEL_OFFSET(0, -5), {0, .6667f, 1, 1}},
|
||||
};
|
||||
|
||||
static void merge_kernel_fields( snes_ntsc_rgb_t* io )
|
||||
static void merge_kernel_fields(snes_ntsc_rgb_t* io)
|
||||
{
|
||||
int n;
|
||||
for ( n = burst_size; n; --n )
|
||||
for (n = burst_size; n; --n)
|
||||
{
|
||||
snes_ntsc_rgb_t p0 = io [burst_size * 0] + rgb_bias;
|
||||
snes_ntsc_rgb_t p1 = io [burst_size * 1] + rgb_bias;
|
||||
snes_ntsc_rgb_t p2 = io [burst_size * 2] + rgb_bias;
|
||||
snes_ntsc_rgb_t p0 = io[burst_size * 0] + rgb_bias;
|
||||
snes_ntsc_rgb_t p1 = io[burst_size * 1] + rgb_bias;
|
||||
snes_ntsc_rgb_t p2 = io[burst_size * 2] + rgb_bias;
|
||||
/* merge colors without losing precision */
|
||||
io [burst_size * 0] =
|
||||
((p0 + p1 - ((p0 ^ p1) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
|
||||
io [burst_size * 1] =
|
||||
((p1 + p2 - ((p1 ^ p2) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
|
||||
io [burst_size * 2] =
|
||||
((p2 + p0 - ((p2 ^ p0) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
|
||||
io[burst_size * 0] =
|
||||
((p0 + p1 - ((p0 ^ p1) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
|
||||
io[burst_size * 1] =
|
||||
((p1 + p2 - ((p1 ^ p2) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
|
||||
io[burst_size * 2] =
|
||||
((p2 + p0 - ((p2 ^ p0) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
|
||||
++io;
|
||||
}
|
||||
}
|
||||
|
||||
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out )
|
||||
static void correct_errors(snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out)
|
||||
{
|
||||
int n;
|
||||
for ( n = burst_count; n; --n )
|
||||
for (n = burst_count; n; --n)
|
||||
{
|
||||
unsigned i;
|
||||
for ( i = 0; i < rgb_kernel_size / 2; i++ )
|
||||
for (i = 0; i < rgb_kernel_size / 2; i++)
|
||||
{
|
||||
snes_ntsc_rgb_t error = color -
|
||||
out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] -
|
||||
out [i + 7] - out [i + 5 +14] - out [i + 3 +28];
|
||||
DISTRIBUTE_ERROR( i+3+28, i+5+14, i+7 );
|
||||
out[i] - out[(i + 12) % 14 + 14] - out[(i + 10) % 14 + 28] -
|
||||
out[i + 7] - out[i + 5 + 14] - out[i + 3 + 28];
|
||||
DISTRIBUTE_ERROR(i+3+28, i+5+14, i+7);
|
||||
}
|
||||
out += alignment_count * rgb_kernel_size;
|
||||
}
|
||||
}
|
||||
|
||||
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup )
|
||||
void snes_ntsc_init(snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup)
|
||||
{
|
||||
int merge_fields;
|
||||
int entry;
|
||||
init_t impl;
|
||||
if ( !setup )
|
||||
if (!setup)
|
||||
setup = &snes_ntsc_composite;
|
||||
init( &impl, setup );
|
||||
init(&impl, setup);
|
||||
|
||||
merge_fields = setup->merge_fields;
|
||||
if ( setup->artifacts <= -1 && setup->fringing <= -1 )
|
||||
if (setup->artifacts <= -1 && setup->fringing <= -1)
|
||||
merge_fields = 1;
|
||||
|
||||
for ( entry = 0; entry < snes_ntsc_palette_size; entry++ )
|
||||
for (entry = 0; entry < snes_ntsc_palette_size; entry++)
|
||||
{
|
||||
/* Reduce number of significant bits of source color. Clearing the
|
||||
low bits of R and B were least notictable. Modifying green was too
|
||||
|
@ -98,7 +98,7 @@ void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup )
|
|||
int ig = entry >> 4 & 0x1F;
|
||||
int ib = entry << 1 & 0x1E;
|
||||
|
||||
#if SNES_NTSC_BSNES_COLORTBL
|
||||
#if SNES_NTSC_BSNES_COLORTBL
|
||||
if ( setup->bsnes_colortbl )
|
||||
{
|
||||
int bgr15 = (ib << 10) | (ig << 5) | ir;
|
||||
|
@ -107,145 +107,145 @@ void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup )
|
|||
ig = rgb16 >> 6 & 0x1F;
|
||||
ib = rgb16 & 0x1E;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
{
|
||||
float rr = impl.to_float [ir];
|
||||
float gg = impl.to_float [ig];
|
||||
float bb = impl.to_float [ib];
|
||||
float rr = impl.to_float[ir];
|
||||
float gg = impl.to_float[ig];
|
||||
float bb = impl.to_float[ib];
|
||||
|
||||
float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i );
|
||||
float y, i, q = RGB_TO_YIQ(rr, gg, bb, y, i);
|
||||
|
||||
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
|
||||
snes_ntsc_rgb_t rgb = PACK_RGB( r, g, b );
|
||||
int r, g, b = YIQ_TO_RGB(y, i, q, impl.to_rgb, int, r, g);
|
||||
snes_ntsc_rgb_t rgb = PACK_RGB(r, g, b);
|
||||
|
||||
snes_ntsc_rgb_t* out = ntsc->table [entry];
|
||||
gen_kernel( &impl, y, i, q, out );
|
||||
if ( merge_fields )
|
||||
merge_kernel_fields( out );
|
||||
correct_errors( rgb, out );
|
||||
snes_ntsc_rgb_t* out = ntsc->table[entry];
|
||||
gen_kernel(&impl, y, i, q, out);
|
||||
if (merge_fields)
|
||||
merge_kernel_fields(out);
|
||||
correct_errors(rgb, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SNES_NTSC_NO_BLITTERS
|
||||
|
||||
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
|
||||
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
|
||||
void snes_ntsc_blit(snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
|
||||
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch)
|
||||
{
|
||||
int chunk_count = (in_width - 1) / snes_ntsc_in_chunk;
|
||||
for ( ; in_height; --in_height )
|
||||
for (; in_height; --in_height)
|
||||
{
|
||||
SNES_NTSC_IN_T const* line_in = input;
|
||||
SNES_NTSC_BEGIN_ROW( ntsc, burst_phase,
|
||||
snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in ) );
|
||||
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
|
||||
SNES_NTSC_BEGIN_ROW(ntsc, burst_phase,
|
||||
snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in ));
|
||||
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*)rgb_out;
|
||||
int n;
|
||||
++line_in;
|
||||
|
||||
for ( n = chunk_count; n; --n )
|
||||
for (n = chunk_count; n; --n)
|
||||
{
|
||||
/* order of input and output pixels must not be altered */
|
||||
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
|
||||
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(0, SNES_NTSC_ADJ_IN( line_in [0] ));
|
||||
SNES_NTSC_RGB_OUT(0, line_out [0], SNES_NTSC_OUT_DEPTH);
|
||||
SNES_NTSC_RGB_OUT(1, line_out [1], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
|
||||
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(1, SNES_NTSC_ADJ_IN( line_in [1] ));
|
||||
SNES_NTSC_RGB_OUT(2, line_out [2], SNES_NTSC_OUT_DEPTH);
|
||||
SNES_NTSC_RGB_OUT(3, line_out [3], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
|
||||
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(2, SNES_NTSC_ADJ_IN( line_in [2] ));
|
||||
SNES_NTSC_RGB_OUT(4, line_out [4], SNES_NTSC_OUT_DEPTH);
|
||||
SNES_NTSC_RGB_OUT(5, line_out [5], SNES_NTSC_OUT_DEPTH);
|
||||
SNES_NTSC_RGB_OUT(6, line_out [6], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
line_in += 3;
|
||||
line_in += 3;
|
||||
line_out += 7;
|
||||
}
|
||||
|
||||
/* finish final pixels */
|
||||
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
|
||||
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(0, snes_ntsc_black);
|
||||
SNES_NTSC_RGB_OUT(0, line_out [0], SNES_NTSC_OUT_DEPTH);
|
||||
SNES_NTSC_RGB_OUT(1, line_out [1], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
|
||||
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(1, snes_ntsc_black);
|
||||
SNES_NTSC_RGB_OUT(2, line_out [2], SNES_NTSC_OUT_DEPTH);
|
||||
SNES_NTSC_RGB_OUT(3, line_out [3], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
|
||||
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(2, snes_ntsc_black);
|
||||
SNES_NTSC_RGB_OUT(4, line_out [4], SNES_NTSC_OUT_DEPTH);
|
||||
SNES_NTSC_RGB_OUT(5, line_out [5], SNES_NTSC_OUT_DEPTH);
|
||||
SNES_NTSC_RGB_OUT(6, line_out [6], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
|
||||
input += in_row_width;
|
||||
rgb_out = (char*) rgb_out + out_pitch;
|
||||
rgb_out = (char*)rgb_out + out_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
|
||||
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
|
||||
void snes_ntsc_blit_hires(snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
|
||||
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch)
|
||||
{
|
||||
int chunk_count = (in_width - 2) / (snes_ntsc_in_chunk * 2);
|
||||
for ( ; in_height; --in_height )
|
||||
for (; in_height; --in_height)
|
||||
{
|
||||
SNES_NTSC_IN_T const* line_in = input;
|
||||
SNES_NTSC_HIRES_ROW( ntsc, burst_phase,
|
||||
snes_ntsc_black, snes_ntsc_black, snes_ntsc_black,
|
||||
SNES_NTSC_ADJ_IN( line_in [0] ),
|
||||
SNES_NTSC_ADJ_IN( line_in [1] ) );
|
||||
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
|
||||
SNES_NTSC_HIRES_ROW(ntsc, burst_phase,
|
||||
snes_ntsc_black, snes_ntsc_black, snes_ntsc_black,
|
||||
SNES_NTSC_ADJ_IN( line_in [0] ),
|
||||
SNES_NTSC_ADJ_IN( line_in [1] ));
|
||||
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*)rgb_out;
|
||||
int n;
|
||||
line_in += 2;
|
||||
|
||||
for ( n = chunk_count; n; --n )
|
||||
for (n = chunk_count; n; --n)
|
||||
{
|
||||
/* twice as many input pixels per chunk */
|
||||
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
|
||||
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(0, SNES_NTSC_ADJ_IN( line_in [0] ));
|
||||
SNES_NTSC_HIRES_OUT(0, line_out [0], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
|
||||
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(1, SNES_NTSC_ADJ_IN( line_in [1] ));
|
||||
SNES_NTSC_HIRES_OUT(1, line_out [1], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
|
||||
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(2, SNES_NTSC_ADJ_IN( line_in [2] ));
|
||||
SNES_NTSC_HIRES_OUT(2, line_out [2], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
SNES_NTSC_COLOR_IN( 3, SNES_NTSC_ADJ_IN( line_in [3] ) );
|
||||
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(3, SNES_NTSC_ADJ_IN( line_in [3] ));
|
||||
SNES_NTSC_HIRES_OUT(3, line_out [3], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
SNES_NTSC_COLOR_IN( 4, SNES_NTSC_ADJ_IN( line_in [4] ) );
|
||||
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(4, SNES_NTSC_ADJ_IN( line_in [4] ));
|
||||
SNES_NTSC_HIRES_OUT(4, line_out [4], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
SNES_NTSC_COLOR_IN( 5, SNES_NTSC_ADJ_IN( line_in [5] ) );
|
||||
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(5, SNES_NTSC_ADJ_IN( line_in [5] ));
|
||||
SNES_NTSC_HIRES_OUT(5, line_out [5], SNES_NTSC_OUT_DEPTH);
|
||||
SNES_NTSC_HIRES_OUT(6, line_out [6], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
line_in += 6;
|
||||
line_in += 6;
|
||||
line_out += 7;
|
||||
}
|
||||
|
||||
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(0, snes_ntsc_black);
|
||||
SNES_NTSC_HIRES_OUT(0, line_out [0], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(1, snes_ntsc_black);
|
||||
SNES_NTSC_HIRES_OUT(1, line_out [1], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(2, snes_ntsc_black);
|
||||
SNES_NTSC_HIRES_OUT(2, line_out [2], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
SNES_NTSC_COLOR_IN( 3, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(3, snes_ntsc_black);
|
||||
SNES_NTSC_HIRES_OUT(3, line_out [3], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
SNES_NTSC_COLOR_IN( 4, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(4, snes_ntsc_black);
|
||||
SNES_NTSC_HIRES_OUT(4, line_out [4], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
SNES_NTSC_COLOR_IN( 5, snes_ntsc_black );
|
||||
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
|
||||
SNES_NTSC_COLOR_IN(5, snes_ntsc_black);
|
||||
SNES_NTSC_HIRES_OUT(5, line_out [5], SNES_NTSC_OUT_DEPTH);
|
||||
SNES_NTSC_HIRES_OUT(6, line_out [6], SNES_NTSC_OUT_DEPTH);
|
||||
|
||||
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
|
||||
input += in_row_width;
|
||||
rgb_out = (char*) rgb_out + out_pitch;
|
||||
rgb_out = (char*)rgb_out + out_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "snes_ntsc_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
|
||||
|
@ -15,19 +15,19 @@ in parenthesis and should remain fairly stable in future versions. */
|
|||
typedef struct snes_ntsc_setup_t
|
||||
{
|
||||
/* Basic parameters */
|
||||
double hue; /* -1 = -180 degrees +1 = +180 degrees */
|
||||
double hue; /* -1 = -180 degrees +1 = +180 degrees */
|
||||
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
|
||||
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
|
||||
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
|
||||
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
|
||||
double sharpness; /* edge contrast enhancement/blurring */
|
||||
double sharpness; /* edge contrast enhancement/blurring */
|
||||
|
||||
/* Advanced parameters */
|
||||
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
|
||||
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
|
||||
double resolution; /* image resolution */
|
||||
double artifacts; /* artifacts caused by color changes */
|
||||
double fringing; /* color artifacts caused by brightness changes */
|
||||
double bleed; /* color bleed (color resolution reduction) */
|
||||
int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */
|
||||
double artifacts; /* artifacts caused by color changes */
|
||||
double fringing; /* color artifacts caused by brightness changes */
|
||||
double bleed; /* color bleed (color resolution reduction) */
|
||||
int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */
|
||||
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
|
||||
|
||||
unsigned long const* bsnes_colortbl; /* undocumented; set to 0 */
|
||||
|
@ -35,26 +35,26 @@ typedef struct snes_ntsc_setup_t
|
|||
|
||||
/* Video format presets */
|
||||
extern snes_ntsc_setup_t const snes_ntsc_composite; /* color bleeding + artifacts */
|
||||
extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */
|
||||
extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */
|
||||
extern snes_ntsc_setup_t const snes_ntsc_monochrome;/* desaturated + artifacts */
|
||||
extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */
|
||||
extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */
|
||||
extern snes_ntsc_setup_t const snes_ntsc_monochrome; /* desaturated + artifacts */
|
||||
|
||||
/* Initializes and adjusts parameters. Can be called multiple times on the same
|
||||
snes_ntsc_t object. Can pass NULL for either parameter. */
|
||||
typedef struct snes_ntsc_t snes_ntsc_t;
|
||||
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup );
|
||||
void snes_ntsc_init(snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup);
|
||||
|
||||
/* Filters one or more rows of pixels. Input pixel format is set by SNES_NTSC_IN_FORMAT
|
||||
and output RGB depth is set by SNES_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
|
||||
In_row_width is the number of pixels to get to the next input row. Out_pitch
|
||||
is the number of *bytes* to get to the next output row. */
|
||||
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
|
||||
long in_row_width, int burst_phase, int in_width, int in_height,
|
||||
void* rgb_out, long out_pitch );
|
||||
void snes_ntsc_blit(snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
|
||||
long in_row_width, int burst_phase, int in_width, int in_height,
|
||||
void* rgb_out, long out_pitch);
|
||||
|
||||
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
|
||||
long in_row_width, int burst_phase, int in_width, int in_height,
|
||||
void* rgb_out, long out_pitch );
|
||||
void snes_ntsc_blit_hires(snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
|
||||
long in_row_width, int burst_phase, int in_width, int in_height,
|
||||
void* rgb_out, long out_pitch);
|
||||
|
||||
/* Number of output pixels written by low-res blitter for given input width. Width
|
||||
might be rounded down slightly; use SNES_NTSC_IN_WIDTH() on result to find rounded
|
||||
|
@ -71,10 +71,10 @@ value. */
|
|||
|
||||
/* Interface for user-defined custom blitters */
|
||||
|
||||
enum { snes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */
|
||||
enum { snes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
|
||||
enum { snes_ntsc_black = 0 }; /* palette index for black */
|
||||
enum { snes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */
|
||||
enum { snes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */
|
||||
enum { snes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
|
||||
enum { snes_ntsc_black = 0 }; /* palette index for black */
|
||||
enum { snes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */
|
||||
|
||||
/* Begins outputting row and starts three pixels. First pixel will be cut off a bit.
|
||||
Use snes_ntsc_black for unused pixels. Declares variables, so must be before first
|
||||
|
@ -132,11 +132,16 @@ statement in a block (unless you're using C++). */
|
|||
|
||||
/* private */
|
||||
enum { snes_ntsc_entry_size = 128 };
|
||||
|
||||
enum { snes_ntsc_palette_size = 0x2000 };
|
||||
|
||||
typedef unsigned long snes_ntsc_rgb_t;
|
||||
struct snes_ntsc_t {
|
||||
snes_ntsc_rgb_t table [snes_ntsc_palette_size] [snes_ntsc_entry_size];
|
||||
|
||||
struct snes_ntsc_t
|
||||
{
|
||||
snes_ntsc_rgb_t table[snes_ntsc_palette_size][snes_ntsc_entry_size];
|
||||
};
|
||||
|
||||
enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count };
|
||||
|
||||
#define SNES_NTSC_RGB16( ktable, n ) \
|
||||
|
@ -200,7 +205,7 @@ enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count };
|
|||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,7 +22,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|||
#define PI 3.14159265358979323846f
|
||||
|
||||
#ifndef LUMA_CUTOFF
|
||||
#define LUMA_CUTOFF 0.20
|
||||
#define LUMA_CUTOFF 0.20
|
||||
#endif
|
||||
#ifndef gamma_size
|
||||
#define gamma_size 1
|
||||
|
@ -31,32 +31,34 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|||
#define rgb_bits 8
|
||||
#endif
|
||||
#ifndef artifacts_max
|
||||
#define artifacts_max (artifacts_mid * 1.5f)
|
||||
#define artifacts_max (artifacts_mid * 1.5f)
|
||||
#endif
|
||||
#ifndef fringing_max
|
||||
#define fringing_max (fringing_mid * 2)
|
||||
#define fringing_max (fringing_mid * 2)
|
||||
#endif
|
||||
#ifndef STD_HUE_CONDITION
|
||||
#define STD_HUE_CONDITION( setup ) 1
|
||||
#define STD_HUE_CONDITION( setup ) 1
|
||||
#endif
|
||||
|
||||
#define ext_decoder_hue (std_decoder_hue + 15)
|
||||
#define rgb_unit (1 << rgb_bits)
|
||||
#define rgb_offset (rgb_unit * 2 + 0.5f)
|
||||
|
||||
enum { burst_size = snes_ntsc_entry_size / burst_count };
|
||||
enum { burst_size = snes_ntsc_entry_size / burst_count };
|
||||
|
||||
enum { kernel_half = 16 };
|
||||
|
||||
enum { kernel_size = kernel_half * 2 + 1 };
|
||||
|
||||
typedef struct init_t
|
||||
{
|
||||
float to_rgb [burst_count * 6];
|
||||
float to_float [gamma_size];
|
||||
float to_rgb[burst_count * 6];
|
||||
float to_float[gamma_size];
|
||||
float contrast;
|
||||
float brightness;
|
||||
float artifacts;
|
||||
float fringing;
|
||||
float kernel [rescale_out * kernel_size * 2];
|
||||
float kernel[rescale_out * kernel_size * 2];
|
||||
} init_t;
|
||||
|
||||
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\
|
||||
|
@ -66,10 +68,10 @@ typedef struct init_t
|
|||
i = t;\
|
||||
}
|
||||
|
||||
static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup )
|
||||
static void init_filters(init_t* impl, snes_ntsc_setup_t const* setup)
|
||||
{
|
||||
#if rescale_out > 1
|
||||
float kernels [kernel_size * 2];
|
||||
float kernels[kernel_size * 2];
|
||||
#else
|
||||
float* const kernels = impl->kernel;
|
||||
#endif
|
||||
|
@ -77,59 +79,59 @@ static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup )
|
|||
/* generate luma (y) filter using sinc kernel */
|
||||
{
|
||||
/* sinc with rolloff (dsf) */
|
||||
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
|
||||
float const rolloff = 1 + (float)setup->sharpness * (float)0.032;
|
||||
float const maxh = 32;
|
||||
float const pow_a_n = (float) pow( rolloff, maxh );
|
||||
float const pow_a_n = (float)pow(rolloff, maxh);
|
||||
float sum;
|
||||
int i;
|
||||
/* quadratic mapping to reduce negative (blurring) range */
|
||||
float to_angle = (float) setup->resolution + 1;
|
||||
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
|
||||
float to_angle = (float)setup->resolution + 1;
|
||||
to_angle = PI / maxh * (float)LUMA_CUTOFF * (to_angle * to_angle + 1);
|
||||
|
||||
kernels [kernel_size * 3 / 2] = maxh; /* default center value */
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
kernels[kernel_size * 3 / 2] = maxh; /* default center value */
|
||||
for (i = 0; i < kernel_half * 2 + 1; i++)
|
||||
{
|
||||
int x = i - kernel_half;
|
||||
float angle = x * to_angle;
|
||||
/* instability occurs at center point with rolloff very close to 1.0 */
|
||||
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
|
||||
if (x || pow_a_n > (float)1.056 || pow_a_n < (float)0.981)
|
||||
{
|
||||
float rolloff_cos_a = rolloff * (float) cos( angle );
|
||||
float rolloff_cos_a = rolloff * (float)cos(angle);
|
||||
float num = 1 - rolloff_cos_a -
|
||||
pow_a_n * (float) cos( maxh * angle ) +
|
||||
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
|
||||
pow_a_n * (float)cos(maxh * angle) +
|
||||
pow_a_n * rolloff * (float)cos((maxh - 1) * angle);
|
||||
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
|
||||
float dsf = num / den;
|
||||
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
|
||||
kernels[kernel_size * 3 / 2 - kernel_half + i] = dsf - (float)0.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* apply blackman window and find sum */
|
||||
sum = 0;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
for (i = 0; i < kernel_half * 2 + 1; i++)
|
||||
{
|
||||
float x = PI * 2 / (kernel_half * 2) * i;
|
||||
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
|
||||
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
|
||||
float blackman = 0.42f - 0.5f * (float)cos(x) + 0.08f * (float)cos(x * 2);
|
||||
sum += (kernels[kernel_size * 3 / 2 - kernel_half + i] *= blackman);
|
||||
}
|
||||
|
||||
/* normalize kernel */
|
||||
sum = 1.0f / sum;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
for (i = 0; i < kernel_half * 2 + 1; i++)
|
||||
{
|
||||
int x = kernel_size * 3 / 2 - kernel_half + i;
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
kernels[x] *= sum;
|
||||
assert(kernels [x] == kernels [x]); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
|
||||
/* generate chroma (iq) filter using gaussian kernel */
|
||||
{
|
||||
float const cutoff_factor = -0.03125f;
|
||||
float cutoff = (float) setup->bleed;
|
||||
float cutoff = (float)setup->bleed;
|
||||
int i;
|
||||
|
||||
if ( cutoff < 0 )
|
||||
if (cutoff < 0)
|
||||
{
|
||||
/* keep extreme value accessible only near upper end of scale (1.0) */
|
||||
cutoff *= cutoff;
|
||||
|
@ -139,22 +141,22 @@ static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup )
|
|||
}
|
||||
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
|
||||
|
||||
for ( i = -kernel_half; i <= kernel_half; i++ )
|
||||
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
|
||||
for (i = -kernel_half; i <= kernel_half; i++)
|
||||
kernels[kernel_size / 2 + i] = (float)exp(i * i * cutoff);
|
||||
|
||||
/* normalize even and odd phases separately */
|
||||
for ( i = 0; i < 2; i++ )
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
float sum = 0;
|
||||
int x;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
sum += kernels [x];
|
||||
for (x = i; x < kernel_size; x += 2)
|
||||
sum += kernels[x];
|
||||
|
||||
sum = 1.0f / sum;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
for (x = i; x < kernel_size; x += 2)
|
||||
{
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
kernels[x] *= sum;
|
||||
assert(kernels [x] == kernels [x]); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -169,7 +171,7 @@ static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup )
|
|||
*/
|
||||
|
||||
/* generate linear rescale kernels */
|
||||
#if rescale_out > 1
|
||||
#if rescale_out > 1
|
||||
{
|
||||
float weight = 1.0f;
|
||||
float* out = impl->kernel;
|
||||
|
@ -179,70 +181,70 @@ static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup )
|
|||
float remain = 0;
|
||||
int i;
|
||||
weight -= 1.0f / rescale_in;
|
||||
for ( i = 0; i < kernel_size * 2; i++ )
|
||||
for (i = 0; i < kernel_size * 2; i++)
|
||||
{
|
||||
float cur = kernels [i];
|
||||
float cur = kernels[i];
|
||||
float m = cur * weight;
|
||||
*out++ = m + remain;
|
||||
remain = cur - m;
|
||||
}
|
||||
}
|
||||
while ( --n );
|
||||
while (--n);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static float const default_decoder [6] =
|
||||
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
|
||||
static float const default_decoder[6] =
|
||||
{0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f};
|
||||
|
||||
static void init( init_t* impl, snes_ntsc_setup_t const* setup )
|
||||
static void init(init_t* impl, snes_ntsc_setup_t const* setup)
|
||||
{
|
||||
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
|
||||
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
|
||||
#ifdef default_palette_contrast
|
||||
impl->brightness = (float)setup->brightness * (0.5f * rgb_unit) + rgb_offset;
|
||||
impl->contrast = (float)setup->contrast * (0.5f * rgb_unit) + rgb_unit;
|
||||
#ifdef default_palette_contrast
|
||||
if ( !setup->palette )
|
||||
impl->contrast *= default_palette_contrast;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
impl->artifacts = (float) setup->artifacts;
|
||||
if ( impl->artifacts > 0 )
|
||||
impl->artifacts = (float)setup->artifacts;
|
||||
if (impl->artifacts > 0)
|
||||
impl->artifacts *= artifacts_max - artifacts_mid;
|
||||
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
|
||||
|
||||
impl->fringing = (float) setup->fringing;
|
||||
if ( impl->fringing > 0 )
|
||||
impl->fringing = (float)setup->fringing;
|
||||
if (impl->fringing > 0)
|
||||
impl->fringing *= fringing_max - fringing_mid;
|
||||
impl->fringing = impl->fringing * fringing_mid + fringing_mid;
|
||||
|
||||
init_filters( impl, setup );
|
||||
init_filters(impl, setup);
|
||||
|
||||
/* generate gamma table */
|
||||
if ( gamma_size > 1 )
|
||||
if (gamma_size > 1)
|
||||
{
|
||||
float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
|
||||
float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
|
||||
float const gamma = 1.1333f - (float)setup->gamma * 0.5f;
|
||||
/* match common PC's 2.2 gamma to TV's 2.65 gamma */
|
||||
int i;
|
||||
for ( i = 0; i < gamma_size; i++ )
|
||||
impl->to_float [i] =
|
||||
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
|
||||
for (i = 0; i < gamma_size; i++)
|
||||
impl->to_float[i] =
|
||||
(float)pow(i * to_float, gamma) * impl->contrast + impl->brightness;
|
||||
}
|
||||
|
||||
/* setup decoder matricies */
|
||||
{
|
||||
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue;
|
||||
float sat = (float) setup->saturation + 1;
|
||||
float hue = (float)setup->hue * PI + PI / 180 * ext_decoder_hue;
|
||||
float sat = (float)setup->saturation + 1;
|
||||
float const* decoder = setup->decoder_matrix;
|
||||
if ( !decoder )
|
||||
if (!decoder)
|
||||
{
|
||||
decoder = default_decoder;
|
||||
if ( STD_HUE_CONDITION( setup ) )
|
||||
if (STD_HUE_CONDITION(setup))
|
||||
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
|
||||
}
|
||||
|
||||
{
|
||||
float s = (float) sin( hue ) * sat;
|
||||
float c = (float) cos( hue ) * sat;
|
||||
float s = (float)sin(hue) * sat;
|
||||
float c = (float)cos(hue) * sat;
|
||||
float* out = impl->to_rgb;
|
||||
int n;
|
||||
|
||||
|
@ -258,12 +260,12 @@ static void init( init_t* impl, snes_ntsc_setup_t const* setup )
|
|||
*out++ = i * c - q * s;
|
||||
*out++ = i * s + q * c;
|
||||
}
|
||||
while ( --n );
|
||||
if ( burst_count <= 1 )
|
||||
while (--n);
|
||||
if (burst_count <= 1)
|
||||
break;
|
||||
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
|
||||
ROTATE_IQ(s, c, 0.866025f, -0.5f); /* +120 degrees */
|
||||
}
|
||||
while ( --n );
|
||||
while (--n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -285,21 +287,22 @@ static void init( init_t* impl, snes_ntsc_setup_t const* setup )
|
|||
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
|
||||
|
||||
enum { rgb_kernel_size = burst_size / alignment_count };
|
||||
|
||||
enum { rgb_bias = rgb_unit * 2 * snes_ntsc_rgb_builder };
|
||||
|
||||
typedef struct pixel_info_t
|
||||
{
|
||||
int offset;
|
||||
float negate;
|
||||
float kernel [4];
|
||||
float kernel[4];
|
||||
} pixel_info_t;
|
||||
|
||||
#if rescale_in > 1
|
||||
#define PIXEL_OFFSET_( ntsc, scaled ) \
|
||||
#define PIXEL_OFFSET_( ntsc, scaled ) \
|
||||
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
|
||||
(kernel_size * 2 * scaled))
|
||||
|
||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
||||
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
|
||||
(((scaled) + rescale_out * 10) % rescale_out) ),\
|
||||
(1.0f - (((ntsc) + 100) & 2))
|
||||
|
@ -309,10 +312,10 @@ typedef struct pixel_info_t
|
|||
(1.0f - (((ntsc) + 100) & 2))
|
||||
#endif
|
||||
|
||||
extern pixel_info_t const snes_ntsc_pixels [alignment_count];
|
||||
extern pixel_info_t const snes_ntsc_pixels[alignment_count];
|
||||
|
||||
/* Generate pixel at all burst phases and column alignments */
|
||||
static void gen_kernel( init_t* impl, float y, float i, float q, snes_ntsc_rgb_t* out )
|
||||
static void gen_kernel(init_t* impl, float y, float i, float q, snes_ntsc_rgb_t* out)
|
||||
{
|
||||
/* generate for each scanline burst phase */
|
||||
float const* to_rgb = impl->to_rgb;
|
||||
|
@ -330,61 +333,61 @@ static void gen_kernel( init_t* impl, float y, float i, float q, snes_ntsc_rgb_t
|
|||
{
|
||||
/* negate is -1 when composite starts at odd multiple of 2 */
|
||||
float const yy = y * impl->fringing * pixel->negate;
|
||||
float const ic0 = (i + yy) * pixel->kernel [0];
|
||||
float const qc1 = (q + yy) * pixel->kernel [1];
|
||||
float const ic2 = (i - yy) * pixel->kernel [2];
|
||||
float const qc3 = (q - yy) * pixel->kernel [3];
|
||||
float const ic0 = (i + yy) * pixel->kernel[0];
|
||||
float const qc1 = (q + yy) * pixel->kernel[1];
|
||||
float const ic2 = (i - yy) * pixel->kernel[2];
|
||||
float const qc3 = (q - yy) * pixel->kernel[3];
|
||||
|
||||
float const factor = impl->artifacts * pixel->negate;
|
||||
float const ii = i * factor;
|
||||
float const yc0 = (y + ii) * pixel->kernel [0];
|
||||
float const yc2 = (y - ii) * pixel->kernel [2];
|
||||
float const yc0 = (y + ii) * pixel->kernel[0];
|
||||
float const yc2 = (y - ii) * pixel->kernel[2];
|
||||
|
||||
float const qq = q * factor;
|
||||
float const yc1 = (y + qq) * pixel->kernel [1];
|
||||
float const yc3 = (y - qq) * pixel->kernel [3];
|
||||
float const yc1 = (y + qq) * pixel->kernel[1];
|
||||
float const yc3 = (y - qq) * pixel->kernel[3];
|
||||
|
||||
float const* k = &impl->kernel [pixel->offset];
|
||||
float const* k = &impl->kernel[pixel->offset];
|
||||
int n;
|
||||
++pixel;
|
||||
for ( n = rgb_kernel_size; n; --n )
|
||||
for (n = rgb_kernel_size; n; --n)
|
||||
{
|
||||
float i = k[0]*ic0 + k[2]*ic2;
|
||||
float q = k[1]*qc1 + k[3]*qc3;
|
||||
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
|
||||
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
|
||||
if ( rescale_out <= 1 )
|
||||
float i = k[0] * ic0 + k[2] * ic2;
|
||||
float q = k[1] * qc1 + k[3] * qc3;
|
||||
float y = k[kernel_size + 0] * yc0 + k[kernel_size + 1] * yc1 +
|
||||
k[kernel_size + 2] * yc2 + k[kernel_size + 3] * yc3 + rgb_offset;
|
||||
if (rescale_out <= 1)
|
||||
k--;
|
||||
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
|
||||
else if (k < &impl->kernel[kernel_size * 2 * (rescale_out - 1)])
|
||||
k += kernel_size * 2 - 1;
|
||||
else
|
||||
k -= kernel_size * 2 * (rescale_out - 1) + 2;
|
||||
{
|
||||
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
|
||||
*out++ = PACK_RGB( r, g, b ) - rgb_bias;
|
||||
int r, g, b = YIQ_TO_RGB(y, i, q, to_rgb, int, r, g);
|
||||
*out++ = PACK_RGB(r, g, b) - rgb_bias;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ( alignment_count > 1 && --alignment_remain );
|
||||
while (alignment_count > 1 && --alignment_remain);
|
||||
|
||||
if ( burst_count <= 1 )
|
||||
if (burst_count <= 1)
|
||||
break;
|
||||
|
||||
to_rgb += 6;
|
||||
|
||||
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
|
||||
ROTATE_IQ(i, q, -0.866025f, -0.5f); /* -120 degrees */
|
||||
}
|
||||
while ( --burst_remain );
|
||||
while (--burst_remain);
|
||||
}
|
||||
|
||||
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out );
|
||||
static void correct_errors(snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out);
|
||||
|
||||
#if DISABLE_CORRECTION
|
||||
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; }
|
||||
#else
|
||||
#define CORRECT_ERROR( a ) { out [a] += error; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) {\
|
||||
#define CORRECT_ERROR( a ) { out [a] += error; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) {\
|
||||
snes_ntsc_rgb_t fourth = (error + 2 * snes_ntsc_rgb_builder) >> 2;\
|
||||
fourth &= (rgb_bias >> 1) - snes_ntsc_rgb_builder;\
|
||||
fourth -= rgb_bias >> 2;\
|
||||
|
@ -408,32 +411,32 @@ static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out );
|
|||
/* blitter related */
|
||||
|
||||
#ifndef restrict
|
||||
#if defined (__GNUC__)
|
||||
#if defined (__GNUC__)
|
||||
#define restrict __restrict__
|
||||
#elif defined (_MSC_VER) && _MSC_VER > 1300
|
||||
#define restrict __restrict
|
||||
#else
|
||||
#elif defined (_MSC_VER) && _MSC_VER > 1300
|
||||
#define restrict __restrict
|
||||
#else
|
||||
/* no support for restricted pointers */
|
||||
#define restrict
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#if SNES_NTSC_OUT_DEPTH <= 16
|
||||
#if USHRT_MAX == 0xFFFF
|
||||
#if USHRT_MAX == 0xFFFF
|
||||
typedef unsigned short snes_ntsc_out_t;
|
||||
#else
|
||||
#else
|
||||
#error "Need 16-bit int type"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
#if UINT_MAX == 0xFFFFFFFF
|
||||
typedef unsigned int snes_ntsc_out_t;
|
||||
#elif ULONG_MAX == 0xFFFFFFFF
|
||||
#if UINT_MAX == 0xFFFFFFFF
|
||||
typedef unsigned int snes_ntsc_out_t;
|
||||
#elif ULONG_MAX == 0xFFFFFFFF
|
||||
typedef unsigned long snes_ntsc_out_t;
|
||||
#else
|
||||
#else
|
||||
#error "Need 32-bit int type"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,307 +18,316 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/////////// THREAD SAFETY
|
||||
/////////// THREAD SAFETY
|
||||
|
||||
// Individual stb_vorbis* handles are not thread-safe; you cannot decode from
|
||||
// them from multiple threads at the same time. However, you can have multiple
|
||||
// stb_vorbis* handles and decode from them independently in multiple thrads.
|
||||
// Individual stb_vorbis* handles are not thread-safe; you cannot decode from
|
||||
// them from multiple threads at the same time. However, you can have multiple
|
||||
// stb_vorbis* handles and decode from them independently in multiple thrads.
|
||||
|
||||
|
||||
/////////// MEMORY ALLOCATION
|
||||
/////////// MEMORY ALLOCATION
|
||||
|
||||
// normally stb_vorbis uses malloc() to allocate memory at startup,
|
||||
// and alloca() to allocate temporary memory during a frame on the
|
||||
// stack. (Memory consumption will depend on the amount of setup
|
||||
// data in the file and how you set the compile flags for speed
|
||||
// vs. size. In my test files the maximal-size usage is ~150KB.)
|
||||
//
|
||||
// You can modify the wrapper functions in the source (setup_malloc,
|
||||
// setup_temp_malloc, temp_malloc) to change this behavior, or you
|
||||
// can use a simpler allocation model: you pass in a buffer from
|
||||
// which stb_vorbis will allocate _all_ its memory (including the
|
||||
// temp memory). "open" may fail with a VORBIS_outofmem if you
|
||||
// do not pass in enough data; there is no way to determine how
|
||||
// much you do need except to succeed (at which point you can
|
||||
// query get_info to find the exact amount required. yes I know
|
||||
// this is lame).
|
||||
//
|
||||
// If you pass in a non-NULL buffer of the type below, allocation
|
||||
// will occur from it as described above. Otherwise just pass NULL
|
||||
// to use malloc()/alloca()
|
||||
// normally stb_vorbis uses malloc() to allocate memory at startup,
|
||||
// and alloca() to allocate temporary memory during a frame on the
|
||||
// stack. (Memory consumption will depend on the amount of setup
|
||||
// data in the file and how you set the compile flags for speed
|
||||
// vs. size. In my test files the maximal-size usage is ~150KB.)
|
||||
//
|
||||
// You can modify the wrapper functions in the source (setup_malloc,
|
||||
// setup_temp_malloc, temp_malloc) to change this behavior, or you
|
||||
// can use a simpler allocation model: you pass in a buffer from
|
||||
// which stb_vorbis will allocate _all_ its memory (including the
|
||||
// temp memory). "open" may fail with a VORBIS_outofmem if you
|
||||
// do not pass in enough data; there is no way to determine how
|
||||
// much you do need except to succeed (at which point you can
|
||||
// query get_info to find the exact amount required. yes I know
|
||||
// this is lame).
|
||||
//
|
||||
// If you pass in a non-NULL buffer of the type below, allocation
|
||||
// will occur from it as described above. Otherwise just pass NULL
|
||||
// to use malloc()/alloca()
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *alloc_buffer;
|
||||
int alloc_buffer_length_in_bytes;
|
||||
} stb_vorbis_alloc;
|
||||
typedef struct
|
||||
{
|
||||
char* alloc_buffer;
|
||||
int alloc_buffer_length_in_bytes;
|
||||
} stb_vorbis_alloc;
|
||||
|
||||
|
||||
/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES
|
||||
/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES
|
||||
|
||||
typedef struct stb_vorbis stb_vorbis;
|
||||
typedef struct stb_vorbis stb_vorbis;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int sample_rate;
|
||||
int channels;
|
||||
typedef struct
|
||||
{
|
||||
unsigned int sample_rate;
|
||||
int channels;
|
||||
|
||||
unsigned int setup_memory_required;
|
||||
unsigned int setup_temp_memory_required;
|
||||
unsigned int temp_memory_required;
|
||||
unsigned int setup_memory_required;
|
||||
unsigned int setup_temp_memory_required;
|
||||
unsigned int temp_memory_required;
|
||||
|
||||
int max_frame_size;
|
||||
} stb_vorbis_info;
|
||||
int max_frame_size;
|
||||
} stb_vorbis_info;
|
||||
|
||||
// get general information about the file
|
||||
extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f);
|
||||
// get general information about the file
|
||||
extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis* f);
|
||||
|
||||
// get the last error detected (clears it, too)
|
||||
extern int stb_vorbis_get_error(stb_vorbis *f);
|
||||
// get the last error detected (clears it, too)
|
||||
extern int stb_vorbis_get_error(stb_vorbis* f);
|
||||
|
||||
// close an ogg vorbis file and free all memory in use
|
||||
extern void stb_vorbis_close(stb_vorbis *f);
|
||||
// close an ogg vorbis file and free all memory in use
|
||||
extern void stb_vorbis_close(stb_vorbis* f);
|
||||
|
||||
// this function returns the offset (in samples) from the beginning of the
|
||||
// file that will be returned by the next decode, if it is known, or -1
|
||||
// otherwise. after a flush_pushdata() call, this may take a while before
|
||||
// it becomes valid again.
|
||||
// NOT WORKING YET after a seek with PULLDATA API
|
||||
extern int stb_vorbis_get_sample_offset(stb_vorbis *f);
|
||||
// this function returns the offset (in samples) from the beginning of the
|
||||
// file that will be returned by the next decode, if it is known, or -1
|
||||
// otherwise. after a flush_pushdata() call, this may take a while before
|
||||
// it becomes valid again.
|
||||
// NOT WORKING YET after a seek with PULLDATA API
|
||||
extern int stb_vorbis_get_sample_offset(stb_vorbis* f);
|
||||
|
||||
// returns the current seek point within the file, or offset from the beginning
|
||||
// of the memory buffer. In pushdata mode it returns 0.
|
||||
extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);
|
||||
// returns the current seek point within the file, or offset from the beginning
|
||||
// of the memory buffer. In pushdata mode it returns 0.
|
||||
extern unsigned int stb_vorbis_get_file_offset(stb_vorbis* f);
|
||||
|
||||
/////////// PUSHDATA API
|
||||
/////////// PUSHDATA API
|
||||
|
||||
#ifndef STB_VORBIS_NO_PUSHDATA_API
|
||||
|
||||
// this API allows you to get blocks of data from any source and hand
|
||||
// them to stb_vorbis. you have to buffer them; stb_vorbis will tell
|
||||
// you how much it used, and you have to give it the rest next time;
|
||||
// and stb_vorbis may not have enough data to work with and you will
|
||||
// need to give it the same data again PLUS more. Note that the Vorbis
|
||||
// specification does not bound the size of an individual frame.
|
||||
// this API allows you to get blocks of data from any source and hand
|
||||
// them to stb_vorbis. you have to buffer them; stb_vorbis will tell
|
||||
// you how much it used, and you have to give it the rest next time;
|
||||
// and stb_vorbis may not have enough data to work with and you will
|
||||
// need to give it the same data again PLUS more. Note that the Vorbis
|
||||
// specification does not bound the size of an individual frame.
|
||||
|
||||
extern stb_vorbis *stb_vorbis_open_pushdata(
|
||||
const unsigned char * datablock, int datablock_length_in_bytes,
|
||||
int *datablock_memory_consumed_in_bytes,
|
||||
int *error,
|
||||
const stb_vorbis_alloc *alloc_buffer);
|
||||
// create a vorbis decoder by passing in the initial data block containing
|
||||
// the ogg&vorbis headers (you don't need to do parse them, just provide
|
||||
// the first N bytes of the file--you're told if it's not enough, see below)
|
||||
// on success, returns an stb_vorbis *, does not set error, returns the amount of
|
||||
// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes;
|
||||
// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed
|
||||
// if returns NULL and *error is VORBIS_need_more_data, then the input block was
|
||||
// incomplete and you need to pass in a larger block from the start of the file
|
||||
extern stb_vorbis* stb_vorbis_open_pushdata(
|
||||
const unsigned char* datablock, int datablock_length_in_bytes,
|
||||
int* datablock_memory_consumed_in_bytes,
|
||||
int* error,
|
||||
const stb_vorbis_alloc* alloc_buffer);
|
||||
// create a vorbis decoder by passing in the initial data block containing
|
||||
// the ogg&vorbis headers (you don't need to do parse them, just provide
|
||||
// the first N bytes of the file--you're told if it's not enough, see below)
|
||||
// on success, returns an stb_vorbis *, does not set error, returns the amount of
|
||||
// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes;
|
||||
// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed
|
||||
// if returns NULL and *error is VORBIS_need_more_data, then the input block was
|
||||
// incomplete and you need to pass in a larger block from the start of the file
|
||||
|
||||
extern int stb_vorbis_decode_frame_pushdata(
|
||||
stb_vorbis *f,
|
||||
const unsigned char *datablock, int datablock_length_in_bytes,
|
||||
int *channels, // place to write number of float * buffers
|
||||
float ***output, // place to write float ** array of float * buffers
|
||||
int *samples // place to write number of output samples
|
||||
);
|
||||
// decode a frame of audio sample data if possible from the passed-in data block
|
||||
//
|
||||
// return value: number of bytes we used from datablock
|
||||
//
|
||||
// possible cases:
|
||||
// 0 bytes used, 0 samples output (need more data)
|
||||
// N bytes used, 0 samples output (resynching the stream, keep going)
|
||||
// N bytes used, M samples output (one frame of data)
|
||||
// note that after opening a file, you will ALWAYS get one N-bytes,0-sample
|
||||
// frame, because Vorbis always "discards" the first frame.
|
||||
//
|
||||
// Note that on resynch, stb_vorbis will rarely consume all of the buffer,
|
||||
// instead only datablock_length_in_bytes-3 or less. This is because it wants
|
||||
// to avoid missing parts of a page header if they cross a datablock boundary,
|
||||
// without writing state-machiney code to record a partial detection.
|
||||
//
|
||||
// The number of channels returned are stored in *channels (which can be
|
||||
// NULL--it is always the same as the number of channels reported by
|
||||
// get_info). *output will contain an array of float* buffers, one per
|
||||
// channel. In other words, (*output)[0][0] contains the first sample from
|
||||
// the first channel, and (*output)[1][0] contains the first sample from
|
||||
// the second channel.
|
||||
extern int stb_vorbis_decode_frame_pushdata(
|
||||
stb_vorbis* f,
|
||||
const unsigned char* datablock, int datablock_length_in_bytes,
|
||||
int* channels, // place to write number of float * buffers
|
||||
float*** output, // place to write float ** array of float * buffers
|
||||
int* samples // place to write number of output samples
|
||||
);
|
||||
// decode a frame of audio sample data if possible from the passed-in data block
|
||||
//
|
||||
// return value: number of bytes we used from datablock
|
||||
//
|
||||
// possible cases:
|
||||
// 0 bytes used, 0 samples output (need more data)
|
||||
// N bytes used, 0 samples output (resynching the stream, keep going)
|
||||
// N bytes used, M samples output (one frame of data)
|
||||
// note that after opening a file, you will ALWAYS get one N-bytes,0-sample
|
||||
// frame, because Vorbis always "discards" the first frame.
|
||||
//
|
||||
// Note that on resynch, stb_vorbis will rarely consume all of the buffer,
|
||||
// instead only datablock_length_in_bytes-3 or less. This is because it wants
|
||||
// to avoid missing parts of a page header if they cross a datablock boundary,
|
||||
// without writing state-machiney code to record a partial detection.
|
||||
//
|
||||
// The number of channels returned are stored in *channels (which can be
|
||||
// NULL--it is always the same as the number of channels reported by
|
||||
// get_info). *output will contain an array of float* buffers, one per
|
||||
// channel. In other words, (*output)[0][0] contains the first sample from
|
||||
// the first channel, and (*output)[1][0] contains the first sample from
|
||||
// the second channel.
|
||||
|
||||
extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
|
||||
// inform stb_vorbis that your next datablock will not be contiguous with
|
||||
// previous ones (e.g. you've seeked in the data); future attempts to decode
|
||||
// frames will cause stb_vorbis to resynchronize (as noted above), and
|
||||
// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it
|
||||
// will begin decoding the _next_ frame.
|
||||
//
|
||||
// if you want to seek using pushdata, you need to seek in your file, then
|
||||
// call stb_vorbis_flush_pushdata(), then start calling decoding, then once
|
||||
// decoding is returning you data, call stb_vorbis_get_sample_offset, and
|
||||
// if you don't like the result, seek your file again and repeat.
|
||||
extern void stb_vorbis_flush_pushdata(stb_vorbis* f);
|
||||
// inform stb_vorbis that your next datablock will not be contiguous with
|
||||
// previous ones (e.g. you've seeked in the data); future attempts to decode
|
||||
// frames will cause stb_vorbis to resynchronize (as noted above), and
|
||||
// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it
|
||||
// will begin decoding the _next_ frame.
|
||||
//
|
||||
// if you want to seek using pushdata, you need to seek in your file, then
|
||||
// call stb_vorbis_flush_pushdata(), then start calling decoding, then once
|
||||
// decoding is returning you data, call stb_vorbis_get_sample_offset, and
|
||||
// if you don't like the result, seek your file again and repeat.
|
||||
#endif
|
||||
|
||||
|
||||
////////// PULLING INPUT API
|
||||
////////// PULLING INPUT API
|
||||
|
||||
#ifndef STB_VORBIS_NO_PULLDATA_API
|
||||
// This API assumes stb_vorbis is allowed to pull data from a source--
|
||||
// either a block of memory containing the _entire_ vorbis stream, or a
|
||||
// FILE * that you or it create, or possibly some other reading mechanism
|
||||
// if you go modify the source to replace the FILE * case with some kind
|
||||
// of callback to your code. (But if you don't support seeking, you may
|
||||
// just want to go ahead and use pushdata.)
|
||||
// This API assumes stb_vorbis is allowed to pull data from a source--
|
||||
// either a block of memory containing the _entire_ vorbis stream, or a
|
||||
// FILE * that you or it create, or possibly some other reading mechanism
|
||||
// if you go modify the source to replace the FILE * case with some kind
|
||||
// of callback to your code. (But if you don't support seeking, you may
|
||||
// just want to go ahead and use pushdata.)
|
||||
|
||||
#if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
|
||||
extern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output);
|
||||
extern int stb_vorbis_decode_filename(const char* filename, int* channels, int* sample_rate, short** output);
|
||||
#endif
|
||||
#if !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
|
||||
extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output);
|
||||
extern int stb_vorbis_decode_memory(const unsigned char* mem, int len, int* channels, int* sample_rate, short** output);
|
||||
#endif
|
||||
// decode an entire file and output the data interleaved into a malloc()ed
|
||||
// buffer stored in *output. The return value is the number of samples
|
||||
// decoded, or -1 if the file could not be opened or was not an ogg vorbis file.
|
||||
// When you're done with it, just free() the pointer returned in *output.
|
||||
// decode an entire file and output the data interleaved into a malloc()ed
|
||||
// buffer stored in *output. The return value is the number of samples
|
||||
// decoded, or -1 if the file could not be opened or was not an ogg vorbis file.
|
||||
// When you're done with it, just free() the pointer returned in *output.
|
||||
|
||||
extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len,
|
||||
int *error, const stb_vorbis_alloc *alloc_buffer);
|
||||
// create an ogg vorbis decoder from an ogg vorbis stream in memory (note
|
||||
// this must be the entire stream!). on failure, returns NULL and sets *error
|
||||
extern stb_vorbis* stb_vorbis_open_memory(const unsigned char* data, int len,
|
||||
int* error, const stb_vorbis_alloc* alloc_buffer);
|
||||
// create an ogg vorbis decoder from an ogg vorbis stream in memory (note
|
||||
// this must be the entire stream!). on failure, returns NULL and sets *error
|
||||
|
||||
#ifndef STB_VORBIS_NO_STDIO
|
||||
extern stb_vorbis * stb_vorbis_open_filename(const char *filename,
|
||||
int *error, const stb_vorbis_alloc *alloc_buffer);
|
||||
// create an ogg vorbis decoder from a filename via fopen(). on failure,
|
||||
// returns NULL and sets *error (possibly to VORBIS_file_open_failure).
|
||||
extern stb_vorbis* stb_vorbis_open_filename(const char* filename,
|
||||
int* error, const stb_vorbis_alloc* alloc_buffer);
|
||||
// create an ogg vorbis decoder from a filename via fopen(). on failure,
|
||||
// returns NULL and sets *error (possibly to VORBIS_file_open_failure).
|
||||
|
||||
extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
|
||||
int *error, const stb_vorbis_alloc *alloc_buffer);
|
||||
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
|
||||
// the _current_ seek point (ftell). on failure, returns NULL and sets *error.
|
||||
// note that stb_vorbis must "own" this stream; if you seek it in between
|
||||
// calls to stb_vorbis, it will become confused. Morever, if you attempt to
|
||||
// perform stb_vorbis_seek_*() operations on this file, it will assume it
|
||||
// owns the _entire_ rest of the file after the start point. Use the next
|
||||
// function, stb_vorbis_open_file_section(), to limit it.
|
||||
extern stb_vorbis* stb_vorbis_open_file(FILE* f, int close_handle_on_close,
|
||||
int* error, const stb_vorbis_alloc* alloc_buffer);
|
||||
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
|
||||
// the _current_ seek point (ftell). on failure, returns NULL and sets *error.
|
||||
// note that stb_vorbis must "own" this stream; if you seek it in between
|
||||
// calls to stb_vorbis, it will become confused. Morever, if you attempt to
|
||||
// perform stb_vorbis_seek_*() operations on this file, it will assume it
|
||||
// owns the _entire_ rest of the file after the start point. Use the next
|
||||
// function, stb_vorbis_open_file_section(), to limit it.
|
||||
|
||||
extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close,
|
||||
int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len);
|
||||
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
|
||||
// the _current_ seek point (ftell); the stream will be of length 'len' bytes.
|
||||
// on failure, returns NULL and sets *error. note that stb_vorbis must "own"
|
||||
// this stream; if you seek it in between calls to stb_vorbis, it will become
|
||||
// confused.
|
||||
extern stb_vorbis* stb_vorbis_open_file_section(FILE* f, int close_handle_on_close,
|
||||
int* error, const stb_vorbis_alloc* alloc_buffer, unsigned int len);
|
||||
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
|
||||
// the _current_ seek point (ftell); the stream will be of length 'len' bytes.
|
||||
// on failure, returns NULL and sets *error. note that stb_vorbis must "own"
|
||||
// this stream; if you seek it in between calls to stb_vorbis, it will become
|
||||
// confused.
|
||||
#endif
|
||||
|
||||
extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number);
|
||||
extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
|
||||
// these functions seek in the Vorbis file to (approximately) 'sample_number'.
|
||||
// after calling seek_frame(), the next call to get_frame_*() will include
|
||||
// the specified sample. after calling stb_vorbis_seek(), the next call to
|
||||
// stb_vorbis_get_samples_* will start with the specified sample. If you
|
||||
// do not need to seek to EXACTLY the target sample when using get_samples_*,
|
||||
// you can also use seek_frame().
|
||||
extern int stb_vorbis_seek_frame(stb_vorbis* f, unsigned int sample_number);
|
||||
extern int stb_vorbis_seek(stb_vorbis* f, unsigned int sample_number);
|
||||
// these functions seek in the Vorbis file to (approximately) 'sample_number'.
|
||||
// after calling seek_frame(), the next call to get_frame_*() will include
|
||||
// the specified sample. after calling stb_vorbis_seek(), the next call to
|
||||
// stb_vorbis_get_samples_* will start with the specified sample. If you
|
||||
// do not need to seek to EXACTLY the target sample when using get_samples_*,
|
||||
// you can also use seek_frame().
|
||||
|
||||
extern int stb_vorbis_seek_start(stb_vorbis *f);
|
||||
// this function is equivalent to stb_vorbis_seek(f,0)
|
||||
extern int stb_vorbis_seek_start(stb_vorbis* f);
|
||||
// this function is equivalent to stb_vorbis_seek(f,0)
|
||||
|
||||
extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);
|
||||
extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f);
|
||||
// these functions return the total length of the vorbis stream
|
||||
extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis* f);
|
||||
extern float stb_vorbis_stream_length_in_seconds(stb_vorbis* f);
|
||||
// these functions return the total length of the vorbis stream
|
||||
|
||||
extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output);
|
||||
// decode the next frame and return the number of samples. the number of
|
||||
// channels returned are stored in *channels (which can be NULL--it is always
|
||||
// the same as the number of channels reported by get_info). *output will
|
||||
// contain an array of float* buffers, one per channel. These outputs will
|
||||
// be overwritten on the next call to stb_vorbis_get_frame_*.
|
||||
//
|
||||
// You generally should not intermix calls to stb_vorbis_get_frame_*()
|
||||
// and stb_vorbis_get_samples_*(), since the latter calls the former.
|
||||
extern int stb_vorbis_get_frame_float(stb_vorbis* f, int* channels, float*** output);
|
||||
// decode the next frame and return the number of samples. the number of
|
||||
// channels returned are stored in *channels (which can be NULL--it is always
|
||||
// the same as the number of channels reported by get_info). *output will
|
||||
// contain an array of float* buffers, one per channel. These outputs will
|
||||
// be overwritten on the next call to stb_vorbis_get_frame_*.
|
||||
//
|
||||
// You generally should not intermix calls to stb_vorbis_get_frame_*()
|
||||
// and stb_vorbis_get_samples_*(), since the latter calls the former.
|
||||
|
||||
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
|
||||
extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);
|
||||
extern int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples);
|
||||
extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis* f, int num_c, short* buffer, int num_shorts);
|
||||
extern int stb_vorbis_get_frame_short(stb_vorbis* f, int num_c, short** buffer, int num_samples);
|
||||
#endif
|
||||
// decode the next frame and return the number of *samples* per channel.
|
||||
// Note that for interleaved data, you pass in the number of shorts (the
|
||||
// size of your array), but the return value is the number of samples per
|
||||
// channel, not the total number of samples.
|
||||
//
|
||||
// The data is coerced to the number of channels you request according to the
|
||||
// channel coercion rules (see below). You must pass in the size of your
|
||||
// buffer(s) so that stb_vorbis will not overwrite the end of the buffer.
|
||||
// The maximum buffer size needed can be gotten from get_info(); however,
|
||||
// the Vorbis I specification implies an absolute maximum of 4096 samples
|
||||
// per channel.
|
||||
// decode the next frame and return the number of *samples* per channel.
|
||||
// Note that for interleaved data, you pass in the number of shorts (the
|
||||
// size of your array), but the return value is the number of samples per
|
||||
// channel, not the total number of samples.
|
||||
//
|
||||
// The data is coerced to the number of channels you request according to the
|
||||
// channel coercion rules (see below). You must pass in the size of your
|
||||
// buffer(s) so that stb_vorbis will not overwrite the end of the buffer.
|
||||
// The maximum buffer size needed can be gotten from get_info(); however,
|
||||
// the Vorbis I specification implies an absolute maximum of 4096 samples
|
||||
// per channel.
|
||||
|
||||
// Channel coercion rules:
|
||||
// Let M be the number of channels requested, and N the number of channels present,
|
||||
// and Cn be the nth channel; let stereo L be the sum of all L and center channels,
|
||||
// and stereo R be the sum of all R and center channels (channel assignment from the
|
||||
// vorbis spec).
|
||||
// M N output
|
||||
// 1 k sum(Ck) for all k
|
||||
// 2 * stereo L, stereo R
|
||||
// k l k > l, the first l channels, then 0s
|
||||
// k l k <= l, the first k channels
|
||||
// Note that this is not _good_ surround etc. mixing at all! It's just so
|
||||
// you get something useful.
|
||||
// Channel coercion rules:
|
||||
// Let M be the number of channels requested, and N the number of channels present,
|
||||
// and Cn be the nth channel; let stereo L be the sum of all L and center channels,
|
||||
// and stereo R be the sum of all R and center channels (channel assignment from the
|
||||
// vorbis spec).
|
||||
// M N output
|
||||
// 1 k sum(Ck) for all k
|
||||
// 2 * stereo L, stereo R
|
||||
// k l k > l, the first l channels, then 0s
|
||||
// k l k <= l, the first k channels
|
||||
// Note that this is not _good_ surround etc. mixing at all! It's just so
|
||||
// you get something useful.
|
||||
|
||||
extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats);
|
||||
extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples);
|
||||
// gets num_samples samples, not necessarily on a frame boundary--this requires
|
||||
// buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES.
|
||||
// Returns the number of samples stored per channel; it may be less than requested
|
||||
// at the end of the file. If there are no more samples in the file, returns 0.
|
||||
extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis* f, int channels, float* buffer, int num_floats);
|
||||
extern int stb_vorbis_get_samples_float(stb_vorbis* f, int channels, float** buffer, int num_samples);
|
||||
// gets num_samples samples, not necessarily on a frame boundary--this requires
|
||||
// buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES.
|
||||
// Returns the number of samples stored per channel; it may be less than requested
|
||||
// at the end of the file. If there are no more samples in the file, returns 0.
|
||||
|
||||
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
|
||||
extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts);
|
||||
extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples);
|
||||
extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis* f, int channels, short* buffer, int num_shorts);
|
||||
extern int stb_vorbis_get_samples_short(stb_vorbis* f, int channels, short** buffer, int num_samples);
|
||||
#endif
|
||||
// gets num_samples samples, not necessarily on a frame boundary--this requires
|
||||
// buffering so you have to supply the buffers. Applies the coercion rules above
|
||||
// to produce 'channels' channels. Returns the number of samples stored per channel;
|
||||
// it may be less than requested at the end of the file. If there are no more
|
||||
// samples in the file, returns 0.
|
||||
// gets num_samples samples, not necessarily on a frame boundary--this requires
|
||||
// buffering so you have to supply the buffers. Applies the coercion rules above
|
||||
// to produce 'channels' channels. Returns the number of samples stored per channel;
|
||||
// it may be less than requested at the end of the file. If there are no more
|
||||
// samples in the file, returns 0.
|
||||
|
||||
#endif
|
||||
|
||||
//////// ERROR CODES
|
||||
//////// ERROR CODES
|
||||
|
||||
enum STBVorbisError
|
||||
{
|
||||
VORBIS__no_error,
|
||||
enum STBVorbisError
|
||||
{
|
||||
VORBIS__no_error,
|
||||
|
||||
VORBIS_need_more_data = 1, // not a real error
|
||||
VORBIS_need_more_data = 1,
|
||||
// not a real error
|
||||
|
||||
VORBIS_invalid_api_mixing, // can't mix API modes
|
||||
VORBIS_outofmem, // not enough memory
|
||||
VORBIS_feature_not_supported, // uses floor 0
|
||||
VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small
|
||||
VORBIS_file_open_failure, // fopen() failed
|
||||
VORBIS_seek_without_length, // can't seek in unknown-length file
|
||||
VORBIS_invalid_api_mixing,
|
||||
// can't mix API modes
|
||||
VORBIS_outofmem,
|
||||
// not enough memory
|
||||
VORBIS_feature_not_supported,
|
||||
// uses floor 0
|
||||
VORBIS_too_many_channels,
|
||||
// STB_VORBIS_MAX_CHANNELS is too small
|
||||
VORBIS_file_open_failure,
|
||||
// fopen() failed
|
||||
VORBIS_seek_without_length,
|
||||
// can't seek in unknown-length file
|
||||
|
||||
VORBIS_unexpected_eof = 10, // file is truncated?
|
||||
VORBIS_seek_invalid, // seek past EOF
|
||||
VORBIS_unexpected_eof = 10,
|
||||
// file is truncated?
|
||||
VORBIS_seek_invalid,
|
||||
// seek past EOF
|
||||
|
||||
// decoding errors (corrupt/invalid stream) -- you probably
|
||||
// don't care about the exact details of these
|
||||
// decoding errors (corrupt/invalid stream) -- you probably
|
||||
// don't care about the exact details of these
|
||||
|
||||
// vorbis errors:
|
||||
VORBIS_invalid_setup = 20,
|
||||
VORBIS_invalid_stream,
|
||||
// vorbis errors:
|
||||
VORBIS_invalid_setup = 20,
|
||||
VORBIS_invalid_stream,
|
||||
|
||||
// ogg errors:
|
||||
VORBIS_missing_capture_pattern = 30,
|
||||
VORBIS_invalid_stream_structure_version,
|
||||
VORBIS_continued_packet_flag_invalid,
|
||||
VORBIS_incorrect_stream_serial_number,
|
||||
VORBIS_invalid_first_page,
|
||||
VORBIS_bad_packet_type,
|
||||
VORBIS_cant_find_last_page,
|
||||
VORBIS_seek_failed
|
||||
};
|
||||
// ogg errors:
|
||||
VORBIS_missing_capture_pattern = 30,
|
||||
VORBIS_invalid_stream_structure_version,
|
||||
VORBIS_continued_packet_flag_invalid,
|
||||
VORBIS_incorrect_stream_serial_number,
|
||||
VORBIS_invalid_first_page,
|
||||
VORBIS_bad_packet_type,
|
||||
VORBIS_cant_find_last_page,
|
||||
VORBIS_seek_failed
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -330,4 +339,3 @@ extern "C" {
|
|||
// HEADER ENDS HERE
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
@ -24,11 +24,11 @@ using std::atomic;
|
|||
using std::atomic_flag;
|
||||
|
||||
#ifndef __MINGW32__
|
||||
#ifdef __clang__
|
||||
#ifdef __clang__
|
||||
#define __forceinline __attribute__((always_inline)) inline
|
||||
#else
|
||||
#ifdef __GNUC__
|
||||
#else
|
||||
#ifdef __GNUC__
|
||||
#define __forceinline __attribute__((always_inline)) inline
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
|
@ -20,14 +20,14 @@
|
|||
|
||||
namespace xbrz
|
||||
{
|
||||
struct ScalerCfg
|
||||
{
|
||||
double luminanceWeight = 1;
|
||||
double equalColorTolerance = 30;
|
||||
double dominantDirectionThreshold = 3.6;
|
||||
double steepDirectionThreshold = 2.2;
|
||||
double newTestAttribute = 0; //unused; test new parameters
|
||||
};
|
||||
struct ScalerCfg
|
||||
{
|
||||
double luminanceWeight = 1;
|
||||
double equalColorTolerance = 30;
|
||||
double dominantDirectionThreshold = 3.6;
|
||||
double steepDirectionThreshold = 2.2;
|
||||
double newTestAttribute = 0; //unused; test new parameters
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -23,72 +23,73 @@
|
|||
|
||||
namespace xbrz
|
||||
{
|
||||
/*
|
||||
-------------------------------------------------------------------------
|
||||
| xBRZ: "Scale by rules" - high quality image upscaling filter by Zenju |
|
||||
-------------------------------------------------------------------------
|
||||
using a modified approach of xBR:
|
||||
http://board.byuu.org/viewtopic.php?f=10&t=2248
|
||||
- new rule set preserving small image features
|
||||
- highly optimized for performance
|
||||
- support alpha channel
|
||||
- support multithreading
|
||||
- support 64-bit architectures
|
||||
- support processing image slices
|
||||
- support scaling up to 6xBRZ
|
||||
*/
|
||||
/*
|
||||
-------------------------------------------------------------------------
|
||||
| xBRZ: "Scale by rules" - high quality image upscaling filter by Zenju |
|
||||
-------------------------------------------------------------------------
|
||||
using a modified approach of xBR:
|
||||
http://board.byuu.org/viewtopic.php?f=10&t=2248
|
||||
- new rule set preserving small image features
|
||||
- highly optimized for performance
|
||||
- support alpha channel
|
||||
- support multithreading
|
||||
- support 64-bit architectures
|
||||
- support processing image slices
|
||||
- support scaling up to 6xBRZ
|
||||
*/
|
||||
|
||||
enum class ColorFormat //from high bits -> low bits, 8 bit per channel
|
||||
{
|
||||
RGB, //8 bit for each red, green, blue, upper 8 bits unused
|
||||
ARGB, //including alpha channel, BGRA byte order on little-endian machines
|
||||
};
|
||||
enum class ColorFormat //from high bits -> low bits, 8 bit per channel
|
||||
{
|
||||
RGB,
|
||||
//8 bit for each red, green, blue, upper 8 bits unused
|
||||
ARGB,
|
||||
//including alpha channel, BGRA byte order on little-endian machines
|
||||
};
|
||||
|
||||
/*
|
||||
-> map source (srcWidth * srcHeight) to target (scale * width x scale * height) image, optionally processing a half-open slice of rows [yFirst, yLast) only
|
||||
-> support for source/target pitch in bytes!
|
||||
-> if your emulator changes only a few image slices during each cycle (e.g. DOSBox) then there's no need to run xBRZ on the complete image:
|
||||
Just make sure you enlarge the source image slice by 2 rows on top and 2 on bottom (this is the additional range the xBRZ algorithm is using during analysis)
|
||||
Caveat: If there are multiple changed slices, make sure they do not overlap after adding these additional rows in order to avoid a memory race condition
|
||||
in the target image data if you are using multiple threads for processing each enlarged slice!
|
||||
/*
|
||||
-> map source (srcWidth * srcHeight) to target (scale * width x scale * height) image, optionally processing a half-open slice of rows [yFirst, yLast) only
|
||||
-> support for source/target pitch in bytes!
|
||||
-> if your emulator changes only a few image slices during each cycle (e.g. DOSBox) then there's no need to run xBRZ on the complete image:
|
||||
Just make sure you enlarge the source image slice by 2 rows on top and 2 on bottom (this is the additional range the xBRZ algorithm is using during analysis)
|
||||
Caveat: If there are multiple changed slices, make sure they do not overlap after adding these additional rows in order to avoid a memory race condition
|
||||
in the target image data if you are using multiple threads for processing each enlarged slice!
|
||||
|
||||
THREAD-SAFETY: - parts of the same image may be scaled by multiple threads as long as the [yFirst, yLast) ranges do not overlap!
|
||||
- there is a minor inefficiency for the first row of a slice, so avoid processing single rows only; suggestion: process 8-16 rows at least
|
||||
*/
|
||||
void scale(size_t factor, //valid range: 2 - 6
|
||||
const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight,
|
||||
ColorFormat colFmt,
|
||||
const ScalerCfg& cfg = ScalerCfg(),
|
||||
int yFirst = 0, int yLast = std::numeric_limits<int>::max()); //slice of source image
|
||||
THREAD-SAFETY: - parts of the same image may be scaled by multiple threads as long as the [yFirst, yLast) ranges do not overlap!
|
||||
- there is a minor inefficiency for the first row of a slice, so avoid processing single rows only; suggestion: process 8-16 rows at least
|
||||
*/
|
||||
void scale(size_t factor, //valid range: 2 - 6
|
||||
const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight,
|
||||
ColorFormat colFmt,
|
||||
const ScalerCfg& cfg = ScalerCfg(),
|
||||
int yFirst = 0, int yLast = std::numeric_limits<int>::max()); //slice of source image
|
||||
|
||||
void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight,
|
||||
uint32_t* trg, int trgWidth, int trgHeight);
|
||||
void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight,
|
||||
uint32_t* trg, int trgWidth, int trgHeight);
|
||||
|
||||
enum SliceType
|
||||
{
|
||||
NN_SCALE_SLICE_SOURCE,
|
||||
NN_SCALE_SLICE_TARGET,
|
||||
};
|
||||
void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, int srcPitch, //pitch in bytes!
|
||||
uint32_t* trg, int trgWidth, int trgHeight, int trgPitch,
|
||||
SliceType st, int yFirst, int yLast);
|
||||
enum SliceType
|
||||
{
|
||||
NN_SCALE_SLICE_SOURCE,
|
||||
NN_SCALE_SLICE_TARGET,
|
||||
};
|
||||
|
||||
//parameter tuning
|
||||
bool equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, double luminanceWeight, double equalColorTolerance);
|
||||
void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight, int srcPitch, //pitch in bytes!
|
||||
uint32_t* trg, int trgWidth, int trgHeight, int trgPitch,
|
||||
SliceType st, int yFirst, int yLast);
|
||||
|
||||
//parameter tuning
|
||||
bool equalColorTest(uint32_t col1, uint32_t col2, ColorFormat colFmt, double luminanceWeight,
|
||||
double equalColorTolerance);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//########################### implementation ###########################
|
||||
inline
|
||||
void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight,
|
||||
uint32_t* trg, int trgWidth, int trgHeight)
|
||||
{
|
||||
nearestNeighborScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t),
|
||||
trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t),
|
||||
NN_SCALE_SLICE_TARGET, 0, trgHeight);
|
||||
}
|
||||
//########################### implementation ###########################
|
||||
inline
|
||||
void nearestNeighborScale(const uint32_t* src, int srcWidth, int srcHeight,
|
||||
uint32_t* trg, int trgWidth, int trgHeight)
|
||||
{
|
||||
nearestNeighborScale(src, srcWidth, srcHeight, srcWidth * sizeof(uint32_t),
|
||||
trg, trgWidth, trgHeight, trgWidth * sizeof(uint32_t),
|
||||
NN_SCALE_SLICE_TARGET, 0, trgHeight);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue