/**
*
* Scrawling
* A little attractor based doodling program
*
*Thomas W. Gonzalez (c) 2009
*
*
*
*Many thanks to David Bollinger http://www.davebollinger.com
*for sharing his FungiScrawl source code
*
*/
// Scrawl
// David Bollinger, June 2006
// http://www.davebollinger.com
// for Processing 0015 Beta
//
// (no original copyright posted by David Bollinger
//
// Modified January 2009
// Thomas Gonzalez
// For Processing 1.0
// Copyright (c) 2009
// interesting effects
//1. Changing Config - very coefficients to alter how continous the shading is
// tracks[i].speed = basespeed - (float)(i) * 0.0001;
// tracks[i].friction = basefriction - (float)(i) * 0.0001;
//2. Changing diffuse factor to create more/less noise/scratchy
import controlP5.*;
ControlP5 controlP5;
float basespeed, basefriction;
// the drawing buffer
FixedPointBuffer buf;
FixedPointBuffer buf2;
// array of points to follow the mouse
Tracker [] tracks;
ArrayList points;
// how many points?
int ntracks;
// mouse-down flag
boolean isDrawing = false;
// HSB current color to rotate
float myhue=0.0, mysat, mybri;
// rate of hue rotation when in rotate mode
float myhueinc=3;
// RGB current color to plot with
int myred, mygrn, myblu;
// alpha value to plot with
float myalf;
// how fine to subdivide each frame
float timeslice = .01;
// flag the applet has mouse focus
boolean bGotMouse = false;
// flag if we are in "rainbow" mode
boolean bHueRotate = true;
int mirror=-1;
boolean recording=false;
boolean playing=false;
int playCounter=0;
int diffuseFactor=2; //effects how smooth/rough tracks fill in
float sat=1; //effects how fast mouse followed and depth of color... smaller==richer 1-->.01
void setup() {
//Create two buffers
//Delay entries into 2nd buffer by X frames make second buffer a trail of first
//Combine buffers at draw time
size(800,600);
colorMode(HSB);
controlP5 = new ControlP5(this);
controlP5.setColorLabel(0);
Slider s = controlP5.addSlider("grain",1,50,20,10,height-20,100,10);
Slider s1 = controlP5.addSlider("friction",1,200,50,10,height-50,100,10);
Slider s2 = controlP5.addSlider("speed",1,200,50,10,height-80,100,10);
PFont myFont = createFont("Helvetica", 11);
fill(0);
textFont(myFont);
text("left-click to draw right-click to clear", 200,height-75);
points=new ArrayList();
buf = new FixedPointBuffer(width,height-100);
buf.background((256 << 16)-1,(256 << 16)-1,(256 << 16)-1);
ntracks = 1000;
tracks = new Tracker[ntracks];
float ctrx = (float)(width/2);
float ctry = (float)(height/2);
for (int i=0; ipoints.size()-1) {
playing=false;
playCounter=0;
}
}
else if (bGotMouse) {
float targetx = (float)(mouseX);
float targety = (float)(mouseY);
float elapsed = 0.0;
while (elapsed < 1.0) {
for (int i=0; i=256.0) mysat -=256.0;
if (myhue >= 256.0) myhue -= 256.0;
color c = color(myhue,mysat,mybri);
myred = ((int)red(c)) << buf.shift;
mygrn = ((int)green(c)) << buf.shift;
myblu = ((int)blue(c)) << buf.shift;
}
void mousePressed() {
if(mouseY > height-100) {
bGotMouse = false;
return;
}
if (!isDrawing) {
resetTracks();
}
bGotMouse = true;
if (mouseButton == LEFT) {
// redundant? yes. but keeps right button from interfering (as with mousePressed)
isDrawing = true;
}
else
if (mouseButton == RIGHT) {
buf.background((256 << 16)-1,(256 << 16)-1,(256 << 16)-1);
}
}
void mouseReleased() {
if (mouseButton == LEFT) {
isDrawing = false;
}
}
void resetTracks() {
for (int i=0; i=wid-1.0) || (y>=hei-1.0)) return;
// integral coordinates
int ix1 = (int)(x);
int iy1 = (int)(y);
int ix2 = ix1 + 1;
int iy2 = iy1 + 1;
// fractional coordinates
float fractx = x - (float)(ix1);
float fracty = y - (float)(iy1);
// reciprocal of fractional coordinates
float recipx = 1.0 - fractx;
float recipy = 1.0 - fracty;
// preconvert color values to floats
float fr = (float)(r);
float fg = (float)(g);
float fb = (float)(b);
// plot it
float ratio;
int idx, c;
// upper-left
ratio = recipx * recipy * alf;
idx = iy1 * width + ix1*mirror;
if (idx<0) idx=0;
c = (int)(redbuf[idx]-(ratio*fr)); if (c<0) c=0; redbuf[idx] = c;
c = (int)(grnbuf[idx]-(ratio*fg)); if (c<0) c=0; grnbuf[idx] = c;
c = (int)(blubuf[idx]-(ratio*fb)); if (c<0) c=0; blubuf[idx] = c;
// upper-right
ratio = fractx * recipy * alf;
idx = iy1 * width + ix2*mirror;
if (idx<0) idx=0;
c = (int)(redbuf[idx]-(ratio*fr)); if (c<0) c=0; redbuf[idx] = c;
c = (int)(grnbuf[idx]-(ratio*fg)); if (c<0) c=0; grnbuf[idx] = c;
c = (int)(blubuf[idx]-(ratio*fb)); if (c<0) c=0; blubuf[idx] = c;
// lower-left
ratio = recipx * fracty * alf;
idx = iy2 * width + ix1;
c = (int)(redbuf[idx]-(ratio*fr)); if (c<0) c=0; redbuf[idx] = c;
c = (int)(grnbuf[idx]-(ratio*fg)); if (c<0) c=0; grnbuf[idx] = c;
c = (int)(blubuf[idx]-(ratio*fb)); if (c<0) c=0; blubuf[idx] = c;
// lower-right
ratio = fractx * fracty * alf;
idx = iy2 * width + ix2;
c = (int)(redbuf[idx]-(ratio*fr)); if (c<0) c=0; redbuf[idx] = c;
c = (int)(grnbuf[idx]-(ratio*fg)); if (c<0) c=0; grnbuf[idx] = c;
c = (int)(blubuf[idx]-(ratio*fb)); if (c<0) c=0; blubuf[idx] = c;
}
// render converts 8.shift format back down to 8 bit rgb
void render() {
for (int idx=area-1; idx>=0; idx--) {
/*
// general-purpose conversion for any shift...
int r = ((redbuf[idx] >> shift) & 0xFF) << 16;
int g = ((grnbuf[idx] >> shift) & 0xFF) << 8;
int b = ((blubuf[idx] >> shift) & 0xFF);
pixels[idx] = 0xFF000000 | r | g | b;
*/
// optimized for shift of 16
pixels[idx] = 0xFF000000 |
(redbuf[idx] & 0xFF0000) |
((grnbuf[idx] & 0xFF0000) >> 8) |
((blubuf[idx] & 0xFF0000) >> 16);
}
updatePixels();
}
}
// a simple "springy follower" thingy
class Tracker {
float x, y, vx, vy;
float speed, friction;
Tracker(float _x, float _y) {
moveto(_x, _y);
speed = 0.001;
friction = 0.001;
}
void moveto(float _x, float _y) {
x = _x;
y = _y;
vx = vy = 0.0;
}
void movetoward(float targetx, float targety, float dt) {
//targetx=targetx*random(-1,1);
// slightly optimized
float axdt = ((targetx-x) * speed) * dt;
float aydt = ((targety-y) * speed) * dt;
x += vx * dt + random(-diffuseFactor,diffuseFactor) * axdt * dt;
y += vy * dt + random(-diffuseFactor,diffuseFactor) * aydt * dt;
vx += axdt;
vy += aydt;
float frictiondt = friction * dt;
vx -= vx * frictiondt;
vy -= vy * frictiondt;
}
}
class Point {
float x;
float y;
Point(float _x, float _y) {
x=_x;
y=_y;
}
}