Compare commits

...

2 Commits

Author SHA1 Message Date
JASON-6700K\jandersen fa7a01593a fix up type o in comments 2023-05-11 11:43:15 -04:00
JASON-6700K\jandersen b3a434a5bd take a stab at supporting fixed data rates 2023-05-11 11:23:58 -04:00
3 changed files with 242 additions and 4 deletions

View File

@ -140,4 +140,134 @@ void C2File::LoadFromFile(const char* pFilePath)
}
//------------------------------------------------------------------------------
//
// How many bytes are different between these frames
//
int C2File::CalcDifference(unsigned char* pC1Data0, unsigned char* pC1Data1)
{
int total = 0;
for (int idx = 0; idx < 160*200; ++idx)
{
if (pC1Data0[idx] != pC1Data1[idx])
{
total+=1;
}
}
return total;
}
//------------------------------------------------------------------------------
//
// I'm only going to apply the throttle to the pixels, not SCB + Palette
// changes, most animations, should not change the SCB or CLUT
//
void C2File::ApplyThrottle(int ThrottleSize, int CellSizeX, int CellSizeY)
{
// I want cells to be updated "Round Robin", we start updating at whichever
// cell we left off on the previous frame.
// Make Sure CellSizes are valid range
if (CellSizeX > 320)
{
CellSizeX = 320;
}
if (CellSizeY > 200)
{
CellSizeY = 200;
}
CellSizeX >>= 1; //from pixels to bytes
if (CellSizeX < 1)
{
CellSizeX = 1;
}
if (CellSizeY < 1)
{
CellSizeY = 1;
}
int numCellsX = 160/CellSizeX;
int numCellsY = 200/CellSizeY;
//-------------------------------------------------------------------------
int totalCells = numCellsX * numCellsY;
int bytesPerCell = CellSizeX * CellSizeY;
// prepare state
int CellIndex = 0; // For Round Robin
std::vector<int> indices;
// Set all initial indices to 0
for (int idx = 0; idx < totalCells; ++idx)
{
indices.push_back((0));
}
// Go through all the frames
for (int index = 1; index < m_pC1PixelMaps.size(); ++index)
{
unsigned char* p0 = m_pC1PixelMaps[index - 1];
unsigned char* p1 = m_pC1PixelMaps[index];
int deltaSize = CalcDifference(p0,p1);
while (deltaSize > ThrottleSize)
{
// Reduce the difference, while the size is too big
// this works by removing differences from the target, until we're in budget
int subIndex = indices[CellIndex];
// Calculate the buffer position by converting CellIndex, and subIndex
// into X,Y position in the buffer
int pixel_y = (CellIndex / numCellsX) * CellSizeY;
int pixel_x = (CellIndex % numCellsX) * CellSizeX;
int sub_pixel_y = (subIndex / CellSizeX);
int sub_pixel_x = (subIndex % CellSizeX);
pixel_x += sub_pixel_x;
pixel_y += sub_pixel_y;
if (pixel_x < 0) pixel_x = 0;
if (pixel_y < 0) pixel_y = 0;
if (pixel_x >= 160) pixel_x=159;
if (pixel_y >= 200) pixel_y=199;
int pixel_index = (pixel_y*160) + pixel_x;
if (p0[pixel_index] != p1[pixel_index])
{
// remove delta
p1[pixel_index] = p0[pixel_index];
deltaSize--;
}
// go to next index in the cell, for the next time we process the cell
subIndex++;
if (subIndex >= bytesPerCell)
{
subIndex = 0;
}
indices[CellIndex] = subIndex;
// next cell
CellIndex++;
if (CellIndex >= totalCells)
{
CellIndex = 0;
}
}
}
}
//------------------------------------------------------------------------------

View File

@ -57,10 +57,14 @@ public:
int GetWidth() { return m_widthPixels; }
int GetHeight() { return m_heightPixels; }
void ApplyThrottle(int ThrottleSize, int CellSizeX, int CellSizeY);
const std::vector<unsigned char*>& GetPixelMaps() { return m_pC1PixelMaps; }
private:
int CalcDifference(unsigned char* pC1Data0, unsigned char* pC1Data1);
int m_widthPixels; // Width of image in pixels
int m_heightPixels; // Height of image in pixels

View File

@ -14,12 +14,15 @@
//------------------------------------------------------------------------------
static void helpText()
{
printf("GSLA - v1.0\n");
printf("GSLA - v1.1\n");
printf("--------------\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("\ngsla [options] <input_file> <outfile>\n\n");
printf("options:\n");
printf("\t-t<bytes> Throttle bytes per frame\n");
printf("\t-g<x>x<y> Grid size, default 8x8\n");
printf("\nExample: gsla -t2960 -g8x8 movie.c2 movie.gsla\n\n");
printf("Converts from C2 to GSLA\n");
exit(-1);
@ -29,6 +32,64 @@ static void helpText()
//------------------------------------------------------------------------------
// Local helper functions
static bool contains(char x, const char* pSeparators)
{
while (*pSeparators)
{
if (x == *pSeparators)
{
return true;
}
pSeparators++;
}
return false;
}
static std::vector<std::string> split(const std::string& s, const char* separators)
{
std::vector<std::string> output;
std::string::size_type prev_pos = 0, pos = 0;
for (int index = 0; index < s.length(); ++index)
{
pos = index;
// if the index is a separator
if (contains(s[index], separators))
{
// if we've skipped a token, collect it
if (prev_pos != index)
{
output.push_back(s.substr(prev_pos, index-prev_pos));
// skip white space here
while (index < s.length())
{
if (contains(s[index], separators))
{
++index;
}
else
{
prev_pos = index;
pos = index;
break;
}
}
}
else
{
prev_pos++;
}
}
}
output.push_back(s.substr(prev_pos, pos-prev_pos+1)); // Last word
return output;
}
static std::string toLower(const std::string s)
{
std::string result = s;
@ -61,6 +122,11 @@ int main(int argc, char* argv[])
char* pInfilePath = nullptr;
char* pOutfilePath = nullptr;
int throttle=0; // no throttling
// default 8x8 grid
int gridSizeX = 8;
int gridSizeY = 8;
// index 0 is the executable name
@ -73,7 +139,29 @@ int main(int argc, char* argv[])
if ('-' == arg[0])
{
// Parse as an option
// Currently I have no options, so I'll just skip
if ('t' == arg[1])
{
// Set throttle size, which enables throttling
throttle = atoi(&arg[2]);
printf("Throttle = %d bytes per frame\n",throttle);
}
if ('g' == arg[1])
{
// set grid size for the throttler (this effects the pattern, when throttling kicks in)
std::string gridstring = toLower(&arg[2]);
std::vector<std::string> values = split(gridstring, "x");
if (values.size() != 2)
{
printf("invalid grid size setting: %s\n", arg);
helpText();
}
gridSizeX = atoi(values[0].c_str());
gridSizeY = atoi(values[1].c_str());
}
}
else if (nullptr == pInfilePath)
{
@ -117,6 +205,22 @@ int main(int argc, char* argv[])
if (pOutfilePath)
{
if (0 != throttle)
{
printf("Grid Size = %dx%d\n", gridSizeX, gridSizeY);
int numCellsX = 320/gridSizeX;
int numCellsY = 200/gridSizeY;
printf("Cell Count = %dx%d\n", numCellsX, numCellsY);
int numCells = numCellsX*numCellsY;
printf("Cell Total = %d\n", numCells);
printf("Each cell min budget = %d bytes\n", throttle/numCells);
c2data.ApplyThrottle(throttle, gridSizeX, gridSizeY);
}
const std::vector<unsigned char*>& c1Datas = c2data.GetPixelMaps();
printf("Saving %s with %d frames\n", pOutfilePath, (int)c1Datas.size());