• fullscreen
  • Colors.pde
  • Kaleidoscope.pde
  • Shapes.pde
  • //=============================================================================================================
    interface Palette {
      color nextColor();
      void reset();
    }
    
    //=============================================================================================================
    class RandomPalette implements Palette {
      color nextColor() {
        return color(random(TWO_PI), random(1), random(1));
      }
      
      void reset() {
      }
    }
    
    //=============================================================================================================
    class RandomBrightPalette implements Palette {
      color nextColor() {
        return color(random(TWO_PI), 1, 1);
      }
      
      void reset() {
      }
    }
    
    //=============================================================================================================
    class ColorWheelPalette implements Palette {
      static final float BLACK_PROBABILITY = 0.4;
      float[] hueOffsets;
      float blackProbability;
      float whiteProbability;
      float saturatedProbability;
      float hueValue;
      
      ColorWheelPalette(float[] hueOffsets) {
        this.hueOffsets = hueOffsets;
      }
      
      color nextColor() {
        float h = (hueValue + hueOffsets[(int)random(hueOffsets.length)]) % TWO_PI;
        float s;
        float b;
        float r = random(1);
        if (r < blackProbability) {
          s = 0;
          b = 0;
        } else if (r < blackProbability+whiteProbability) {
          s = 0;
          b = 1;
        } else if (r < blackProbability+whiteProbability+saturatedProbability) {
          s = 1;
          b = 1;
        } else {
          if (random(1) < 0.5) {
            s = random(1);
            b = 1;
          } else {
            s = 1;
            b = random(1);
          }
        }
        return color(h, s, b);
      }
      
      void reset() {    
        hueValue = random(TWO_PI);
        blackProbability = 0;
        whiteProbability = 0;
        saturatedProbability = 0;
        float r = random(1);
        if (random(1) < 0.3) {
          // Only saturated
          saturatedProbability = 1;
        } else if (random(1) < 0.4) {
          // saturated + black
          blackProbability = 1.0/(1+hueOffsets.length);
          saturatedProbability = 1 - blackProbability;
        } else if (random(1) < 0.5) {
          // saturated + white
          whiteProbability = 1.0/(1+hueOffsets.length);
          saturatedProbability = 1 - whiteProbability;
        } else if (random(1) < 0.6) {
          // saturated + black + white
          blackProbability = 1.0/(2+hueOffsets.length);
          whiteProbability = 1.0/(2+hueOffsets.length);
          saturatedProbability = 1 - blackProbability - whiteProbability;
        } else {
          // Unsaturated
        }
      }
    }
    
    //=============================================================================================================
    Palette allPalettes[] = {
      new RandomPalette(),
      new RandomBrightPalette(), new RandomBrightPalette(), new RandomBrightPalette(), // Extra probability for random bright palette
      // Following palettes are based on color scheme described by ColorJack (http://www.colorjack.com/articles/color_formulas.html)
      new ColorWheelPalette(new float[]{0}), // Monochrome
      new ColorWheelPalette(new float[]{0, PI}), // Complementaty
      new ColorWheelPalette(new float[]{0, TWO_PI/12*5, TWO_PI/12*7}), // Split-Complementary
      new ColorWheelPalette(new float[]{0, TWO_PI/3, TWO_PI/3*2}), // Triadic
      new ColorWheelPalette(new float[]{0, TWO_PI/4, TWO_PI/4*2, TWO_PI/4*3}), // Tetradic
      new ColorWheelPalette(new float[]{0, TWO_PI/6, TWO_PI/6*3, TWO_PI/6*4}), // Four-tone
      new ColorWheelPalette(new float[]{0, TWO_PI/72*23, TWO_PI/72*31, TWO_PI/72*41, TWO_PI/72*49}), // Five-tone
      new ColorWheelPalette(new float[]{0, TWO_PI/12, TWO_PI/12*4, TWO_PI/12*5, TWO_PI/12*8, TWO_PI/12*9}), // Six-tone
      new ColorWheelPalette(new float[]{0, TWO_PI/24, TWO_PI/24*2, TWO_PI/24*3, TWO_PI/24*4, TWO_PI/24*5}) // Neutral
    };
    
    Palette getRandomPalette() {
      Palette palette = allPalettes[(int)random(allPalettes.length)];
      palette.reset();
      return palette;
    }
    
    
    /* 
     * Kaleidoscope by Algirdas Rascius (http://mydigiverse.com). 
     */
    /** 
     * Mouse-click to change pattern and color.
     */ 
     
    static final int SCREEN_SIZE = 200;
    static final int SIDE = 150;
    static final float MAX_TILE_ROTATION_DELTA = 0.02;
    static final float MAX_ROTATION_DELTA = 0.008;
    static final int AUTO_INITIALIZE_COUNT = 3000;
    
    PGraphics tile;
    ArrayList shapes;
    Palette palette;
    ShapeGenerator shapeGenerator;
    float tileRotation;
    float rotation;
    float tileRotationDelta;
    float rotationDelta;
    int nextAutoInitialize;
    
    void setup() {
      size(750, 500, P3D);
      colorMode(HSB, TWO_PI, 1, 1);
      noStroke();
      textureMode(NORMALIZED);
      tile = createGraphics(SCREEN_SIZE, SCREEN_SIZE, JAVA2D);
      tile.background(color(0));   
      shapes = new ArrayList();
      frameRate(30);
      initialize();
    }
    
    void initialize() {
      shapes.clear();
      palette = getRandomPalette();
      shapeGenerator = getRandomShapeGenerator();
      tileRotationDelta = random(-MAX_TILE_ROTATION_DELTA, MAX_TILE_ROTATION_DELTA);
      rotationDelta = random(-MAX_ROTATION_DELTA, MAX_ROTATION_DELTA);
      nextAutoInitialize = AUTO_INITIALIZE_COUNT;
    }
    
    void mousePressed() {
      initialize();
    }
    
    void keyPressed() {
      initialize();
    }
    
    void draw() {
      drawTile();
      drawAllTiles();
      if (nextAutoInitialize-- < 0) {
        initialize();
      }
    }
    
    void drawTile() {
       tile.beginDraw();
       tile.filter(BLUR);
       shapeGenerator.createShapes(shapes, tile, palette);
       for (Iterator i=shapes.iterator(); i.hasNext();) {
         Shape s = (Shape)i.next();
         if (!s.draw(tile)) {
           i.remove();
         }
       }
       tile.endDraw();
    }
    
    final static float SIN_30 = sin(TWO_PI/12);
    final static float COS_30 = cos(TWO_PI/12);
    
    void drawAllTiles() {
      tileRotation = (tileRotation + tileRotationDelta + TWO_PI) % TWO_PI;
      rotation = (rotation + rotationDelta + TWO_PI) % TWO_PI;
        
      float tx1 = 0.5+0.49*sin(tileRotation);
      float ty1 = 0.5+0.49*cos(tileRotation);
      float tx2 = 0.5+0.49*sin(tileRotation+TWO_PI/3);
      float ty2 = 0.5+0.49*cos(tileRotation+TWO_PI/3);
      float tx3 = 0.5+0.49*sin(tileRotation+TWO_PI/3*2);
      float ty3 = 0.5+0.49*cos(tileRotation+TWO_PI/3*2);
    
      translate(width/2, height/2);
      scale(SIDE, SIDE);
      rotate(rotation);
      
      for (int y=-2; y<=2; y++) {
        pushMatrix();
        translate(0, y*(1+SIN_30));
        for (int x=-2; x<=2; x++) {
          pushMatrix();
          translate(x*2*COS_30, 0);
          if (abs(y)%2==1) {
            translate(COS_30, 0);
          }
          for (int i=0; i<3; i++) {
            rotate(TWO_PI/3);
            for (int j=0; j<2; j++) { 
              scale(-1,1);
              beginShape();
              texture(tile);
              vertex(0, 0, tx1, ty1);
              vertex(0, 1, tx2, ty2);
              vertex(COS_30, SIN_30, tx3, ty3);
              endShape();
            }
          }
          popMatrix();
        }
        popMatrix();
      }
    
    }
    
    
    
    
    //=============================================================================================================
    interface Shape {
      boolean draw(PGraphics g);  
    }
    
    //=============================================================================================================
    class Point implements Shape {
      static final float MAX_WEIGHT = 7;
      static final float DELTA_WEIGHT = 0.2;
      
      float x;
      float y;
      color clr;
      float w;
      
      Point(PGraphics g, Palette p) {
         x = random(0, g.width);
         y = random(0, g.height);
         clr = p.nextColor();
         w = 0;
      }
      
      boolean draw(PGraphics g) {
        w += DELTA_WEIGHT;
        g.strokeWeight(w);
        g.stroke(clr);
        g.point(x, y);
        return w < MAX_WEIGHT;
      }  
    }
    
    //=============================================================================================================
    class Spiral implements Shape {
      static final float MIN_RADIUS = 0.3;
      static final float MAX_RADIUS = 0.6;
      static final int WEIGHT = 5;
      static final int STEPS = 10;
      static final float R_STEP = 0.003;
      static final float A_STEP = 0.05;
      
      float radius;
      float x;
      float y;
      color clr;
      float r;
      float a;
      float aDelta;
      
      Spiral(PGraphics g, Palette p) {
         radius = random(g.width*MIN_RADIUS, g.width*MAX_RADIUS);
         x = random(g.width*MIN_RADIUS, g.width*(1-MIN_RADIUS));
         y = random(g.height*MIN_RADIUS, g.height*(1-MIN_RADIUS));
         clr = p.nextColor();
         r = 0;
         a = random(TWO_PI);
         aDelta = random(-A_STEP, A_STEP);
      }
      
      boolean draw(PGraphics g) {
        g.strokeWeight(WEIGHT);
        g.stroke(clr);
        for (int i=0; i<STEPS; i++) {
          float x0 = x + r*radius*sin(a);
          float y0 = y + r*radius*cos(a);
          r += R_STEP;
          a += aDelta;
          float x1 = x + r*radius*sin(a);
          float y1 = y + r*radius*cos(a);
          g.line(x0, y0, x1, y1);
          if (r >= 1) {
            return false;
          }
        }
        return true;
      }  
    }
    
    //=============================================================================================================
    class Circle implements Shape {
      static final float MIN_RADIUS = 0.1;
      static final float MAX_RADIUS = 0.4;
      static final float R_STEP = 0.05;
      
      float radius;
      float x;
      float y;
      color clr;
      float r;
      
      Circle(PGraphics g, Palette p) {
         radius = random(g.width*MIN_RADIUS, g.width*MAX_RADIUS);
         x = random(g.width*MIN_RADIUS, g.width*(1-MIN_RADIUS));
         y = random(g.height*MIN_RADIUS, g.height*(1-MIN_RADIUS));
         clr = p.nextColor();
         r = 0;
      }
      
      boolean draw(PGraphics g) {
        r += R_STEP;
        g.stroke(clr);
        g.noFill();
        g.strokeWeight(1);
        g.ellipseMode(RADIUS);
        g.ellipse(x, y, radius*r, radius*r);
        return r < 1;
      }  
      
    }
    
    //=============================================================================================================
    class Blot implements Shape {
      static final int MIN_SIDES = 6;
      static final int MAX_SIDES = 40;
      static final float MIN_RADIUS = 0.1;
      static final float MAX_RADIUS = 0.4;
      static final float R_STEP = 0.05;
      
      int sides;
      float radiuses[];
      float x;
      float y;
      color clr;
      float r;
      
      Blot(PGraphics g, Palette p) {
         sides = (int)random(MIN_SIDES, MAX_SIDES);
         radiuses = new float[sides];
         for(int i=0; i<sides; i++) {
           radiuses[i] = random(g.width*MIN_RADIUS, g.width*MAX_RADIUS);
         }
         x = random(g.width*MIN_RADIUS, g.width*(1-MIN_RADIUS));
         y = random(g.height*MIN_RADIUS, g.height*(1-MIN_RADIUS));
         clr = p.nextColor();
         r = 0;
      }
      
      boolean draw(PGraphics g) {
        r += R_STEP;
        g.stroke(clr);
        g.noFill();
        g.strokeWeight(1);
        g.beginShape();
        for(int i=0; i<sides+3; i++) {
          g.curveVertex(x+r*radiuses[i%sides]*sin(TWO_PI/sides*i), y+r*radiuses[i%sides]*cos(TWO_PI/sides*i));
        }     
        g.endShape();
        return r < 1;
      }  
    }
    
    //=============================================================================================================
    class ShapeGenerator {
      float pointProbability;
      float spiralProbability;
      float circleProbability;
      float blotProbability;
      
      ShapeGenerator(float pointProbability, float spiralProbability,
                     float circleProbability, float blotProbability) {
        this.pointProbability = pointProbability;
        this.spiralProbability = spiralProbability;
        this.circleProbability = circleProbability;
        this.blotProbability = blotProbability;
      }
      
      void createShapes(ArrayList shapes, PGraphics g, Palette p) {
        if (random(1) < pointProbability) {
          shapes.add(new Point(g, p));
        }
        if (random(1) < spiralProbability) {
          shapes.add(new Spiral(g, p));
        }
        if (random(1) < circleProbability) {
          shapes.add(new Circle(g, p));
        }
        if (random(1) < blotProbability) {
          shapes.add(new Blot(g, p));
        }
      }
    }
    
    //=============================================================================================================
    ShapeGenerator allShapeGenerators[] = {
      new ShapeGenerator(0, 0.07, 0, 0), // Spirals only
      new ShapeGenerator(0, 0.04, 0, 0), // Spirals only (less frequent)
      new ShapeGenerator(0.5, 0.03, 0, 0), // Points ant spirals
      new ShapeGenerator(0, 0, 0, 0.07), // Blots only
      new ShapeGenerator(0, 0, 0, 0.04), // Blots only (less frequent)
      new ShapeGenerator(0, 0, 0.03, 0.04), // Circles and blots
      new ShapeGenerator(0, 0.02, 0.02, 0.03), // Spirals, circles and blots
      new ShapeGenerator(0, 0.02, 0.01, 0.02), // Spirals, circles and blots (less frequent)
      new ShapeGenerator(0.3, 0.02, 0.01, 0.02), // Points, spirals, circles and blots
    };
    
    
    ShapeGenerator getRandomShapeGenerator() {
      return allShapeGenerators[(int)random(allShapeGenerators.length)];
    }
    
    
    
    

    code

    tweaks (0)

    about this sketch

    This sketch is running as Java applet, exported from Processing.

    license

    advertisement

    Algirdas Rascius

    Kaleidoscope

    Add to Faves Me Likey@! 13
    You must login/register to add this sketch to your favorites.

    Kaleidoscope was one of my childhood toys. Here is a Processing version of it.

    Mouse-click to change pattern and color.

    Eh! Amo todo lo que subes a la página
    (Ey! I love all your post)
    Trisha
    29 Nov 2010
    Just a question.. how do you set up a mouse click interaction on something like this?
    I have a sketch that I'm working on with PGraphics but I have no idea how to set up the mouse clicked option, especially to change the direction of the image. If you could help that would be wonderful! Thanks.
    Guy Yitzhaki
    11 Mar 2011
    I added some more shapes to your kaleidoscope, and made it react to sound. You can check it out here http://www.openprocessing.org/visuals/?visualID=23260
    morphogen
    30 Jun 2013
    This doesn't seem to work in Processing v2.0 -- anyone know why that is?
    Xavier Righetti
    16 Sep 2013
    @asymptoticdesign just replace textureMode(NORMALIZED); with textureMode(NORMAL);
    You need to login/register to comment.