I have a sketch that is a grid of squares, 10 down, 15 across. Among other animations, what it does is start on the top left square and spin it around. Then it goes across the first row, spinning each square one by one. Then down to the second row, spinning squares left to right. It continues like this until it gets to the bottom right corner of the screen, and then starts back up in the top left.
I’m doing a saveFrame() to .tga format so the movie maker can make a video of it.
However, the resulting movie doesn’t run forwards, and it doesn’t run in reverse. Somehow it’s incorrectly starting on the bottom left square on row 10, properly works its way across the row, and then incorrectly goes up to the first square in the 9th row. Across and then up to the 8th row. This is not the order of the frames.
It’s not even a logical wrong place to start. It’s not confusing name_001.tga with name_0001.tga. It’s starting on the file Patchwork_012867.tga, which is somehow the exact start of the 10th row. Then when it gets to the end it moves back to Patchwork_012200.tga (the beginning of the 9th row) so it’s not like it’s getting confused by leading zeros.
I’m not really sure where to start troubleshooting this because it’s not in my code. Running the sketch creates the desired animation and all the image files are created properly and in order. But there’s something happening between there and the resulting .mov file.
What could be causing it to start in such a strangely wrong spot?
Movie Maker Settings:
- Framerate 60
- Compression Animation
- Same size as originals checked
- No audio
Sketch code:
Summary
int numRows;
int numColumns;
final int SECONDS_TO_CAPTURE = 240;
final int VIDEO_FRAME_RATE = 60;
boolean recordVideo = true;
int videoFramesCaptured = 0;
GridSystem gridSystem;
void setup()
{
fullScreen(P2D);
rectMode(CENTER);
//blendMode(DIFFERENCE);
//blendMode(LIGHTEST);
blendMode(ADD);
numRows = 10;
numColumns = (int)( numRows * ( (float)width) / (float)height );
gridSystem = new GridSystem();
}
void draw()
{
background(0);
gridSystem.run();
//saveFrame("output/patchwork_#####.png");
if (recordVideo)
{
saveFrame("output/Patchwork_######.tga");
if (videoFramesCaptured > VIDEO_FRAME_RATE * SECONDS_TO_CAPTURE)
{
recordVideo = false;
videoFramesCaptured = 0;
}
else
{
videoFramesCaptured++;
}
// If recording show red square
pushStyle();
noFill();
strokeWeight(2);
stroke(255,0,0);
rect(width / 2, height / 2, width, height);
popStyle();
}
}
Summary
class GridSystem
{
ArrayList<GridItem> gridItems;
GridSystem()
{
// Initialize 2D Array List of GridItem
gridItems = new ArrayList<GridItem>();
int index = 0;
// Create an ArrayList for the row.
// Populate the row's ArrayList.
// Put that ArrayList into 2D ArrayList
for (int row = 0; row < numRows; row++)
{
for (int column = 0; column < numColumns; column++)
{
gridItems.add( new GridItem(column, row, index) );
index++;
}
}
}
void run()
{
for (GridItem i : gridItems)
{
i.run();
}
}
}
Summary
class GridItem
{
color renderColor;
color morphColor;
int index;
float col;
float rw;
float posX;
float posY;
boolean isLerping;
float timeMarker;
// Constructor
GridItem(int col_, int rw_, int ind)
{
// Member variable setup
col = col_;
rw = rw_;
index = ind;
// Color Setup
float r1 = random(255);
float g1 = random(255);
float b1 = random(255);
renderColor = color( r1, g1, b1 );
// mod setup
isLerping = false;
timeMarker = 0.0f;
}
void run()
{
render();
}
void render()
{
noStroke();
// Box dimensions
float boxW = (float)width / (float)numColumns;
float boxH = (float)height / (float)numRows;
// Offset for rectMode(CENTER)
float centerOffsetW = boxW * 0.5f;
float centerOffsetH = boxH * 0.5f;
// Position
posX = (boxW * col) + centerOffsetW;
posY = (boxH * rw) + centerOffsetH;
// Timers and modulators
int colTimer = (int)(millis() * 0.005f) % numColumns;
int itemTimer = (int)(millis() * 0.001f) % gridSystem.gridItems.size();
float breather = sin( (millis() * 0.0005f ) * TWO_PI ); // shrink/grow pattern
float rotMult; // Rotation speed multiplier
// Increment through individual
if (itemTimer % (numColumns * numRows) == index)
{
breather *= 2.0f; // Grow size
rotMult = 10.0f; // Speed rotation
}
else
{
rotMult = 1.0f; // Standard rotation speed
//outColor = c1;
}
// Translate, rotate, and draw
pushMatrix();
translate( posX, posY );
// Column spins backwards and faster at colTimer modulo
if (colTimer == col)
{
float rotateVal = radians(millis() * -1.0f) * rotMult;
rotate( rotateVal );
//float colorLerpVal = map( sin(rotateVal), -1.0f, 1.0f, 0.0f, 1.0f);//(sin(-rotateVal) + 1.0f) * 0.5f;
float colorLerpVal = (millis() - timeMarker) * 0.01f;
if (colorLerpVal > 1.0f)
colorLerpVal = 1.0f;
renderColor = colorFlip( renderColor, colorLerpVal);
isLerping = true;
}
else
{
rotate( radians(millis() * 0.01f) * rotMult );
isLerping = false;
timeMarker = millis();
}
fill(renderColor);
rect(0, 0, boxW * breather, boxH * breather);
if ( (millis() % 50000.0f) > 40000.0f && (millis() % 50000.0f) < 50000.0f)
randFlash(boxW);
popMatrix();
}
void randFlash(float diameter)
{
if ( (int)random(gridSystem.gridItems.size()) == index )
{
fill(255);
circle(0, 0, diameter);
}
}
// Flips from a color to its inverse
color colorFlip(color colorIn, float lerpVal)
{
if (!isLerping)
{
morphColor = colorIn;
}
float rIn = morphColor >> 16 & 0xFF;
float gIn = morphColor >> 8 & 0xFF;
float bIn = morphColor & 0xFF;
float minRGB = min( rIn, ( min(gIn, bIn) ) );
float maxRGB = max( rIn, ( max(gIn, bIn) ) );
float minMax = minRGB + maxRGB;
color colorInv = color( minMax - rIn, minMax - gIn, minMax - bIn );
return lerpColor( colorIn, colorInv, lerpVal );
}
}
Thanks!