/** * Swimming Icons 1f: *
* Flickr is used as a source of images. Each icon steers itself based * on rules including avoidance, alignment, and coherence. You can tag, * cluster, and delete icons, or they die on their own after they swim * off screen. Designed for very large screens, this tiny web version * does not do justice to the idea of a sea of images. The flickr query * is based on tags. Please refer to the source comments for more * information and acknowledgements. This is a rough prototype of an * evolving project. Your comments and suggestions are encouraged via * http://kino-eye.com/contact/ *
* @author David Tames, http://kino-eye.com/dmi/ *
* @version 1f, July 19, 2010 */ // SwimmingIcons that are not tagged are deleted when they swim out of bounds // and are replaced with new images. A constant flow of images is presented // to the viewer if the query returns a sufficient number of images. Eventually // the system will be smart enough to expand the search dynamically and do other // interesting things. // // Copyright 2010 by David Tames, some rights reserved. This code is released // under the terms of a Creative Commons Share-Alike Attribution License, for // license text visit http://creativecommons.org/licenses/by-sa/2.5/ and for // attribution please link to: http://kino-eye.com/dmi/swimming-icons/ // libraries // import processing.opengl.*; // import controlP5.*; PFont messageText; // a school of icons, as in a school of fish // School school = new School(); ArrayList SwimmingIcons; final boolean DEBUG = false; final boolean TRACE = false; // various initialization parameters for the icons final float initMaxForce = 0.04; // was 0.05 final float initMaxSpeed = 0.5; // was 3.0 final float initMaxIcons = 50; // was 150 final int iconMaxCount = 50; // UI for lightbox and other goodies boolean lightBoxActive = false; // various constants related to our space dimensions, margins, etc. final float screenWidth = 900; // must match parameters of size() function below final float screenHeight = 500; // must match parameters of size() function below final float screenMargin = 150; float topBorder; float rightBorder; float leftBorder; float bottomBorder; // various variables related to our Background Loader BackgroundLoader loader; Thread loadThread; boolean iconsAvailable = false; boolean swimmingIconsLocked = false; // LOCK to avoid problems w/ get responding w/ wrong index void setup() { // we can't use variables here if we're going to deply as a web applet, but OK for development. // size(1536, 862, OPENGL); size(900, 500); frameRate(24); topBorder = 0 - screenMargin; rightBorder= screenWidth + screenMargin; leftBorder = 0 - screenMargin; bottomBorder = screenHeight + screenMargin; smooth(); // Initialize the arraylist of SwimmingIcons SwimmingIcons = new ArrayList(); // get the BackgroundLoader running loader = new BackgroundLoader(); loadThread = new Thread(loader); loader.setQuery("iMac,iPhone,iPad"); // start off with something fun and with plenty of results loadThread.start(); messageText = loadFont("Monaco-14.vlw"); textFont(messageText, 14); //for (int i = 0; i < initMaxIcons; i++) { // school.addSwimmingIcon(new SwimmingIcon(new PVector(width/2,height/2), initMaxSpeed, initMaxForce)); //} } void draw() { background(0); if (!iconsAvailable) { fill (250); textAlign(CENTER); text("Connecting to server, this might take a moment...\nfetching \"interesting images\" from Flickr tagged w/ iMac or iPhone or iPad", width/2, height/2); delay (4000); } // tell the the SwimmingIcons to swim // We pass the entire list of SwimmingIcons to each SwimmingIcon individually, // this makes it slow if there are too many SwimmingIcons in the school, so we // prune the school as we go in BackgroundLoader for (int i = 0; i < SwimmingIcons.size(); i++) { SwimmingIcon thisIcon = (SwimmingIcon) SwimmingIcons.get(i); thisIcon.run(SwimmingIcons); } } // mousePressed: Handle Mouse Presses and other UI things // void mousePressed() { boolean hit = false; if (lightBoxActive) { lightBoxActive = false; } else { int i = SwimmingIcons.size()-1; while (!hit && i > 0) { // the first one we hit (the Icon on top gets hit) SwimmingIcon thisIcon = (SwimmingIcon) SwimmingIcons.get(i--); if (thisIcon.over(mouseX, mouseY)) { if (mouseButton == LEFT) { if (TRACE) println ("tagging to keep: " + thisIcon.getImageName()); thisIcon.tag(); hit = true; } else if (mouseButton == RIGHT) { if (TRACE) println ("tagging for deletion: " + thisIcon.getImageName()); thisIcon.delete(); hit = true; } } } } } PApplet getMyParent () { return this; }