// Scrawl // David Bollinger, June 2006 // http://www.davebollinger.com // for Processing 0015 Beta // // the drawing buffer FixedPointBuffer buf; // array of points to follow the mouse Tracker [] tracks; // 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=0.25; // 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 = 0.2; // flag the applet has mouse focus boolean bGotMouse = false; // flag if we are in "rainbow" mode boolean bHueRotate = true; void setup() { size(480,480,P3D); colorMode(HSB); buf = new FixedPointBuffer(width,height); ntracks = 100; tracks = new Tracker[ntracks]; float ctrx = (float)(width/2); float ctry = (float)(height/2); for (int i=0; i= 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 draw() { // don't move towards mouse until we're sure applet has been focused // (otherwise they all bunch up at 0,0 before first mouse down - yuck) if (bGotMouse) { if (bHueRotate) rotatehue(); float targetx = (float)(mouseX); float targety = (float)(mouseY); float elapsed = 0.0; while (elapsed < 1.0) { 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; c = (int)((ratio*fr) + redbuf[idx]); if (c>maxrgb) c=maxrgb; redbuf[idx] = c; c = (int)((ratio*fg) + grnbuf[idx]); if (c>maxrgb) c=maxrgb; grnbuf[idx] = c; c = (int)((ratio*fb) + blubuf[idx]); if (c>maxrgb) c=maxrgb; blubuf[idx] = c; // upper-right ratio = fractx * recipy * alf; idx = iy1 * width + ix2; c = (int)((ratio*fr) + redbuf[idx]); if (c>maxrgb) c=maxrgb; redbuf[idx] = c; c = (int)((ratio*fg) + grnbuf[idx]); if (c>maxrgb) c=maxrgb; grnbuf[idx] = c; c = (int)((ratio*fb) + blubuf[idx]); if (c>maxrgb) c=maxrgb; blubuf[idx] = c; // lower-left ratio = recipx * fracty * alf; idx = iy2 * width + ix1; c = (int)((ratio*fr) + redbuf[idx]); if (c>maxrgb) c=maxrgb; redbuf[idx] = c; c = (int)((ratio*fg) + grnbuf[idx]); if (c>maxrgb) c=maxrgb; grnbuf[idx] = c; c = (int)((ratio*fb) + blubuf[idx]); if (c>maxrgb) c=maxrgb; blubuf[idx] = c; // lower-right ratio = fractx * fracty * alf; idx = iy2 * width + ix2; c = (int)((ratio*fr) + redbuf[idx]); if (c>maxrgb) c=maxrgb; redbuf[idx] = c; c = (int)((ratio*fg) + grnbuf[idx]); if (c>maxrgb) c=maxrgb; grnbuf[idx] = c; c = (int)((ratio*fb) + blubuf[idx]); if (c>maxrgb) c=maxrgb; 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.01; friction = 0.01; } void moveto(float _x, float _y) { x = _x; y = _y; vx = vy = 0.0; } void movetoward(float targetx, float targety, float dt) { /* // long-winded version float dx = targetx - x; float dy = targety - y; float ax = (dx * speed); float ay = (dy * speed); // 2nd order Euler integrator, good enough x = x + vx * dt + 0.5 * ax * dt * dt; y = y + vy * dt + 0.5 * ay * dt * dt; vx = vx + ax * dt; vy = vy + ay * dt; vx = vx - vx * friction * dt; vy = vy - vy * friction * dt; */ // slightly optimized float axdt = ((targetx-x) * speed) * dt; float aydt = ((targety-y) * speed) * dt; x += vx * dt + 0.5 * axdt * dt; y += vy * dt + 0.5 * aydt * dt; vx += axdt; vy += aydt; float frictiondt = friction * dt; vx -= vx * frictiondt; vy -= vy * frictiondt; } }