package Turbine;
 
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
 
import java.util.Vector;
import processing.core.*;
 
/**
*
* @author Matt
*/
public class Bird {
 
PVector loc, vel;
float spd = 0f;
float wings = 0.f;
float rate = 0.f;
Vector node = null;
int col;
public boolean outOfBounds = false; //are they outside the accelerator?
float sc = 1.f;
public boolean hilite = false; //I'm British!
public int hit = 0;
 
public Bird(PVector loc) {
 
this.loc = loc;
vel = new PVector(-.5f, -.5f + (float) Math.random(), -.5f + (float) Math.random());
 
wings = (float) Math.random();
rate = .25f + .1f * (float) Math.random();
spd = .75f + 2 * (float) Math.random();
//spd = 0;
//loc.y = -1;
int gray = (int) (32 + 64 * Math.random());
int red = 64;
col = 0xff000000 | (red << 16) | (gray << 8) | gray;
 
sc = .25f + (float) Math.random();
}
 
public void render(PGraphics3D g3d, float bladeAngle, float adjacency, float interest) {
 
 
 
if (hit > 0) {
hit--;
vel.y += .15f;
if (loc.y > -5) {
vel.mult(0);
spd = .75f + 2 * (float) Math.random();
//reset integrator to separate velocity and dir
}
else {
//euler integrate
loc.add(vel);
}
}
else {
 
//only flap when going up
//increase flap rate by vertical dx to simulate
//increased flap effort, or flapfort, when rising
if (vel.y < 0) {
wings += rate - vel.y;
}
 
PVector toward;
if (outOfBounds) {
PVector center = new PVector(0, -87.5f, 0);
toward = PVector.sub(center, loc);
toward.normalize();
toward.mult(.1f);
vel.x -= .1;
vel.add(toward);
}
 
 
if (node != null) {
 
float len;
//cohesion
//for every nearby bird (as defined by the accelerator)
Bird other;
for (int i = 0; i < node.size(); i++) {
other = (Bird) node.elementAt(i);
if (other != this && other.hit == 0) {
//cohesion
toward = PVector.sub(other.loc, loc);
len = toward.mag();
 
//normalize
toward.div(len);
 
//cohesion
if (len > adjacency) {
toward.mult(interest);
vel.add(toward);
}
if (len < adjacency) {
toward.mult(-2*interest);
vel.add(toward);
}
 
//direction sharing
vel.add(PVector.mult(other.vel, interest));
 
//velocity sharing
//if (other.spd > spd) spd += .2*(other.spd - spd);
 
//avoid the ground
if (loc.y > -10) {
vel.y -= .1f;
}
}
}
}
//wander
vel.normalize();
 
//euler integration
loc.add(PVector.mult(vel, spd));
 
}
 
//handle collisions
hilite = false;
if (loc.x < 5 && loc.x > -5) {
 
//check for collision with Blade
PVector blade = new PVector(0, 1, 0);
 
rot(blade, bladeAngle);
PVector bangle = new PVector(0, loc.y + 87.5f, loc.z);
 
 
//get angle between bird and blade
float diffAng = PVector.angleBetween(blade, bangle);
float PIThirds = 2 * PApplet.PI / 3;
float tol = .02f;
if (diffAng < tol ||
(diffAng < PIThirds + tol && diffAng > PIThirds - tol)) {
//hilite = true;
 
//check if they are close enough radially
float dist = bangle.mag();
if (dist < 90) {
//time for them to be stunned
hit = 150;
//mogrify to a ballistic euler integrator
//with spd premultiplied into vel
vel.mult(spd);
 
//thwack the bird
//use cross product to find the direction of blade motion
bangle.div(dist);
//windturbine facing direction
PVector flow = new PVector(-1, 0, 0);
PVector thwack = new PVector();
//I will write a song with this title
PVector.cross( bangle, flow, thwack);
thwack.normalize();
thwack.mult(dist/20.f);
 
vel.add(thwack);
 
}
 
}
 
}
 
 
 
//draw the bird
g3d.fill(col);
/*
if (outOfBounds) {
g3d.fill(255, 0, 0);
}
*/
if (hilite) {
g3d.fill(255, 255, 0);
}
g3d.noStroke();
 
g3d.pushMatrix();
g3d.translate(loc.x, loc.y, loc.z);
g3d.scale(sc);
//g3d.translate(loc.x, loc.y + 2 * PApplet.sin(wings), loc.z);
//g3d.box(2);
 
float wingFlap = 5 * PApplet.sin(wings);
 
float ang = PApplet.atan2(-vel.z, vel.x);
 
//not strictly correct, but fast and user won't be able to see glitches
float up = PApplet.atan(vel.y);
 
g3d.rotateY(ang);
g3d.rotateZ(up);
g3d.beginShape(PGraphics3D.QUADS);
g3d.vertex(-2, 0, 0);
g3d.vertex(3f, 0, 0);
g3d.vertex(2f, wingFlap, 4);
g3d.vertex(-2, wingFlap, 4);
g3d.endShape();
 
g3d.beginShape(PGraphics3D.QUADS);
g3d.vertex(-2, 0, 0);
g3d.vertex(3f, 0, 0);
g3d.vertex(2f, wingFlap, -4);
g3d.vertex(-2, wingFlap, -4);
g3d.endShape();
 
 
g3d.stroke(255);
g3d.beginShape(PGraphics3D.LINES);
//g3d.vertex(0,0,0);
// g3d.vertex(20,0,0);
//g3d.vertex(5*spd*vel.x,5*spd*vel.y,5*spd*vel.z);
g3d.endShape();
 
g3d.popMatrix();
 
//wrapping
if (loc.x < -200) {
loc.x = 200;
}
 
}
 
//I miss Tuple
void rot(PVector vec, float angle) {
float y = vec.y * PApplet.cos(angle) - vec.z * PApplet.sin(angle);
vec.z = vec.y * PApplet.sin(angle) + vec.z * PApplet.cos(angle);
vec.y = y;
 
}
}
package Turbine;
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
 
import java.util.Vector;
import processing.core.PGraphics3D;
import processing.core.PVector;
 
/**
*
* @author Matt
*/
public class GridAccel {
 
PVector min, max, span, step;
int resX, resY, resZ;
Vector[][][] nodes;
 
//res is the size of the cube
public GridAccel(float res, PVector min, PVector max) {
 
this.min = min;
this.max = max;
this.span = PVector.sub(max, min);
System.out.println(span);
this.step = span.get();
 
resX = (int) (span.x / res);
resY = (int) (span.y / res);
resZ = (int) (span.z / res);
 
System.out.println("Accelerator is " + resX + ":" + resY + ":" + resZ);
 
step.x /= resX;
step.y /= resY;
step.z /= resZ;
 
 
//that is a lot of nodes, potentially
nodes = new Vector[resX][resY][resZ];
 
//initialize the nodes
for (int i = 0; i < resX; i++) {
for (int j = 0; j < resY; j++) {
for (int k = 0; k < resZ; k++) {
nodes[i][j][k] = new Vector();
}
}
}
}
 
//put the bird into the appropriate node
//tell bird which node it is in
//then, bird only operates on nearby
public Vector update(Bird bird) {
 
int i, j, k;
i = (int) ((bird.loc.x - min.x) / step.x);
j = (int) ((bird.loc.y - min.y) / step.y);
k = (int) ((bird.loc.z - min.z) / step.z);
//out of bounds
if (i >= resX || i < 0 || j >= resY || j < 0 || k >= resZ || k < 0) {
if (bird.node != null) {
bird.node.remove(bird);
}
bird.node = null;
bird.outOfBounds = true;
}
else {
bird.outOfBounds = false;
//System.out.println(i + ":" + j + ":" + k);
//if bird was in this node last time, do nothing
//if it is different, remove from the last node, and add to this one
if (bird.node != nodes[i][j][k] && bird.node != null) {
bird.node.remove(bird);
nodes[i][j][k].add(bird);
}
bird.node = nodes[i][j][k];
}
return null;
 
}
 
public void draw(PGraphics3D p3d) {
p3d.stroke(0);
p3d.beginShape(PGraphics3D.LINES);
p3d.vertex(min.x, min.y, min.z);
p3d.vertex(max.x, max.y, max.z);
p3d.endShape();
}
}
package Turbine;
 
import SGCamera.SGCamera;
import processing.core.*;
import SGCamera.*;
import SGQuickVar.*;
import Raytracing.*;
import java.util.Vector;
 
 
public class Turbine extends PApplet {
 
SGCamera cam;
int time = 0;
 
Vector splats;
 
float rot;
 
SGVariable numBirds;
SGVariable adjacency;
SGVariable interest;
PFont font;
Raytracer blade, body;
 
Vector flock;
GridAccel accel;
public void setup() {
size(550, 450, P3D);
frameRate(30);
cam = new SGCamera(this, 10, 10, 0, 0, 0, 0, SGCamera.ORBIT, SGCamera.DOLLY);
 
flock = new Vector();
cam.lookAt(0, -20, 0);
cam.setPosition(90, -10, -153);
 
cam.setRhoLimits(100,500);
cam.setVerticalLimits(0, PI/2);
 
accel = new GridAccel(40, new PVector(-250,-150,-80), new PVector(250,-0,80));
for (int i =0; i < 1000; i++){
flock.add(new Bird(new PVector(random(-200,200),random(-120,-10),random(-60,60))));
}
time = 0;
font = loadFont("writing.vlw");
textFont(font);
 
numBirds = new SGVariable(this, font, "Num Birds", 'a', 'z',900f, 50f, 10f, 1500);
numBirds.setTextColor(0);
adjacency = new SGVariable(this, font, "Adjacency", 's', 'x', 15, 1, 10, 20);
adjacency.setTextColor(0);
interest = new SGVariable(this, font, "Interest", 'd', 'c', .02f, .005f, 0, .1f);
interest.setTextColor(0);
 
 
body = new Raytracer(this);
body.openFile("turbineBody.mra");
 
blade = new Raytracer(this);
blade.openFile("turbineBlade.mra");
 
}
 
 
public void draw() {
rot += .1f;
 
background(255);
cam.feed();
 
pushMatrix();
scale(.1f);
body.draw();
translate(0,-875,0);
rotateX(rot);
blade.draw();
popMatrix();
Bird b;
PGraphics3D g3d = (PGraphics3D)g;
//make the flock fly
for (int i =0; i < flock.size(); i++){
b = (Bird)flock.elementAt(i);
b.render(g3d, rot, adjacency.val, interest.val);
accel.update(b);
}
 
while (flock.size() < numBirds.val){
flock.add(new Bird(new PVector(random(-200,200),random(-120,-10),random(-60,60))));
}
while (flock.size() > numBirds.val){
flock.removeElementAt(0);
}
}
 
 
 
 
public void keyPressed() {
Bird b = (Bird)flock.elementAt(0);
b.spd = 2;
 
}
 
 
static public void main(String args[]) {
PApplet.main(new String[]{"Turbine.Turbine"});
}
}