#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();
}