Permalink
Browse files

added music visualiser and fixed some beat functions

  • Loading branch information...
1 parent a248d0e commit f9d9ad24cdffd60bf72794892e4f7a729535f83c @pixelpusher committed May 9, 2012
Showing with 2,934 additions and 44 deletions.
  1. +278 −0 BoidRevealerInsaneEdition/AnimatedImageNode.pde
  2. +66 −0 BoidRevealerInsaneEdition/AnimationModifier.pde
  3. +183 −0 BoidRevealerInsaneEdition/Beat.pde
  4. +107 −0 BoidRevealerInsaneEdition/BeatMatcher.pde
  5. +261 −0 BoidRevealerInsaneEdition/BeatStuff.pde
  6. +123 −0 BoidRevealerInsaneEdition/Boid.pde
  7. +455 −0 BoidRevealerInsaneEdition/BoidRevealerInsaneEdition.pde
  8. +261 −0 BoidRevealerInsaneEdition/DrawableNode.pde
  9. +86 −0 BoidRevealerInsaneEdition/FileFuncs.pde
  10. +69 −0 BoidRevealerInsaneEdition/Fires.pde
  11. +252 −0 BoidRevealerInsaneEdition/Flock.pde
  12. +32 −0 BoidRevealerInsaneEdition/GUI.pde
  13. +139 −0 BoidRevealerInsaneEdition/GeometryFunctions.pde
  14. +87 −0 BoidRevealerInsaneEdition/ImageNode.pde
  15. +143 −0 BoidRevealerInsaneEdition/WiiChuck.pde
  16. +138 −0 BoidRevealerInsaneEdition/WiiStuff.pde
  17. +15 −0 BoidRevealerInsaneEdition/data/Blend4.glsl
  18. +11 −0 BoidRevealerInsaneEdition/data/Blend4.xml
  19. +22 −0 BoidRevealerInsaneEdition/data/Blur.glsl
  20. +8 −0 BoidRevealerInsaneEdition/data/Blur.xml
  21. +49 −0 BoidRevealerInsaneEdition/data/Blur1D.glsl
  22. +11 −0 BoidRevealerInsaneEdition/data/Blur1D.xml
  23. +6 −0 BoidRevealerInsaneEdition/data/Copy.glsl
  24. +6 −0 BoidRevealerInsaneEdition/data/Copy.xml
  25. +19 −0 BoidRevealerInsaneEdition/data/ExtractBloom.glsl
  26. +11 −0 BoidRevealerInsaneEdition/data/ExtractBloom.xml
  27. +5 −0 BoidRevealerInsaneEdition/data/SimpleVS.glsl
  28. +26 −0 BoidRevealerInsaneEdition/data/ToneMap.glsl
  29. +14 −0 BoidRevealerInsaneEdition/data/ToneMap.xml
  30. BIN BoidRevealerInsaneEdition/data/attracted01.ser
  31. BIN BoidRevealerInsaneEdition/data/blue-acrobats.png
  32. BIN BoidRevealerInsaneEdition/data/carstiled.png
  33. BIN BoidRevealerInsaneEdition/data/cloud.png
  34. BIN BoidRevealerInsaneEdition/data/fingertop.png
  35. BIN BoidRevealerInsaneEdition/data/fire.png
  36. BIN BoidRevealerInsaneEdition/data/fire128.png
  37. BIN BoidRevealerInsaneEdition/data/inv_map_gps_london_Eric_Fischer.jpg
  38. BIN BoidRevealerInsaneEdition/data/skullhand.png
  39. BIN BoidRevealerInsaneEdition/data/tv.png
  40. BIN BoidRevealerInsaneEdition/data/whitetoady.png
  41. +1 −1 WiiBeatMatchingMadeEasy/Beat.pde
  42. +50 −43 WiiBeatMatchingMadeEasy/WiiChuck.pde
View
278 BoidRevealerInsaneEdition/AnimatedImageNode.pde
@@ -0,0 +1,278 @@
+//
+// NOTE - YOU MUST HAVE AT LEAST A 1px BUFFER BETWEEN FRAMES OTHERWISE IT
+// PICKS UP AN EXTRA FRAME
+
+
+class AnimatedImageNode extends DrawableNode
+{
+ // This is the sprite sheet
+ PImage img = null;
+
+ private PImage currentSprite = null; // current frame to be drawn
+
+ // rows and columns in the sprite sheet
+ int rows = 1;
+ int cols = 1;
+
+ //current index in the sprite sheet (from 0 to Max # sprites - 1)
+ int spriteIndex = 0;
+
+ int msPerFrame = 1000 / 10; // at 10 fps, in 1000ms (1 sec) we've shown 10 frames
+ int lastFrameTime = 0; // last time we drew a frame, in ms
+
+ boolean forwards = true; // forwards or backwards?
+ boolean flipped = false; // reverse drawing this in the x direction
+
+ boolean animating = true;
+
+ // these are animation variables
+ private int imgW;
+ private int imgH;
+ private int imgX;
+ private int imgY;
+
+ //////////////////////////////////////////////////////
+ /// Constructors /////////////////////////////////////
+ //////////////////////////////////////////////////////
+
+ AnimatedImageNode() // default
+ {
+ super();
+ hasFill = hasStroke = false;
+ }
+
+ AnimatedImageNode(float _x, float _y, float _w, float _h)
+ {
+ super( _x, _y, _w, _h);
+ hasFill = hasStroke = false;
+ }
+
+ AnimatedImageNode(PImage newImg, float _x, float _y)
+ {
+ super( _x, _y, newImg.width, newImg.height);
+ setImage(newImg);
+ hasFill = hasStroke = false;
+ }
+
+ AnimatedImageNode(PImage newImg, float _x, float _y, float _w, float _h)
+ {
+ super( _x, _y, _w, _h);
+ setImage(newImg);
+ hasFill = hasStroke = false;
+ }
+
+ AnimatedImageNode(PImage newImg, float _x, float _y, float _w, float _h, int _cols, int _rows)
+ {
+ super( _x, _y, _w, _h);
+ rows = _rows;
+ cols = _cols;
+ setImage(newImg);
+ hasFill = hasStroke = false;
+ }
+ //////////////////////////////////////////////////////
+ /// End Constructors /////////////////////////////////
+ //////////////////////////////////////////////////////
+
+
+ void setImage(PImage newImg)
+ {
+ img = newImg;
+
+ spriteIndex = 0;
+ lastFrameTime = millis(); // update current time
+
+ imgW = img.width/cols ;
+ imgH = img.height/rows;
+
+ // update the image of the current sprite
+ updateCurrentSprite();
+ }
+
+ void setImage(PImage newImg, int _w, int _h)
+ {
+ setW(_w);
+ setH(_h);
+
+ setImage(newImg);
+ }
+
+
+ void setImage(PImage newImg, int _w, int _h, int _rows, int _cols)
+ {
+ rows = _rows;
+ cols = _cols;
+
+ setImage(newImg, _w/_rows, _h/_cols);
+ }
+
+
+ void setRowsCols(int _rows, int _cols)
+ {
+ rows = _rows;
+ cols = _cols;
+
+ updateCurrentSprite();
+ }
+
+
+ void stop()
+ {
+ animating = false;
+ }
+
+ void start()
+ {
+ animating = true;
+ }
+
+
+ void animate()
+ {
+ if (!animating)
+ lastFrameTime = millis(); // update current time
+ animating = true;
+ }
+
+ // ovverides DrawableNode's version
+ void finishedMoving()
+ {
+ //println("stopped!");
+ stop();
+ }
+
+
+ /// updateCurrentSprite /////////////////////////////
+ //////////////////////////////////////////////////////
+
+ // get the next sprite image in the series
+
+ void updateCurrentSprite()
+ {
+ int currentCol = spriteIndex % cols;
+ int currentRow = spriteIndex/cols;
+
+ imgX = currentCol*imgW;
+ //println("x=" +imgX);
+ imgY = currentRow*imgH;
+ }
+
+
+ /// update ///////////////////////////////////////////
+ //////////////////////////////////////////////////////
+
+ void update()
+ {
+
+ if (animating)
+ {
+ // animate - update currentFrameTime
+ // move to next index
+
+ // has enough time elapsed that we need to go to the next frame?
+ int currentTime = millis();
+ int timeDiff = currentTime-lastFrameTime; // difference in time
+
+ // how many frames do we jump?
+ int framesToJump = timeDiff/msPerFrame;
+
+
+ if (framesToJump > 0)
+ {
+ // println("frame to jump: " + framesToJump);
+
+ // for smooth animation, should also account for extra time elapsed...
+ lastFrameTime = lastFrameTime + framesToJump*msPerFrame;
+
+ // println("last frame time: " + lastFrameTime);
+
+
+ if (forwards)
+ {
+ // increase current frame index by 1
+ spriteIndex = (spriteIndex+framesToJump) % (rows*cols);
+ }
+ else
+ {
+ spriteIndex = spriteIndex-framesToJump;
+
+ if (spriteIndex < 0)
+ {
+ spriteIndex = (-spriteIndex) % (rows*cols);
+
+ spriteIndex = rows*cols - spriteIndex;
+ }
+ }
+
+ // println("sprite index: " + spriteIndex + " / " + rows*cols);
+
+ // update the image of the current sprite
+ updateCurrentSprite();
+ }
+ }
+
+ // call normal DrawableNode update() to handle movement
+ super.update();
+
+ ////////////////////////////////////////////
+ // handle accelerating in opposite direction
+ if (vel.x > 0) flipped = true;
+ else if (vel.x < 0) flipped = false;
+ }
+
+
+ //////////////////////////////////////////////////////
+ /// draw /////////////////////////////////////////////
+ //////////////////////////////////////////////////////
+
+
+ void draw(PGraphics renderer)
+ {
+ // fill, or tint in this case
+ if (hasFill)
+ {
+ renderer.tint(fillColor);
+ }
+
+ else {
+ renderer.noTint();
+ renderer.noFill();
+ }
+
+ // stroke
+ if (hasStroke)
+ {
+ renderer.stroke(strokeColor);
+ }
+ else
+ {
+ renderer.noStroke();
+ }
+
+
+ //imgX, imgY, imgW, imgH
+
+ // 1 *---* 2
+ // | |
+ // 4 *---* 3
+ renderer.textureMode(IMAGE);
+ renderer.beginShape();
+ renderer.texture( img );
+ renderer.vertex(pos.x, pos.y, imgX, imgY);
+
+ // subtract 1px from width because of Processing bug?
+ renderer.vertex(pos.x+w, pos.y, imgX+imgW-1, imgY);
+ renderer.vertex(pos.x+w, pos.y+h, imgX+imgW-1, imgY+imgH);
+ renderer.vertex(pos.x, pos.y+h, imgX, imgY+imgH);
+ renderer.endShape();
+ }
+
+
+ void unload()
+ {
+ img = null;
+ currentSprite = null;
+ }
+
+ // end class
+}
+
View
66 BoidRevealerInsaneEdition/AnimationModifier.pde
@@ -0,0 +1,66 @@
+public interface IAnimationModifier
+{
+ public void start(int _timelength);
+ public void pause();
+ public void stop();
+ public void update(int _currentTime);
+ public boolean isFinished(); // true if this is done and can be removed
+}
+
+
+public class TimedAnimationModifier implements IAnimationModifier
+{
+ int startTime = -1;
+ int currentTime = -1;
+ boolean paused = false;
+ int pauseStartTime = -1;
+ int timelength; // in ms
+ float percentFinished=0f;
+
+ private float timelengthInv = 1f; // inverse of timelnegth, for efficiency
+
+ public void start(int _timelength)
+ {
+ startTime = millis();
+
+ timelength = _timelength;
+ timelengthInv = 1f/timelength;
+ }
+
+ public void pause()
+ {
+ if (startTime > -1) // handle if pause before start?
+ {
+ if (paused)
+ {
+ paused = false;
+ startTime += (millis()-pauseStartTime);
+ pauseStartTime = -1;
+ }
+ else
+ {
+ paused = true;
+ pauseStartTime = millis();
+ }
+ }
+ }
+
+ public void stop()
+ {
+ }
+
+ public void update(int _currentTime)
+ {
+ if (startTime > -1)
+ {
+ currentTime = _currentTime;
+ int timeDiff = currentTime-startTime;
+ percentFinished = timeDiff * timelengthInv;
+ }
+ }
+ public boolean isFinished() // true if this is done and can be removed
+ {
+ return (currentTime-startTime) >= timelength;
+ }
+}
+
View
183 BoidRevealerInsaneEdition/Beat.pde
@@ -0,0 +1,183 @@
+// listens for beats
+public interface IBeatListener
+{
+ public void beatChanged(int beat); // when a beat changes value, e.g. from 0 to 1
+ public void beatReset(); // when a Beat object wraps back to 0 (counts out all the beats)
+}
+
+
+// Simple class representing a "beat" based on a time interval
+// and maximum number of beats
+class Beat
+{
+ // 120bpm in ms
+ int beatInterval = (int)(60000f/120f);
+ private int lastBeat = 0;
+ private int maxBeats = 4;
+ private float partialBeat = 0f;
+ private int _currentBeat = 0;
+ private int _lastTime = 0;
+
+ private ArrayList<IBeatListener> listeners;
+
+ private boolean reset;
+
+ Beat()
+ {
+ _lastTime = millis();
+ listeners = new ArrayList<IBeatListener>();
+ reset = true;
+ }
+
+ Beat(int mb)
+ {
+ maxBeats = mb;
+ listeners = new ArrayList<IBeatListener>();
+ _lastTime = millis();
+ reset = true;
+ }
+
+ int getMaxBeats()
+ {
+ return maxBeats;
+ }
+
+ Beat setMaxBeats(int mb)
+ {
+ maxBeats = mb;
+ return this;
+ }
+
+ int getCurrentBeat()
+ {
+ return _currentBeat;
+ }
+
+ float getPartialBeat()
+ {
+ return partialBeat;
+ }
+
+
+ Beat addListener(IBeatListener ibl)
+ {
+ listeners.add(ibl);
+ return this;
+ }
+
+ Beat removeListener(IBeatListener ibl)
+ {
+ listeners.remove(ibl);
+ return this;
+ }
+
+ Beat removeAllListeners()
+ {
+ listeners.clear();
+ return this;
+ }
+
+
+ // start the beats in motion
+ void reset(int startTimeMillis)
+ {
+ partialBeat = 0f;
+ _currentBeat = lastBeat = 0;
+ _lastTime = startTimeMillis;
+ reset = true;
+ }
+
+ void reset()
+ {
+ reset(millis());
+ }
+
+ void defaults()
+ {
+ // 120bpm in ms
+ beatInterval = (int)(60000f/120f);
+ lastBeat = 0;
+ maxBeats = 4;
+ partialBeat = 0f;
+ _currentBeat = 0;
+ _lastTime = 0;
+ }
+
+ //---------------------------
+ // set the interval btw beats in ms, reset beat count
+ void setBeatInterval(int bms)
+ {
+ beatInterval = bms;
+ reset();
+ }
+
+
+ // -----------------------------------
+ // Decide whether or not we are on a beat, and which
+ // beat. Returns an int from 0..(maxBeats-1)
+
+ float update()
+ {
+ return update( millis() );
+ }
+
+
+ float update(int currentTimeMillis)
+ {
+ // get beat interval
+ int _interval = (currentTimeMillis - _lastTime);
+
+ if (reset)
+ {
+ reset = false;
+ lastBeat = -1;
+ }
+ else
+ if (_interval > beatInterval) // see if a beat worth of time has elapsed
+ {
+
+ //increment current beat
+ _currentBeat = (_currentBeat + 1) % maxBeats;
+
+ // we may have missed the beat by a fraction or a second!
+ _interval -= beatInterval;
+
+ // for debugging
+ //println("interval:" + beatInterval);
+
+ // update current time, taking into account
+ // time past the beat interval (that we missed because Processing was SLOOOW)
+ _lastTime = currentTimeMillis - _interval;
+ }
+
+ partialBeat = (_currentBeat + (float)_interval/(float)beatInterval);
+
+ // check if beat changed
+ if (lastBeat != _currentBeat)
+ {
+ println("beat:"+_currentBeat+"/"+lastBeat);
+
+ lastBeat = _currentBeat;
+
+ for (IBeatListener ibl : listeners)
+ ibl.beatChanged( _currentBeat );
+
+ if (_currentBeat == 0)
+ {
+ for (IBeatListener ibl : listeners)
+ ibl.beatReset( );
+ }
+ }
+
+
+ return _currentBeat;
+ }
+
+ void destroy()
+ {
+ removeAllListeners();
+ }
+
+// end class Beat
+}
+
View
107 BoidRevealerInsaneEdition/BeatMatcher.pde
@@ -0,0 +1,107 @@
+//interface for an object that does something on a beat
+public interface IBeatEvent
+{
+ public void trigger();
+}
+
+
+public class BeatEventList<IBeatEvent> extends ArrayList<IBeatEvent>
+{
+}
+
+class BeatMatcher implements IBeatListener
+{
+ // array list of events for each beat, in order (e.g. beat 0..maxBeats has an arraylist of events attached to it)
+ private BeatEventList[] events;
+
+ private BeatEventList resetEvents; // when beats are reset
+
+
+ BeatMatcher(int maxBeats)
+ {
+ events = new BeatEventList[maxBeats];
+ resetEvents = new BeatEventList();
+
+ for (int i=0; i<events.length; i++)
+ {
+ events[i] = new BeatEventList(); // default - not matched
+ }
+ }
+
+ BeatMatcher addResetEvent(IBeatEvent ibe)
+ {
+ resetEvents.add( ibe );
+ return this;
+ }
+
+ BeatMatcher removeResetEvent(IBeatEvent ibe)
+ {
+ resetEvents.remove( ibe );
+ return this;
+ }
+
+ BeatMatcher clearResetEvents()
+ {
+ resetEvents.clear( );
+ return this;
+ }
+
+ BeatMatcher addBeatEvent(int beat, IBeatEvent ibe)
+ {
+ BeatEventList ibes = events[beat];
+ ibes.add( ibe );
+ return this;
+ }
+
+ BeatMatcher removeBeatEvent(int beat, IBeatEvent ibe)
+ {
+ BeatEventList ibes = events[beat];
+ ibes.remove( ibe );
+ return this;
+ }
+
+ BeatMatcher clearBeatEvents(int beat) // start
+ {
+ BeatEventList ibes = events[beat];
+ ibes.clear( );
+ return this;
+ }
+
+ BeatMatcher clearAllBeatEvents()
+ {
+ for (int i=0; i<events.length; i++)
+ {
+ events[i].clear();
+ }
+ return this;
+ }
+
+ public void beatChanged(int beat) // when a beat changes value, e.g. from 0 to 1
+ {
+ BeatEventList ibes = events[beat];
+ ListIterator<IBeatEvent> li = ibes.listIterator();
+
+ while ( li.hasNext () )
+ {
+ IBeatEvent ibe = li.next();
+ ibe.trigger();
+ }
+ }
+
+ public void beatReset() // when a Beat object wraps back to 0 (counts out all the beats)
+ {
+ ListIterator<IBeatEvent> li = resetEvents.listIterator();
+
+ while ( li.hasNext() )
+ li.next().trigger();
+ }
+
+ public void clear()
+ {
+ clearResetEvents();
+ clearAllBeatEvents();
+ }
+
+ // end class BeatMatcher
+}
+
View
261 BoidRevealerInsaneEdition/BeatStuff.pde
@@ -0,0 +1,261 @@
+final int MAX_BEAT_INTERVAL = 1500; // max time between beats in ms
+
+int[] intervals = new int[3];
+int index = 0;
+int lastTime = 0;
+int medianTime = 500;
+Beat[] beats;
+
+PFont font;
+
+final int NUM_SCENES = 4;
+int beatsCounted, beatsPerScene; // current number of beats in this scene
+int currentBeatIndex = 0; //current Beat scene
+
+LinkedList<IAnimationModifier> animModifiers;
+
+
+void updateBeatStuff()
+{
+ int ms = millis();
+
+ Iterator<IAnimationModifier> iter = animModifiers.iterator();
+
+ while (iter.hasNext ())
+ {
+ IAnimationModifier animod = iter.next();
+ animod.update(ms);
+ if (animod.isFinished())
+ {
+ animod.stop();
+ iter.remove();
+ animod = null;
+ }
+ }
+
+ // update beat objects in motions
+ //for (int b=0; b<beats.length; b++)
+
+ beats[currentBeatIndex].update(ms);
+
+ //float f1 = map(chuck1.stickY, -100, 100, 0, 255);
+ //float f2 = map(chuck1.stickX, -100, 100, 0, 255);
+}
+
+
+
+//
+// Update for a new beat.
+// If necessary, change to a random new beat scene
+//
+
+void updateBeatScene()
+{
+ beatsCounted++;
+
+ if (beatsCounted >= beatsPerScene)
+ {
+ int newBeatIndex = int ( random(0, NUM_SCENES) );
+ beats[newBeatIndex].reset();
+ beatsCounted = 0;
+ beatsPerScene = int( random(1, 4)) * 4;
+ currentBeatIndex = newBeatIndex;
+ println("Changed beat:" + newBeatIndex);
+ }
+}
+
+
+
+//
+// TAP TEMPO
+//
+//////////////////
+
+void tapTempo()
+{
+ int currentTime = millis();
+ int timeInterval = currentTime - lastTime;
+ lastTime = currentTime;
+
+ if (timeInterval < MAX_BEAT_INTERVAL)
+ {
+
+ intervals[index] = timeInterval;
+ index = (index + 1) % intervals.length;
+ intervals = sort(intervals);
+ medianTime = intervals[(intervals.length-1)/2]; /// middle element
+
+ for (int b=0; b<beats.length; b++)
+ beats[b].setBeatInterval( medianTime );
+ println("Median time:" + medianTime);
+
+ for (DrawableNode fire : fireNodes)
+ {
+ fire.rotationSpeed = 30f*TWO_PI/(medianTime); // sort of based on framerate
+ }
+ }
+}
+
+
+//
+// SETUP BEAT STUFF
+//
+////////////////////
+
+void setupBeatStuff()
+{
+
+ lastTime = millis();
+
+ beats = new Beat[NUM_SCENES];
+
+ animModifiers = new LinkedList<IAnimationModifier>();
+
+
+ // start beat objects in motions
+ for (int b=0; b<beats.length; b++)
+ {
+ beats[b] = new Beat(4);
+
+ beats[b].addListener(
+ new IBeatListener()
+ {
+ public void beatChanged(int beat)
+ {
+ updateBeatScene();
+ println("Beat changed:" + beat);
+ }
+
+ public void beatReset()
+ {
+ println("Beat reset");
+ }
+ }
+ );
+ }
+
+
+
+ BeatMatcher matcher1 = new BeatMatcher( beats[0].getMaxBeats() );
+
+ matcher1.addBeatEvent( 0,
+ new IBeatEvent() {
+ public void trigger() {
+ println("Beat 1 MATCHED!");
+ IAnimationModifier animod = new TimedAnimationModifier()
+ {
+ public void update(int t)
+ {
+ super.update(t);
+ attraction = 4f*(1f-percentFinished);
+ //println("attract:" + attraction);
+ }
+ };
+
+ animod.start(beats[0].beatInterval*2);
+ animModifiers.add( animod );
+ }
+ }
+ );
+
+ beats[0].addListener( matcher1 );
+
+
+
+
+ BeatMatcher matcher2 = new BeatMatcher( beats[1].getMaxBeats() );
+
+ matcher2.addBeatEvent( 0,
+ new IBeatEvent() {
+ public void trigger() {
+ println("Beat2 MATCHED!");
+ IAnimationModifier animod = new TimedAnimationModifier()
+ {
+ public void update(int t)
+ {
+ super.update(t);
+ desiredseparation = 120f*(1f-percentFinished);
+ //println("attract:" + attraction);
+ }
+ public void stop()
+ {
+ desiredseparation = 16f;
+ }
+ };
+
+ neighbordist = 100f;
+ boidMaxSpeed = random(8, 16);
+ animod.start(beats[1].beatInterval*2);
+ animModifiers.add( animod );
+ }
+ }
+ );
+
+
+ beats[1].addListener( matcher2 );
+
+ BeatMatcher matcher3 = new BeatMatcher( beats[1].getMaxBeats() );
+
+ matcher3.addBeatEvent( 0,
+ new IBeatEvent() {
+ public void trigger() {
+ println("Beat2 MATCHED!");
+ IAnimationModifier animod = new TimedAnimationModifier()
+ {
+ public void update(int t)
+ {
+ super.update(t);
+ boidMaxSpeed = 8f+30f*sin(PI*(1f-percentFinished));
+ }
+ };
+
+ neighbordist = 100f;
+ boidMaxSpeed = random(8, 16);
+ animod.start(beats[2].beatInterval*4);
+ animModifiers.add( animod );
+ }
+ }
+ );
+
+
+ beats[2].addListener( matcher3 );
+
+
+ BeatMatcher matcher4 = new BeatMatcher( beats[3].getMaxBeats() );
+
+
+ matcher4.addBeatEvent( 0,
+ new IBeatEvent() {
+ public void trigger() {
+
+ fx = 0.5;
+ fy = 1.0;
+ }
+ }
+ );
+
+ matcher4.addBeatEvent( 2,
+ new IBeatEvent() {
+ public void trigger() {
+
+ fx = 0.08;
+ fy = 0.6;
+
+ tintColors[0]=color(0, random(100, 255), random(100, 255));
+ tintColors[1]= color(0, random(80, 255), 0);
+ tintColors[2]= color(random(80, 200), 0, 0);
+ tintColors[3]= color(255, 0, 255);
+ }
+ }
+ );
+
+ beats[3].addListener( matcher4 );
+ beats[0].addListener( matcher4 );
+
+ //initialize beat intervals
+ for (int i=0; i<intervals.length; i++)
+ {
+ intervals[i] = medianTime;
+ }
+}
+
View
123 BoidRevealerInsaneEdition/Boid.pde
@@ -0,0 +1,123 @@
+// The Boid class
+
+class Boid {
+
+ PVector loc;
+ PVector vel;
+ PVector acc;
+ float r;
+ GLTexture tex;
+ float maxforce;
+
+
+ Boid(PVector l, float ms, float mf, GLTexture _tex)
+ {
+ acc = new PVector(0, 0);
+ vel = new PVector(random(-2, 2), random(-2, 2));
+ loc = l.get();
+ r = 2.0 + random(-1, 1);
+
+ tex = _tex;
+ }
+
+
+ void seek(PVector target, float maxspeed) {
+ accelerate(steer(target, maxspeed));
+ }
+
+ void arrive(PVector target, float maxspeed) {
+ accelerate(steer(target, maxspeed));
+ }
+
+
+ PVector steer(PVector target, float maxspeed)
+ {
+ return steer( target, maxspeed, 0f);
+ }
+
+ // A method that calculates a steering vector towards a target
+ // Takes a second argument, if true, it slows down as it approaches the target
+ PVector steer(PVector target, float maxspeed, float slowdown)
+ {
+ PVector steer; // The steering vector
+ PVector desired = target.sub(target, loc); // A vector pointing from the location to the target
+ float d = desired.mag(); // Distance from the target is the magnitude of the vector
+ // If the distance is greater than 0, calc steering (otherwise return zero vector)
+ if (d > EPSILON)
+ {
+ // Normalize desired
+ desired.normalize();
+ // Two options for desired vector magnitude (1 -- based on distance, 2 -- maxspeed)
+ if (d < slowdown) desired.mult(maxspeed*(d/slowdown)); // This damping is somewhat arbitrary
+ else desired.mult(maxspeed);
+ // Steering = Desired minus Velocity
+ steer = target.sub(desired, vel);
+ }
+ else {
+ steer = new PVector(0, 0);
+ }
+ return steer;
+ }
+
+ void render(PGraphics renderer) {
+ renderer.imageMode(CENTER);
+
+ // Draw a triangle rotated in the direction of velocity
+ float theta = vel.heading2D() + PI/2;
+ renderer.fill(boidFill);
+ renderer.stroke(boidStroke);
+ renderer.pushMatrix();
+ renderer.translate(loc.x, loc.y);
+ renderer.rotate(theta);
+ renderer.image(tex, 0, 0);
+/*
+ renderer.noFill();
+ renderer.stroke(255);
+ renderer.ellipse(0,0,desiredseparation*2,desiredseparation*2);
+ renderer.stroke(255,0,0);
+ renderer.ellipse(0,0,neighbordist*2,neighbordist*2);
+ */
+ renderer.popMatrix();
+ }
+
+ // Wraparound
+ void wrapBorders()
+ {
+ if (loc.x < -r) loc.x = width+r;
+ if (loc.y < -r) loc.y = height+r;
+ if (loc.x > width+r) loc.x = -r;
+ if (loc.y > height+r) loc.y = -r;
+ }
+
+
+ Boid accelerate(PVector accel)
+ {
+
+ acc.add( accel );
+ acc.limit(maxforce);
+ return this;
+ }
+
+ Boid accelerate(float ax, float ay)
+ {
+ acc.add( ax, ay, 0f );
+ acc.limit(maxforce);
+ return this;
+ }
+
+ Boid applyAcceleration(float maxforce, float maxspeed)
+ {
+ //acc.limit(maxforce);
+ // Update velocity
+ vel.add(acc);
+ // Limit speed
+ vel.limit(maxspeed);
+ loc.add(vel);
+
+ // Reset accelertion to 0 each cycle
+ acc.set(0f, 0f, 0f);
+
+ return this;
+ }
+}
+
View
455 BoidRevealerInsaneEdition/BoidRevealerInsaneEdition.pde
@@ -0,0 +1,455 @@
+// Using flocking and effects to reveal a map underneath.
+//
+// All images produced by this sketch must be licensed: (CC BY-SA 2.0) http://creativecommons.org/licenses/by-sa/2.0/
+//
+// All code is licensed under GNU AGPL 3.0+ http://www.gnu.org/licenses/agpl.html
+//
+// By Evan Raskob 2012
+// info@pixelist.info
+//
+// for a project with Ravensbourne http://rave.ac.uk
+//
+// Based on Shiffman's flocking and Evan's scenegraph and Andres Colubri's Neon
+// example from GLGraphics 1.0
+//
+// Neon effect, based on this discussion:
+// http://processing.org/discourse/yabb2/YaBB.pl?num=1262637573/0
+// It uses the OCD library for camera motion:
+// http://www.gdsstudios.com/processing/libraries/ocd/reference/
+//
+// ControlP5 for onscreen controls: http://www.sojamo.de/libraries/controlP5/ (version 0.6.12 used)
+// GLGraphics for OPENGL rendering tricks: http://glgraphics.sourceforge.net/
+//
+
+
+import processing.opengl.*;
+import javax.media.opengl.*;
+import codeanticode.glgraphics.*;
+//import damkjer.ocd.*;
+// using toxiclibs for vectors, better than Processing's built-in ones
+import toxi.geom.Vec2D;
+import controlP5.*;
+
+// list of things to draw
+LinkedList<DrawableNode> nodesToDraw = null;
+
+// list of things to collide with
+LinkedList<DrawableNode> nodesToCollide = null;
+
+// our character
+DrawableNode myCharacter = null;
+ControlP5 gui;
+
+
+
+
+ColorPicker cpFill, cpStroke;
+
+String bgImageSrc = "carstiled.png";
+static final String spriteImages[] = {
+ "tv.png", "blue-acrobats.png", "whitetoady.png", "fire128.png"
+};
+
+color tintColors[] = {
+ color(0,0,200), color(0, 128, 0), color(200, 0, 0), color(255, 0, 255),
+};
+
+
+GLTexture bgImage, spriteTexs[];
+
+Flock[] flocks;
+final int FLOCKS = 4;
+int BOIDS = 100;
+
+
+// for attraction to objects:
+float MinNodeDistanceSquared = 8*8;
+float MaxNodeDistanceSquared = 200*200;
+
+
+// this prevents the loading of GUI presets from looping forever...
+boolean loadingGUIPreset = false;
+
+boolean keyDown = false; // for checking for keys held down
+
+// boids variables:
+
+float desiredseparation = 25.0;
+float avoidWallsFactor = 0.8;
+float attraction = 0.08;
+float neighbordist = 25.0;
+color boidFill = color(255, 30, 0);
+color boidStroke = color(255, 0, 0);
+float boidMaxSpeed = 8, boidMaxForce=0.8;
+
+// texture params
+float fx = 0.001;
+float fy = 0.001;
+
+Textfield presetName; // for saving gui presets
+DropdownList filesList = null;
+String[] savedFiles = null;
+
+GLGraphics pgl;
+GLGraphicsOffScreen offscreen;
+GL gl;
+
+GLTexture srcTex, bloomMask, destTex;
+GLTexture tex0, tex2, tex4, tex8, tex16;
+GLTexture tmp2, tmp4, tmp8, tmp16;
+GLTextureFilter extractBloom, blur, blend4, toneMap;
+
+//Camera cam;
+
+void setup()
+{
+ size(screenWidth, screenHeight, GLConstants.GLGRAPHICS);
+ noStroke();
+ hint( ENABLE_OPENGL_4X_SMOOTH );
+ //noCursor();
+ {
+ PGraphicsOpenGL pgl = (PGraphicsOpenGL) g; // g may change
+ gl = pgl.beginGL(); // always use the GL object returned by beginGL
+ gl.glClearColor(0.0, 0.0, 0.0, 1);
+ gl.setSwapInterval( 1 ); // use value 0 to disable v-sync
+ pgl.endGL();
+ }
+
+ // Loading required filters.
+ extractBloom = new GLTextureFilter(this, "ExtractBloom.xml");
+ blur = new GLTextureFilter(this, "Blur.xml");
+ blend4 = new GLTextureFilter(this, "Blend4.xml");
+ toneMap = new GLTextureFilter(this, "ToneMap.xml");
+
+ destTex = new GLTexture(this, width, height);
+
+ // Initializing bloom mask and blur textures.
+ bloomMask = new GLTexture(this, width, height, GLTexture.FLOAT);
+ tex0 = new GLTexture(this, width, height, GLTexture.FLOAT);
+ tex2 = new GLTexture(this, width / 2, height / 2, GLTexture.FLOAT);
+ tmp2 = new GLTexture(this, width / 2, height / 2, GLTexture.FLOAT);
+ tex4 = new GLTexture(this, width / 4, height / 4, GLTexture.FLOAT);
+ tmp4 = new GLTexture(this, width / 4, height / 4, GLTexture.FLOAT);
+ tex8 = new GLTexture(this, width / 8, height / 8, GLTexture.FLOAT);
+ tmp8 = new GLTexture(this, width / 8, height / 8, GLTexture.FLOAT);
+ tex16 = new GLTexture(this, width / 16, height / 16, GLTexture.FLOAT);
+ tmp16 = new GLTexture(this, width / 16, height / 16, GLTexture.FLOAT);
+
+ //cam = new Camera(this, 0, 0, 200);
+
+ offscreen = new GLGraphicsOffScreen(this, width, height, true, 4);
+ pgl = (GLGraphics) g;
+ gl = offscreen.gl;
+ gl.glClearColor(0.0, 0.0, 0.0, 0.0);
+
+
+ // textures
+ spriteTexs = new GLTexture[spriteImages.length];
+
+ for (int i=0; i < spriteImages.length; ++i)
+ {
+ spriteTexs[i] = new GLTexture(this, spriteImages[i]);
+ }
+
+ bgImage = new GLTexture(this, bgImageSrc);
+
+ //
+ // setup flocks
+ //
+
+ flocks = new Flock[FLOCKS];
+
+ for (int i=0; i < FLOCKS; ++i)
+ {
+ flocks[i] = new Flock();
+
+ // Add an initial set of boids into the system
+ for (int ii = 0; ii < BOIDS; ++ii)
+ {
+ flocks[i].addBoid(new Boid(new PVector(width/2, height/2), boidMaxSpeed, boidMaxForce, spriteTexs[i]));
+ }
+ flocks[i].active = true;
+ }
+
+ // create some random nodes to attract to
+ nodesToDraw = new LinkedList<DrawableNode>();
+
+ // create our "character"
+ myCharacter = new DrawableNode(random(0, width), random(0, height), random(10, 40), random(10, 40));
+ myCharacter.fillColor= color(0, 255, 0);
+
+ nodesToDraw.add(myCharacter);
+
+ myCharacter = new DrawableNode(random(0, width), random(0, height), random(10, 40), random(10, 40));
+ myCharacter.fillColor= color(0, 255, 0);
+
+ //
+ nodesToCollide = new LinkedList<DrawableNode>();
+
+ // nodes to be attracted towards
+ nodesToCollide.add(myCharacter);
+
+ for (int i=0; i < 10; i++)
+ {
+ // x,y,w,h
+ DrawableNode node = new DrawableNode(random(0, width), random(0, height), random(10, 40), random(10, 40));
+ node.fillColor= color(random(255), 255, random(255));
+ nodesToCollide.add(node);
+ nodesToDraw.add(node);
+ }
+
+ //
+ // setup the GUI
+ //
+ setupGUI();
+ setupBeatStuff();
+
+ setupFires(offscreen);
+ setupWiiChuck();
+
+ frameRate(60);
+}
+
+
+
+void draw()
+{
+
+ updateBeatStuff();
+
+ background(0);
+ hint(DISABLE_DEPTH_TEST);
+
+ boolean b = gui.window(this).isMouseOver(); // returns true or false
+ if (b)
+ {
+ boidStroke = cpStroke.getColorValue();
+ boidFill = cpFill.getColorValue();
+ }
+
+ // BLOOM EFFECT SETUP STUFF
+ srcTex = offscreen.getTexture();
+ offscreen.hint(DISABLE_DEPTH_TEST);
+ offscreen.beginDraw();
+ offscreen.background(0);
+ offscreen.gl.glEnable( GL.GL_BLEND );
+ offscreen.gl.glDisable( GL.GL_DEPTH );
+ // ggl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE);
+ //ggl.glBlendFunc(GL.GL_SRC_COLOR, GL.GL_ONE);
+
+
+ offscreen.gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_DST_ALPHA);
+ // draw fires first
+ animateFires(offscreen);
+
+
+ offscreen.gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE);
+ int f=0;
+ for (Flock flock : flocks)
+ {
+ offscreen.tint(tintColors[f++]);
+ flock.run(offscreen);
+ }
+
+ // update position and draw
+ if (false)
+ for (DrawableNode node : nodesToDraw)
+ {
+ //update ball position
+ node.update();
+ offscreen.fill(255, 255, 0, 40);
+ Vec2D p = node.middle();
+ float d = sqrt(MaxNodeDistanceSquared);
+ offscreen.ellipse(p.x, p.y, d, d);
+ node.draw(offscreen);
+ }
+
+
+ if (keyPressed)
+ {
+ fill(255, 120);
+ ellipse(mouseX, mouseY, 20, 20);
+ }
+
+ //cam.circle(radians(noise(millis()*2)*noise(millis())*50));
+ //cam.circle(radians(mouseX / 800.) * PI);
+ //cam.feed();
+
+ //offscreen.glDisable( GL.GL_DEPTH_TEST );
+ //offscreen.glEnable( GL.GL_BLEND );
+ //offscreen.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE);
+
+ offscreen.endDraw();
+
+ // Extracting the bright regions from input texture.
+ extractBloom.setParameterValue("bright_threshold", fx);
+ extractBloom.apply(srcTex, tex0);
+
+ // Downsampling with blur
+ tex0.filter(blur, tex2);
+ tex2.filter(blur, tmp2);
+ tmp2.filter(blur, tex2);
+
+ tex2.filter(blur, tex4);
+ tex4.filter(blur, tmp4);
+ tmp4.filter(blur, tex4);
+ tex4.filter(blur, tmp4);
+ tmp4.filter(blur, tex4);
+
+ tex4.filter(blur, tex8);
+ tex8.filter(blur, tmp8);
+ tmp8.filter(blur, tex8);
+ tex8.filter(blur, tmp8);
+ tmp8.filter(blur, tex8);
+ tex8.filter(blur, tmp8);
+ tmp8.filter(blur, tex8);
+
+ tex8.filter(blur, tex16);
+ tex16.filter(blur, tmp16);
+ tmp16.filter(blur, tex16);
+ tex16.filter(blur, tmp16);
+ tmp16.filter(blur, tex16);
+ tex16.filter(blur, tmp16);
+ tmp16.filter(blur, tex16);
+ tex16.filter(blur, tmp16);
+ tmp16.filter(blur, tex16);
+
+ // Blending downsampled textures.
+ blend4.apply(new GLTexture[] {
+ tex2, tex4, tex8, tex16
+ }
+ , new GLTexture[] {
+ bloomMask
+ }
+ );
+
+ // Final tone mapping into destination texture.
+ toneMap.setParameterValue("exposure", fy);
+ toneMap.setParameterValue("bright", fx);
+ toneMap.apply(new GLTexture[] {
+ srcTex, bloomMask
+ }
+ , new GLTexture[] {
+ destTex
+ }
+ );
+
+
+ PGraphicsOpenGL gpgl = (PGraphicsOpenGL) g; // g may change
+ GL ggl = gpgl.beginGL(); // always use the GL object returned by beginGL
+ ggl.glDepthMask(false);
+ ggl.glDisable( GL.GL_DEPTH_TEST );
+ ggl.glEnable( GL.GL_BLEND );
+ // ggl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE);
+ //ggl.glBlendFunc(GL.GL_SRC_COLOR, GL.GL_ONE);
+ ggl.glBlendFunc(GL.GL_ONE, GL.GL_ONE);
+ // ggl.glAlphaFunc(GL.GL_GREATER,0.0);
+ gpgl.endGL();
+
+ // DRAW BACKGROUND IMAGE
+
+ textureMode(NORMALIZED);
+ beginShape(QUADS);
+ texture(bgImage);
+
+ vertex(0, 0, 0, 0);
+ vertex(width/2, 0, 1, 0);
+ vertex(width/2, height, 1, 1);
+ vertex(0, height, 0, 1);
+
+ vertex(width/2, 0, 0, 0);
+ vertex(width, 0, 1, 0);
+ vertex(width, height, 1, 1);
+ vertex(width/2, height, 0, 1);
+ endShape();
+
+ ggl = gpgl.beginGL();
+
+ //this is nice and ghostly, revealing the image below
+ ggl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_SRC_COLOR);
+
+ //this is more ghostly, only revealing it by color, like a multiply effect
+ // ggl.glBlendFunc(GL.GL_SRC_COLOR, GL.GL_SRC_COLOR);
+
+ image(destTex, 0, 0, destTex.width*2, destTex.height*2);
+ ggl.glAlphaFunc(GL.GL_ONE, GL.GL_SRC_ALPHA);
+ ggl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE);
+ // ggl.glDisable( GL.GL_BLEND );
+ gpgl.endGL();
+}
+
+
+
+
+// Update the paddle position when we move the mouse:
+
+void keyPressed()
+{
+
+ if (key == CODED)
+ {
+ if (keyCode == UP) {
+ myCharacter.accel.y -= 1;
+ }
+ else if (keyCode == DOWN) {
+ myCharacter.accel.y += 1;
+ }
+ else if (keyCode == LEFT) {
+ myCharacter.accel.x -= 1;
+ }
+ else if (keyCode == RIGHT) {
+ myCharacter.accel.x += 1;
+ }
+ }
+ else
+ if (!keyDown)
+ {
+ keyDown = true;
+
+ switch(key)
+ {
+
+ case('s'):
+ gui.getProperties().setSnapshot(presetName.getText());
+ break;
+
+ case('g'):
+ gui.getProperties().getSnapshot(presetName.getText());
+ break;
+
+ case('r'):
+ gui.getProperties().removeSnapshot(presetName.getText());
+ break;
+
+ case('S'):
+ gui.getProperties().saveSnapshot("data/" + presetName.getText());
+ println("Saved preset:" + "data/" + presetName.getText());
+ break;
+
+ case('L'):
+ loadingGUIPreset = true;
+ gui.getProperties().load("data/" + presetName.getText()+".ser");
+ println("Loaded preset:" + "data/" + presetName.getText()+".ser");
+ loadingGUIPreset = false;
+ break;
+
+ case(' '):
+ tapTempo();
+ break;
+ }
+ }
+
+ //println(gui.getProperties().getSnapshotIndices());
+}
+
+
+void keyReleased()
+{
+ keyDown = false;
+}
+
+
+void mousePressed()
+{
+}
+
View
261 BoidRevealerInsaneEdition/DrawableNode.pde
@@ -0,0 +1,261 @@
+class DrawableNode
+{
+ //internal variables ///////
+
+ // bounding box
+ float maxX, minX;
+ float maxY, minY;
+
+ float w;
+ float h;
+
+ float frictionCoeff = 0.95f;
+ static final float MIN_VELOCITY = 0.1f;
+
+ // movement variables
+ boolean moving;
+
+ Vec2D pos; // position
+ Vec2D prevPos; // previous position, for hit testing
+
+ Vec2D vel; // velocity
+ Vec2D accel; // acceleration
+
+ float rotation; // z rotation, clockwise in radians
+ float rotationSpeed; // z rotation speed per frame, clockwise in radians
+
+ // drawing variables
+ boolean hasStroke = false;
+ color strokeColor = color(0);
+ boolean hasFill = true;
+ color fillColor = color(255);
+
+ boolean wrap = true; // for screen wrap
+
+ HashMap<String, Object> data = null; // in case you need some custom data storage...
+
+ /// Constructor //////////////////////////////////////
+ //////////////////////////////////////////////////////
+
+ // default:
+ DrawableNode()
+ {
+ pos = new Vec2D();
+ prevPos = new Vec2D();
+
+ w = 20;
+ h = 20;
+
+ vel = new Vec2D();
+ accel = new Vec2D();
+
+ rotationSpeed = 0f;
+
+ updateBoundingBox();
+ }
+
+
+ DrawableNode(float _x, float _y, float _w, float _h)
+ {
+ pos = new Vec2D(_x, _y);
+ prevPos = new Vec2D(_x, _y);
+
+ vel = new Vec2D();
+ accel = new Vec2D();
+
+ w = _w;
+ h = _h;
+
+ updateBoundingBox();
+
+ data = new HashMap<String, Object>();
+ }
+
+
+ void setX(float _x)
+ {
+ pos.x = _x;
+ minX = pos.x;
+ maxX = pos.x + w;
+ }
+
+ void setY(float _y)
+ {
+ pos.y = _y;
+ minY = pos.y;
+ maxY = pos.y + h;
+ }
+
+ void setW(float _w)
+ {
+ w = _w;
+ maxX = pos.x + w;
+ }
+
+ void setH(float _h)
+ {
+ h = _h;
+ maxY = pos.y + h;
+ }
+
+
+ void accelerate(Vec2D a)
+ {
+ accel.addSelf(a);
+ moving = true;
+ }
+
+
+ void updateBoundingBox()
+ {
+ minX = pos.x;
+ maxX = pos.x + w;
+
+ minY = pos.y;
+ maxY = pos.y + h;
+ }
+
+
+ Vec2D middle()
+ {
+ return (new Vec2D(pos.x+w/2, pos.y+h/2));
+ }
+
+
+
+ void putData(String key, Object val)
+ {
+ data.put(key, val);
+ }
+
+ Object getData(String key)
+ {
+ return data.get(key);
+ }
+
+
+ /// update ///////////////////////////////////////////
+ //////////////////////////////////////////////////////
+
+ void update()
+ {
+
+ rotation += rotationSpeed;
+
+ if (moving)
+ {
+
+ prevPos.set(pos);
+ // apply acceleration
+ vel.addSelf(accel);
+ pos.addSelf(vel);
+
+ if (wrap)
+ {
+ if (pos.x < 0) setX(width-w-1);
+ if (pos.x > width) setX(0);
+ if (pos.y < 0) setY(height-h-1);
+ if (pos.y > height) setY(0);
+ }
+
+ updateBoundingBox();
+
+ // apply drag
+ vel.scaleSelf(frictionCoeff);
+ // clear acceleration
+ accel.set(0, 0);
+
+ if (vel.magnitude() < MIN_VELOCITY)
+ {
+ vel.x = vel.y = 0f;
+ moving = false;
+
+ // do something?
+ finishedMoving();
+ }
+ }
+ }
+
+
+ /// moveTo /////////////////////////////////////////////
+ //////////////////////////////////////////////////////
+
+ void moveTo(float x, float y)
+ {
+ prevPos.set(pos);
+ pos.set(x, y);
+
+ // update minX, maxX, etc
+ }
+
+ /// draw /////////////////////////////////////////////
+ //////////////////////////////////////////////////////
+
+ void draw(PGraphics renderer)
+ {
+ // stroke
+ if (hasStroke)
+ {
+ renderer.stroke(strokeColor);
+ }
+ else
+ {
+ renderer.noStroke();
+ }
+ // fill
+ if (hasFill)
+ {
+ renderer.fill(fillColor);
+ }
+ else {
+ renderer.noFill();
+ }
+
+ // you can change this in subclasses to make custom objects
+
+ //rectMode(CORNER);
+ //rect(pos.x, pos.y, w,h);
+ if (rotationSpeed == 0f)
+ {
+ renderer.rectMode(CORNERS);
+ renderer.rect(minX, minY, maxX, maxY);
+ }
+ else
+ {
+ Vec2D m = middle();
+ renderer.translate(m.x, m.y);
+ renderer.rectMode(CENTER);
+ renderer.rotate(rotation);
+ renderer.rect(0, 0, w, h);
+ }
+ }
+
+
+
+
+ // simple rectangluar boundary hit test
+ boolean intersects(DrawableNode other)
+ {
+
+ if (minX > other.maxX || other.minX > maxX)
+ return false;
+
+ if (minY > other.maxY || other.minY > maxY)
+ return false;
+
+ return true;
+ }
+
+
+ void unload()
+ {
+ }
+
+ void finishedMoving()
+ {
+ }
+
+
+ // end class DrawableNode
+}
+
View
86 BoidRevealerInsaneEdition/FileFuncs.pde
@@ -0,0 +1,86 @@
+String[] getFilesWithExtension(final String ext)
+{
+
+ // we'll have a look in the data folder
+ java.io.File folder = new java.io.File(dataPath(""));
+
+ // let's set a filter (which returns true if file's extension is .jpg)
+ java.io.FilenameFilter fileFilter = new java.io.FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.toLowerCase().endsWith(ext);
+ }
+ };
+
+ // list the files in the data folder, passing the filter as parameter
+ String[] filenames = folder.list(fileFilter);
+
+ if (filenames != null)
+ {
+ // get and display the number of jpg files
+ println(filenames.length + " ." + ext + " files in specified directory");
+
+ // display the filenames
+ for (int i = 0; i < filenames.length; i++) {
+ println(filenames[i]);
+ }
+ }
+ return filenames;
+}
+
+
+
+void refreshPresetFilesList(int guiX, int guiY)
+{
+ savedFiles = getFilesWithExtension("ser");
+ if (savedFiles != null)
+ {
+ if (filesList != null) filesList.clear();
+ else
+ filesList = gui.addDropdownList("savedFileNames", guiX, guiY, 100, 120);
+
+ filesList.setItemHeight(20);
+ filesList.setBarHeight(15);
+ filesList.captionLabel().set("preset files");
+ filesList.captionLabel().style().marginTop = 3;
+ filesList.captionLabel().style().marginLeft = 3;
+ filesList.valueLabel().style().marginTop = 3;
+
+ int i=0;
+
+ for (String item : savedFiles)
+ {
+ filesList.addItem(item, i++);
+ }
+ }
+}
+
+
+
+
+
+void controlEvent(ControlEvent theEvent) {
+ // DropdownList is of type ControlGroup.
+ // A controlEvent will be triggered from inside the ControlGroup class.
+ // therefore you need to check the originator of the Event with
+ // if (theEvent.isGroup())
+ // to avoid an error message thrown by controlP5.
+
+ if (theEvent.isGroup() && !loadingGUIPreset)
+ {
+ // check if the Event was triggered from a ControlGroup
+ println("GROUP::" + theEvent.getGroup().getValue()+" from "+theEvent.getGroup());
+
+ if (theEvent.getGroup().name().equals("savedFileNames") )
+ {
+ loadingGUIPreset = true;
+ String loadFileName = savedFiles[int(theEvent.getGroup().getValue())];
+ println("selected file: " + loadFileName);
+ gui.getProperties().load("data/" + loadFileName);
+ loadingGUIPreset = false;
+ }
+ }
+
+// else if (theEvent.isController()) {
+// println(theEvent.getController().getValue()+" from "+theEvent.getController());
+// }
+}
View
69 BoidRevealerInsaneEdition/Fires.pde
@@ -0,0 +1,69 @@
+
+LinkedList<DrawableNode> fireNodes;
+int numberOfFires = 40;
+int firesStartY = 400;
+int fireRows = 2;
+float fireRotationSpeed = PI/20f;
+float fireOverlap = 0.8f;
+
+void animateFires(PGraphics renderer)
+{
+ for (DrawableNode fire : fireNodes)
+ {
+ fire.update();
+ fire.draw(renderer);
+ }
+}
+
+
+void setupFires(PGraphics renderer)
+{
+ int firesPerRow = numberOfFires / fireRows;
+ int fireWidth = renderer.width/firesPerRow;
+ int fireHeight = (renderer.height-firesStartY)/fireRows;
+ fireHeight = fireWidth = min(fireWidth, fireHeight);
+
+
+ // get rid of all previous bricks, if there are any
+ if (fireNodes != null)
+ {
+ fireNodes.clear();
+ }
+ else
+ {
+ // otherwise make a new ArrayList to hold our game bricks
+ fireNodes = new LinkedList<DrawableNode>();
+ }
+
+ PImage fireImg = loadImage("fire128.png");
+
+ // loop through and make new brick objects and add to bricks list
+ for (int i=0; i<numberOfFires; i++)
+ {
+ int rowNum = i/firesPerRow;
+ // coords
+ int x = fireWidth*i;
+ x -= rowNum*firesPerRow*fireWidth;
+ int y = firesStartY + rowNum*fireHeight;
+ // color
+ // int num = min(rowNum, rowsColors.length-1);
+ // color rowColor = rowsColors[num];
+ // create brick
+
+
+ DrawableNode fire = new ImageNode(fireImg, x, y, fireWidth*(1+fireOverlap), fireHeight*(1+fireOverlap));
+ fire.rotation = random(0, TWO_PI); // all random rotations
+ fire.rotationSpeed = fireRotationSpeed;
+ fire.update();
+ println("r:" + fire.rotation + "/" + fire.rotationSpeed);
+
+ // fire.fillColor = rowColor;
+ //fire.hasFill = true;
+ //brick.hasStroke = true;
+
+ fire.putData ("type", "fire" + nf(i, 3));
+
+ fireNodes.add(fire);
+ }
+}
+
View
252 BoidRevealerInsaneEdition/Flock.pde
@@ -0,0 +1,252 @@
+// The Flock (a list of Boid objects)
+
+class Flock
+{
+ LinkedList<Boid> boids; // An arraylist for all the boids
+ boolean active;
+ PGraphics renderer;
+ /*
+ float desiredseparation = 25.0;
+ float avoidWallsFactor = 0.8;
+ float charAttract = 3.8;
+ float attraction = 0.08;
+ float neighbordist = 25.0;
+ color boidFill = color(255, 30, 0);
+ color boidStroke = color(255, 0, 0);
+ float boidMaxSpeed = 8, boidMaxForce=0.8;
+ */
+ float maxforce; // Maximum steering force
+ float maxspeed; // Maximum speed
+
+
+ Flock()
+ {
+ boids = new LinkedList<Boid>(); // Initialize the arraylist
+ active = false;
+ maxspeed = 6;
+ maxforce = 10;
+ }
+
+
+
+ // We accumulate a new acceleration each time based on three rules
+ void flock()
+ {
+ maxspeed = boidMaxSpeed;
+ maxforce = boidMaxForce;
+
+
+ for (Boid b : boids)
+ {
+ b.maxforce = maxforce;
+ PVector sep = separate(b, boids); // Separation
+ PVector ali = align(b, boids); // Alignment
+ //PVector coh = cohesion(b, boids); // Cohesion
+ // Arbitrarily weight these forces
+ sep.mult(1.0);
+ ali.mult(0.6);
+ //coh.mult(0.2);
+
+ // Add the force vectors to acceleration
+ b.accelerate( sep );
+ //b.applyAcceleration(maxforce, maxspeed);
+ b.accelerate( ali);
+ //b.accelerate( coh );
+ update(b);
+ b.render(renderer);
+ }
+ }
+
+
+ void run(PGraphics _renderer)
+ {
+ renderer = _renderer;
+
+ if (active)
+ {
+ flock();
+ /*
+ ListIterator<Boid> li = boids.listIterator();
+
+ while (li.hasNext ())
+ {
+ Boid b = li.next();
+
+ b.render(renderer);
+ if (hit) li.remove();
+ }
+ */
+ }
+ // end run
+ }
+
+ void addBoid(Boid b)
+ {
+ boids.add(b);
+ }
+
+ void setTexture(GLTexture tex)
+ {
+ for (Boid b : boids)
+ b.tex = tex;
+ }
+
+
+
+ // Method to update location
+ // true if hit character
+ boolean update(Boid b)
+ {
+ boolean hit = false;
+
+ // Avoid walls
+ float dLeft = b.loc.x;
+ float dRight = width-b.loc.x;
+ float dTop = b.loc.y;
+ float dBot = height-b.loc.y;
+
+ float sumAccelX = 0;
+
+ if (dLeft > EPSILON)
+ sumAccelX += (1f/dLeft)*avoidWallsFactor;
+ if (dRight > EPSILON)
+ sumAccelX -= (1f/dRight)*avoidWallsFactor;
+
+ float sumAccelY = 0;
+
+ if (dTop > EPSILON)
+ sumAccelY += (1f/dTop)*avoidWallsFactor;
+ if (dBot > EPSILON)
+ sumAccelY -= (1f/dBot)*avoidWallsFactor;
+
+ b.accelerate(sumAccelX, sumAccelY);
+
+ // attraction towards "characters"
+
+ for (DrawableNode node : nodesToCollide )
+ {
+
+ float charDiffX = node.pos.x - b.loc.x;
+ float charDiffY = node.pos.y - b.loc.y;
+
+ float d = charDiffX*charDiffX + charDiffY*charDiffY;
+
+ if (d > MinNodeDistanceSquared && d < MaxNodeDistanceSquared)
+ {
+ float dInv = attraction-constrain(1/d, 0, attraction);
+
+ float m = max(abs(charDiffX), abs(charDiffY));
+ float dirX = charDiffX/m;
+ float dirY = charDiffY/m;
+
+ float cX = dirX*dInv;
+ float cY = dirY*dInv;
+
+ b.accelerate(cX, cY);
+ }
+ }
+
+ b.applyAcceleration(maxforce, maxspeed);
+ b.wrapBorders();
+
+ return hit;
+ }
+
+
+
+ // Separation
+ // Method checks for nearby boids and steers away
+ PVector separate (Boid b, LinkedList<Boid> boids)
+ {
+
+ PVector sum = new PVector(0, 0, 0);
+ int count = 0;
+ // For every boid in the system, check if it's too close
+ for (Boid other : boids)
+ {
+ if (other != b)
+ {
+ float d = PVector.dist(b.loc, other.loc);
+ // If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
+ if (d < desiredseparation)
+ {
+ d = constrain(d, 0.1, desiredseparation);
+ // Calculate vector pointing away from neighbor
+ PVector diff = PVector.sub(b.loc, other.loc);
+ //diff.normalize();
+ diff.div(d/desiredseparation); // Weight by distance
+ //diff.mult(1f/d);
+ sum.add(diff);
+ count++; // Keep track of how many
+ }
+ }
+ }
+ /*
+ if (count > 0)
+ {
+ sum.div((float)count);
+ }
+ */
+ // As long as the vector is greater than 0
+ if (sum.mag() > 0) {
+ // Implement Reynolds: Steering = Desired - Velocity
+ //sum.normalize();
+ //sum.mult(maxspeed);
+ sum.sub(b.vel);
+ sum.limit(maxforce);
+ }
+ return sum;
+ }
+
+ // Alignment
+ // For every nearby boid in the system, calculate the average velocity
+ PVector align (Boid b, LinkedList<Boid> boids) {
+ PVector sum = new PVector(0, 0, 0);
+ int count = 0;
+ for (Boid other : boids) {
+ float d = PVector.dist(b.loc, other.loc);
+ if ((d > 0) && (d < neighbordist)) {
+ sum.add(other.vel);
+ count++;
+ }
+ }
+
+ if (count > 0) {
+ sum.div((float)count);
+ }
+ // As long as the vector is greater than 0
+ if (sum.mag() > 0) {
+ // Implement Reynolds: Steering = Desired - Velocity
+ sum.normalize();
+ sum.mult(maxspeed);
+ sum.sub(b.vel);
+ sum.limit(maxforce);
+ }
+ return sum;
+ }
+
+ // Cohesion
+ // For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location
+ PVector cohesion (Boid b, LinkedList<Boid> boids) {
+
+ PVector sum = new PVector(0, 0); // Start with empty vector to accumulate all locations
+ int count = 0;
+ for (Boid other : boids)
+ {
+ if (b != other)
+ {
+ float d = b.loc.dist(other.loc);
+ if (d < neighbordist)
+ {
+ sum.add(other.loc); // Add location
+ count++;
+ }
+ }
+ }
+ if (count > 0) {
+ sum.div((float)count);
+ }
+ return b.steer(sum, maxspeed);
+ }
+}
+
View
32 BoidRevealerInsaneEdition/GUI.pde
@@ -0,0 +1,32 @@
+void setupGUI()
+{
+ gui = new ControlP5(this);
+ cpFill = gui.addColorPicker("boidStroke", 10, 10, 255, 20);
+ cpStroke = gui.addColorPicker("boidFill", 10, 80+cpFill.getHeight(), 255, 20);
+
+ int guiX = 10;
+ int guiY = 200;
+
+ Slider slider = gui.addSlider("desiredseparation", 2f, 100f, 25f, guiX, guiY, 100, 20);
+ guiY += slider.getHeight()+2;
+ slider = gui.addSlider("avoidWallsFactor", 0f, 1f, 0.8f, guiX, guiY, 100, 20);
+ guiY += slider.getHeight()+2;
+ slider = gui.addSlider("attraction", 0.01f, 2f, 0.08f, guiX, guiY, 100, 20);
+ guiY += slider.getHeight()+2;
+ slider = gui.addSlider("neighbordist", 8f, 80f, 25f, guiX, guiY, 100, 20);
+ guiY += slider.getHeight()+2;
+ slider = gui.addSlider("boidMaxSpeed", 1f, 300f, 120f, guiX, guiY, 100, 20);
+ guiY += slider.getHeight()+2;
+ slider = gui.addSlider("boidMaxForce", 0.01f, 3f, 0.8f, guiX, guiY, 100, 20);
+ guiY += slider.getHeight()+2;
+ slider = gui.addSlider("fx", 0.01f, 1f, 0.1f, guiX, guiY, 100, 20);
+ guiY += slider.getHeight()+2;
+ slider = gui.addSlider("fy", 0.01f, 1f, 0.1f, guiX, guiY, 100, 20);
+ guiY += slider.getHeight()+4;
+
+ presetName = gui.addTextfield("preset", guiX, guiY, 200, 20);
+
+ guiY += slider.getHeight()+36;
+
+ refreshPresetFilesList(guiX, guiY);
+}
View
139 BoidRevealerInsaneEdition/GeometryFunctions.pde
@@ -0,0 +1,139 @@
+
+
+// COLLISION DETECTION FUNCTIONS
+// -------------------------------------
+
+
+// Find the closest point (x,y) to a piece of a line, and return it.
+
+Vec2D closestPointToLine(Vec2D l0, Vec2D l1, Vec2D p)
+{
+ Vec2D direction = l1.sub(l0);
+ Vec2D w = p.sub(l0);
+ float proj = w.dot(direction);
+
+ if (proj <= 0)
+ return l0;
+ else
+ {
+ float vsq = direction.dot(direction);
+ if (proj >= vsq)
+ return l0.add(direction);
+ else
+ return l0.add( direction.scaleSelf(proj/vsq));
+ }
+}
+
+
+// Find the shortest possible distance between a point and a line.
+
+float distancePointToLine(Vec2D l0, Vec2D l1, Vec2D p)
+{
+ Vec2D direction = l1.sub(l0);
+ Vec2D w = p.sub(l0);
+ float proj = w.dot(direction);
+
+ if (proj <= 0)
+ return w.dot(w);
+ else
+ {
+ float vsq = direction.dot(direction);
+ if (proj >= vsq)
+ return w.dot(w) - 2.0f*proj+vsq;
+ else
+ return w.dot(w) - proj*proj/vsq;
+ }
+}
+
+
+
+
+// "Bounces" a Ball object off of a rectangle, and returns the closest point.
+// This could easily be generalised for a "MovingRectangle" class instead of
+// a "Ball" class to get a simple rigid body dynamics system.
+
+Vec2D bounceBallOffRectangle(DrawableNode ball, DrawableNode r)
+{
+ // First, find the boundary points for our rectangle.
+
+ Vec2D pTopL = new Vec2D(r.minX,r.minY);
+ Vec2D pTopR = new Vec2D(r.maxX,r.minY);
+ Vec2D pBotL = new Vec2D(r.minX,r.maxY);
+ Vec2D pBotR = new Vec2D(r.maxX, r.maxY);
+
+ // The previous position of the ball. At this point in time
+ // the ball is possibly intersecting the rectangle, so we look at
+ // the previous position to find out the direction in which it
+ // was traveling as it hit the rectangle.
+ Vec2D ballPrevPos = new Vec2D(ball.prevPos.x,ball.prevPos.y);
+
+ // For each border (line segment) of the rectangle, find the point that
+ // falls directly on the border that is closest to the previous ball
+ // position:
+ Vec2D closestTopPoint = closestPointToLine(pTopL,pTopR,ballPrevPos);
+ Vec2D closestBotPoint = closestPointToLine(pBotL,pBotR,ballPrevPos);
+ Vec2D closestLeftPoint = closestPointToLine(pTopL,pBotL,ballPrevPos);
+ Vec2D closestRightPoint = closestPointToLine(pTopR,pBotR,ballPrevPos);
+
+ float dt, db, dl, dr; // Distance to the points from prev ball pos
+
+ // Find the distance between the previous ball position and the
+ // closest point on each border:
+ dt = closestTopPoint.distanceToSquared(ballPrevPos);
+ db = closestBotPoint.distanceToSquared(ballPrevPos);
+ dl = closestLeftPoint.distanceToSquared(ballPrevPos);
+ dr = closestRightPoint.distanceToSquared(ballPrevPos);
+
+ // Go through all the closest points and find the closest of them,
+ // which will tell us which side the ball (most likely) hit.
+ // Then, based on which side the ball hit, change the ball's velocity
+ // so it appears to have bounced (reflected) off that side.
+
+ // There are better ways to do this, generally (such as calculating
+ // the slope of the line that represents the rectangle's border
+ // and then geometrically reflecting the velocity vector off it),
+ // but this way works fine (and is a bit more straightforward).
+
+ float bestDistance = dt;
+ float newBallVx, newBallVy;
+
+ Vec2D closestPoint = closestTopPoint;
+ ball.moveTo(closestPoint.x, closestPoint.y-ball.h-1);
+ newBallVx = ball.vel.x;
+ newBallVy = -ball.vel.y;
+ //println("TOP");
+
+ if (db < bestDistance)
+ {
+ closestPoint = closestBotPoint;
+ ball.moveTo(closestPoint.x,closestPoint.y+1);
+ newBallVx = ball.vel.x;
+ newBallVy = -ball.vel.y;
+ //println("BOT");
+ }
+ else if (dl < bestDistance)
+ {
+ bestDistance = db;
+ closestPoint = closestLeftPoint;
+ ball.moveTo(closestPoint.x-ball.w-1,closestPoint.y);
+ newBallVx = -ball.vel.x;
+ newBallVy = ball.vel.y;
+ //println("LEFT");
+ }
+ else if (dr < bestDistance)
+ {
+ bestDistance = dr;
+ closestPoint = closestRightPoint;
+ ball.moveTo(closestPoint.x,closestPoint.y+1);
+ newBallVx = -ball.vel.x;
+ newBallVy = ball.vel.y;
+ // println("RIGHT");
+ }
+
+ // now, finally, update the ball's velocity:
+ ball.vel.x = newBallVx;
+ ball.vel.y = newBallVy;
+
+ return closestPoint;
+}
+
View
87 BoidRevealerInsaneEdition/ImageNode.pde
@@ -0,0 +1,87 @@
+class ImageNode extends DrawableNode
+{
+ PImage img = null;
+
+ ImageNode()
+ {
+ super();
+ }
+
+ ImageNode(float _x, float _y, float _w, float _h)
+ {
+ super( _x, _y, _w, _h);
+ }
+
+
+ ImageNode(PImage newImg, float _x, float _y, float _w, float _h)
+ {
+ super( _x, _y, _w, _h);
+ setImage(newImg);
+ }
+
+ ImageNode(PImage newImg, float _x, float _y)
+ {
+ super( _x, _y, newImg.width, newImg.height);
+ setImage(newImg);
+ }
+
+
+ void setImage(PImage newImg)
+ {
+ img = newImg;
+ }
+
+
+ void setImage(PImage newImg, boolean alterDims)
+ {
+ img = newImg;
+
+ if (alterDims)
+ {
+ setW(img.width);
+ setH(img.height);
+ }
+ }
+
+
+
+ void draw(PGraphics renderer)
+ {
+ // fill, or tint in this case
+ if (hasFill)
+ {
+ renderer.tint(fillColor);
+ }
+ else {
+ renderer.noTint();
+ }
+
+ if (rotationSpeed == 0f)
+ {
+ renderer.imageMode(CORNERS);
+ renderer.image(img,minX, minY, maxX, maxY);
+ }
+ else
+ {
+ renderer.pushMatrix();
+ Vec2D m = middle();
+ renderer.translate(m.x, m.y);
+ renderer.imageMode(CENTER);
+ renderer.rotate(rotation);
+ renderer.image(img,0, 0, w, h);
+ renderer.popMatrix();
+ }
+ }
+
+
+ void unload()
+ {
+ img = null;
+ super.unload();
+ }
+
+// end class
+}
+
+
+
View
143 BoidRevealerInsaneEdition/WiiChuck.pde
@@ -0,0 +1,143 @@
+//
+// Interfce for responding to WiiChuck events
+//
+public interface IWiiChuckListener
+{
+ public void zPressed();
+ public void cPressed();
+ public void stateUpdated(WiiChuck chuck);
+}
+
+//
+// WiiChuck storage and events class
+//
+//
+
+class WiiChuck
+{
+ float roll, pitch;
+ int ax, ay, az, stickX, stickY;
+
+ boolean debug = false;
+
+ // button states
+ final static int UP = 0;
+ final static int PRESSED = 1;
+ final static int HELD = 2; // anything greater than PRESSED means held (and we keep counting...)
+
+ final static int NUM_VALUES = 9;
+
+ int zButton, cButton, zPressed, cPressed; // should be above states only - could use enum but I'm lazy today
+
+ private LinkedList<IWiiChuckListener> listeners; // event listeners (see above)
+
+
+ WiiChuck()
+ {
+ listeners = new LinkedList<IWiiChuckListener>();
+ }
+
+
+ void addListener(IWiiChuckListener wiiLi)
+ {
+ listeners.add(wiiLi);
+ }
+
+ void removeListener(IWiiChuckListener wiiLi)
+ {
+ listeners.remove(wiiLi);
+ }
+
+
+ void update(String values[]) // for converting from Serial object
+ {
+ if (values.length == NUM_VALUES)
+ {
+ /*
+ print("VALUES:" );
+ for (int i=0; i<values.length; ++i)
+ print(" ["+i+"]:"+values[i]);
+ println();
+ */
+
+ int _roll=int(values[0]);
+ int _pitch=int(values[1]);
+ int _ax=int(values[2]);
+ int _ay=int(values[3]);
+ int _az=int(values[4]);
+ int _stickX=int(values[5]);
+ int _stickY=int(values[6]);
+ int _zPressed=int(values[7]);
+ int _cPressed=int(trim(values[