mirror of https://github.com/dwsJason/gsla.git
GSLA: might have a version 1 encoder finished... all that's left is to debug / test / make sure the thing works
This commit is contained in:
parent
6956281d1e
commit
8dfb3028c7
|
@ -403,7 +403,7 @@ void GSLAFile::SaveToFile(const char* pFilenamePath)
|
||||||
{
|
{
|
||||||
// I don't want random data in the bank gaps, so initialize this
|
// I don't want random data in the bank gaps, so initialize this
|
||||||
// buffer with zero
|
// buffer with zero
|
||||||
memset(pWorkBuffer, 0, m_frameSize * 2);
|
//memset(pWorkBuffer, 0, m_frameSize * 2);
|
||||||
|
|
||||||
int frameSize = LZBA_Compress(pWorkBuffer, m_pC1PixelMaps[ frameIndex],
|
int frameSize = LZBA_Compress(pWorkBuffer, m_pC1PixelMaps[ frameIndex],
|
||||||
m_frameSize, pWorkBuffer-bytes.size(),
|
m_frameSize, pWorkBuffer-bytes.size(),
|
||||||
|
@ -416,7 +416,7 @@ void GSLAFile::SaveToFile(const char* pFilenamePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the RING Frame
|
// Add the RING Frame
|
||||||
memset(pWorkBuffer, 0, m_frameSize * 2);
|
//memset(pWorkBuffer, 0, m_frameSize * 2);
|
||||||
|
|
||||||
int ringSize = LZBA_Compress(pWorkBuffer, m_pC1PixelMaps[ 0 ],
|
int ringSize = LZBA_Compress(pWorkBuffer, m_pC1PixelMaps[ 0 ],
|
||||||
m_frameSize, pWorkBuffer-bytes.size(),
|
m_frameSize, pWorkBuffer-bytes.size(),
|
||||||
|
@ -430,6 +430,8 @@ void GSLAFile::SaveToFile(const char* pFilenamePath)
|
||||||
delete[] pCanvas; pCanvas = nullptr;
|
delete[] pCanvas; pCanvas = nullptr;
|
||||||
|
|
||||||
// Insert End of file/ End of Animation Done opcode
|
// Insert End of file/ End of Animation Done opcode
|
||||||
|
// -- There has to be room for this, or there wouldn't be room to insert
|
||||||
|
// -- a source bank skip opcode
|
||||||
bytes.push_back( 0x06 );
|
bytes.push_back( 0x06 );
|
||||||
bytes.push_back( 0x00 );
|
bytes.push_back( 0x00 );
|
||||||
|
|
||||||
|
|
160
source/lzb.cpp
160
source/lzb.cpp
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include "bctypes.h"
|
#include "bctypes.h"
|
||||||
|
|
||||||
|
#include "assert.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// This is written specifically for the GSLA, so opcodes emitted are designed
|
// This is written specifically for the GSLA, so opcodes emitted are designed
|
||||||
// to work with our version of a run/skip/dump
|
// to work with our version of a run/skip/dump
|
||||||
|
@ -387,12 +389,12 @@ DataString LongestMatch(const DataString& data, const DataString& dictionary, in
|
||||||
{
|
{
|
||||||
// Check for pattern sizes, start small
|
// Check for pattern sizes, start small
|
||||||
int max_pattern_size = 4096;
|
int max_pattern_size = 4096;
|
||||||
if (dictionary.size < max_pattern_size) max_pattern_size = dictionary.size;
|
if (cursorPosition < max_pattern_size) max_pattern_size = cursorPosition;
|
||||||
if (data.size < max_pattern_size) max_pattern_size = data.size;
|
if (data.size < max_pattern_size) max_pattern_size = data.size;
|
||||||
|
|
||||||
for (int pattern_size = 1; pattern_size <= max_pattern_size; ++pattern_size)
|
for (int pattern_size = 1; pattern_size <= max_pattern_size; ++pattern_size)
|
||||||
{
|
{
|
||||||
int pattern_start = dictionary.size - pattern_size;
|
int pattern_start = cursorPosition - pattern_size;
|
||||||
|
|
||||||
for (int dataIndex = 0; dataIndex < data.size; ++dataIndex)
|
for (int dataIndex = 0; dataIndex < data.size; ++dataIndex)
|
||||||
{
|
{
|
||||||
|
@ -406,9 +408,6 @@ DataString LongestMatch(const DataString& data, const DataString& dictionary, in
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (candidate.size < pattern_size)
|
|
||||||
// break;
|
|
||||||
|
|
||||||
if (candidate.size > result.size)
|
if (candidate.size > result.size)
|
||||||
{
|
{
|
||||||
result = candidate;
|
result = candidate;
|
||||||
|
@ -416,9 +415,9 @@ DataString LongestMatch(const DataString& data, const DataString& dictionary, in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// As an optimization
|
// This will keep us from finding matches that we can't use
|
||||||
int dictionarySize = dictionary.size; // - 1; // This last string has already been checked by, the
|
|
||||||
// run-length matcher above
|
int dictionarySize = cursorPosition;
|
||||||
|
|
||||||
// As the size grows, we're missing potential matches in here
|
// As the size grows, we're missing potential matches in here
|
||||||
// I think the best way to counter this is to attempt somthing
|
// I think the best way to counter this is to attempt somthing
|
||||||
|
@ -457,6 +456,43 @@ DataString LongestMatch(const DataString& data, const DataString& dictionary, in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Look for matches beyond the cursor
|
||||||
|
dictionarySize = dictionary.size;
|
||||||
|
|
||||||
|
if ((dictionarySize-cursorPosition) > candidate.size)
|
||||||
|
{
|
||||||
|
// Check the dictionary for a match, brute force
|
||||||
|
for (int dictionaryIndex = cursorPosition; dictionaryIndex <= (dictionarySize-candidate.size); ++dictionaryIndex)
|
||||||
|
{
|
||||||
|
int sizeAvailable = dictionarySize - dictionaryIndex;
|
||||||
|
|
||||||
|
if (sizeAvailable > data.size) sizeAvailable = data.size;
|
||||||
|
|
||||||
|
// this could index off the end of the dictionary!!! FIX ME
|
||||||
|
for (int dataIndex = 0; dataIndex < sizeAvailable; ++dataIndex)
|
||||||
|
{
|
||||||
|
if (data.pData[ dataIndex ] == dictionary.pData[ dictionaryIndex + dataIndex ])
|
||||||
|
{
|
||||||
|
if (dataIndex >= candidate.size)
|
||||||
|
{
|
||||||
|
candidate.pData = dictionary.pData + dictionaryIndex;
|
||||||
|
candidate.size = dataIndex + 1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidate.size > result.size)
|
||||||
|
{
|
||||||
|
result = candidate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -660,6 +696,63 @@ static void my_memcpy(u8* pDest, u8* pSrc, int length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Emit a Cursor Skip forward opcode
|
||||||
|
//
|
||||||
|
int EmitSkip(unsigned char* pDest, int skipSize)
|
||||||
|
{
|
||||||
|
int outSize = 2;
|
||||||
|
|
||||||
|
unsigned short length = (unsigned short)skipSize;
|
||||||
|
length -= 1;
|
||||||
|
|
||||||
|
unsigned short opcode = length<<1;
|
||||||
|
opcode |= 0x8001;
|
||||||
|
// Opcode out
|
||||||
|
*pDest++ = (unsigned char)( opcode & 0xFF );
|
||||||
|
*pDest++ = (unsigned char)(( opcode>>8)&0xFF);
|
||||||
|
|
||||||
|
return outSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Forcibly Emit a source Skip Opcode
|
||||||
|
//
|
||||||
|
// return space_left_in_Bank
|
||||||
|
//
|
||||||
|
int EmitSourceSkip(unsigned char*& pDest, int space_left_in_bank)
|
||||||
|
{
|
||||||
|
assert(space_left_in_bank >= 2);
|
||||||
|
|
||||||
|
*pDest++ = 0;
|
||||||
|
*pDest++ = 0;
|
||||||
|
space_left_in_bank-=2;
|
||||||
|
|
||||||
|
while (space_left_in_bank)
|
||||||
|
{
|
||||||
|
space_left_in_bank--;
|
||||||
|
*pDest++ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0x10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Conditionally shit out the Source Bank Skip
|
||||||
|
//
|
||||||
|
int CheckEmitSourceSkip(int checkSpace, unsigned char*& pDest, int space_left_in_bank)
|
||||||
|
{
|
||||||
|
if ((checkSpace+2) > space_left_in_bank)
|
||||||
|
{
|
||||||
|
return EmitSourceSkip(pDest, space_left_in_bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
return space_left_in_bank;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Compress a Frame in the GSLA LZB Format
|
// Compress a Frame in the GSLA LZB Format
|
||||||
|
@ -699,6 +792,10 @@ int LZBA_Compress(unsigned char* pDest, unsigned char* pSource, int sourceSize,
|
||||||
|
|
||||||
int lastEmittedCursorPosition = 0; // This is the default for each frame
|
int lastEmittedCursorPosition = 0; // This is the default for each frame
|
||||||
|
|
||||||
|
int space_left_in_bank = (int)0x10000 - (int)((pDest - pDataStart)&0xFFFF);
|
||||||
|
|
||||||
|
space_left_in_bank = CheckEmitSourceSkip(0, pDest, space_left_in_bank);
|
||||||
|
|
||||||
for (int cursorPosition = 0; cursorPosition < dictionarySize;)
|
for (int cursorPosition = 0; cursorPosition < dictionarySize;)
|
||||||
{
|
{
|
||||||
if (pSource[ cursorPosition ] != pDictionary[ cursorPosition ])
|
if (pSource[ cursorPosition ] != pDictionary[ cursorPosition ])
|
||||||
|
@ -709,6 +806,20 @@ int LZBA_Compress(unsigned char* pDest, unsigned char* pSource, int sourceSize,
|
||||||
// Do we need to emit a Skip opcode?, compare cursor to last emit
|
// Do we need to emit a Skip opcode?, compare cursor to last emit
|
||||||
// and emit a skip command if we need it (I'm going want a gap of
|
// and emit a skip command if we need it (I'm going want a gap of
|
||||||
// at least 3 bytes? before we call it the end
|
// at least 3 bytes? before we call it the end
|
||||||
|
int skipSize = cursorPosition - lastEmittedCursorPosition;
|
||||||
|
|
||||||
|
if (skipSize)
|
||||||
|
{
|
||||||
|
space_left_in_bank = CheckEmitSourceSkip(2, pDest, space_left_in_bank);
|
||||||
|
|
||||||
|
// We need to Skip
|
||||||
|
pDest += EmitSkip(pDest, skipSize);
|
||||||
|
bLastEmitIsLiteral = false;
|
||||||
|
lastEmittedCursorPosition = cursorPosition;
|
||||||
|
|
||||||
|
space_left_in_bank = (int)0x10000 - (int)((pDest - pDataStart)&0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
int tempCursorPosition = cursorPosition;
|
int tempCursorPosition = cursorPosition;
|
||||||
int gapCount = 0;
|
int gapCount = 0;
|
||||||
for (; tempCursorPosition < dictionarySize; ++tempCursorPosition)
|
for (; tempCursorPosition < dictionarySize; ++tempCursorPosition)
|
||||||
|
@ -757,21 +868,48 @@ int LZBA_Compress(unsigned char* pDest, unsigned char* pSource, int sourceSize,
|
||||||
|
|
||||||
if (candidateData.size > 3)
|
if (candidateData.size > 3)
|
||||||
{
|
{
|
||||||
|
space_left_in_bank = CheckEmitSourceSkip(4, pDest, space_left_in_bank);
|
||||||
|
|
||||||
// Emit a dictionary reference
|
// Emit a dictionary reference
|
||||||
pDest += (int)EmitReference(pDest, (int)(candidateData.pData - dictionaryData.pData), candidateData);
|
pDest += (int)EmitReference(pDest, (int)(candidateData.pData - dictionaryData.pData), candidateData);
|
||||||
bLastEmitIsLiteral = false;
|
bLastEmitIsLiteral = false;
|
||||||
|
|
||||||
|
space_left_in_bank = (int)0x10000 - (int)((pDest - pDataStart)&0xFFFF);
|
||||||
}
|
}
|
||||||
else if (bLastEmitIsLiteral)
|
else if (bLastEmitIsLiteral)
|
||||||
{
|
{
|
||||||
// Concatenate this literal onto the previous literal
|
// This is a problem for the source bank skip, we can't
|
||||||
pDest += ConcatLiteral(pLastLiteralDest, candidateData);
|
// concatenate if we end up injecting a source bank skip opcode
|
||||||
|
// into the stream... what to do???, if insert, we will need to
|
||||||
|
// do a "normal" literal emission, ugly
|
||||||
|
|
||||||
|
int space = CheckEmitSourceSkip(candidateData.size, pDest, space_left_in_bank);
|
||||||
|
|
||||||
|
if (space != space_left_in_bank)
|
||||||
|
{
|
||||||
|
// Emit a new literal
|
||||||
|
pLastLiteralDest = pDest;
|
||||||
|
bLastEmitIsLiteral = true;
|
||||||
|
pDest += EmitLiteral(pDest, candidateData);
|
||||||
|
|
||||||
|
space_left_in_bank = (int)0x10000 - (int)((pDest - pDataStart)&0xFFFF);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Concatenate this literal onto the previous literal
|
||||||
|
pDest += ConcatLiteral(pLastLiteralDest, candidateData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
space_left_in_bank = CheckEmitSourceSkip(2 + candidateData.size, pDest, space_left_in_bank);
|
||||||
|
|
||||||
// Emit a new literal
|
// Emit a new literal
|
||||||
pLastLiteralDest = pDest;
|
pLastLiteralDest = pDest;
|
||||||
bLastEmitIsLiteral = true;
|
bLastEmitIsLiteral = true;
|
||||||
pDest += EmitLiteral(pDest, candidateData);
|
pDest += EmitLiteral(pDest, candidateData);
|
||||||
|
|
||||||
|
space_left_in_bank = (int)0x10000 - (int)((pDest - pDataStart)&0xFFFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -782,6 +920,8 @@ int LZBA_Compress(unsigned char* pDest, unsigned char* pSource, int sourceSize,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
space_left_in_bank = CheckEmitSourceSkip(2, pDest, space_left_in_bank);
|
||||||
|
|
||||||
// Emit the End of Frame Opcode
|
// Emit the End of Frame Opcode
|
||||||
*pDest++ = 0x02;
|
*pDest++ = 0x02;
|
||||||
*pDest++ = 0x00;
|
*pDest++ = 0x00;
|
||||||
|
|
Loading…
Reference in New Issue