Browse Source

added fxPixelDrifter and fxDrawGenerative

master
Victor Giers 1 year ago
parent
commit
20eb0d3f72
4 changed files with 494 additions and 5 deletions
  1. 1
    1
      data/saves.sav
  2. 479
    1
      effects.pde
  3. 11
    0
      secondapplet.pde
  4. 3
    3
      statics_and_lists.pde

+ 1
- 1
data/saves.sav View File

@@ -1,2 +1,2 @@
//globals
uptime = 116755249
uptime = 116775809

+ 479
- 1
effects.pde View File

@@ -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;
}
}




+ 11
- 0
secondapplet.pde View File

@@ -1,5 +1,7 @@
//contains the GUI (ie CP5) in the secondapplet. also contains 3 classes: shaderManager, Brick and Slider

/* todo: implement "solo" and "only up till here" button on bricks */

PImage bin;
int maxSurfaceHeight = 500;
int nativeResoX, nativeResoY;
@@ -590,6 +592,15 @@ public class SecondApplet extends PApplet {
case(19):
shaderManager.addShader(new MASK());
break;
case(20):
shaderManager.addShader(new DRAWSTROKES());
break;
case(21):
shaderManager.addShader(new DRAWGENERATIVE());
break;
case(22):
shaderManager.addShader(new PIXELDRIFTER());
break;
/*
case(4):
shaderManager.addShader(new AUECHO());

+ 3
- 3
statics_and_lists.pde View File

@@ -64,8 +64,8 @@ String availableFx[] = {
"fxSubtleSort",
"fxScanker",
"Mask",
"fxMosh",
"fxDrawStrokes",
"fxDrawGenerative",
"fxPixelDrifter",
"fxDrawGenerative",
"fxDrawStrokes"
"fxMosh"
};

Loading…
Cancel
Save