mirror of
https://github.com/dwsJason/gsla.git
synced 2024-06-14 06:29:27 +00:00
take a stab at supporting fixed data rates
This commit is contained in:
parent
e19209dea0
commit
b3a434a5bd
|
@ -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 indix 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
112
source/main.cpp
112
source/main.cpp
|
@ -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());
|
||||
|
|
Loading…
Reference in New Issue
Block a user