Movie Maker using incorrect image order

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!

check out hamoid video export library please

see Movie Maker video doesn't sync - #12 by hamoid

see https://funprogramming.org/VideoExport-for-Processing/examples/basic/basic.pde

Weird. I tried the Video Export library earlier before i posted and the resulting video was choppy and the wrong speed. I gave it another try after you suggested it and it output a smooth video at the right speed. :man_shrugging: Don’t know why but i’ll take it.

Thanks!

1 Like