Blame onefile/rubber.c

a5e8d6
a5e8d6
#include <math.h></math.h>
a5e8d6
#include <stdlib.h></stdlib.h>
a5e8d6
#include <helianthus.h></helianthus.h>
a5e8d6
a5e8d6
a5e8d6
#define MAX_BALLS   1000
a5e8d6
#define MAX_LINKS   10000
a5e8d6
#define BALL_RADIUS 1.0
a5e8d6
#define BALL_FADE   0.8
a5e8d6
#define LINK_K      0.05
a5e8d6
a5e8d6
a5e8d6
typedef struct {
a5e8d6
  double x, y;
a5e8d6
  double vx, vy;
a5e8d6
} Ball;
a5e8d6
a5e8d6
a5e8d6
typedef struct {
a5e8d6
  double dx, dy;
a5e8d6
  Ball *a, *b;
a5e8d6
} Link;
a5e8d6
a5e8d6
a5e8d6
Ball balls[MAX_BALLS];
a5e8d6
Link links[MAX_LINKS];
a5e8d6
int ballsCount = 0;
a5e8d6
int linksCount = 0;
a5e8d6
a5e8d6
double remainDt;
a5e8d6
a5e8d6
Ball *mball;
a5e8d6
double mdx, mdy;
a5e8d6
double mx, my;
a5e8d6
a5e8d6
a5e8d6
void ballUpdate(Ball *ball, double dt) {
a5e8d6
  double fade = pow(BALL_FADE, dt);
a5e8d6
  ball->x += ball->vx*dt;
a5e8d6
  ball->y += ball->vy*dt;
a5e8d6
  ball->vx *= fade;
a5e8d6
  ball->vy *= fade;
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void linkUpdate(Link *link, double dt) {
a5e8d6
  double dx = link->b->x - link->a->x;
a5e8d6
  double dy = link->b->y - link->a->y;
a5e8d6
a5e8d6
  double dvx = (dx - link->dx)*0.5*LINK_K;
a5e8d6
  double dvy = (dy - link->dy)*0.5*LINK_K;
a5e8d6
a5e8d6
  link->a->vx += dvx; link->b->vx -= dvx;
a5e8d6
  link->a->vy += dvy; link->b->vy -= dvy;
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void update(double dt) {
a5e8d6
  remainDt += dt;
a5e8d6
  while(remainDt > 0.001) {
a5e8d6
    remainDt -= 0.001;
a5e8d6
    for(int i = 0; i < linksCount; ++i)
a5e8d6
      linkUpdate(&links[i], dt);
a5e8d6
    for(int i = 0; i < ballsCount; ++i)
a5e8d6
      ballUpdate(&balls[i], dt);
a5e8d6
  }
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void init() {
a5e8d6
  int cnt = 10;
a5e8d6
  double dist = 3*BALL_RADIUS;
a5e8d6
  for(int i = 0; i < cnt; ++i) {
a5e8d6
    for(int j = 0; j < cnt; ++j) {
a5e8d6
      Ball *ball = &balls[ballsCount++];
a5e8d6
      ball->x = (i - 0.5*(cnt - 1))*dist;
a5e8d6
      ball->y = (j - 0.5*(cnt - 1))*dist;
a5e8d6
      if (i > 0) {
a5e8d6
        Link *link = &links[linksCount++];
a5e8d6
        link->a = ball - cnt;
a5e8d6
        link->b = ball;
a5e8d6
        link->dx = dist;
a5e8d6
      }
a5e8d6
      if (j > 0) {
a5e8d6
        Link *link = &links[linksCount++];
a5e8d6
        link->a = ball - 1;
a5e8d6
        link->b = ball;
a5e8d6
        link->dy = dist;
a5e8d6
      }
a5e8d6
    }
a5e8d6
  }
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
void draw() {
a5e8d6
  double dt = windowGetFrameTime();
a5e8d6
  double w = windowGetWidth();
a5e8d6
  double h = windowGetHeight();
a5e8d6
a5e8d6
  saveState();
a5e8d6
  translate(w/2, h/2);
a5e8d6
  zoom(20);
a5e8d6
a5e8d6
  mx = mouseTransformedX();
a5e8d6
  my = mouseTransformedY();
a5e8d6
  if (mouseDown("left")) {
a5e8d6
    if (!mball) {
a5e8d6
      for(int i = ballsCount-1; i >= 0; --i) {
a5e8d6
        Ball *ball = &balls[i];
a5e8d6
        double dx = mx - ball->x;
a5e8d6
        double dy = my - ball->y;
a5e8d6
        if (dx*dx + dy*dy <= BALL_RADIUS*BALL_RADIUS) {
a5e8d6
          mball = ball;
a5e8d6
          mdx = dx;
a5e8d6
          mdy = dy;
a5e8d6
          break;
a5e8d6
        }
a5e8d6
      }
a5e8d6
    }
a5e8d6
  } else {
a5e8d6
    mball = NULL;
a5e8d6
  }
a5e8d6
a5e8d6
a5e8d6
  update(dt);
a5e8d6
a5e8d6
  if (mball) {
a5e8d6
    mball->x = mx - mdx;
a5e8d6
    mball->y = my - mdy;
a5e8d6
    mball->vx = 0;
a5e8d6
    mball->vy = 0;
a5e8d6
  }
a5e8d6
a5e8d6
  stroke(0xffe666ff);
a5e8d6
  strokeWidth(BALL_RADIUS*0.1);
a5e8d6
  noFill();
a5e8d6
  for(int i = 0; i < linksCount; ++i) {
a5e8d6
    Link *link = &links[i];
a5e8d6
    line(link->a->x, link->a->y, link->b->x, link->b->y);
a5e8d6
  }
a5e8d6
a5e8d6
  noStroke();
a5e8d6
  fill(0xffe666ff);
a5e8d6
  for(int i = 0; i < ballsCount; ++i) {
a5e8d6
    Ball *ball = &balls[i];
a5e8d6
    circle(ball->x, ball->y, BALL_RADIUS);
a5e8d6
  }
a5e8d6
a5e8d6
  restoreState();
a5e8d6
}
a5e8d6
a5e8d6
a5e8d6
int main() {
a5e8d6
  windowSetResizable(TRUE);
a5e8d6
  windowSetVariableFrameRate();
a5e8d6
  windowSetInit(&init);
a5e8d6
  windowSetDraw(&draw);
a5e8d6
  windowRun();
a5e8d6
}