Blob Blame Raw

#include <math.h>
#include <string.h>
#include <helianthus.h>


#define MAXCOUNT 10000
#define SPEED    1
#define SPS      500
#define PERSP    0.5


typedef struct Star {
  double x, y, z;
  double px, py;
  int visible;
} Star;

Star stars[MAXCOUNT];
double step;
double mx, my;


Framebuffer buffer;
Animation anim;


void update(double dt) {
  double dz = SPEED*dt;
  double sx =  mx*dz*PERSP;
  double sy = -my*dz*PERSP;
  int j = 0, count = 0;
  for(int i = 0; i < MAXCOUNT; ++i) {
    if (stars[i].visible) {
      double x = stars[i].x - sx*stars[i].z;
      double y = stars[i].y - sy*stars[i].z;
      double z = stars[i].z + sx*stars[i].x + sy*stars[i].y;
      stars[i].x = x;
      stars[i].y = y;
      stars[i].z = z - dz;
    } else {
      j = i;
      ++count;
    }
  }

  step += SPS*dt;
  if (count > (int)step) count = (int)step;
  step -= (int)step;
  for(int i = 0; i < count; ++i) {
    while(stars[j].visible) j = (j+1)%MAXCOUNT;
    stars[j].px = 2*randomFloat() - 1;
    stars[j].py = 2*randomFloat() - 1;
    stars[j].z = 1 - randomFloat()*dz;
    stars[j].x = stars[j].px * stars[j].z / PERSP;
    stars[j].y = stars[j].py * stars[j].z / PERSP;
    stars[j].visible = TRUE;
  }
}


void init() {
  background(COLOR_BLACK);
  buffer = createFramebuffer(windowGetWidth(), windowGetHeight());
  anim = createAnimationFromFramebuffer(buffer);
}


void draw() {
  double w = windowGetWidth();
  double h = windowGetHeight();
  double s = 0.5*(w > h ? w : h);

  saveState();
  noStroke();
  target(buffer);
  update(windowGetFrameTime());

  fill(colorByRGBA(0, 0, 0, 0.25));
  rect(0, 0, w, h);

  saveState();
  translate(w/2, h/2);
  zoom(s);
  mx = mouseTransformedX();
  my = mouseTransformedY();
  stroke(COLOR_WHITE);
  double dz = 0.01;
  for(int i = 0; i < MAXCOUNT; ++i) {
    if (stars[i].visible) {
      double z = stars[i].z > dz ? stars[i].z : dz;
      double x = stars[i].x/z*PERSP;
      double y = stars[i].y/z*PERSP;
      double r = 0.25/s/z;
      strokeWidth(r);

      line(stars[i].px, stars[i].py, x, y);
      stars[i].px = x;
      stars[i].py = y;
      stars[i].visible = stars[i].z > dz && fabs(x)-r < 1 && fabs(y)-r < 1;
    }
  }
  restoreState();

  noTarget(buffer);
  fill(COLOR_WHITE);
  rectTextured(anim, 0, 0, w, h);

  restoreState();
}


int main() {
  windowSetSize(1024, 768);
  windowSetVariableFrameRate();
  windowSetInit(&init);
  windowSetDraw(&draw);
  windowRun();
}