saveFrame() doesn't match real time

Hello everyone, I have a very tricky question here.
Why saveFrame() doesn’t write all the frames as it should? I mean, if I have a grid of 28 tiles (println(points.size());), and I wait 1 second to fill each tile:

if (millis() - timer >= 1000) {
    ruin();
    timer = millis();
  }

Shouldn’t I end with 28 seconds * 60 fps = 1680 frames? Why even if I fill up all the tiles in 28 seconds I end up with less then 300 frames written in the out folder? :thinking:

Thank you so much

ArrayList<GridPoint> points = new ArrayList<GridPoint>();

ArrayList<Integer> indexes = new ArrayList<Integer>();

float tileWidth = 200, tileHeight = 200;

int timer;

void setup() {
  size(1280, 720);
  noStroke();

  for (float x = 0; x < width; x += tileWidth) {
    for (float y = 0; y < height; y += tileHeight) {
      points.add(new GridPoint(x, y, tileWidth, tileHeight));
    }
  }

  for (int i = 0; i < points.size(); i++) {
    indexes.add(i);
  }

  println(points.size());
}

void draw() {
  background(255);

  for (int i = 0; i < points.size(); i++) {
    if (points.get(i).black) {
      fill(0);
    } else {
      noFill();
    }
    points.get(i).show();
  }

  saveFrame("out/a#############.png");

  if (millis() - timer >= 1000) {
    ruin();
    timer = millis();
  }
}

void ruin() {
  if (indexes.size() != 0) {
    int chosen = (int) random(0, indexes.size()); 
    int index = indexes.get(chosen); 
    GridPoint p = points.get(index); 
    p.black = true; 
    indexes.remove(chosen);
  }
}

class GridPoint {
  float x, y, tileWidth, tileHeight;
  boolean black = false;

  GridPoint(float x, float y, float tileWidth, float tileHeight) {
    this.x = x;
    this.y = y;
    this.tileWidth = tileWidth;
    this.tileHeight = tileHeight;
  }

  void show() {
    rect(x, y, tileWidth, tileHeight);
  }
}

It seems that using:

if (frameCount - timer >= 60) {
    //println("OK");
    ruin();
    timer = frameCount;
  }

Actually works.
So, when the fps real time drop as in case as using saveFrame(), it doesn’t stop millis() to continue to count time passed. This asynchronous behaviour is causing frames dropping and when I use saveFrame() I better not use millis()

:disappointed_relieved:

2 Likes

Saving to a *.png I get 20 fps.
Saving to a *.tga I get 60 fps.

Your solution works well if you want to save frames synced to frameCount and keep them synchronized to frames; I have done this before to save frames for later processing (sometimes with Movie Maker in Processing Tools).

Saving to *.tga will let you watch it unfold in real-time (depending on code).

I like to monitor frameRate with:

And use this in draw():

surface.setTitle(str(frameRate));