Created
July 29, 2016 17:45
-
-
Save joelhooks/ca10d89baba93e1fb1a1ffe52ed25694 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import hype.*; | |
import hype.extended.colorist.HPixelColorist; | |
int myStageW = 1920; | |
int myStageH = 1080; | |
color clrBG = #FFFFFF; | |
// ******************************************************************************************************************** | |
// AUDIO VARS | |
import ddf.minim.*; | |
import ddf.minim.analysis.*; | |
Minim minim; | |
AudioPlayer myAudioPlayer; | |
AudioInput myAudioInput; | |
boolean myAudioToggle = true; // true = myAudioPlayer / false = myAudioInput | |
FFT myAudioFFT; | |
int myAudioRange = 32; | |
int myAudioMax = 100; | |
float myAudioAmp = 22.0; | |
float myAudioIndex = 0.19; | |
float myAudioIndexAmp = myAudioIndex; | |
float myAudioIndexStep = 0.225; | |
float[] myAudioData = new float[myAudioRange]; | |
float[] myAudioDataMax = new float[myAudioRange]; | |
int fontSize = 16; | |
int fontSpacing = 50; | |
int showVisualizerH = 320; | |
boolean shiftKeyToggle = false; | |
boolean showVisualizer = false; | |
boolean[] keys = {false, false, false, false, false}; // 0=SHIFT, 1=S (PAUSE), 2=P (PLAY), 3=M (MUTE or UNMUTE), 4=R (RESTART AUDIO) | |
boolean myAudioMute = false; | |
boolean myAudioPaused = false; | |
boolean useTimeCodes = true; | |
String timeCodeState; | |
int[] timeCode = {0, 10000, 20000, 30000}; | |
int timeCodeLength = timeCode.length; | |
int timeCodePosition = 0; | |
int timeCodeFuture = timeCodePosition+1; | |
// ******************************************************************************************************************** | |
// ******************************************************************************************************************** | |
// COLOR | |
HImage clrI1 = new HImage(); | |
HPixelColorist clrH1 = new HPixelColorist(); | |
int clrFlowMax1 = 0; | |
int clrFlowIndex1 = 0; | |
IntList clrFlowNums1; | |
color[] clrFlow1; | |
PImage clr1; | |
int clr1IntPositions; | |
void settings() { | |
size(myStageW,myStageH,P3D); | |
// smooth(4); | |
// noSmooth(); | |
// fullScreen(1); | |
} | |
PGraphics myCanvas; | |
HCanvas myHCanvas; | |
void setup(){ | |
H.init(this).background(clrBG).autoClear(true).use3D(true); | |
pixelDensity(2); | |
// noCursor(); | |
clr1IntPositions = NUM_DOTS; | |
setupColorFlows1("color3.png", 800); | |
myCanvas = createGraphics(width,height,P3D); | |
// myAudioDataSetup(); // AudioInput / use this function to start listening to LineIn | |
myHCanvas = (HCanvas) H.add(new HCanvas(width,height,P3D).autoClear(false)); | |
myAudioDataSetup("audio.wav", 0, "loop"); // AudioPlayer / audio file, start position in Milliseconds, state = stop / play / loop | |
for (int i = 0; i < movers.length; i++) { | |
movers[i] = new Mover(random(0.1, 2), random(width), random(height)); | |
} | |
for (int i = 0; i < movers2.length; i++) { | |
movers2[i] = new Mover(random(0.1, 2), random(50, width-50), random(50, width-50)); | |
} | |
a = new Attractor(); | |
a2 = new Attractor(); | |
a3 = new Attractor(); | |
a4 = new Attractor(); | |
a2.position.set(100,100); | |
a3.position.set(width - 100,100); | |
a4.position.set(100,height-100); | |
} | |
import java.util.Arrays; | |
final static color BG = -1, FG = 0; | |
final static short DOT_DIST = 30, DOT_OPAC = 60; | |
final static float DOT_SPEED = 5, FPS = 60, BOLD = 1; | |
final static short NUM_DOTS = 1500; | |
Mover[] movers = new Mover[590]; | |
Mover[] movers2 = new Mover[90]; | |
Attractor a; | |
Attractor a2; | |
Attractor a3; | |
Attractor a4; | |
int dotConnects; | |
void draw(){ | |
myAudioDataUpdate(); | |
myCanvas.beginDraw(); | |
strokeWeight(3); | |
fill(0); | |
myCanvas.clear(); | |
final float size = map(myAudioData[0], 0, myAudioMax, 42, 3); | |
dotConnects = 0; | |
final int fftA1 = (int)map(myAudioData[0], 0, myAudioMax, 225, 255); | |
final int fftC = (int)map(myAudioData[1], 0, myAudioMax, 255, 250); | |
fill( fftC, fftA1 ); | |
// fill(255); | |
final int fftStrokeC = (int)map(myAudioData[0], 0, myAudioMax, 20, 5); | |
final int fftStrokeA = (int)map(myAudioData[0], 0, myAudioMax, 50, 225); | |
stroke(fftStrokeC, fftStrokeA); | |
final float connectDistance = map(myAudioData[0], 0, myAudioMax, 40, 265); | |
final float particleMass = map(myAudioData[0], 0, myAudioMax, .02, 8); | |
final float a1Mass = map(myAudioData[0], 0, myAudioMax, 200, 550); | |
final float a1Speed = map(myAudioData[0], 0, myAudioMax, 4.4, 1.9); | |
a.G = a1Speed; | |
a.mass = a1Mass; | |
// a.display(); | |
final float a2Mass = map(myAudioData[11], 0, myAudioMax, 2, 275); | |
final float a2Speed = map(myAudioData[11], 0, myAudioMax, 1, 1.4); | |
a2.G = a2Speed; | |
a2.mass = a2Mass; | |
// a2.display(); | |
final float a3Mass = map(myAudioData[6], 0, myAudioMax, 2, 376); | |
final float a3Speed = map(myAudioData[6], 0, myAudioMax, -1, 1.4); | |
a3.G = a3Speed; | |
a3.mass = a3Mass; | |
// a3.display(); | |
final float a4Mass = map(myAudioData[20], 0, myAudioMax, 2, 476); | |
final float a4Speed = map(myAudioData[20], 0, myAudioMax, -.9, 2.9); | |
a3.G = a4Speed; | |
a4.mass = a4Mass; | |
// a4.display(); | |
for (int i = 0; i < movers.length; i++) { | |
Mover mover = movers[i]; | |
mover.mass = particleMass; | |
for (int j = 0; j < movers.length; j++) { | |
if (i != j) { | |
PVector force = movers[j].attract(movers[i]); | |
movers[i].applyForce(force); | |
} | |
} | |
PVector force = a.attract(mover); | |
PVector force2 = a2.attract(mover); | |
PVector force3 = a3.attract(movers[i]); | |
PVector force4 = a4.attract(mover); | |
mover.applyForce(force); | |
mover.applyForce(force2); | |
mover.applyForce(force3); | |
mover.applyForce(force4); | |
// movers[i].applyForce(new PVector(speed, speed)); | |
nearestNeighbors(mover, i, connectDistance); | |
// fill(clrFlow1[clrFlowNums1.get(i)]); | |
mover.update(); | |
movers[i].display(); | |
} | |
final float particleMass2 = map(myAudioData[0], 0, myAudioMax, .5, 4); | |
for (int h = 0; h < movers2.length; ++h) { | |
Mover mover = movers2[h]; | |
mover.mass = particleMass2; | |
for (int j = 0; j < movers2.length; j++) { | |
if (h != j) { | |
PVector force = movers2[j].attract(mover); | |
mover.applyForce(force); | |
} | |
} | |
PVector force = a.attract(mover); | |
PVector force2 = a3.attract(mover); | |
PVector force3 = a3.attract(mover); | |
// fill(clrFlow1[clrFlowNums1.get((int)myAudioData[0])]); | |
fill(0); | |
mover.applyForce(force); | |
mover.applyForce(force2); | |
mover.applyForce(force3); | |
strokeWeight(0); | |
mover.update(); | |
mover.display(); | |
} | |
myCanvas.endDraw(); | |
myCanvas = myHCanvas.graphics(); | |
H.drawStage(); | |
if (showVisualizer) myAudioDataWidget(); | |
// saveFrame("../frames/#########.tif"); if (frameCount == 900) exit(); | |
surface.setTitle( int(frameRate) + " FPS" ); | |
flowTheColors(); | |
} | |
void nearestNeighbors(Mover p1, int i, float maxDist) { | |
float x = p1.position.x, y = p1.position.y; | |
for (int j = i; j != movers.length;) { | |
final PVector p2 = movers[j++].position; | |
// final float dx = p2.x - x; | |
// if (dx > maxDist) return; | |
// final float dy = abs(p2.y - y); | |
// if (dy > maxDist) continue; | |
if (dist(x, y, p2.x, p2.y) < maxDist) { | |
p1.drawLine(p2); | |
dotConnects++; | |
} | |
} | |
} | |
// ******************************************************************************************************************** | |
void keyPressed() { | |
switch (key) { | |
case 'v': | |
if (showVisualizer) showVisualizer = false; | |
else showVisualizer = true; | |
break; | |
} | |
if (myAudioToggle) { | |
if(keyCode == SHIFT) keys[0]=true; | |
if(key=='S') keys[1]=true; // STOP / PAUSE | |
if(key=='P') keys[2]=true; // PLAY | |
if(key=='M') keys[3]=true; // MUTE or UNMUTE | |
if(key=='R') keys[4]=true; // RESTART | |
if (keys[0] && keys[1]) { | |
myAudioPaused = true; | |
myAudioPlayer.pause(); | |
} | |
if (keys[0] && keys[2]) { | |
myAudioPaused = false; | |
myAudioPlayer.play(); | |
} | |
if (keys[0] && keys[3]) { | |
if (myAudioMute) { | |
myAudioPlayer.unmute(); | |
myAudioMute = false; | |
} else { | |
myAudioPlayer.mute(); | |
myAudioMute = true; | |
} | |
} | |
if (keys[0] && keys[4]) { | |
timeCodePosition = 0; | |
timeCodeFuture = timeCodePosition+1; | |
letsAudioJumpMMS(0); | |
} | |
} | |
} | |
void keyReleased() { | |
if (myAudioToggle) { | |
if(keyCode == SHIFT) keys[0]=false; | |
if(key=='s' || key=='S') keys[1]=false; | |
if(key=='p' || key=='P') keys[2]=false; | |
if(key=='m' || key=='M') keys[3]=false; | |
if(key=='r' || key=='R') keys[4]=false; | |
} | |
} | |
// ******************************************************************************************************************** | |
void mousePressed() { | |
if (myAudioToggle && keys[0]) { | |
int position = int( map( mouseX, 0, width, 0, myAudioPlayer.length() ) ); | |
myAudioPlayer.cue( position ); | |
for (int i = 0; i < timeCodeLength; ++i) { | |
if (position<timeCode[i]) { | |
timeCodePosition = i-1; | |
timeCodeFuture = i; | |
break; | |
} | |
} | |
} | |
} | |
// ******************************************************************************************************************** | |
// AUDIO FUNCTIONS / DO NOT EDIT | |
void myAudioDataSetup() { | |
myAudioToggle = false; | |
minim = new Minim(this); | |
myAudioInput = minim.getLineIn(Minim.MONO); | |
myAudioFFT = new FFT(myAudioInput.bufferSize(), myAudioInput.sampleRate()); | |
myAudioFFT.linAverages(myAudioRange); | |
myAudioFFT.window(FFT.GAUSS); | |
} | |
void myAudioDataSetup(String str, int pos, String state) { | |
timeCodeState = state; | |
minim = new Minim(this); | |
myAudioPlayer = minim.loadFile(str); | |
if (state == "stop") { | |
myAudioPlayer.play(); | |
myAudioPlayer.mute(); | |
myAudioPlayer.pause(); | |
myAudioPlayer.unmute(); | |
letsAudioJumpMMS(pos); | |
} else if (state == "play") { | |
letsAudioJumpMMS(pos); | |
myAudioPlayer.play(); | |
} else if (state == "loop") { | |
letsAudioJumpMMS(pos); | |
myAudioPlayer.play(); | |
} | |
myAudioFFT = new FFT(myAudioPlayer.bufferSize(), myAudioPlayer.sampleRate()); | |
myAudioFFT.linAverages(myAudioRange); | |
myAudioFFT.window(FFT.GAUSS); | |
} | |
void myAudioDataUpdate() { | |
if (myAudioToggle) myAudioFFT.forward(myAudioPlayer.mix); | |
else myAudioFFT.forward(myAudioInput.mix); | |
for (int i = 0; i < myAudioRange; ++i) { | |
float tempIndexAvg = (myAudioFFT.getAvg(i) * myAudioAmp) * myAudioIndexAmp; | |
float tempIndexCon = constrain(tempIndexAvg, 0, myAudioMax); | |
myAudioData[i] = tempIndexCon; | |
myAudioIndexAmp+=myAudioIndexStep; | |
} | |
myAudioIndexAmp = myAudioIndex; | |
if (myAudioToggle) { | |
// timecodes | |
if( myAudioPlayer.position()>timeCode[timeCodeFuture] && timeCodeFuture!=0 ) { | |
timeCodePosition = timeCodeFuture; | |
timeCodeFuture = ++timeCodeFuture%timeCodeLength; | |
} | |
// loop | |
if (timeCodeState=="loop" && !myAudioPaused && !myAudioPlayer.isPlaying()) { | |
timeCodePosition = 0; | |
timeCodeFuture = timeCodePosition+1; | |
letsAudioJumpMMS(0); | |
myAudioPlayer.play(); | |
} | |
} | |
} | |
void myAudioDataWidget() { | |
perspective(PI/3.0, (float)width/height, 0.1, 1000000); | |
noLights(); | |
hint(DISABLE_DEPTH_TEST); | |
resetShader(); | |
noStroke(); | |
fill(0,200); | |
rect(0, height-showVisualizerH, width, (showVisualizerH-10)); | |
strokeWeight(0.5); | |
stroke(255,50); | |
noFill(); | |
line(185, height-61, width, height-61); | |
stroke(255,100); | |
line(0, height-(showVisualizerH-16), width, height-(showVisualizerH-16)); | |
if (myAudioToggle) { | |
fill(#CCCCCC); | |
int position = (int)map( myAudioPlayer.position(), 0, myAudioPlayer.length(), 0, width ); | |
rect(position, height-(showVisualizerH-6), 1, 20); | |
} | |
if (myAudioToggle && useTimeCodes) { | |
for (int i = 0; i < timeCodeLength; ++i) { | |
if (i==timeCodePosition) { stroke(#CC6600); fill(#CC6600); } | |
else { stroke(#00CC00); fill(#00CC00); } | |
int timeCodePos = (int)map(timeCode[i], 0, myAudioPlayer.length(), 0, width); | |
rect(timeCodePos, height-(showVisualizerH-6), 1, 20); | |
} | |
} | |
noFill(); | |
stroke(#FF0000); line(10, height-31, 169, height-31); | |
stroke(#FF3300); line(10, height-51, 169, height-51); | |
stroke(#FF6600); line(10, height-71, 169, height-71); | |
stroke(#FF9900); line(10, height-91, 169, height-91); | |
stroke(#FFCC00); line(10, height-111, 169, height-111); | |
strokeWeight(1.0); | |
noStroke(); | |
for (int i = 0; i < myAudioRange; ++i) { | |
fill(#ECECEC); | |
rect(10 + (i*5), (height-myAudioData[i])-11, 4, myAudioData[i]); | |
} | |
textAlign(CENTER); | |
int rectY = 107; | |
int textY = 80; | |
int yOffset = 0; | |
int yOffsetAmp = 45; | |
int yThreshold; | |
for (int j = 0; j < myAudioRange; ++j) { | |
// 20 % | |
yThreshold = 20; yOffset = yOffsetAmp*0; | |
if (myAudioData[j]>=yThreshold) { fill(#FF0000); myAudioDataMax[j] = yThreshold; } | |
else { fill(#181818); myAudioDataMax[j] = 0; } | |
rect(185 + (j*fontSpacing), height-(rectY+yOffset), 44, 40); | |
if (myAudioData[j]>=yThreshold) fill(0); | |
else fill(#4D4D4D); | |
text(str(j), 207 + (j*fontSpacing), height-(textY+yOffset)); | |
// 40 % | |
yThreshold = 40; yOffset = yOffsetAmp*1; | |
if (myAudioData[j]>=yThreshold) { fill(#FF3300); myAudioDataMax[j] = yThreshold; } | |
else { fill(#181818); } | |
rect(185 + (j*fontSpacing), height-(rectY+yOffset), 44, 40); | |
if (myAudioData[j]>=yThreshold) fill(0); | |
else fill(#4D4D4D); | |
text(str(j), 207 + (j*fontSpacing), height-(textY+yOffset)); | |
// 60 % | |
yThreshold = 60; yOffset = yOffsetAmp*2; | |
if (myAudioData[j]>=yThreshold) { fill(#FF6600); myAudioDataMax[j] = yThreshold; } | |
else { fill(#181818); } | |
rect(185 + (j*fontSpacing), height-(rectY+yOffset), 44, 40); | |
if (myAudioData[j]>=yThreshold) fill(0); | |
else fill(#4D4D4D); | |
text(str(j), 207 + (j*fontSpacing), height-(textY+yOffset)); | |
// 80 % | |
yThreshold = 80; yOffset = yOffsetAmp*3; | |
if (myAudioData[j]>=yThreshold) { fill(#FF9900); myAudioDataMax[j] = yThreshold; } | |
else { fill(#181818); } | |
rect(185 + (j*fontSpacing), height-(rectY+yOffset), 44, 40); | |
if (myAudioData[j]>=yThreshold) fill(0); | |
else fill(#4D4D4D); | |
text(str(j), 207 + (j*fontSpacing), height-(textY+yOffset)); | |
// 100 % | |
yThreshold = 100; yOffset = yOffsetAmp*4; | |
if (myAudioData[j]>=yThreshold) { fill(#FFCC00); myAudioDataMax[j] = yThreshold; } | |
else { fill(#181818); } | |
rect(185 + (j*fontSpacing), height-(rectY+yOffset), 44, 40); | |
if (myAudioData[j]>=yThreshold) fill(0); | |
else fill(#4D4D4D); | |
text(str(j), 207 + (j*fontSpacing), height-(textY+yOffset)); | |
int tempInt = (int)myAudioDataMax[j]; | |
int tempAlpha = (int)map(tempInt, 0, 100, 55, 255); | |
fill(#ECECEC, tempAlpha); | |
text(str(tempInt), 207 + (j*fontSpacing), height-30); | |
} | |
fill(#999999); | |
textAlign(RIGHT); | |
text("20 %", width-25, height-(textY+(yOffsetAmp*0))); | |
text("40 %", width-25, height-(textY+(yOffsetAmp*1))); | |
text("60 %", width-25, height-(textY+(yOffsetAmp*2))); | |
text("80 %", width-25, height-(textY+(yOffsetAmp*3))); | |
text("100 %", width-25, height-(textY+(yOffsetAmp*4))); | |
if (myAudioToggle) { | |
if (useTimeCodes) { | |
fill(#CC6600); | |
String curPos = "timeCodePosition = " + str(timeCodePosition); | |
text(curPos, 170, height-215); | |
} | |
String curTime = str(myAudioPlayer.position()/60000) + " : " + str((myAudioPlayer.position()/1000)%60) ; | |
fill(#00616f); | |
text(curTime, 170, height-170); | |
fill(#0095A8); | |
text(str(myAudioPlayer.position()), 170, height-125); | |
} | |
hint(ENABLE_DEPTH_TEST); | |
} | |
void letsAudioJump(int _m, int _s) { if (myAudioToggle) myAudioPlayer.cue( (_m*60000)+(_s*1000) ); } | |
void letsAudioJumpMMS(int _time) { if (myAudioToggle) myAudioPlayer.cue( _time ); } | |
void stop() { | |
if (myAudioToggle) myAudioPlayer.close(); | |
else myAudioInput.close(); | |
minim.stop(); | |
super.stop(); | |
} | |
// ******************************************************************************************************************** | |
// COLOR FLOW | |
void flowTheColors() { | |
for (int i=0; i<clr1IntPositions; i++) { | |
int _tempNum1 = clrFlowNums1.get(i); | |
_tempNum1++; | |
if(_tempNum1 >= clrFlowMax1) _tempNum1 = 0; | |
clrFlowNums1.set(i, _tempNum1); | |
} | |
} | |
void setupColorFlows1(String _clrImg1, int _clrMax1) { | |
clrFlowMax1 = clrFlowIndex1 = 0; | |
clrI1.image(_clrImg1); clr1 = loadImage(_clrImg1); | |
clrH1.image(_clrImg1); | |
clrFlowMax1 = _clrMax1; | |
clrFlow1 = new color[ _clrMax1 ]; | |
for (int i = 0; i < _clrMax1; i++) { | |
float tempPos = (clrI1.width() / _clrMax1) * i; | |
clrFlow1[i] = clrH1.getColor(tempPos,1); | |
} | |
clrFlowNums1 = new IntList(); | |
for (int j = 0; j < clr1IntPositions; j++) { | |
// clrFlowNums1.append( (int)random(_clrMax1) ); | |
clrFlowNums1.append( clrFlowIndex1 ); | |
clrFlowIndex1++; | |
if (clrFlowIndex1==_clrMax1) clrFlowIndex1 = 0; | |
} | |
} | |
// The Nature of Code | |
// Daniel Shiffman | |
// http://natureofcode.com | |
class Mover { | |
PVector position; | |
PVector velocity; | |
PVector acceleration; | |
float mass; | |
Mover(float m, float x, float y) { | |
mass = m; | |
position = new PVector(x, y); | |
velocity = new PVector(1, 0); | |
acceleration = new PVector(0, 0); | |
} | |
void applyForce(PVector force) { | |
PVector f = PVector.div(force, mass); | |
acceleration.add(f); | |
} | |
void update() { | |
velocity.add(acceleration); | |
position.add(velocity); | |
acceleration.mult(0); | |
} | |
void drawLine(PVector other) { | |
line(position.x, position.y, other.x, other.y); | |
} | |
void display() { | |
// stroke(0); | |
// strokeWeight(2); | |
// fill(0,100); | |
ellipse(position.x, position.y, mass*25, mass*25); | |
} | |
PVector attract(Mover m) { | |
PVector force = PVector.sub(position, m.position); // Calculate direction of force | |
float distance = force.mag(); // Distance between objects | |
distance = constrain(distance, 5.0, 25.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects | |
force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction | |
float strength = (2.1 * mass * m.mass) / (distance * distance); // Calculate gravitional force magnitude | |
force.mult(strength); // Get force vector --> magnitude * direction | |
return force; | |
} | |
} | |
// The Nature of Code | |
// Daniel Shiffman | |
// http://natureofcode.com | |
// A class for a draggable attractive body in our world | |
class Attractor { | |
float mass; // Mass, tied to size | |
float G; // Gravitational Constant | |
PVector position; // position | |
boolean dragging = false; // Is the object being dragged? | |
boolean rollover = false; // Is the mouse over the ellipse? | |
PVector dragOffset; // holds the offset for when object is clicked on | |
Attractor() { | |
position = new PVector(width/2,height/2); | |
mass = 20; | |
G = 1; | |
dragOffset = new PVector(0.0,0.0); | |
} | |
PVector attract(Mover m) { | |
PVector force = PVector.sub(position,m.position); // Calculate direction of force | |
float d = force.mag(); // Distance between objects | |
d = constrain(d,5.0,25.0); // Limiting the distance to eliminate "extreme" results for very close or very far objects | |
force.normalize(); // Normalize vector (distance doesn't matter here, we just want this vector for direction) | |
float strength = (G * mass * m.mass) / (d * d); // Calculate gravitional force magnitude | |
force.mult(strength); // Get force vector --> magnitude * direction | |
return force; | |
} | |
// Method to display | |
void display() { | |
ellipseMode(CENTER); | |
strokeWeight(4); | |
stroke(0); | |
if (dragging) fill (50); | |
else if (rollover) fill(100); | |
else fill(175,200); | |
ellipse(position.x,position.y,mass*2,mass*2); | |
} | |
// The methods below are for mouse interaction | |
void clicked(int mx, int my) { | |
float d = dist(mx,my,position.x,position.y); | |
if (d < mass) { | |
dragging = true; | |
dragOffset.x = position.x-mx; | |
dragOffset.y = position.y-my; | |
} | |
} | |
void hover(int mx, int my) { | |
float d = dist(mx,my,position.x,position.y); | |
if (d < mass) { | |
rollover = true; | |
} | |
else { | |
rollover = false; | |
} | |
} | |
void stopDragging() { | |
dragging = false; | |
} | |
void drag() { | |
if (dragging) { | |
position.x = mouseX + dragOffset.x; | |
position.y = mouseY + dragOffset.y; | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment