mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-27 07:34:00 +08:00
implemented ERISA decoder for ERI images.
This commit is contained in:
parent
8514f261cd
commit
c92229b714
@ -46,6 +46,7 @@ namespace GameRes.Formats.Entis
|
||||
int[] m_pArrangeTable = new int[4];
|
||||
|
||||
HuffmanTree m_pHuffmanTree;
|
||||
ErisaProbModel m_pProbERISA;
|
||||
|
||||
PtrProcedure[] m_pfnColorOperation;
|
||||
|
||||
@ -95,7 +96,6 @@ namespace GameRes.Formats.Entis
|
||||
switch (m_info.Architecture)
|
||||
{
|
||||
case EriCode.Nemesis:
|
||||
throw new NotSupportedException ("Not supported ERI compression");
|
||||
case EriCode.RunlengthHuffman:
|
||||
case EriCode.RunlengthGamma:
|
||||
break;
|
||||
@ -143,15 +143,15 @@ namespace GameRes.Formats.Entis
|
||||
{
|
||||
m_pHuffmanTree = new HuffmanTree();
|
||||
}
|
||||
/*
|
||||
else if (EriCode.Nemesis == m_info.Architecture)
|
||||
{
|
||||
m_pProbERISA = new ERISA_PROB_MODEL ;
|
||||
m_pProbERISA = new ErisaProbModel();
|
||||
}
|
||||
*/
|
||||
}
|
||||
if (EriCode.RunlengthHuffman == m_info.Architecture)
|
||||
m_context = new HuffmanDecodeContext (0x10000);
|
||||
else if (EriCode.Nemesis == m_info.Architecture)
|
||||
m_context = new ProbDecodeContext (0x10000);
|
||||
else
|
||||
m_context = new RLEDecodeContext (0x10000);
|
||||
}
|
||||
@ -283,18 +283,18 @@ namespace GameRes.Formats.Entis
|
||||
var pfnRestoreFunc = GetLLRestoreFunc (m_info.FormatType, m_info.BPP);
|
||||
if (null == pfnRestoreFunc)
|
||||
throw new InvalidFormatException();
|
||||
/*
|
||||
|
||||
if (EriCode.Nemesis == m_info.Architecture)
|
||||
{
|
||||
Debug.Assert (m_pProbERISA != null);
|
||||
m_pProbERISA.Initialize();
|
||||
}
|
||||
*/
|
||||
int i;
|
||||
int ptrNextOperation = 0; // index within m_ptrOperations
|
||||
if ((0 != (fEncodeType & 0x01)) && (m_nChannelCount >= 3))
|
||||
{
|
||||
Debug.Assert (m_info.Architecture != EriCode.Nemesis);
|
||||
if (m_info.Architecture == EriCode.Nemesis)
|
||||
throw new InvalidFormatException();
|
||||
int nAllBlockCount = (int)(m_nWidthBlocks * m_nHeightBlocks);
|
||||
for (i = 0; i < nAllBlockCount; i++)
|
||||
{
|
||||
@ -323,13 +323,11 @@ namespace GameRes.Formats.Entis
|
||||
{
|
||||
(context as HuffmanDecodeContext).PrepareToDecodeERINACode();
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
Debug.Assert (EriCode.Nemesis == m_info.Architecture);
|
||||
context.PrepareToDecodeERISACode();
|
||||
(context as ProbDecodeContext).PrepareToDecodeERISACode();
|
||||
}
|
||||
*/
|
||||
int nWidthSamples = (int)(m_nChannelCount * m_nWidthBlocks * m_nBlockSize);
|
||||
for (i = 0; i < nWidthSamples; ++i)
|
||||
m_ptrLineBuf[i] = 0;
|
||||
@ -367,12 +365,10 @@ namespace GameRes.Formats.Entis
|
||||
{
|
||||
dwOperationCode = (uint)(context as HuffmanDecodeContext).GetHuffmanCode (m_pHuffmanTree);
|
||||
}
|
||||
/*
|
||||
else if (m_info.Architecture == EriCode.Nemesis)
|
||||
{
|
||||
dwOperationCode = context.DecodeERISACode (m_pProbERISA);
|
||||
dwOperationCode = (uint)(context as ProbDecodeContext).DecodeERISACode (m_pProbERISA);
|
||||
}
|
||||
*/
|
||||
else
|
||||
{
|
||||
Debug.Assert (EriCode.RunlengthGamma == m_info.Architecture);
|
||||
@ -1369,4 +1365,254 @@ namespace GameRes.Formats.Entis
|
||||
return nCode;
|
||||
}
|
||||
}
|
||||
|
||||
internal class ProbDecodeContext : RLEDecodeContext
|
||||
{
|
||||
uint m_dwCodeRegister;
|
||||
uint m_dwAugendRegister;
|
||||
int m_nPostBitCount;
|
||||
byte[] m_bytLastSymbol = new byte[4];
|
||||
|
||||
ErisaProbModel m_pPhraseLenProb = new ErisaProbModel();
|
||||
ErisaProbModel m_pPhraseIndexProb = new ErisaProbModel();
|
||||
ErisaProbModel m_pRunLenProb = new ErisaProbModel();
|
||||
ErisaProbModel m_pLastERISAProb;
|
||||
ErisaProbModel[] m_ppTableERISA;
|
||||
|
||||
public ProbDecodeContext (uint nBufferingSize) : base (nBufferingSize)
|
||||
{
|
||||
}
|
||||
|
||||
public void PrepareToDecodeERISACode ()
|
||||
{
|
||||
if (null == m_ppTableERISA)
|
||||
{
|
||||
m_ppTableERISA = new ErisaProbModel[0x101];
|
||||
for (int i = 0; i < 0x101; ++i)
|
||||
{
|
||||
m_ppTableERISA[i] = new ErisaProbModel();
|
||||
m_ppTableERISA[i].Initialize();
|
||||
}
|
||||
}
|
||||
m_pLastERISAProb = m_ppTableERISA[0];
|
||||
m_pPhraseLenProb.Initialize();
|
||||
m_pPhraseIndexProb.Initialize();
|
||||
m_pRunLenProb.Initialize();
|
||||
|
||||
InitializeERISACode();
|
||||
}
|
||||
|
||||
public override uint DecodeBytes (Array ptrDst, uint nCount)
|
||||
{
|
||||
return DecodeERISACodeBytes (ptrDst as sbyte[], nCount);
|
||||
}
|
||||
|
||||
uint DecodeERISACodeBytes (sbyte[] ptrDst, uint nCount)
|
||||
{
|
||||
var pProb = m_pLastERISAProb;
|
||||
int nSymbol, iSym;
|
||||
uint i = 0;
|
||||
while (i < nCount)
|
||||
{
|
||||
if (m_nLength > 0)
|
||||
{
|
||||
uint nCurrent = nCount - i;
|
||||
if (nCurrent > m_nLength)
|
||||
nCurrent = m_nLength;
|
||||
m_nLength -= nCurrent;
|
||||
for (uint j = 0; j < nCurrent; j++)
|
||||
{
|
||||
ptrDst[i++] = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
iSym = DecodeERISACodeIndex (pProb);
|
||||
if (iSym < 0)
|
||||
break;
|
||||
nSymbol = pProb.SymTable[iSym].Symbol;
|
||||
pProb.IncreaseSymbol (iSym);
|
||||
ptrDst[i++] = (sbyte)nSymbol;
|
||||
|
||||
if (0 == nSymbol)
|
||||
{
|
||||
iSym = DecodeERISACodeIndex (m_pRunLenProb);
|
||||
if (iSym < 0)
|
||||
break;
|
||||
m_nLength = (uint)m_pRunLenProb.SymTable[iSym].Symbol;
|
||||
m_pRunLenProb.IncreaseSymbol (iSym);
|
||||
}
|
||||
pProb = m_ppTableERISA[nSymbol & 0xFF];
|
||||
}
|
||||
m_pLastERISAProb = pProb;
|
||||
return i;
|
||||
}
|
||||
|
||||
void InitializeERISACode ()
|
||||
{
|
||||
m_nLength = 0;
|
||||
m_dwCodeRegister = GetNBits (32);
|
||||
m_dwAugendRegister = 0xFFFF;
|
||||
m_nPostBitCount = 0;
|
||||
}
|
||||
|
||||
public int DecodeERISACode (ErisaProbModel pModel)
|
||||
{
|
||||
int iSym = DecodeERISACodeIndex (pModel);
|
||||
int nSymbol = ErisaProbModel.EscCode;
|
||||
if (iSym >= 0)
|
||||
{
|
||||
nSymbol = pModel.SymTable[iSym].Symbol;
|
||||
pModel.IncreaseSymbol (iSym);
|
||||
}
|
||||
return nSymbol;
|
||||
}
|
||||
|
||||
int DecodeERISACodeIndex (ErisaProbModel pModel)
|
||||
{
|
||||
uint dwAcc = m_dwCodeRegister * pModel.TotalCount / m_dwAugendRegister;
|
||||
if (dwAcc >= ErisaProbModel.TotalLimit)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
int iSym = 0;
|
||||
ushort wAcc = (ushort)dwAcc;
|
||||
ushort wFs = 0;
|
||||
ushort wOccured;
|
||||
for (;;)
|
||||
{
|
||||
wOccured = pModel.SymTable[iSym].Occured;
|
||||
if (wAcc < wOccured)
|
||||
break;
|
||||
wAcc -= wOccured;
|
||||
wFs += wOccured;
|
||||
if (++iSym >= pModel.SymbolSorts)
|
||||
return -1;
|
||||
}
|
||||
m_dwCodeRegister -= (m_dwAugendRegister * wFs + pModel.TotalCount - 1) / pModel.TotalCount;
|
||||
m_dwAugendRegister = m_dwAugendRegister * wOccured / pModel.TotalCount;
|
||||
Debug.Assert (m_dwAugendRegister != 0);
|
||||
|
||||
while (0 == (m_dwAugendRegister & 0x8000))
|
||||
{
|
||||
int nNextBit = GetABit();
|
||||
if (1 == nNextBit)
|
||||
{
|
||||
if ((++m_nPostBitCount) >= 256)
|
||||
return -1;
|
||||
nNextBit = 0 ;
|
||||
}
|
||||
m_dwCodeRegister = (m_dwCodeRegister << 1) | ((uint)nNextBit & 1);
|
||||
m_dwAugendRegister <<= 1;
|
||||
}
|
||||
m_dwCodeRegister &= 0xFFFF;
|
||||
return iSym;
|
||||
}
|
||||
}
|
||||
|
||||
internal class ErisaProbModel
|
||||
{
|
||||
public const int TotalLimit = 0x2000;
|
||||
public const int SymbolSortMax = 0x101;
|
||||
public const int SubSortMax = 0x80;
|
||||
public const int ProbSlotMax = 0x800;
|
||||
public const short EscCode = -1;
|
||||
|
||||
internal struct CodeSymbol
|
||||
{
|
||||
public ushort Occured;
|
||||
public short Symbol;
|
||||
}
|
||||
|
||||
public uint TotalCount;
|
||||
public int SymbolSorts;
|
||||
public CodeSymbol[] SymTable = new CodeSymbol[SymbolSortMax];
|
||||
public CodeSymbol[] SubModel = new CodeSymbol[SubSortMax];
|
||||
|
||||
public void Initialize ()
|
||||
{
|
||||
TotalCount = SymbolSortMax;
|
||||
SymbolSorts = SymbolSortMax;
|
||||
|
||||
for (short i = 0; i < 0x100; ++i)
|
||||
{
|
||||
SymTable[i].Occured = 1;
|
||||
SymTable[i].Symbol = i;
|
||||
}
|
||||
SymTable[0x100].Occured = 1 ;
|
||||
SymTable[0x100].Symbol = EscCode;
|
||||
|
||||
for (short i = 0; i < SubSortMax; ++i)
|
||||
{
|
||||
SubModel[i].Occured = 0;
|
||||
SubModel[i].Symbol = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int AccumulateProb (short wSymbol)
|
||||
{
|
||||
int index = FindSymbol (wSymbol);
|
||||
Debug.Assert (index >= 0);
|
||||
int occured = SymTable[index].Occured;
|
||||
int i = 0;
|
||||
while (occured < TotalCount)
|
||||
{
|
||||
occured <<= 1;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public void HalfOccuredCount ()
|
||||
{
|
||||
TotalCount = 0;
|
||||
for (int i = 0; i < SymbolSorts; ++i)
|
||||
{
|
||||
TotalCount += SymTable[i].Occured = (ushort)((SymTable[i].Occured + 1) >> 1);
|
||||
}
|
||||
for (int i = 0; i < SubSortMax; ++i)
|
||||
{
|
||||
SubModel[i].Occured >>= 1 ;
|
||||
}
|
||||
}
|
||||
|
||||
public int IncreaseSymbol (int index)
|
||||
{
|
||||
ushort occured = ++SymTable[index].Occured;
|
||||
short symbol = SymTable[index].Symbol;
|
||||
|
||||
while (--index >= 0)
|
||||
{
|
||||
if (SymTable[index].Occured >= occured)
|
||||
break;
|
||||
SymTable[index + 1] = SymTable[index];
|
||||
}
|
||||
SymTable[++index].Occured = occured;
|
||||
SymTable[index].Symbol = symbol;
|
||||
|
||||
if (++TotalCount >= TotalLimit)
|
||||
{
|
||||
HalfOccuredCount();
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
public int FindSymbol (short symbol)
|
||||
{
|
||||
for (int index = 0; index < SymbolSorts; ++index)
|
||||
{
|
||||
if (SymTable[index].Symbol == symbol)
|
||||
return index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int AddSymbol (short symbol)
|
||||
{
|
||||
int index = SymbolSorts++;
|
||||
TotalCount++;
|
||||
SymTable[index].Symbol = symbol;
|
||||
SymTable[index].Occured = 1;
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user