|
|
@@ -2134,9 +2134,487 @@ class MASK extends Shader { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* todo: implement "solo" and "only up till here" button on bricks */ |
|
|
|
class DRAWSTROKES extends Shader { |
|
|
|
|
|
|
|
int stat_type = ABSDIST2; // type of diff calculation: fast: ABSDIST, DIST, slow: HUE, SATURATION, BRIGHTNESS |
|
|
|
int stroke_len = 3; // length of the stroke, values: 1 and above |
|
|
|
int angles_no = 30; // number of directions stroke can be drew, 2 and above |
|
|
|
int segments = 500; // number of segments of single thread |
|
|
|
float stroke_width = 1; // width of the stroke, 0.5 - 3 |
|
|
|
int stroke_alpha = 100; // alpha channel of the stroke: 30 - 200 |
|
|
|
|
|
|
|
color background_color = color(255, 255, 255); // RGB |
|
|
|
|
|
|
|
boolean interactive = false; |
|
|
|
int max_display_size = 800; // viewing window size (regardless image size) |
|
|
|
|
|
|
|
int len; |
|
|
|
// working buffer |
|
|
|
PGraphics buffer; |
|
|
|
|
|
|
|
int currx, curry; |
|
|
|
int[] sintab, costab; |
|
|
|
int sqwidth; |
|
|
|
|
|
|
|
int iterations; |
|
|
|
|
|
|
|
int calcDiff(PImage img1, PImage img2) { |
|
|
|
int err = 0; |
|
|
|
for (int i=0; i<img1.pixels.length; i++) |
|
|
|
err += getStat(img1.pixels[i], img2.pixels[i]); |
|
|
|
return err; |
|
|
|
} |
|
|
|
|
|
|
|
DRAWSTROKES() { |
|
|
|
name = "fxDrawStrokes"; |
|
|
|
params.add(new Param ("stat type", INTVAL, 0, 5, new int[]{SAWTOOTH, TRIANG, SINE, TAN, TANINVERSE, RAMPUPDOWN, RAMP, RAMPINVERSE})); // 4 und 5 sind mit abstand die schnellsten |
|
|
|
params.add(new Param ("stroke length", INTVAL, 1, 10, new int[]{SAWTOOTH, TRIANG, SINE, TAN, TANINVERSE, RAMPUPDOWN, RAMP, RAMPINVERSE})); |
|
|
|
params.add(new Param ("amount of angles", INTVAL, 2, 30, new int[]{SAWTOOTH, TRIANG, SINE, TAN, TANINVERSE, RAMPUPDOWN, RAMP, RAMPINVERSE})); |
|
|
|
params.add(new Param ("amount of segments", INTVAL, 50, 1500, new int[]{SAWTOOTH, TRIANG, SINE, TAN, TANINVERSE, RAMPUPDOWN, RAMP, RAMPINVERSE})); |
|
|
|
params.add(new Param ("stroke width", FLOATVAL, 0.5, 5, new int[]{SAWTOOTH, TRIANG, SINE, TAN, TANINVERSE, RAMPUPDOWN, RAMP, RAMPINVERSE})); |
|
|
|
params.add(new Param ("stroke transparency", INTVAL, 30, 220, new int[]{SAWTOOTH, TRIANG, SINE, TAN, TANINVERSE, RAMPUPDOWN, RAMP, RAMPINVERSE})); |
|
|
|
params.add(new Param ("iterations", INTVAL, 1, 500, new int[]{SAWTOOTH, TRIANG, SINE, TAN, TANINVERSE, RAMPUPDOWN, RAMP, RAMPINVERSE})); |
|
|
|
|
|
|
|
len = (renderer.width<renderer.height?renderer.width:renderer.height)/3; |
|
|
|
|
|
|
|
buffer = createGraphics(renderer.width, renderer.height); |
|
|
|
buffer.smooth(2); |
|
|
|
buffer.beginDraw(); |
|
|
|
buffer.strokeWeight(stroke_width); |
|
|
|
buffer.noFill(); |
|
|
|
buffer.endDraw(); |
|
|
|
|
|
|
|
rw = renderer.width; |
|
|
|
rh = renderer.height; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int rw, rh; |
|
|
|
void apply() { |
|
|
|
stat_type = (int)params.get(0).value; |
|
|
|
stroke_len = (int)params.get(1).value; |
|
|
|
angles_no = (int)params.get(2).value; |
|
|
|
segments = (int)params.get(3).value; |
|
|
|
stroke_width = params.get(4).value; |
|
|
|
stroke_alpha = (int)params.get(5).value; |
|
|
|
iterations = (int)params.get(6).value; |
|
|
|
|
|
|
|
if (rw != canvas.width || rh != canvas.height) { //doesnt account image swap |
|
|
|
len = (canvas.width<canvas.height?canvas.width:canvas.height)/3; |
|
|
|
rw = canvas.width; |
|
|
|
rh = canvas.height; |
|
|
|
PGraphics save = createGraphics(canvas.width, canvas.height); |
|
|
|
save.beginDraw(); |
|
|
|
save.image(buffer, 0, 0, save.width, save.height); |
|
|
|
save.endDraw(); |
|
|
|
buffer.setSize(canvas.width, canvas.height); |
|
|
|
buffer.beginDraw(); |
|
|
|
buffer.image(save, 0, 0, buffer.width, buffer.height); // ???? |
|
|
|
buffer.endDraw(); |
|
|
|
} |
|
|
|
|
|
|
|
for (int j = 0; j < iterations; j++) { |
|
|
|
|
|
|
|
currx = (int)random(canvas.width); |
|
|
|
curry = (int)random(canvas.height); |
|
|
|
sintab = new int[angles_no]; |
|
|
|
costab = new int[angles_no]; |
|
|
|
|
|
|
|
for (int i=0; i<angles_no; i++) { |
|
|
|
sintab[i] = (int)(stroke_len * sin(TWO_PI*i/(float)angles_no)); |
|
|
|
costab[i] = (int)(stroke_len * cos(TWO_PI*i/(float)angles_no)); |
|
|
|
} |
|
|
|
|
|
|
|
sqwidth = stroke_len * 2 + 4; |
|
|
|
|
|
|
|
buffer.beginDraw(); |
|
|
|
buffer.strokeWeight(stroke_width); |
|
|
|
//draw whole segment using current color |
|
|
|
buffer.stroke(canvas.get(currx, curry), stroke_alpha); |
|
|
|
|
|
|
|
for (int iter=0; iter<segments; iter++) { |
|
|
|
// corners of square containing new strokes |
|
|
|
int corx = currx-stroke_len-2; |
|
|
|
int cory = curry-stroke_len-2; |
|
|
|
|
|
|
|
// take square from image and current screen |
|
|
|
PImage imgpart = canvas.get(corx, cory, sqwidth, sqwidth); |
|
|
|
PImage mypart = buffer.get(corx, cory, sqwidth, sqwidth); |
|
|
|
imgpart.loadPixels(); |
|
|
|
mypart.loadPixels(); |
|
|
|
|
|
|
|
// calc current diff |
|
|
|
float localerr = calcDiff(imgpart, mypart); |
|
|
|
|
|
|
|
// chosen stroke will be here |
|
|
|
PImage destpart = null; |
|
|
|
int _nx=currx, _ny=curry; |
|
|
|
|
|
|
|
// start with random angle |
|
|
|
int i = (int)random(angles_no); |
|
|
|
int iterangles = angles_no; |
|
|
|
|
|
|
|
while (iterangles-- > 0) { |
|
|
|
// take end points |
|
|
|
int nx = currx + costab[i]; |
|
|
|
int ny = curry + sintab[i]; |
|
|
|
|
|
|
|
// if not out of the screen |
|
|
|
if (nx>=0 && nx<canvas.width-1 && ny>=0 && ny<canvas.height-1) { |
|
|
|
// clean region and draw line |
|
|
|
buffer.image(mypart, corx, cory); |
|
|
|
buffer.line(currx, curry, nx, ny); |
|
|
|
|
|
|
|
// take region with line and calc diff |
|
|
|
PImage curr = buffer.get(corx, cory, sqwidth, sqwidth); |
|
|
|
curr.loadPixels(); |
|
|
|
int currerr = calcDiff(imgpart, curr); |
|
|
|
|
|
|
|
// if better, remember this region and line endpoint |
|
|
|
if (currerr < localerr) { |
|
|
|
destpart = curr; |
|
|
|
_nx = nx; |
|
|
|
_ny = ny; |
|
|
|
localerr = currerr; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// next angle |
|
|
|
i = (i+1)%angles_no; |
|
|
|
} |
|
|
|
|
|
|
|
// if we have new stroke, draw it |
|
|
|
if (destpart != null) { |
|
|
|
buffer.image(destpart, corx, cory); |
|
|
|
currx = _nx; |
|
|
|
curry = _ny; |
|
|
|
} else { |
|
|
|
break; // skip |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
buffer.endDraw(); |
|
|
|
} |
|
|
|
canvas.beginDraw(); |
|
|
|
canvas.image(buffer, canvas.width/2, canvas.height/2); |
|
|
|
canvas.endDraw(); |
|
|
|
} |
|
|
|
|
|
|
|
final static int DIST = 0; |
|
|
|
final static int HUE = 1; |
|
|
|
final static int BRIGHTNESS = 2; |
|
|
|
final static int SATURATION = 3; |
|
|
|
final static int ABSDIST = 4; |
|
|
|
final static int ABSDIST2 = 5; |
|
|
|
|
|
|
|
final float getStat(color c1, color c2) { |
|
|
|
switch(stat_type) { |
|
|
|
case HUE: |
|
|
|
abs(hue(c1)-hue(c2)); |
|
|
|
case BRIGHTNESS: |
|
|
|
abs(brightness(c1)-brightness(c2)); |
|
|
|
case SATURATION: |
|
|
|
abs(saturation(c1)-saturation(c2)); |
|
|
|
case ABSDIST: |
|
|
|
return abs(red(c1)-red(c2))+abs(green(c1)-green(c2))+abs(blue(c1)-blue(c2)); |
|
|
|
case ABSDIST2: |
|
|
|
return abs( (red(c1)+blue(c1)+green(c1)) - (red(c2)+blue(c2)+green(c2)) ); |
|
|
|
default: |
|
|
|
return sq(red(c1)-red(c2)) + sq(green(c1)-green(c2)) + sq(blue(c1)-blue(c2)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
DRAWGENERATIVE |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
class DRAWGENERATIVE extends Shader { |
|
|
|
|
|
|
|
// choose channel |
|
|
|
int channel = HUE; |
|
|
|
|
|
|
|
// run, after 30 iterations result will be saved automatically |
|
|
|
// or press SPACE |
|
|
|
|
|
|
|
|
|
|
|
// channels to work with |
|
|
|
final static int RED = 0; |
|
|
|
final static int GREEN = 1; |
|
|
|
final static int BLUE = 2; |
|
|
|
final static int HUE = 3; |
|
|
|
final static int SATURATION = 4; |
|
|
|
final static int BRIGHTNESS = 5; |
|
|
|
final static int NRED = 6; |
|
|
|
final static int NGREEN = 7; |
|
|
|
final static int NBLUE = 8; |
|
|
|
final static int NHUE = 9; |
|
|
|
final static int NSATURATION = 10; |
|
|
|
final static int NBRIGHTNESS = 11; |
|
|
|
|
|
|
|
int n=2000; |
|
|
|
float [] cx=new float[n]; |
|
|
|
float [] cy=new float[n]; |
|
|
|
|
|
|
|
int len; |
|
|
|
|
|
|
|
// working buffer |
|
|
|
PGraphics buffer; |
|
|
|
|
|
|
|
|
|
|
|
int tick = 0; |
|
|
|
|
|
|
|
|
|
|
|
DRAWGENERATIVE() { |
|
|
|
name = "fxDrawGenerative"; |
|
|
|
params.add(new Param ("stroke width", FLOATVAL, 0.3, 5, new int[]{SAWTOOTH, TRIANG, SINE, TAN, TANINVERSE, RAMPUPDOWN, RAMP, RAMPINVERSE})); // 4 und 5 sind mit abstand die schnellsten |
|
|
|
buffer = createGraphics(renderer.width, renderer.height); |
|
|
|
buffer.noFill(); |
|
|
|
buffer.beginDraw(); |
|
|
|
//buffer.background(0); //ENABLE THIS TO DRAW FROM BLANK |
|
|
|
buffer.endDraw(); |
|
|
|
rw = canvas.width; |
|
|
|
rh = canvas.height; |
|
|
|
len = (canvas.width<canvas.height?canvas.width:canvas.height)/6; |
|
|
|
|
|
|
|
for (int i=0; i<n; i++) { |
|
|
|
cx[i]=random(canvas.width); |
|
|
|
cy[i]=random(canvas.height); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int rw, rh; |
|
|
|
void apply() { |
|
|
|
if (rw != canvas.width || rh != canvas.height) { |
|
|
|
rw = canvas.width; |
|
|
|
rh = canvas.height; |
|
|
|
PGraphics save = createGraphics(canvas.width, canvas.height); |
|
|
|
save.beginDraw(); |
|
|
|
save.image(buffer, 0, 0, save.width, save.height); |
|
|
|
save.endDraw(); |
|
|
|
buffer.setSize(canvas.width, canvas.height); |
|
|
|
buffer.beginDraw(); |
|
|
|
buffer.image(save, 0, 0, buffer.width, buffer.height); |
|
|
|
buffer.endDraw(); |
|
|
|
} |
|
|
|
buffer.beginDraw(); |
|
|
|
buffer.strokeWeight(params.get(0).value); |
|
|
|
for (int i=1; i<n; i++) { |
|
|
|
color c = canvas.get((int)cx[i], (int)cy[i]); |
|
|
|
buffer.stroke(c); |
|
|
|
buffer.point(cx[i], cy[i]); |
|
|
|
// you can choose channels: red(c), blue(c), green(c), hue(c), saturation(c) or brightness(c) |
|
|
|
cy[i]+=sin(map(getChannel(c), 0, 255, 0, TWO_PI)); |
|
|
|
cx[i]+=cos(map(getChannel(c), 0, 255, 0, TWO_PI)); |
|
|
|
} |
|
|
|
if (frameCount>len) { |
|
|
|
frameCount=0; |
|
|
|
//println("iteration: " + tick++); |
|
|
|
for (int i=0; i<n; i++) { |
|
|
|
cx[i]=random(canvas.width); //same problem as in slitscan here |
|
|
|
cy[i]=random(canvas.height); |
|
|
|
} |
|
|
|
} |
|
|
|
buffer.endDraw(); |
|
|
|
canvas.beginDraw(); |
|
|
|
canvas.image(buffer, canvas.width/2, canvas.height/2); |
|
|
|
canvas.endDraw(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
float getChannel(color c) { |
|
|
|
int ch = channel>5?channel-6:channel; |
|
|
|
float cc; |
|
|
|
|
|
|
|
switch(ch) { |
|
|
|
case RED: |
|
|
|
cc = red(c); |
|
|
|
break; |
|
|
|
case GREEN: |
|
|
|
cc = green(c); |
|
|
|
break; |
|
|
|
case BLUE: |
|
|
|
cc = blue(c); |
|
|
|
break; |
|
|
|
case HUE: |
|
|
|
cc = hue(c); |
|
|
|
break; |
|
|
|
case SATURATION: |
|
|
|
cc = saturation(c); |
|
|
|
break; |
|
|
|
default: |
|
|
|
cc= brightness(c); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
return channel>5?255-cc:cc; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
PIXELDRIFTER |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
class PIXELDRIFTER extends Shader { |
|
|
|
int channel = HUE; // channel data used for shift |
|
|
|
float channel_off = 60; // channel value offset |
|
|
|
int iteration_no = 50; // number of iterations 1-100 |
|
|
|
int max_iter = iteration_no; |
|
|
|
int direction = UP; // UP, DOWN, LEFT, RIGHT |
|
|
|
boolean automate_channel_offset = false; // if true, change channel_offset every iteration |
|
|
|
float scale = 0.03; // 0.01 - 0.1, step size (0.01: 2px, 0.1:25px) |
|
|
|
float feedback = 0.9; // 0.9 - 0.999 ; blend ratio with original image |
|
|
|
|
|
|
|
boolean do_blend = false; // blend image after process |
|
|
|
int blend_mode = OVERLAY; // blend type |
|
|
|
|
|
|
|
// working buffer |
|
|
|
PGraphics buffer; |
|
|
|
|
|
|
|
// image |
|
|
|
PImage imgb; |
|
|
|
PImage img; |
|
|
|
String sessionid; |
|
|
|
float acho_step; |
|
|
|
int rw, rh; |
|
|
|
|
|
|
|
PIXELDRIFTER() { |
|
|
|
name = "fxPixelDrifter"; |
|
|
|
params.add(new Param ("channel offset", FLOATVAL, 0, 1, new int[]{SAWTOOTH, TRIANG, SINE, TAN, TANINVERSE, RAMPUPDOWN, RAMP, RAMPINVERSE})); |
|
|
|
params.add(new Param ("iterations", INTVAL, 1, 100, new int[]{SAWTOOTH, TRIANG, SINE, TAN, TANINVERSE, RAMPUPDOWN, RAMP, RAMPINVERSE})); |
|
|
|
params.add(new Param ("step size", FLOATVAL, 0.01, 0.1, new int[]{SAWTOOTH, TRIANG, SINE, TAN, TANINVERSE, RAMPUPDOWN, RAMP, RAMPINVERSE})); |
|
|
|
params.add(new Param ("feedback", FLOATVAL, 0.1, 1, new int[]{SAWTOOTH, TRIANG, SINE, TAN, TANINVERSE, RAMPUPDOWN, RAMP, RAMPINVERSE})); |
|
|
|
params.add(new Param ("direction", INTVAL, 37, 40, new int[]{SAWTOOTH, TRIANG, SINE, TAN, TANINVERSE, RAMPUPDOWN, RAMP, RAMPINVERSE})); |
|
|
|
params.add(new Param ("do blend", INTVAL, 0, 1, new int[]{RANDOM, SQUAR})); |
|
|
|
params.add(new Param ("blend mode", INTVAL, 0, blends.length-1, new int[]{RANDOM})); |
|
|
|
params.add(new Param ("channel", INTVAL, 0, 1, new int[]{SQUAR, RANDOM})); |
|
|
|
rw = canvas.width; |
|
|
|
rh = canvas.height; |
|
|
|
|
|
|
|
img = createImage(rw, rh, ARGB); |
|
|
|
|
|
|
|
buffer = createGraphics(rw, rh); |
|
|
|
buffer.beginDraw(); |
|
|
|
buffer.noStroke(); |
|
|
|
buffer.smooth(8); |
|
|
|
buffer.background(0); |
|
|
|
buffer.image(img, 0, 0); |
|
|
|
buffer.endDraw(); |
|
|
|
|
|
|
|
scale = abs(scale); |
|
|
|
acho_step = 256.0 / iteration_no; |
|
|
|
} |
|
|
|
|
|
|
|
void apply() { |
|
|
|
|
|
|
|
if (rw != canvas.width || rh != canvas.height) { |
|
|
|
rw = canvas.width; |
|
|
|
rh = canvas.height; |
|
|
|
img.resize(rw, rh); |
|
|
|
buffer = createGraphics(rw, rh); |
|
|
|
} |
|
|
|
channel_off = map(params.get(0).value, 0, 1, 10, max(rw, rh)); |
|
|
|
iteration_no = (int)params.get(1).value; |
|
|
|
scale = params.get(2).value; |
|
|
|
feedback = params.get(3).value; |
|
|
|
direction = (int)params.get(4).value; |
|
|
|
do_blend = boolean((int)params.get(5).value); |
|
|
|
blend_mode = blends[(int)params.get(6).value]; |
|
|
|
channel = (int)params.get(7).value == 1 ? HUE : RGB; |
|
|
|
|
|
|
|
img = canvas.get(); |
|
|
|
|
|
|
|
// if (iteration_no>0) { |
|
|
|
for (int i = 0; i < iteration_no; i++) { |
|
|
|
processImage(); |
|
|
|
} |
|
|
|
//iteration_no--; |
|
|
|
//iteration_no=(iteration_no==0)?max_iter:iteration_no; |
|
|
|
// if (iteration_no == 0) |
|
|
|
// iteration_no = 50; |
|
|
|
// } |
|
|
|
// } else { |
|
|
|
|
|
|
|
canvas.beginDraw(); |
|
|
|
if (do_blend) { |
|
|
|
canvas.blend(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height, blend_mode); |
|
|
|
} else { |
|
|
|
canvas.image(buffer, canvas.width/2, canvas.height/2, canvas.width, canvas.height); |
|
|
|
} |
|
|
|
canvas.endDraw(); |
|
|
|
// canvas.image(img, 0, 0, renderer.width, renderer.height); |
|
|
|
// noLoop(); |
|
|
|
// } |
|
|
|
} |
|
|
|
|
|
|
|
void processImage() { |
|
|
|
buffer.beginDraw(); |
|
|
|
for (int x=0; x<img.width; x++) { |
|
|
|
for (int y=0; y<img.height; y++) { |
|
|
|
color c = img.get(x, y); |
|
|
|
color c2; |
|
|
|
if (direction == UP || direction == DOWN) { |
|
|
|
c2 = img.get(x, ((int)(y+img.height+( (channel_off+getChannel(c, channel))%255 )*(direction==DOWN?-1.0:1.0)*scale))%img.height); |
|
|
|
} else { |
|
|
|
c2 = img.get(((int)(x+img.width+( (channel_off+getChannel(c, channel))%255)*(direction==RIGHT?-1.0:1.0)*scale))%img.width, y); |
|
|
|
} |
|
|
|
buffer.set(x, y, lerpColor(c, c2, feedback) ); |
|
|
|
} |
|
|
|
} |
|
|
|
buffer.endDraw(); |
|
|
|
//canvas.image(buffer, 0, 0, width, height); |
|
|
|
img = buffer.get(); |
|
|
|
if (automate_channel_offset) channel_off += acho_step; |
|
|
|
} |
|
|
|
// ALL Channels, Nxxx stand for negative (255-value) |
|
|
|
// channels to work with |
|
|
|
final static int RED = 0; |
|
|
|
final static int GREEN = 1; |
|
|
|
final static int BLUE = 2; |
|
|
|
final static int HUE = 3; |
|
|
|
final static int SATURATION = 4; |
|
|
|
final static int BRIGHTNESS = 5; |
|
|
|
final static int NRED = 6; |
|
|
|
final static int NGREEN = 7; |
|
|
|
final static int NBLUE = 8; |
|
|
|
final static int NHUE = 9; |
|
|
|
final static int NSATURATION = 10; |
|
|
|
final static int NBRIGHTNESS = 11; |
|
|
|
|
|
|
|
float getChannel(color c, int channel) { |
|
|
|
int ch = channel>5?channel-6:channel; |
|
|
|
float cc; |
|
|
|
|
|
|
|
switch(ch) { |
|
|
|
case RED: |
|
|
|
cc = red(c); |
|
|
|
break; |
|
|
|
case GREEN: |
|
|
|
cc = green(c); |
|
|
|
break; |
|
|
|
case BLUE: |
|
|
|
cc = blue(c); |
|
|
|
break; |
|
|
|
case HUE: |
|
|
|
cc = hue(c); |
|
|
|
break; |
|
|
|
case SATURATION: |
|
|
|
cc = saturation(c); |
|
|
|
break; |
|
|
|
default: |
|
|
|
cc= brightness(c); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
return channel>5?255-cc:cc; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|