mirror of https://github.com/dwsJason/gsla.git
Compare commits
2 Commits
e19209dea0
...
fa7a01593a
Author | SHA1 | Date |
---|---|---|
JASON-6700K\jandersen | fa7a01593a | |
JASON-6700K\jandersen | 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 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -57,10 +57,14 @@ public:
|
||||||
int GetWidth() { return m_widthPixels; }
|
int GetWidth() { return m_widthPixels; }
|
||||||
int GetHeight() { return m_heightPixels; }
|
int GetHeight() { return m_heightPixels; }
|
||||||
|
|
||||||
|
void ApplyThrottle(int ThrottleSize, int CellSizeX, int CellSizeY);
|
||||||
|
|
||||||
const std::vector<unsigned char*>& GetPixelMaps() { return m_pC1PixelMaps; }
|
const std::vector<unsigned char*>& GetPixelMaps() { return m_pC1PixelMaps; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
int CalcDifference(unsigned char* pC1Data0, unsigned char* pC1Data1);
|
||||||
|
|
||||||
int m_widthPixels; // Width of image in pixels
|
int m_widthPixels; // Width of image in pixels
|
||||||
int m_heightPixels; // Height 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()
|
static void helpText()
|
||||||
{
|
{
|
||||||
printf("GSLA - v1.0\n");
|
printf("GSLA - v1.1\n");
|
||||||
printf("--------------\n");
|
printf("--------------\n");
|
||||||
printf("GS Lzb Animation Creation Tool\n");
|
printf("GS Lzb Animation Creation Tool\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("\ngsla [options] <input_file> <outfile>\n");
|
printf("\ngsla [options] <input_file> <outfile>\n\n");
|
||||||
printf("\n\n There are no [options] yet\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");
|
printf("Converts from C2 to GSLA\n");
|
||||||
|
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
@ -29,6 +32,64 @@ static void helpText()
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Local helper functions
|
// 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)
|
static std::string toLower(const std::string s)
|
||||||
{
|
{
|
||||||
std::string result = s;
|
std::string result = s;
|
||||||
|
@ -61,6 +122,11 @@ int main(int argc, char* argv[])
|
||||||
char* pInfilePath = nullptr;
|
char* pInfilePath = nullptr;
|
||||||
char* pOutfilePath = nullptr;
|
char* pOutfilePath = nullptr;
|
||||||
|
|
||||||
|
int throttle=0; // no throttling
|
||||||
|
// default 8x8 grid
|
||||||
|
int gridSizeX = 8;
|
||||||
|
int gridSizeY = 8;
|
||||||
|
|
||||||
|
|
||||||
// index 0 is the executable name
|
// index 0 is the executable name
|
||||||
|
|
||||||
|
@ -73,7 +139,29 @@ int main(int argc, char* argv[])
|
||||||
if ('-' == arg[0])
|
if ('-' == arg[0])
|
||||||
{
|
{
|
||||||
// Parse as an option
|
// 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)
|
else if (nullptr == pInfilePath)
|
||||||
{
|
{
|
||||||
|
@ -117,6 +205,22 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
if (pOutfilePath)
|
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();
|
const std::vector<unsigned char*>& c1Datas = c2data.GetPixelMaps();
|
||||||
|
|
||||||
printf("Saving %s with %d frames\n", pOutfilePath, (int)c1Datas.size());
|
printf("Saving %s with %d frames\n", pOutfilePath, (int)c1Datas.size());
|
||||||
|
|
Loading…
Reference in New Issue