You are on page 1of 11

Working with Toxiclibs [Processing, Tutorial

]

Would you like to create what you see in those videos? Well, read on! Because in this article I will show you how you can do just that using Processing and Toxiclibs. As Processing’s biggest open source collection of libraries, Toxiclibs can assist you in areas like geometry, physics, math and color. With so much code candy for the taking, the libs can still be a bit daunting for many people, especially Processing beginners. That’s why – in addition to great functionality and documentation – clear and inspiring examples on how to use the library are so important. Fortunately the collection of code examples bundled with the libs is growing steadily. I hope my examples can add to that and be helpful to those learning how to use this wonderful collection of code which is shared and continuously developed by Karsten Schmidt.

An INFINITE rope! This example demonstrates both the creation and efficient removal of particles.I’ve already shared the two code examples from the first video on my blog. you should be able to understand what’s going on. Specifically it uses the VerletSpring2D class. more specifically the VerletSpring2D class (example 3) and we will explore a whole new area of the libs. The full source code and a more detailed explanation of those two examples can be found HERE. This explains why the visuals when running the code may differ ever so slightly from what you see in the movie. So by running them and looking through the code. picking and dragging polygon shapes (example 1) and the destruction of voronoi tesselated circles (example 2). which of course I was happy to apply. In this follow-up I will share the source code for the two brand new examples you see in the second video. This time I’m venturing a little deeper into the physics capabilities of Toxiclibs. Example 3: The Infinite Rope What’s better than a rope? Exactly. The rest of this blog post can be considered additional background information ranging from general description to specific pointers. As the video shows these concern creating. namely the color library (example 4). which can . Note (06/05/2011): Karsten came up with some useful suggestions to further improve the code. The three pillars of the physics system. All of the examples are commented as much as possible. springs and behaviors.

springs. import toxi. Second. The most important part of the sketch however. effectively making a digital rope. int continuous. Let me elaborate on two specific aspects with regard to the removeOffscreen() function.connect two VerletParticles in space. but everything with regard to physics in Toxiclibs also has a 3D equivalent.720.*. gravity) physics. the color of every segment is determined by the direction of each spring. Release the mouse to start a new rope. Therefore the behavior of particle 1 can be found in position 2 of the behavior list and so on.OPENGL).0.geom.*. it’s running backwards through the for loop! This is because we are removing things from the list. // draw a line segment for each spring and change the color of it based on the x position for(VerletSpring2D s : physics. is the code that removes off-screen objects.addBehavior(new GravityBehavior(new Vec2D(0.*. import toxi.update(). Meaning the list is getting shorter while you are going through it. VerletParticle2D prev. notice that I remove behavior(i+1) for particle(i). For aesthetic reasons.current. Push behavior is added to each particle to make it look a little more realistic. VerletPhysics2D physics. physics = new VerletPhysics2D().color.opengl. For simplicity it’s kept 2D. // set the stroke weight of the line strokeWeight(2). This is absolutely imperative to keep things running smoothly.springs) { . import toxi.*.physics2d.physics2d. Let me describe the way it works and some of the specific choices and solutions. The reason is that the first behavior on the list is the gravity we added in setup().behaviors. // variables to create a new continuous line on each mouse drag void setup() { size(1280.1))). import toxi. First. When the mouse is dragged a new particle is created and connected to the last one.*. // // // Toxiclibs Code Example: The Infinite Rope by Amnon Owed (05/05/2011) minor refactorings by Karsten Schmidt (06/05/2011) import processing. // update all the physics stuff (particles. // add gravity in positive Y direction physics. } void draw() { background(255). Therefore you need to go backwards to prevent problems and to make sure you cover every item in the list.

ParticleBehavior2D b = physics.size()-1). physics.-) removeOffscreen().particles.x.y > height+200) { physics.b.1).removeParticle(p).a).get(i).toARGB()).-PI.y. } // remove stuff that is off the screen to keep things running smoothly . } } // remove off-screen particles & behaviors for (int i=physics.sub(s. } } } void mouseDragged() { // create a locked (unmovable) particle at the mouse position VerletParticle2D p = new VerletParticle2D(mouseX.get(i+1).size() > 0 && continuous == current) { // get the previous particle (aka the last in the list) VerletParticle2D prev = physics.PI.x.b.particles. if (p. // add the spring to the physics system physics. // create a spring between the previous and the current particle of length 10 and strength 1 VerletSpring2D s = new VerletSpring2D(p. i>=0. } else { .lock(). line(s. i--) { VerletParticle2D p = physics.behaviors.hasNext(). i.particles.b.size()-1.1).remove().iterator().y > height+100) { i.1).a.particles.newHSV(currHue.1.prev.s.y > height+100 || s.heading(). p.springs.mouseY).b.0.a. } void removeOffscreen() { // remove off-screen springs for (Iterator i=physics.s.s.particles. // define a color in HSV and convert into ARGB format (32bit packed integer) stroke(TColor.10.y).a.removeBehavior(b).next().// map the direction of each spring to a hue float currHue=map(s.) { VerletSpring2D s=i.addSpring(s). // if there is at least one particle and this is the current continuous line if (physics.get(physics. if (s.

prev=p.addParticle(p). It’s the basis for much greater possibilities such as color ranges. In the color portion of Toxiclibs there is a list of 143 NamedColors that you can use..5 (aka push) ParticleBehavior2D b = new AttractionBehavior(p. but technically completely different. // create a forcefield around this particle with radius 20 and force -1. If Vec2D/Vec3D is the heart of the geometry lib. themes and gradients. } // unlock previous particle if (prev!=null) { prev. // add the behavior to the physics system (will be applied to all particles) physics.-1.20.current = continuous.unlock().addBehavior(b). } Example 4: NamedColors Aesthetically somewhat similar.. I think it’s best to start with a basic example. } continuous++. then you could say TColor is the heart of the color lib. But to grasp this part of Toxiclibs.unlock().5). } // add the particle to the physics system physics. } void mouseReleased() { if (prev!=null) { prev. // make current particle the previous one. this example is meant to demonstrate how to use TColors in general and NamedColors in particular. They have . For this I chose the NamedColors since they are less abstract than working with numbers alone.

void setup() { size(1280. the line is drawn. The right mouse button changes the background color. import toxi. OPENGL). The colorWorm is basically a list of up to 25 points.*. It starts at the mouse position and then moves randomly.*. orange and last but not least peachpuff.names like azure. // create a list of all the Toxiclibs NamedColors names = NamedColor. // background color (readonly colors can't be modified) ReadonlyTColor bg. import toxi. Running the sketch presents you with the full color palette.*. the mouse functionality will keep working. int selectedColorID. . while the left mouse button creates a colorWorm at the mouse position. adding new points along the way. it’s converted into a packed ARGB int using the toARGB() function. height/2).getNames(). In this example you can see that every time the color is actually used. Since the directional change is limited to 30 degrees. a direction and a certain color. ZoomLensInterpolation zoomLens = new ZoomLensInterpolation(). it will generally keep going into a certain direction instead of wriggling around the same spot. Press any key to toggle the palette on/off. 720. ArrayList ArrayList names = new ArrayList worms = new ArrayList ().color.geom. (). There are some checks to make sure both the name and it’s background are kept within the boundaries of the screen. lavender. darkturquoise. center = new Vec2D(width/2. So let me walk through the sketch real quick. In setup() all the names are loaded into an ArrayList of strings for the purpose of sorting them alphabetically. To make it a little smoother all the points are loaded into a Spline2D which is then subdivided.opengl.sort(names). From the vertices that come out. When working with TColors it’s important to remember that you need to convert them into something that can be used in a Processing fill() or stroke() function.*. // screen center Vec2D center.math. // sort it alphabetically Collections. I’ve applied some ZoomLensInterpolation to bring out the selected color (mouseX) and made it move up and down with the user (mouseY). // // // Toxiclibs Code Example: NamedColors by Amnon Owed (05/05/2011) minor refactorings by Karsten Schmidt (06/05/2011) import processing. import toxi. boolean showColorPalette = true.

// set zoom lens to a dilating characteristic // setting the first parameter to a negative value will create a bundling effect zoomLens.iterator().0 . width. i<=num.getForName("deepskyblue").45.next().distanceToSquared(center) > 640000) { i.hasNext(). } } . } } // set the zoom location based on the normalized mouseX (0.0 interval) float normX=(float)mouseX / width.15).size()-1. width.textFont(createFont("SansSerif". // set the background color to deepskyblue bg = NamedColor.remove(). i. // interpolate focal point to new mouse position (15% step per frame) zoomLens.. float x2=zoomLens. width. 1.get(0). // run through all the worms (backwards cause we are also removing some from the list) for (Iterator i=worms. break.points. // select color if focalX is between x and x2 if (focalX >= x && focalX < x2) { selectedColorID=i. num=names. w. i++) { float x=zoomLens. 0. if (w.setLensStrength(0. // determine the selected color based on mouseX // by finding which color area contains mouseX float focalX=zoomLens..toARGB()). 1). 28)). // if the worm's last point is 'off the screen' remove the worm // distanceToSquared() is faster than distanceTo() since it avoids // the square root calculation and we don't need precise values here.interpolate(0.display().update().) { ColorWorm w = i. normX).. for (int i=0.interpolate(0.interpolate(0. } else { // otherwise update and display the worm w. (float)(i+1)/num). } void draw() { // convert the bg color into ARGB color format (32bit packed integer) background(bg.setLensPos(normX. (float)i/num).

c = c.add(origin). } if (mousePressed) { // Create worms with the LEFT mouse button if (mouseButton == LEFT) { Vec2D mouse = new Vec2D(mouseX.size()-1). } void update() { // every second frame (not too fast. } } } // Press ANY key to toggle the color palette void keyPressed() { showColorPalette = !showColorPalette. ReadonlyTColor c) { // at the origin point (mouseX. mouseY). } class ColorWorm { List points = new ArrayList ().getForName(names.getForName(names. // Change the background color with the RIGHT or MIDDLE mouse button } else { bg = NamedColor. ReadonlyTColor c = NamedColor. // create a copy of the readonly color for later manipulation this.copy().get(selectedColorID)).randomVector().// toggle the color palette if (showColorPalette) { drawColorPalette(). worms.add(new ColorWorm(mouse. c)).get(points. TColor c. Vec2D direction. // create a random direction direction = Vec2D.get(selectedColorID)).mouseY) points. ColorWorm(Vec2D origin. not too slow) if (frameCount % 2 == 0) { // create a new point given the last point's coordinates Vec2D p = points.copy(). .

v.addSelf(move). } } } void drawColorPalette() { noStroke(). } // truncate at 25 points (remove the oldest point) while (points. 30)). } endShape(). 0.size()>2) { // create Spline2D from the points Spline2D s = new Spline2D(points).rotate(radians(random(-30. // move the point in that direction and with that distance p.getNormalizedTo(random(15. i++) { Vec2D v = vertices.size()-1. i<=num.num=vertices. // convert the color into ARGB color format (32bit packed integer) stroke(c. vertex(v.setAlpha(map(i.computeVertices(8).x.toARGB()). num.y). // create a movement vector in that direction with a random magnitude between 15 and 30 Vec2D move = direction. strokeWeight(2). // draw a line through all the vertices beginShape(). } } void display() { // need at least 3 points to construct a spline if (points. 1)).get(i). // display all the colors over the width of the screen . 0.size () > 25) { points. for (int i=0.remove(0).add(p). 30))).// rotate the direction randomly somewhere between -30 and 30 degrees direction. // the position in the list determines the transparency of the segment c. noFill(). // subdivide it by 8 into a list of vertices List vertices = s. // add the new point to the list points.

(float)i / num). width. i++) { // determine the color swatch's position & width based on // it's relative position and the zoom location (mouseX) float x = zoomLens. If you would like to know if and how Toxiclibs can help you with your project. height-4).for (int i=0. y). } That concludes this round of code sharing. float x2 = zoomLens.toARGB()). x2-x. (float)(i+1) / num). float ascent = textAscent(). ascent+8). width.size()-1.num=names. A description of how to install contributed libraries for Processing can be found here. y-ascent-4. // move the colors vertically with mouseY rect(x. // convert the color into ARGB color format (32bit packed integer) fill(NamedColor. mouseY-15. } // get the name of the selectedColor String name = names. i<=num. For all things Toxiclibs go to toxiclibs. There are quite a few people over there (including Karsten himself sometimes) who can help you out with advice and maybe even code examples. // draw a black text fill(0). x+4. // draw a white text background fill(255). width-textwidth-8).interpolate(0. // keep the text and it's background fill within screen boundaries float x = min(mouseX. text(name.-) . but are unsure of where to start.get(selectedColorID).org. float y = min(mouseY + 52.interpolate(0. I suggest asking for help in the Processing forum. So good luck and get creative! .get(i)). textwidth+8.getForName(names. rect(x. 30). float textwidth = textWidth(name).