GSLA encoder: WIP

This commit is contained in:
JASON-6700K\jandersen 2020-07-18 15:49:27 -04:00
parent 89f6eb72e5
commit 7712398e0c
5 changed files with 246 additions and 7 deletions

View File

@ -114,17 +114,21 @@
//
// xxx_xxxx_xxxx_xxx is the number of bytes 1-16384 to follow (0 == 1 byte)
//
//%0xxx_xxxx_xxxx_xxx0 - Copy Bytes - straight copy bytes
//%0xxx_xxxx_xxxx_xxx1 - Copy Bytes - straight copy bytes
//%1xxx_xxxx_xxxx_xxx1 - Skip Bytes - skip bytes / move the cursor
//%1xxx_xxxx_xxxx_xxx0 - Dictionary Copy Bytes from frame buffer to frame buffer
//
//%0000_0000_0000_0001- Source Skip -> Source pointer skips to next bank of data
//%0000_0000_0000_0011- End of Frame - end of frame
//%0000_0000_0000_0111- End of Animation / End of File / no more frames
//%0000_0000_0000_0000- Source Skip -> Source pointer skips to next bank of data
//%0000_0000_0000_0010- End of Frame - end of frame
//%0000_0000_0000_0110- End of Animation / End of File / no more frames
//
//
// other remaining codes, are reserved for future expansion
#include "gsla_file.h"
#include "lzb.h"
#include <stdio.h>
// If these structs are the wrong size, there's an issue with type sizes, and
@ -143,6 +147,17 @@ GSLAFile::GSLAFile(const char *pFilePath)
{
LoadFromFile(pFilePath);
}
//------------------------------------------------------------------------------
GSLAFile::GSLAFile(int iWidthPixels, int iHeightPixels, int iFrameSizeBytes )
: m_widthPixels(iWidthPixels)
, m_heightPixels(iHeightPixels)
, m_frameSize( iFrameSizeBytes )
{
}
//------------------------------------------------------------------------------
GSLAFile::~GSLAFile()
@ -270,3 +285,177 @@ void GSLAFile::UnpackAnimation(GSLA_ANIM* pANIM, GSLA_Header* pHeader)
//DecompressAnim(pTargetBuffer, pData);
}
//------------------------------------------------------------------------------
//
// Append a copy of raw image data into the class
//
void GSLA::AddImages( const std::vector<unsigned char*>& pFrameBytes )
{
for (int idx = 0; idx < pFrameBytes.size(); ++idx)
{
unsigned char* pPixels = new unsigned char[ m_frameSize ];
memcpy(pPixels, pFrameBytes[ idx ], m_frameSize );
m_pC1PixelMaps.push_back( pPixels );
}
}
//------------------------------------------------------------------------------
//
// Compress / Serialize a new GSLA File
//
void GSLA::SaveToFile(const char* pFilenamePath)
{
// We're not going to even try encoding an empty file
if (m_pC1PixelMaps.size() < 1)
{
return;
}
// serialize to memory, then save that to a file
std::vector<unsigned char> bytes;
//--------------------------------------------------------------------------
// Add the header
bytes.resize( bytes.size() + sizeof(GSLA_Header) );
//$$JGA Rememeber, you have to set the pointer, before every access
//$$JGA to the header data, because vector is going to change out
//$$JGA memory addresses from underneath you
GSLA_Header* pHeader = (GSLA_Header*)&bytes[0];
pHeader->G = 'G'; pHeader->S = 'S'; pHeader->L = 'L'; pHeader->A = 'A';
pHeader->file_length = 0; // Temp File Length
pHeader->version = 0x8000; // Version 0, with a Ring/Loop Frame at the end
pHeader->width = m_widthPixels >> 1;
pHeader->height = m_widthHeight;
pHeader->frame_size = m_frameSize;
pHeader->frame_count = m_pC1PixelMaps.size() + 1; // + 1 for the ring frame
//--------------------------------------------------------------------------
// Add the INITial frame chunk
//
// If there's only an initial frame, I guess this becomes a picture
//
size_t init_offset = bytes.size();
// Add space for the INIT header
bytes.resize( bytes.size() + sizeof(GSLA_INIT) );
GSLA_INIT* pINIT = (GSLA_INIT*) &bytes[ init_offset ];
pINIT->I = 'I'; pINIT->N = 'N'; pINIT->i = 'I'; pINIT->T = 'T';
pINIT->chunk_length = 0; // temp chunk size
// Need a place to put compressed data, in theory it could be bigger
// than the original data, I think if that happens, the image was probably
// designed to break this, anyway, give double theoretical max
unsigned char* pWorkBuffer = new unsigned char[ m_frameSize * 2 ];
unsigned char* pInitialFrame = m_pC1PixelMaps[ 0 ];
// We're not worried about bank wrap on the first frame, and we don't have a pre-populated
// dictionary
int compressedSize = LZBA_Compress(pWorkBuffer, pInitialFrame, m_frameSize,
pInitialFrame, pInitialFrame);
for (int compressedIndex = 0; compressedIndex < compressedSize; ++compressedIndex)
{
bytes.push_back(pWorkBuffer[ compressedIndex ]);
}
// Insert EOF/ End of Animation Done opcode
bytes.push_back( 0x06 );
bytes.push_back( 0x00 );
// Reset pointer to the pINIT (as the baggage may have shifted)
pINIT = (GSLA_INIT*) &bytes[ init_offset ];
pINIT->chunk_length = (unsigned int) (bytes.size() - init_offset);
//--------------------------------------------------------------------------
// Add the ANIMation frames chunk
//
// We always add this, because we always add a Ring/Loop frame, we always
// end up with at least 2 frames
//
size_t anim_offset = bytes.size();
// Add Space for the ANIM Header
bytes.resize( bytes.size() + sizeof(GLSA_ANIM) );
GSLA_ANIM* pANIM = (GSLA_ANIM*) &bytes[ anim_offset ];
pANIM->A = 'A'; pANIM->N = 'N'; pANIM->I ='I'; pANIM->M = 'M';
pANIM->chunk_length = 0; // temporary chunk size
// Initialize the Canvas with the initial frame (we alread exported this)
unsigned char *pCanvas = new unsigned char[ m_frameSize ];
memcpy(pCanvas, m_pC1PixelMaps[0], m_frameSize);
memcpy(pCanvas, m_pC1PixelMaps[0], m_frameSize);
// Let's encode some frames buddy
for (int frameIndex = 1; frameIndex < m_pC1PixelMaps.size(); ++frameIndex)
{
// I don't want random data in the bank gaps, so initialize this
// buffer with zero
memset(pWorkBuffer, 0, m_frameSize * 2);
int frameSize = LZBA_Compress(pWorkBuffer, m_pC1PixelMaps[ frameIndex],
m_frameSize, pWorkBuffer-bytes.size(),
pCanvas, m_frameSize );
for (int frameIndex = 0; frameIndex < frameSize; ++frameIndex)
{
bytes.push_back(pWorkBuffer[ frameIndex ]);
}
}
// Add the RING Frame
memset(pWorkBuffer, 0, m_frameSize * 2);
int ringSize = LZBA_Compress(pWorkBuffer, m_pC1PixelMaps[ 0 ],
m_frameSize, pWorkBuffer-bytes.size(),
pCanvas, m_frameSize );
for (int ringIndex = 0; ringIndex < ringSize; ++ringIndex)
{
bytes.push_back(pWorkBuffer[ ringIndex ]);
}
delete[] pCanvas; pCanvas = nullptr;
// Insert End of file/ End of Animation Done opcode
bytes.push_back( 0x06 );
bytes.push_back( 0x00 );
// Update the chunk length
pFRAM = (FanFile_FRAM*)&bytes[ fram_offset ];
pFRAM->chunk_length = (unsigned int) (bytes.size() - fram_offset);
// Update the header
pHeader = (FanFile_Header*)&bytes[0]; // Required
pHeader->file_length = (unsigned int)bytes.size(); // get some valid data in there
// Try not to leak memory, even though we probably do
delete[] pWorkBuffer;
//--------------------------------------------------------------------------
// Create the file and write it
FILE* pFile = nullptr;
errno_t err = fopen_s(&pFile, pFilenamePath, "wb");
if (0==err)
{
fwrite(&bytes[0], sizeof(unsigned char), bytes.size(), pFile);
fclose(pFile);
}
}
//------------------------------------------------------------------------------

View File

@ -112,9 +112,13 @@ class GSLAFile
public:
// Load in a C2 File
GSLAFile(const char *pFilePath);
~GSLAFile();
// Creation
GSLAFile(int iWidthPixels, int iHeightPixels, int iFrameSizeBytes);
void AddImages( const std::vector<unsigned char*>& pFrameBytes );
void SaveToFile(const char* pFilenamePath);
// Retrieval
void LoadFromFile(const char* pFilePath);
int GetFrameCount() { return (int)m_pC1PixelMaps.size(); }

View File

@ -574,4 +574,20 @@ void LZB_Decompress(unsigned char* pDest, unsigned char* pSource, int destSize)
}
//------------------------------------------------------------------------------
//
// Encode a Frame in GSLA LZB Format
//
int LZBA_Compress(unsigned char* pDest, unsigned char* pSource, int sourceSize, unsigned char* pDataStart, int dictionarySize)
{
}
//------------------------------------------------------------------------------
//
// Decompress a Frame in the GSLA LZB Format
//
int LZBA_Decompress(unsigned char* pDest, unsigned char* pSource, unsigned char* pDataStart)
{
}
//------------------------------------------------------------------------------

View File

@ -11,5 +11,11 @@ int LZB_Compress(unsigned char* pDest, unsigned char* pSource, int sourceSize);
int Old_LZB_Compress(unsigned char* pDest, unsigned char* pSource, int sourceSize);
void LZB_Decompress(unsigned char* pDest, unsigned char* pSource, int destSize);
//
// LZB Compressor that uses GSLA Opcodes while encoding
//
int LZBA_Compress(unsigned char* pDest, unsigned char* pSource, int sourceSize, unsigned char* pDataStart, unsigned char* pDictionary, int dictionarySize=0);
int LZBA_Decompress(unsigned char* pDest, unsigned char* pSource, unsigned char* pDataStart);
#endif // LZB_H

View File

@ -1,5 +1,7 @@
//
// GSLA - GS LZB Animation Tool
//
// Look in gsla_file.cpp/h for more information about the file format
//
#include <stdio.h>
@ -7,16 +9,20 @@
#include <string>
#include "c2_file.h"
#include "gsla_file.h"
#include "lzb.h"
//------------------------------------------------------------------------------
static void helpText()
{
printf("GSLA - v0.0\n");
printf("GSLA - v1.0\n");
printf("--------------\n");
printf("GS Lzb Animation Tool\n");
printf("GS Lzb Animation Creation Tool\n");
printf("\n");
printf("\ngsla [options] <input_file> <outfile>\n");
printf("\n\n There are no [options] yet\n");
printf("Converts from C2 to GSLA\n");
exit(-1);
}
@ -111,8 +117,25 @@ int main(int argc, char* argv[])
helpText();
}
if (pOutfilePath)
{
const std::vector<unsigned char*>& c1Datas = c2data.GetPixelMaps();
printf("Saving %s with %d frames\n", pOutfilePath, (int)c1Datas.size());
GSLAFile anim(320,200, 0x8000);
anim.AddImages(c1Datas);
anim.SaveToFile(pOutfilePath);
}
#if 0
const std::vector<unsigned char*>& c1Datas = c2data.GetPixelMaps();
// LZB Testing Code, that I should probalby remove from this file
// Just ignore this block of code
#if 1
unsigned char workbuffer[64*1024];
for (int idx = 0; idx < frameCount; ++idx)
@ -160,6 +183,7 @@ int main(int argc, char* argv[])
}
#endif
#endif
}
}