Stipple Cat
// Stipple Cat Jim Bumgardner
//
// @pjs preload="/assets/cats2_0.png";
// @pjs preload="/assets/cats2_1.png";
// @pjs preload="/assets/cats2_2.png";
// @pjs preload="/assets/cats2_3.png";
// @pjs preload="/assets/cats2_4.png";
// @pjs preload="/assets/cats2_5.png";
// @pjs preload="/assets/cats2_6.png";
// @pjs preload="/assets/cats2_7.png";
// Play with these...
float imageScale;
float dotDensity = .24; // higher ratios = more dots
// Probably don't need to play with these as much...
float damping = 0.7;
float kRadiusFactor = 0.5;
float kSpeed = 3.0;
float minDistFactor = 2.5; // area of influence - smaller numbers make rendering go faster
int nbrParticles = 2200;
int catSpeed = 2;
PImage reference; // for dithering initialilzation...
int nbrCatFrames = 8;
PImage[] cats = new PImage[nbrCatFrames];
class Particle
{
float x, y, vx, vy, rad;
float fx, fy, wt;
Particle(float _x, float _y)
{
vx = 0;
vy = 0;
x = _x;
y = _y;
rad = 1;
}
}
Particle[] particles;
float minRadius, maxRadius, medRadius;
void setup()
{
size(500, 214);
for (int i = 0; i < nbrCatFrames; ++i) {
cats[i] = loadImage("/assets/cats2_" + i + ".png");
}
reference = cats[0];
int dwidth = 136;
int dheight = 68;
imageScale = width/(float) dwidth;
particles = new Particle[nbrParticles];
for (int i = 0; i < nbrParticles; ++i) {
particles[i] = new Particle(random(width), random(height));
}
frameRate(24);
// noLoop();
smooth();
noStroke();
float medArea = (width*height)/nbrParticles;
medRadius = sqrt(medArea/PI);
minRadius = medRadius;
maxRadius = medRadius*medRadius*1;
// println("nbrParticles = " + nbrParticles);
// println("medrad = " + medRadius);
// println("min-max = " + minRadius + " --> " + maxRadius);
background(255);
}
void doPhysics()
{
if (frameCount % catSpeed == 0) {
int frameCtr = (frameCount/catSpeed % nbrCatFrames);
reference = cats[frameCtr];
}
for (int i = 0; i < nbrParticles; ++i) {
int px = (int) (particles[i].x / imageScale);
int py = (int) (particles[i].y / imageScale);
if (px >= 0 && px < reference.width && py >= 0 && py < reference.height) {
int v = (int) red(reference.pixels[ py*reference.width + px ]);
particles[i].rad = map(v/255.0, 0, 1, minRadius, maxRadius);
}
}
for (int i = 0; i < nbrParticles; ++i) {
Particle p = particles[i];
p.fx = p.fy = p.wt = 0;
p.vx *= damping;
p.vy *= damping;
}
// Particle -> particle interactions
for (int i = 0; i < nbrParticles-1; ++i) {
Particle p = particles[i];
for (int j = i+1; j < nbrParticles; ++j) {
Particle pj = particles[j];
if (i== j || Math.abs(pj.x - p.x) > p.rad*minDistFactor ||
Math.abs(pj.y - p.y) > p.rad*minDistFactor)
continue;
double dx = p.x - pj.x;
double dy = p.y - pj.y;
double distance = Math.sqrt(dx*dx+dy*dy);
double maxDist = (p.rad + pj.rad);
double diff = maxDist - distance;
if (diff > 0) {
double scle = diff/maxDist;
scle = scle*scle;
p.wt += scle;
pj.wt += scle;
scle = scle*kSpeed/distance;
p.fx += dx*scle;
p.fy += dy*scle;
pj.fx -= dx*scle;
pj.fy -= dy*scle;
}
}
}
for (int i = 0; i < nbrParticles; ++i) {
Particle p = particles[i];
// keep within edges
double dx, dy, distance, scle, diff;
double maxDist = p.rad;
// left edge
distance = dx = p.x - 0;
dy = 0;
diff = maxDist - distance;
if (diff > 0) {
scle = diff/maxDist;
scle = scle*scle;
p.wt += scle;
scle = scle*kSpeed/distance;
p.fx += dx*scle;
p.fy += dy*scle;
}
// right edge
dx = p.x - width;
dy = 0;
distance = -dx;
diff = maxDist - distance;
if (diff > 0) {
scle = diff/maxDist;
scle = scle*scle;
p.wt += scle;
scle = scle*kSpeed/distance;
p.fx += dx*scle;
p.fy += dy*scle;
}
// top edge
distance = dy = p.y - 0;
dx = 0;
diff = maxDist - distance;
if (diff > 0) {
scle = diff/maxDist;
scle = scle*scle;
p.wt += scle;
scle = scle*kSpeed/distance;
p.fx += dx*scle;
p.fy += dy*scle;
}
// bot edge
dy = p.y - height;
dx = 0;
distance = -dy;
diff = maxDist - distance;
if (diff > 0) {
scle = diff/maxDist;
scle = scle*scle;
p.wt += scle;
scle = scle*kSpeed/distance;
p.fx += dx*scle;
p.fy += dy*scle;
}
if (p.wt > 0) {
p.vx += p.fx/p.wt;
p.vy += p.fy/p.wt;
}
p.x += p.vx;
p.y += p.vy;
}
}
void draw()
{
doPhysics();
fill(255, 72);
rect(0, 0, width, height);
stroke(0);
strokeWeight(medRadius*1.1);
for (int i = 0; i < nbrParticles; ++i) {
point(particles[i].x, particles[i].y);
}
// if (frameCount % 60 == 0)
// println("fps = " + frameRate);
}