Skip to content

Commit cbf7984

Browse files
committed
filters with glvideo
1 parent c8ac812 commit cbf7984

File tree

5 files changed

+242
-0
lines changed

5 files changed

+242
-0
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#ifdef GL_ES
2+
precision mediump float;
3+
precision mediump int;
4+
#endif
5+
6+
#define PROCESSING_TEXTURE_SHADER
7+
8+
uniform sampler2D texture;
9+
10+
varying vec4 vertColor;
11+
varying vec4 vertTexCoord;
12+
13+
const vec4 lumcoeff = vec4(0.299, 0.587, 0.114, 0);
14+
15+
void main() {
16+
vec4 col = texture2D(texture, vertTexCoord.st);
17+
float lum = dot(col, lumcoeff);
18+
if (0.5 < lum) {
19+
gl_FragColor = vertColor;
20+
} else {
21+
gl_FragColor = vec4(0, 0, 0, 1);
22+
}
23+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// This implementation is based on GLSL code by ArKano22:
2+
// http://www.gamedev.net/topic/590070-glsl-droste/
3+
uniform float globalTime;
4+
uniform sampler2D texture; // iChannel0 in Shadertoy
5+
uniform vec2 sketchSize; // iResolution in Shadertoy
6+
uniform int mode;
7+
8+
const float TWO_PI = 3.141592*2.0;
9+
//ADJUSTABLE PARAMETERS:
10+
const float Branches = 1.0;
11+
const float scale = 0.4;
12+
const float off = 0.6;
13+
//Complex Math:
14+
vec2 complexExp(in vec2 z){
15+
return vec2(exp(z.x)*cos(z.y),exp(z.x)*sin(z.y));
16+
}
17+
vec2 complexLog(in vec2 z){
18+
return vec2(log(length(z)), atan(z.y, z.x));
19+
}
20+
vec2 complexMult(in vec2 a,in vec2 b){
21+
return vec2(a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x);
22+
}
23+
float complexMag(in vec2 z){
24+
return float(pow(length(z), 2.0));
25+
}
26+
vec2 complexReciprocal(in vec2 z){
27+
return vec2(z.x / complexMag(z), -z.y / complexMag(z));
28+
}
29+
vec2 complexDiv(in vec2 a,in vec2 b){
30+
return complexMult(a, complexReciprocal(b));
31+
}
32+
vec2 complexPower(in vec2 a, in vec2 b){
33+
return complexExp( complexMult(b,complexLog(a)) );
34+
}
35+
//Misc Functions:
36+
float nearestPower(in float a, in float base){
37+
return pow(base, ceil( log(abs(a))/log(base) )-1.0 );
38+
}
39+
float map(float value, float istart, float istop, float ostart, float ostop) {
40+
return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
41+
}
42+
43+
void main( void ){
44+
45+
//SHIFT AND SCALE COORDINATES
46+
vec2 uv=gl_FragCoord.xy/sketchSize.xy - off;
47+
48+
//ESCHER GRID TRANSFORM:
49+
float factor = pow(1.0/scale,Branches);
50+
uv= complexPower(uv, complexDiv(vec2( log(factor) ,TWO_PI), vec2(0.0,TWO_PI) ) );
51+
52+
//RECTANGULAR DROSTE EFFECT:
53+
float FT = fract(globalTime);
54+
FT = log(FT+1.)/log(2.);
55+
uv *= 1.0+FT*(scale-1.0);
56+
57+
float npower = max(nearestPower(uv.x,scale),nearestPower(uv.y,scale));
58+
uv.x = map(uv.x,-npower,npower,-1.0,1.0);
59+
uv.y = map(uv.y,-npower,npower,-1.0,1.0);
60+
61+
//UNDO SHIFT AND SCALE:
62+
gl_FragColor = texture(texture,uv*off+vec2(off));
63+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Original shader by RavenWorks
2+
// Fake Floyd-Steinberg dithering
3+
// https://www.shadertoy.com/view/4sjGRD
4+
5+
// Adapted for JRubyArt by Martin Prout <@monkstoneT>
6+
7+
#ifdef GL_ES
8+
precision mediump float;
9+
precision mediump int;
10+
#endif
11+
12+
uniform sampler2D texture; // iChannel0 in Shadertoy
13+
uniform vec2 sketchSize; // iResolution in Shadertoy
14+
15+
const int lookupSize = 64;
16+
const float errorCarry = 0.3;
17+
18+
float getGrayscale(vec2 coords){
19+
vec2 uv = coords / sketchSize.xy;
20+
// processing is already using inverted y coordinates
21+
// uv.y = 1.0-uv.y;
22+
vec3 sourcePixel = texture2D(texture, uv).rgb;
23+
return length(sourcePixel*vec3(0.2126,0.7152,0.0722));
24+
}
25+
26+
// in regular glsl was
27+
// void mainImage( out vec4 fragColor, in vec2 fragCoord )
28+
29+
void main() {
30+
31+
int topGapY = int(sketchSize.y - gl_FragCoord.y);
32+
33+
int cornerGapX = int((gl_FragCoord.x < 10.0) ? gl_FragCoord.x : sketchSize.x - gl_FragCoord.x);
34+
int cornerGapY = int((gl_FragCoord.y < 10.0) ? sketchSize.y : gl_FragCoord.y - gl_FragCoord.y);
35+
int cornerThreshhold = ((cornerGapX == 0) || (topGapY == 0)) ? 5 : 4;
36+
37+
if (cornerGapX+cornerGapY < cornerThreshhold) {
38+
39+
gl_FragColor = vec4(0,0,0,1);
40+
41+
} else if (topGapY < 20) {
42+
43+
if (topGapY == 19) {
44+
45+
gl_FragColor = vec4(0,0,0,1);
46+
47+
} else {
48+
49+
gl_FragColor = vec4(1,1,1,1);
50+
51+
}
52+
53+
} else {
54+
55+
float xError = 0.0;
56+
for(int xLook=0; xLook<lookupSize; xLook++){
57+
float grayscale = getGrayscale(gl_FragCoord.xy + vec2(-lookupSize+xLook,0));
58+
grayscale += xError;
59+
float bit = grayscale >= 0.5 ? 1.0 : 0.0;
60+
xError = (grayscale - bit)*errorCarry;
61+
}
62+
63+
float yError = 0.0;
64+
for(int yLook=0; yLook<lookupSize; yLook++){
65+
float grayscale = getGrayscale(gl_FragCoord.xy + vec2(0,-lookupSize+yLook));
66+
grayscale += yError;
67+
float bit = grayscale >= 0.5 ? 1.0 : 0.0;
68+
yError = (grayscale - bit)*errorCarry;
69+
}
70+
71+
float finalGrayscale = getGrayscale(gl_FragCoord.xy);
72+
finalGrayscale += xError*0.5 + yError*0.5;
73+
float finalBit = finalGrayscale >= 0.5 ? 1.0 : 0.0;
74+
75+
gl_FragColor = vec4(finalBit,finalBit,finalBit,1);
76+
77+
}
78+
79+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env jruby
2+
require 'propane'
3+
4+
# hold down mouse to see unfiltered output
5+
class Droste < Propane::App
6+
load_library :glvideo
7+
include_package 'gohai.glvideo'
8+
attr_reader :cam, :my_filter, :origin
9+
10+
def settings
11+
size(1280, 960, P2D)
12+
end
13+
14+
def setup
15+
sketch_title 'Droste'
16+
@origin = Time.now
17+
@my_filter = load_shader(data_path('droste.glsl'))
18+
my_filter.set('sketchSize', width.to_f, height.to_f)
19+
start_capture
20+
end
21+
22+
def time
23+
(Time.now - origin) * 0.5
24+
end
25+
26+
def start_capture
27+
@cam = GLCapture.new(self)
28+
cam.start
29+
end
30+
31+
def draw
32+
background 0
33+
cam.read if cam.available
34+
image(cam, 0, 0, width, height)
35+
my_filter.set('globalTime', time)
36+
return if mouse_pressed?
37+
filter(my_filter)
38+
end
39+
end
40+
41+
Droste.new
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env jruby
2+
require 'propane'
3+
# Because this sketch uses a glsl shader it needs to run using
4+
# jruby-complete (typically rp5 --nojruby sketch.rb)
5+
# hold down mouse to see unfiltered output
6+
class Steinberg < Propane::App
7+
load_library :glvideo
8+
include_package 'gohai.glvideo'
9+
attr_reader :cam, :my_shader
10+
11+
def settings
12+
size(640, 480, P2D)
13+
end
14+
15+
def setup
16+
sketch_title 'Steinberg'
17+
@my_shader = load_shader(data_path('steinberg.glsl'))
18+
my_shader.set('sketchSize', width.to_f, height.to_f)
19+
start_capture(width, height)
20+
end
21+
22+
def start_capture(w, h)
23+
@cam = GLCapture.new(self)
24+
cam.start
25+
end
26+
27+
def draw
28+
background 0
29+
cam.read if cam.available
30+
image(cam, 0, 0, width, height)
31+
return if mouse_pressed?
32+
filter(my_shader)
33+
end
34+
end
35+
36+
Steinberg.new

0 commit comments

Comments
 (0)