// Pierre MARZIN // Trying to learn Processing... First project, much inspired by "Mycelium" by Scloopy? // http://marzinp.free.fr/applets //GUI and Drag 'n drop: great libraries ! Thanks to Andreas Schlegel (http://www.sojamo.de/libraries/index.html) import controlP5.*; import sojamo.drop.*; //GUI variables SDrop drop; public String mUrl; ControlP5 controlP5; Textlabel weightlabel; Textlabel seuilmaxlabel; Textlabel seuilminlabel; Textlabel modeCouleurLabel; Textlabel pInfo; Textlabel rangelabel; RadioButton radio ; Button onOffButton; Button soundButton; Button resetButton; Button limitButton; //PGraphics pInfo; String monInfo; PFont f; //I just wanted to play with sound a bit. /*sound import ddf.minim.*; import ddf.minim.signals.*; Minim minim; AudioOutput out; SineWave [] sine; boolean useSound;*/ PImage source; // Source image //for each "worm", variables: position //position PVector [] p; //speed PVector [] v; //aimed direction PVector vise=new PVector(); //"seeking" vector PVector deviation=new PVector(); //worm's length int [] longueurVer; //worms maxwidth int []maxwidth; //worms decreaserate int [] decreaserate; //like pixels[], to keep track of how many times a point is reached by a worm int [] buffer; boolean[] typeVer; int [] limiteDown; float [] seekerWeight; //number of worms at the beginning int nbePoints; //width and length of the drawing area int larg; int haut; int largI; int hautI; //brightness of the destination pixel float briMax; //minimum brightness threshold public int seuilBrillanceMini; //maximum brightness threshold public int seuilBrillanceMaxi; //location of the tested point in pixels[] int locTest; //around a point (worms position), how many pixels will we look at... int amplitudeTest; //constrain the aimed direction vector into an r radius circle int r; //constrain the acceleration vector into a devMax radius circle float devMax; //constrain the speed vector into a vMax radius circle int vMax; //not used:random factor int hasard; //stroke's weight (slider) or radius of ellipse used for drawing public float myweight; //draw or not (button onOffButton) public boolean dessine; //different drawing options public int modeCouleur; //fill color int macouleur; boolean limite; //setup only sets up what won't change:GUI and window params //I use initialiser() to set up what has to be initialised //when you hit "ResetButton" and dessin() to set the drawing parameters void setup() { larg=largI=900; haut=hautI=600; size(1000,750); //sound useSound=false; limite=false; //sound minim = new Minim(this); drop = new SDrop(this); f = loadFont("ArialUnicodeMS-12.vlw"); source = loadImage("tiger.jpg"); if(hautI*source.width>largI*source.height){ larg=largI; haut=larg*source.height/source.width; }else{ haut=hautI; larg=haut*source.width/source.height; } source.resize(larg,haut); source.loadPixels(); //info text textFont(f); fill(0); //GUI controlP5 = new ControlP5(this); controlP5.setControlFont(new ControlFont(createFont("ArialUnicodeMS",10,true),12)); // add radioButton for drawing modes radio = controlP5.addRadioButton("radioButton",110,haut+115); //radio.disableCollapse(); radio.setColorForeground(color(120)); radio.setColorLabel(color(0)); radio.setItemsPerRow(4); radio.setSpacingColumn(100); radio.addItem("Normal",1); radio.addItem("Pic Colors",2); radio.addItem("Growing",3); radio.activate("Normal"); //add switch button for limit to threshold limitButton= controlP5.addButton("short_strokes",0,250,haut+40,110,15); limitButton.setSwitch(true); //add onOffButton,sound and ResetButton Buttons onOffButton=controlP5.addButton("onOff",0,610,haut+40,50,15); onOffButton.setSwitch(true); //sound soundButton=controlP5.addButton("sound",0,680,610,50,15); //sound soundButton.setSwitch(true); resetButton=controlP5.addButton("Reset",0,750,haut+40,50,15); // add horizontal sliders and labels for stroke, threshold and drawing modes controlP5.addSlider("myweight",1,15,1,100,haut+40,100,15); Slider s2 = (Slider)controlP5.controller("myweight"); s2.setLabel(""); s2.setDecimalPrecision(0); s2.setNumberOfTickMarks(10); s2.setSliderMode(Slider.FIX); weightlabel = new Textlabel(controlP5,"Stroke width:",10,haut+40,10,10); weightlabel.setColorValue(0); Range range=controlP5.addRange("rangeController",0,255, 0,128, 100,haut+85,200,15); seuilBrillanceMaxi=128; seuilBrillanceMini=0; range.setDecimalPrecision(0); range.setCaptionLabel(""); range.setSliderMode(Slider.FIX); seuilmaxlabel = new Textlabel( controlP5,"light",350,haut+80,10,10); seuilmaxlabel.setColorValue(0); seuilminlabel = new Textlabel(controlP5,"dark",10,haut+80,10,10); seuilminlabel.setColorValue(0); modeCouleurLabel = new Textlabel(controlP5,"Drawing modes:",10,haut+110,10,10); modeCouleurLabel.setColorValue(0); pInfo=new Textlabel( controlP5,"You can drag and drop a picture (not too big!) from your web or file browser...",10,haut+10,10,10); pInfo.setColorValue(0); rangelabel=new Textlabel(controlP5,"Range",180,haut+67,10,10); rangelabel.setColorValue(0); //frameRate(15); initialiser(); } //launched after setup and any time you hit the ResetButton button void initialiser() { nbePoints=6; weightlabel.draw(this); seuilmaxlabel.draw(this); seuilminlabel.draw(this); modeCouleurLabel.draw(this); rangelabel.draw(this); pInfo.draw(this); //sound minim.stop(); // get a line out from Minim, default bufferSize is 1024, default sample rate is 44100, bit depth is 16 //sound out = minim.getLineOut(Minim.STEREO); //sound sine=new SineWave[nbePoints]; fill( 255 ); stroke( 255 ); rect( 0, 0, larg,haut ); onOffButton.setOn(); buffer=new int[haut*larg]; smooth(); dessine=true; p=new PVector[nbePoints]; v=new PVector[nbePoints]; longueurVer=new int[nbePoints] ; seekerWeight=new float[nbePoints]; limiteDown=new int[nbePoints] ; typeVer=new boolean[nbePoints]; decreaserate=new int[nbePoints]; maxwidth=new int[nbePoints]; for(int i=0;iseuilBrillanceMaxi)||(brightness(source.pixels[floor(p[i].x)+floor(p[i].y)*larg])largI*source.height){ larg=largI; haut=larg*source.height/source.width; }else{ haut=hautI; larg=haut*source.width/source.height; } // println(source.width+" "+source.height); background(200); source.resize(larg,haut); source.loadPixels(); initialiser(); mUrl=null; } if(dessine) { //sound if (useSound) {out.sound();} dessin(); } /*sound else { if (useSound) {out.noSound();} }*/ } void dessin() { amplitudeTest=2; vise.x=0; vise.y=0; r=12; hasard=0; devMax=2; vMax=50; locTest=0; //pour chaque mobile for(int t=0;t0)&& (p[t].y+j>0)&&(p[t].x+i0)&& (p[t].y>0)&&(p[t].x10) { //source.pixels[floor(p[t].x)+floor(p[t].y)*larg]=0; deplacePoint(t); } //on compte les segments de chaque ver longueurVer[t]++; /*//si c'est trop long on déménage if (longueurVer[t]>200){ longueurVer[t]=0; deplacePoint(t);}*/ //coeur du comportement de seeker: vise.normalize(); vise.mult(r); v[t].add(new PVector(vise.x,vise.y)); //+hasard-random(2*hasard) deviation=v[t].get(); deviation.normalize(); deviation.mult(devMax); v[t].normalize(); v[t].mult(vMax); p[t].x=p[t].x+deviation.x; p[t].y=p[t].y+deviation.y; //if (t==1){print(" x:"+p[t].x+" p[t].x1:"+(p[t].x-deviation.x/rdessin)+" y:"+p[t].y+" p[t].y2:"+(p[t].y-deviation.y/rdessin)+" ");} //noLoop(); if (((p[t].x>0)&& (p[t].y>0)&&(p[t].x=seuilBrillanceMini)))) {if (limiteDown[t]!=0){limiteDown[t]-=2;} } if (((p[t].x<0)|| (p[t].y<0)||(p[t].x>larg-1)||(p[t].y>haut-1))||((limite)&&((brightness(source.pixels[floor(p[t].x)+floor(p[t].y)*larg])>seuilBrillanceMaxi)||(brightness(source.pixels[floor(p[t].x)+floor(p[t].y)*larg])=52/myweight){ limiteDown[t]=0;deplacePoint(t);} } if ((p[t].x<0)|| (p[t].y<0)||(p[t].x>larg-1)||(p[t].y>haut-1)||((deviation.x==0)&&(deviation.y==0)))//|| {limiteDown[t]=0; deplacePoint(t); } else { briMax=brightness(source.pixels[floor(p[t].x)+floor(p[t].y)*larg]); } //if (brightness(source.pixels[floor(p[t].x)+floor(p[t].y)*larg])10)myweight=1; /*sound if (useSound) { sine[t].setFreq(900-p[t].y); sine[t].setPan((p[t].x/512)-1); }*/ //important: on cree un nouveau vers de temps en temps (on pourrait tester selon la brilance de la zone...) if (random(1)>1-(255-briMax)/80000) {//0.997 p=(PVector[])append(p,new PVector(p[t].x,p[t].y)); v=(PVector[])append(v,new PVector(v[t].x*(5+random(6)),v[t].x*(5+random(6)))); /*sound sine=(SineWave[])append(sine,new SineWave(p[t].y, 0.02, out.sampleRate())); if (random(1)>0.998) { out.addSignal(sine[sine.length-1]); }*/ longueurVer=append(longueurVer,0); seekerWeight=append(seekerWeight,random(myweight)); limiteDown=append(limiteDown,0); decreaserate=append(decreaserate,10+int(random(100))); } } } void deplacePoint(int t) { p[t].x=int(random(larg)); p[t].y=int(random(haut)); while((brightness(source.pixels[floor(p[t].x)+floor(p[t].y)*larg])>seuilBrillanceMaxi)||(brightness(source.pixels[floor(p[t].x)+floor(p[t].y)*larg])