danabr75-ashton 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +0 -0
- data/LICENSE +21 -0
- data/README.md +95 -0
- data/Rakefile +42 -0
- data/examples/bloom_example.rb +59 -0
- data/examples/lighting_example.rb +127 -0
- data/examples/media/Earth.png +0 -0
- data/examples/media/LargeStar.png +0 -0
- data/examples/media/SmallStar.png +0 -0
- data/examples/media/Star.png +0 -0
- data/examples/media/Starfighter.bmp +0 -0
- data/examples/media/Starfighter.png +0 -0
- data/examples/media/simple.png +0 -0
- data/examples/noise_example.rb +94 -0
- data/examples/outline_example.rb +86 -0
- data/examples/particle_emitter_example.rb +114 -0
- data/examples/pixelate_example.rb +52 -0
- data/examples/pixelated_texture_example.rb +69 -0
- data/examples/radial_blur_example.rb +61 -0
- data/examples/shader_image_example.rb +75 -0
- data/examples/shockwave_example.rb +75 -0
- data/examples/stencil_shader_example.rb +104 -0
- data/examples/texture_render_example.rb +54 -0
- data/examples/tv_screen_and_static_example.rb +60 -0
- data/ext/ashton/GLee.c +18170 -0
- data/ext/ashton/GLee.h +17648 -0
- data/ext/ashton/ashton.c +42 -0
- data/ext/ashton/ashton.h +31 -0
- data/ext/ashton/color.c +45 -0
- data/ext/ashton/color.h +25 -0
- data/ext/ashton/common.h +41 -0
- data/ext/ashton/extconf.rb +45 -0
- data/ext/ashton/fast_math.c +30 -0
- data/ext/ashton/fast_math.h +30 -0
- data/ext/ashton/font.c +8 -0
- data/ext/ashton/font.h +16 -0
- data/ext/ashton/gosu.c +18 -0
- data/ext/ashton/gosu.h +19 -0
- data/ext/ashton/image.c +8 -0
- data/ext/ashton/image.h +16 -0
- data/ext/ashton/particle_emitter.c +788 -0
- data/ext/ashton/particle_emitter.h +171 -0
- data/ext/ashton/pixel_cache.c +237 -0
- data/ext/ashton/pixel_cache.h +58 -0
- data/ext/ashton/shader.c +9 -0
- data/ext/ashton/shader.h +16 -0
- data/ext/ashton/texture.c +442 -0
- data/ext/ashton/texture.h +63 -0
- data/ext/ashton/vendor/gl/include/GL/GL.H +1526 -0
- data/ext/ashton/window.c +8 -0
- data/ext/ashton/window.h +16 -0
- data/lib/ashton.rb +38 -0
- data/lib/ashton/gosu_ext/color.rb +25 -0
- data/lib/ashton/gosu_ext/font.rb +58 -0
- data/lib/ashton/gosu_ext/gosu_module.rb +16 -0
- data/lib/ashton/gosu_ext/image.rb +96 -0
- data/lib/ashton/gosu_ext/window.rb +79 -0
- data/lib/ashton/image_stub.rb +33 -0
- data/lib/ashton/lighting/light_source.rb +146 -0
- data/lib/ashton/lighting/manager.rb +98 -0
- data/lib/ashton/mixins/version_checking.rb +23 -0
- data/lib/ashton/particle_emitter.rb +87 -0
- data/lib/ashton/pixel_cache.rb +24 -0
- data/lib/ashton/shader.rb +386 -0
- data/lib/ashton/shaders/bloom.frag +41 -0
- data/lib/ashton/shaders/color_inversion.frag +11 -0
- data/lib/ashton/shaders/contrast.frag +16 -0
- data/lib/ashton/shaders/default.frag +22 -0
- data/lib/ashton/shaders/default.vert +14 -0
- data/lib/ashton/shaders/fade.frag +14 -0
- data/lib/ashton/shaders/grayscale.frag +15 -0
- data/lib/ashton/shaders/include/classicnoise2d.glsl +113 -0
- data/lib/ashton/shaders/include/classicnoise3d.glsl +177 -0
- data/lib/ashton/shaders/include/classicnoise4d.glsl +302 -0
- data/lib/ashton/shaders/include/noise2d.glsl +70 -0
- data/lib/ashton/shaders/include/noise3d.glsl +102 -0
- data/lib/ashton/shaders/include/noise4d.glsl +128 -0
- data/lib/ashton/shaders/include/rand.glsl +5 -0
- data/lib/ashton/shaders/lighting/distort.frag +57 -0
- data/lib/ashton/shaders/lighting/draw_shadows.frag +60 -0
- data/lib/ashton/shaders/lighting/shadow_blur.frag +60 -0
- data/lib/ashton/shaders/mezzotint.frag +22 -0
- data/lib/ashton/shaders/multitexture2.vert +19 -0
- data/lib/ashton/shaders/outline.frag +45 -0
- data/lib/ashton/shaders/pixelate.frag +48 -0
- data/lib/ashton/shaders/radial_blur.frag +63 -0
- data/lib/ashton/shaders/sepia.frag +26 -0
- data/lib/ashton/shaders/shockwave.frag +38 -0
- data/lib/ashton/shaders/signed_distance_field.frag +80 -0
- data/lib/ashton/shaders/static.frag +25 -0
- data/lib/ashton/shaders/stencil.frag +27 -0
- data/lib/ashton/shaders/tv_screen.frag +23 -0
- data/lib/ashton/signed_distance_field.rb +151 -0
- data/lib/ashton/texture.rb +186 -0
- data/lib/ashton/version.rb +3 -0
- data/lib/ashton/window_buffer.rb +16 -0
- data/spec/ashton/ashton_spec.rb +22 -0
- data/spec/ashton/gosu_ext/color_spec.rb +34 -0
- data/spec/ashton/gosu_ext/font_spec.rb +57 -0
- data/spec/ashton/gosu_ext/gosu_spec.rb +11 -0
- data/spec/ashton/gosu_ext/image_spec.rb +66 -0
- data/spec/ashton/gosu_ext/window_spec.rb +71 -0
- data/spec/ashton/image_stub_spec.rb +46 -0
- data/spec/ashton/particle_emitter_spec.rb +123 -0
- data/spec/ashton/pixel_cache_spec.rb +153 -0
- data/spec/ashton/shader_spec.rb +152 -0
- data/spec/ashton/signed_distance_field_spec.rb +163 -0
- data/spec/ashton/texture_spec.rb +347 -0
- data/spec/helper.rb +12 -0
- metadata +309 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
#version 110
|
2
|
+
|
3
|
+
#include <rand>
|
4
|
+
|
5
|
+
uniform sampler2D in_Texture;
|
6
|
+
uniform int in_WindowWidth;
|
7
|
+
|
8
|
+
uniform int in_T;
|
9
|
+
|
10
|
+
varying vec2 var_TexCoord;
|
11
|
+
|
12
|
+
void main() {
|
13
|
+
vec4 color = texture2D(in_Texture, var_TexCoord);
|
14
|
+
vec3 mezzo = vec3(0.0);
|
15
|
+
float width = float(in_WindowWidth);
|
16
|
+
|
17
|
+
if(rand(var_TexCoord + float(in_T) / width) <= color.r) { mezzo.r = 1.0; }
|
18
|
+
if(rand(var_TexCoord + float(in_T) / width) <= color.g) { mezzo.g = 1.0; }
|
19
|
+
if(rand(var_TexCoord + float(in_T) / width) <= color.b) { mezzo.b = 1.0; }
|
20
|
+
|
21
|
+
gl_FragColor.rgb = mezzo;
|
22
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#version 110
|
2
|
+
|
3
|
+
attribute vec4 in_Color;
|
4
|
+
|
5
|
+
varying vec4 var_Color;
|
6
|
+
varying vec2 var_TexCoord0;
|
7
|
+
varying vec2 var_TexCoord1;
|
8
|
+
|
9
|
+
void main()
|
10
|
+
{
|
11
|
+
gl_Position = ftransform();
|
12
|
+
var_Color = in_Color;
|
13
|
+
|
14
|
+
// Set the coordinates for TEXTURE0
|
15
|
+
var_TexCoord0 = gl_MultiTexCoord0.xy;
|
16
|
+
|
17
|
+
// Set the coordinates for TEXTURE1
|
18
|
+
var_TexCoord1 = gl_MultiTexCoord1.xy;
|
19
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#version 110
|
2
|
+
|
3
|
+
const float ALPHA_THRESHOLD = 0.5;
|
4
|
+
|
5
|
+
const vec2 TextureSize = vec2(1024.0, 1024.0); // Gosu-specific!
|
6
|
+
const vec2 PixelSize = 1.0 / TextureSize;
|
7
|
+
|
8
|
+
// Automatically set by Ray (actually passed from the vertex shader).
|
9
|
+
uniform sampler2D in_Texture; // Original texture.
|
10
|
+
//uniform int in_WindowWidth;
|
11
|
+
//uniform int in_WindowHeight;
|
12
|
+
|
13
|
+
uniform vec4 in_OutlineColor;
|
14
|
+
uniform float in_OutlineWidth; // In pixels.
|
15
|
+
|
16
|
+
varying vec2 var_TexCoord; // Pixel to process on this pass
|
17
|
+
varying vec4 var_Color;
|
18
|
+
|
19
|
+
void main()
|
20
|
+
{
|
21
|
+
gl_FragColor = texture2D(in_Texture, var_TexCoord); // * var_Color;
|
22
|
+
|
23
|
+
if(gl_FragColor.a < ALPHA_THRESHOLD)
|
24
|
+
{
|
25
|
+
for(int i = -1; i < 2; i++)
|
26
|
+
{
|
27
|
+
for(int j = -1; j < 2; j++)
|
28
|
+
{
|
29
|
+
if(i != 0 && j != 0)
|
30
|
+
{
|
31
|
+
// Get the color of the adjacent pixel.
|
32
|
+
vec2 pos = var_TexCoord + vec2(i, j) * PixelSize * in_OutlineWidth;
|
33
|
+
if(texture2D(in_Texture, pos).a > ALPHA_THRESHOLD)
|
34
|
+
{
|
35
|
+
gl_FragColor = in_OutlineColor;
|
36
|
+
|
37
|
+
// Simplified return, since GLSL 1.10 hates `return`.
|
38
|
+
i = 2;
|
39
|
+
j = 2;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
#version 110
|
2
|
+
|
3
|
+
#define KERNEL_SIZE 9
|
4
|
+
|
5
|
+
uniform int in_WindowWidth;
|
6
|
+
uniform int in_WindowHeight;
|
7
|
+
|
8
|
+
uniform sampler2D in_Texture;
|
9
|
+
uniform int in_PixelSize;
|
10
|
+
|
11
|
+
varying vec2 var_TexCoord;
|
12
|
+
|
13
|
+
vec2 texCoords[KERNEL_SIZE];
|
14
|
+
|
15
|
+
void main(void)
|
16
|
+
{
|
17
|
+
vec4 avgColor;
|
18
|
+
vec2 texCoordsStep = 1.0 /
|
19
|
+
(vec2(float(in_WindowWidth), float(in_WindowHeight))/float(in_PixelSize));
|
20
|
+
vec2 pixelBin = floor(var_TexCoord / texCoordsStep);
|
21
|
+
vec2 inPixelStep = texCoordsStep / 3.0;
|
22
|
+
vec2 inPixelHalfStep = inPixelStep / 2.0;
|
23
|
+
|
24
|
+
|
25
|
+
texCoords[0] = vec2(inPixelHalfStep.x, inPixelStep.y*2.0 + inPixelHalfStep.y) + pixelBin * texCoordsStep;
|
26
|
+
texCoords[1] = vec2(inPixelStep.x + inPixelHalfStep.x, inPixelStep.y*2.0 + inPixelHalfStep.y) + pixelBin * texCoordsStep;
|
27
|
+
texCoords[2] = vec2(inPixelStep.x*2.0 + inPixelHalfStep.x, inPixelStep.y*2.0 + inPixelHalfStep.y) + pixelBin * texCoordsStep;
|
28
|
+
texCoords[3] = vec2(inPixelHalfStep.x, inPixelStep.y + inPixelHalfStep.y) + pixelBin * texCoordsStep;
|
29
|
+
texCoords[4] = vec2(inPixelStep.x + inPixelHalfStep.x, inPixelStep.y + inPixelHalfStep.y) + pixelBin * texCoordsStep;
|
30
|
+
texCoords[5] = vec2(inPixelStep.x*2.0 + inPixelHalfStep.x, inPixelStep.y + inPixelHalfStep.y) + pixelBin * texCoordsStep;
|
31
|
+
texCoords[6] = vec2(inPixelHalfStep.x, inPixelHalfStep.y) + pixelBin * texCoordsStep;
|
32
|
+
texCoords[7] = vec2(inPixelStep.x + inPixelHalfStep.x, inPixelHalfStep.y) + pixelBin * texCoordsStep;
|
33
|
+
texCoords[8] = vec2(inPixelStep.x*2.0 + inPixelHalfStep.x, inPixelHalfStep.y) + pixelBin * texCoordsStep;
|
34
|
+
|
35
|
+
avgColor = texture2D(in_Texture, texCoords[0]) +
|
36
|
+
texture2D(in_Texture, texCoords[1]) +
|
37
|
+
texture2D(in_Texture, texCoords[2]) +
|
38
|
+
texture2D(in_Texture, texCoords[3]) +
|
39
|
+
texture2D(in_Texture, texCoords[4]) +
|
40
|
+
texture2D(in_Texture, texCoords[5]) +
|
41
|
+
texture2D(in_Texture, texCoords[6]) +
|
42
|
+
texture2D(in_Texture, texCoords[7]) +
|
43
|
+
texture2D(in_Texture, texCoords[8]);
|
44
|
+
|
45
|
+
avgColor /= float(KERNEL_SIZE);
|
46
|
+
|
47
|
+
gl_FragColor = avgColor;
|
48
|
+
}
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#version 110
|
2
|
+
|
3
|
+
// http://www.gamerendering.com/2008/12/20/radial-blur-filter/
|
4
|
+
|
5
|
+
uniform sampler2D in_Texture; // Texture to manipulate.
|
6
|
+
uniform int in_WindowWidth;
|
7
|
+
uniform int in_WindowHeight;
|
8
|
+
|
9
|
+
uniform float in_Spacing; // good value is 1.0;
|
10
|
+
uniform float in_Strength; // good value is 2.2;
|
11
|
+
|
12
|
+
varying vec2 var_TexCoord;
|
13
|
+
|
14
|
+
void main(void)
|
15
|
+
{
|
16
|
+
// some sample positions. GLSL 1.10 is painfully dumb with arrays :)
|
17
|
+
float samples[10];
|
18
|
+
samples[0] = -0.08;
|
19
|
+
samples[1] = -0.05;
|
20
|
+
samples[2] = -0.03;
|
21
|
+
samples[3] = -0.02;
|
22
|
+
samples[4] = -0.01;
|
23
|
+
samples[5] = 0.01;
|
24
|
+
samples[6] = 0.02;
|
25
|
+
samples[7] = 0.03;
|
26
|
+
samples[8] = 0.05;
|
27
|
+
samples[9] = 0.08;
|
28
|
+
|
29
|
+
// 0.5,0.5 is the center of the screen
|
30
|
+
// so substracting uv from it will result in
|
31
|
+
// a vector pointing to the middle of the screen
|
32
|
+
vec2 dir = 0.5 - var_TexCoord;
|
33
|
+
|
34
|
+
// calculate the distance to the center of the screen
|
35
|
+
float dist = sqrt(dir.x * dir.x + dir.y * dir.y);
|
36
|
+
|
37
|
+
// normalize the direction (reuse the distance)
|
38
|
+
dir /= dist;
|
39
|
+
|
40
|
+
// this is the original colour of this fragment
|
41
|
+
// using only this would result in a non-blurred version
|
42
|
+
vec4 color = texture2D(in_Texture, var_TexCoord);
|
43
|
+
|
44
|
+
vec4 sum = color;
|
45
|
+
|
46
|
+
// take 10 additional blur samples in the direction towards
|
47
|
+
// the center of the screen
|
48
|
+
for (int i = 0; i < 10; i++)
|
49
|
+
{
|
50
|
+
sum += texture2D(in_Texture, var_TexCoord + dir * samples[i] * in_Spacing);
|
51
|
+
}
|
52
|
+
|
53
|
+
// we have taken eleven samples
|
54
|
+
sum *= 1.0/11.0;
|
55
|
+
|
56
|
+
// weighten the blur effect with the distance to the
|
57
|
+
// center of the screen ( further out is blurred more)
|
58
|
+
float t = dist * in_Strength;
|
59
|
+
t = clamp(t, 0.0, 1.0); //0 <= t <= 1
|
60
|
+
|
61
|
+
// Blend the original color with the averaged pixels
|
62
|
+
gl_FragColor = mix(color, sum, t);
|
63
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#version 110
|
2
|
+
|
3
|
+
uniform sampler2D in_Texture;
|
4
|
+
|
5
|
+
varying vec2 var_TexCoord;
|
6
|
+
|
7
|
+
void main()
|
8
|
+
{
|
9
|
+
vec4 Sepia1 = vec4( 0.2, 0.05, 0.0, 1.0 );
|
10
|
+
vec4 Sepia2 = vec4( 1.0, 0.9, 0.5, 1.0 );
|
11
|
+
|
12
|
+
vec4 Color = texture2D(in_Texture, vec2(var_TexCoord));
|
13
|
+
|
14
|
+
if(Color.a == 0.0)
|
15
|
+
{
|
16
|
+
gl_FragColor = Color;
|
17
|
+
}
|
18
|
+
else
|
19
|
+
{
|
20
|
+
float SepiaMix = dot(vec3(0.3, 0.59, 0.11), vec3(Color));
|
21
|
+
Color = mix(Color, vec4(SepiaMix), vec4(0.5));
|
22
|
+
vec4 Sepia = mix(Sepia1, Sepia2, SepiaMix);
|
23
|
+
|
24
|
+
gl_FragColor = mix(Color, Sepia, 1.0);
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#version 110
|
2
|
+
|
3
|
+
// http://empire-defense.crystalin.fr/blog/2d_shock_wave_texture_with_shader
|
4
|
+
// http://www.geeks3d.com/20091116/shader-library-2d-shockwave-post-processing-filter-glsl/
|
5
|
+
|
6
|
+
uniform sampler2D in_Texture; // 0
|
7
|
+
uniform vec2 in_Center; // Mouse position
|
8
|
+
uniform float in_Time; // effect elapsed time. Multiply this to affect speed.
|
9
|
+
|
10
|
+
// Amplitude?, Refraction?, Width? e.g. 10.0, 0.8, 0.1
|
11
|
+
uniform vec3 in_ShockParams;
|
12
|
+
|
13
|
+
uniform int in_WindowWidth;
|
14
|
+
uniform int in_WindowHeight;
|
15
|
+
|
16
|
+
varying vec2 var_TexCoord;
|
17
|
+
|
18
|
+
void main()
|
19
|
+
{
|
20
|
+
vec2 uv = var_TexCoord;
|
21
|
+
vec2 texCoord = uv;
|
22
|
+
float x = in_Center.x / float(in_WindowWidth);
|
23
|
+
float y = (float(in_WindowHeight) - in_Center.y) / float(in_WindowHeight);
|
24
|
+
float distance = distance(uv, vec2(x, y));
|
25
|
+
|
26
|
+
if ( (distance <= (in_Time + in_ShockParams.z)) &&
|
27
|
+
(distance >= (in_Time - in_ShockParams.z)) )
|
28
|
+
{
|
29
|
+
float diff = (distance - in_Time);
|
30
|
+
float powDiff = 1.0 - pow(abs(diff * in_ShockParams.x),
|
31
|
+
in_ShockParams.y);
|
32
|
+
float diffTime = diff * powDiff;
|
33
|
+
vec2 diffUV = normalize(uv - in_Center);
|
34
|
+
texCoord = uv + (diffUV * diffTime);
|
35
|
+
}
|
36
|
+
|
37
|
+
gl_FragColor = texture2D(in_Texture, texCoord);
|
38
|
+
}
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#version 110
|
2
|
+
|
3
|
+
// Calculates a signed distance field, based on how far any pixel is from an opaque pixel.
|
4
|
+
// In each pixel, the signed value is actually r/g/b - 128
|
5
|
+
// if r/g/b > 0 => distance from an opaque pixel.
|
6
|
+
// if r/g/b <= 0 => distance from an opaque pixel that is adjacent to a transparent pixel.
|
7
|
+
|
8
|
+
uniform sampler2D in_Texture; // Original texture.
|
9
|
+
|
10
|
+
uniform vec2 in_TextureSize; // Width and height of the texture, so we know how big pixels are.
|
11
|
+
uniform int in_StepSize; // Distance to check each time (larger steps will be faster, but less accurate).
|
12
|
+
uniform int in_MaxDistance; // Maximum distance to search out to. Cannot be more than 127!
|
13
|
+
|
14
|
+
varying vec2 var_TexCoord; // Pixel to process on this pass.
|
15
|
+
|
16
|
+
const float NUM_SPOKES = 36.0; // Number of radiating lines to check in.
|
17
|
+
const float ANGULAR_STEP = 360.0 / NUM_SPOKES;
|
18
|
+
|
19
|
+
const int ZERO_VALUE = 128; // Color channel containing 0 => -128, 128 => 0, 255 => +127
|
20
|
+
|
21
|
+
// Returns true an alpha value is found at this distance (any direction).
|
22
|
+
bool find_alpha_at_distance(in vec2 center, in vec2 distance, in float alpha)
|
23
|
+
{
|
24
|
+
bool found = false;
|
25
|
+
|
26
|
+
for(float angle = 0.0; angle < 360.0; angle += ANGULAR_STEP)
|
27
|
+
{
|
28
|
+
vec2 position = center + distance * vec2(cos(angle), sin(angle));
|
29
|
+
|
30
|
+
if(texture2D(in_Texture, position).a == alpha)
|
31
|
+
{
|
32
|
+
found = true;
|
33
|
+
angle = 361.0;
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
return found;
|
38
|
+
}
|
39
|
+
|
40
|
+
void main()
|
41
|
+
{
|
42
|
+
vec2 pixel_size = 1.0 / in_TextureSize;
|
43
|
+
|
44
|
+
int distance;
|
45
|
+
|
46
|
+
if(texture2D(in_Texture, var_TexCoord).a == 0.0)
|
47
|
+
{
|
48
|
+
// Texel is transparent, search for nearest opaque.
|
49
|
+
distance = ZERO_VALUE + 1;
|
50
|
+
for(int i = in_StepSize; i < in_MaxDistance; i += in_StepSize)
|
51
|
+
{
|
52
|
+
if(find_alpha_at_distance(var_TexCoord, float(i) * pixel_size, 1.0))
|
53
|
+
{
|
54
|
+
i = in_MaxDistance + 1; // BREAK!
|
55
|
+
}
|
56
|
+
else
|
57
|
+
{
|
58
|
+
distance = ZERO_VALUE + 1 + i;
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
else
|
63
|
+
{
|
64
|
+
// Texel is opaque, search for nearest transparent.
|
65
|
+
distance = ZERO_VALUE;
|
66
|
+
for(int i = in_StepSize; i <= in_MaxDistance; i += in_StepSize)
|
67
|
+
{
|
68
|
+
if(find_alpha_at_distance(var_TexCoord, float(i) * pixel_size, 0.0))
|
69
|
+
{
|
70
|
+
i = in_MaxDistance + 1; // BREAK!
|
71
|
+
}
|
72
|
+
else
|
73
|
+
{
|
74
|
+
distance = ZERO_VALUE - i;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
gl_FragColor = vec4(vec3(float(distance) / 255.0), 1.0);
|
80
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#version 110
|
2
|
+
|
3
|
+
#include <rand>
|
4
|
+
|
5
|
+
// Rather poor quality noise generation, but better than nothing and sort of looks like TV static a bit.
|
6
|
+
|
7
|
+
uniform sampler2D in_Texture;
|
8
|
+
|
9
|
+
uniform int in_WindowWidth; // Not used.
|
10
|
+
uniform int in_WindowHeight; // Not used.
|
11
|
+
|
12
|
+
uniform float in_Intensity;
|
13
|
+
uniform float in_T;
|
14
|
+
|
15
|
+
varying vec2 var_TexCoord;
|
16
|
+
|
17
|
+
void main() {
|
18
|
+
vec4 color = texture2D(in_Texture, var_TexCoord);
|
19
|
+
|
20
|
+
vec4 influence = min(color, 1.0 - color);
|
21
|
+
|
22
|
+
float noise = 1.0 - 2.0 * rand(var_TexCoord + float(in_T));
|
23
|
+
|
24
|
+
gl_FragColor = color + in_Intensity * influence * noise;
|
25
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#version 110
|
2
|
+
|
3
|
+
// Use a stencil texture to selectively draw. Drawing of the image will occur
|
4
|
+
// where the stencil is transparent (or only where the stencil is opaque if
|
5
|
+
// inverted).
|
6
|
+
//
|
7
|
+
// Partial transparency in the stencil will allow the image to be drawn
|
8
|
+
// partially too.
|
9
|
+
|
10
|
+
varying vec4 var_Color;
|
11
|
+
varying vec2 var_TexCoord0; // The texture/image to draw.
|
12
|
+
varying vec2 var_TexCoord1; // The stencil (multitexture).
|
13
|
+
|
14
|
+
uniform sampler2D in_Texture0; // The texture/image to draw.
|
15
|
+
uniform sampler2D in_Texture1; // The stencil (multitexture).
|
16
|
+
uniform bool in_Inverted; // true to draw in opaque areas / false to draw in transparent areas.
|
17
|
+
|
18
|
+
void main()
|
19
|
+
{
|
20
|
+
vec4 texColor = texture2D(in_Texture0, var_TexCoord0);
|
21
|
+
vec4 maskColor = texture2D(in_Texture1, var_TexCoord1);
|
22
|
+
|
23
|
+
// Only draw the texture where the stencil is transparent (unless inverted).
|
24
|
+
float mask_alpha = in_Inverted ? (1.0 - maskColor.a) : maskColor.a;
|
25
|
+
|
26
|
+
gl_FragColor = vec4(texColor.r, texColor.g, texColor.b, texColor.a - mask_alpha);
|
27
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#version 110
|
2
|
+
|
3
|
+
uniform sampler2D in_Texture;
|
4
|
+
|
5
|
+
uniform float in_ColumnWidth; // In pixels.
|
6
|
+
uniform int in_WindowWidth;
|
7
|
+
uniform int in_WindowHeight; // Not used in this shader.
|
8
|
+
|
9
|
+
varying vec2 var_TexCoord;
|
10
|
+
|
11
|
+
void main()
|
12
|
+
{
|
13
|
+
vec3 color = texture2D(in_Texture, var_TexCoord).rgb;
|
14
|
+
|
15
|
+
gl_FragColor = vec4(color * 0.25, 1.0);
|
16
|
+
|
17
|
+
float column_index = var_TexCoord.x * float(in_WindowWidth) / in_ColumnWidth;
|
18
|
+
|
19
|
+
int c = int(mod(column_index, 3.0));
|
20
|
+
if(c == 0) { gl_FragColor.r = color.r; }
|
21
|
+
else if(c == 1) { gl_FragColor.g = color.g; }
|
22
|
+
else if(c == 2) { gl_FragColor.b = color.b; }
|
23
|
+
}
|
@@ -0,0 +1,151 @@
|
|
1
|
+
module Ashton
|
2
|
+
class SignedDistanceField
|
3
|
+
ZERO_DISTANCE = 128 # color channel containing 0 => -128, 128 => 0, 129 => +1, 255 => +128
|
4
|
+
|
5
|
+
attr_reader :width, :height
|
6
|
+
|
7
|
+
# Creates a Signed Distance Field based on a given image.
|
8
|
+
# When drawing into the SDF, drawing should ONLY have alpha of 0 (clear) or 255 (solid)
|
9
|
+
#
|
10
|
+
# @param width [Integer]
|
11
|
+
# @param height [Integer]
|
12
|
+
# @param max_distance [Integer] Maximum distance to measure.
|
13
|
+
# @option options :step_size [Integer] (1) pixels to step out.
|
14
|
+
# @option options :scale [Integer] (1) Scale relative to the image.
|
15
|
+
def initialize(width, height, max_distance, options = {}, &block)
|
16
|
+
options = {
|
17
|
+
scale: 1,
|
18
|
+
step_size: 1,
|
19
|
+
}.merge! options
|
20
|
+
|
21
|
+
@width, @height = width, height
|
22
|
+
@scale = options[:scale].to_f
|
23
|
+
|
24
|
+
@shader = Shader.new fragment: :signed_distance_field, uniforms: {
|
25
|
+
max_distance: max_distance.ceil,
|
26
|
+
step_size: options[:step_size].floor, # One pixel.
|
27
|
+
texture_size: [width, height].map(&:to_f),
|
28
|
+
}
|
29
|
+
|
30
|
+
@field = Texture.new (width / @scale).ceil, (height / @scale).ceil
|
31
|
+
@mask = Texture.new @field.width, @field.height
|
32
|
+
|
33
|
+
if block_given?
|
34
|
+
render_field(&block)
|
35
|
+
else
|
36
|
+
@field.clear color: Gosu::Color.rgb(*([ZERO_DISTANCE + max_distance] * 3))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Is the position clear for a given radius around it.
|
41
|
+
def position_clear?(x, y, radius)
|
42
|
+
sample_distance(x, y) >= radius
|
43
|
+
end
|
44
|
+
|
45
|
+
# If positive, distance, in pixels, to the nearest opaque pixel.
|
46
|
+
# If negative, distance in pixels to the nearest transparent pixel.
|
47
|
+
def sample_distance(x, y)
|
48
|
+
x = [[x, width - 1].min, 0].max
|
49
|
+
y = [[y, height - 1].min, 0].max
|
50
|
+
# Could be checking any of red/blue/green.
|
51
|
+
@field.red((x / @scale).round, (y / @scale).round) - ZERO_DISTANCE
|
52
|
+
end
|
53
|
+
|
54
|
+
# Gets the gradient of the field at a given point.
|
55
|
+
# @return [Float, Float] gradient_x, gradient_y
|
56
|
+
def sample_gradient(x, y)
|
57
|
+
d0 = sample_distance x, y - 1
|
58
|
+
d1 = sample_distance x - 1, y
|
59
|
+
d2 = sample_distance x + 1, y
|
60
|
+
d3 = sample_distance x, y + 1
|
61
|
+
|
62
|
+
[(d2 - d1) / @scale, (d3 - d0) / @scale]
|
63
|
+
end
|
64
|
+
|
65
|
+
# Get the normal at a given point.
|
66
|
+
# @return [Float, Float] normal_x, normal_y
|
67
|
+
def sample_normal(x, y)
|
68
|
+
gradient_x, gradient_y = sample_gradient x, y
|
69
|
+
length = Gosu::distance 0, 0, gradient_x, gradient_y
|
70
|
+
if length == 0
|
71
|
+
[0, 0] # This could be NaN in edge cases.
|
72
|
+
else
|
73
|
+
[gradient_x / length, gradient_y / length]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Does the point x1, x2 have line of sight to x2, y2 (that is, no solid in the way).
|
78
|
+
def line_of_sight?(x1, y1, x2, y2)
|
79
|
+
!line_of_sight_blocked_at(x1, y1, x2, y2)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns blocking position, else nil if line of sight isn't blocked.
|
83
|
+
def line_of_sight_blocked_at(x1, y1, x2, y2)
|
84
|
+
distance_to_travel = Gosu::distance x1, y1, x2, y2
|
85
|
+
distance_x, distance_y = x2 - x1, y2 - y1
|
86
|
+
distance_travelled = 0
|
87
|
+
x, y = x1, y1
|
88
|
+
|
89
|
+
loop do
|
90
|
+
distance = sample_distance x, y
|
91
|
+
|
92
|
+
# Blocked?
|
93
|
+
return [x, y] if distance <= 0
|
94
|
+
|
95
|
+
distance_travelled += distance
|
96
|
+
|
97
|
+
# Got to destination in the clear.
|
98
|
+
return nil if distance_travelled >= distance_to_travel
|
99
|
+
|
100
|
+
lerp = distance_travelled.fdiv distance_to_travel
|
101
|
+
x = x1 + distance_x * lerp
|
102
|
+
y = y1 + distance_y * lerp
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Update the SDF should the image have changed.
|
107
|
+
# Draw the mask in the passed block.
|
108
|
+
def render_field
|
109
|
+
raise ArgumentError, "Block required" unless block_given?
|
110
|
+
|
111
|
+
@mask.render do
|
112
|
+
@mask.clear
|
113
|
+
$window.scale 1.0 / @scale do
|
114
|
+
yield self
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
@shader.enable do
|
119
|
+
@field.render do
|
120
|
+
@mask.draw 0, 0, 0
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
nil
|
125
|
+
end
|
126
|
+
|
127
|
+
# Draw the field, usually for debugging purposes.
|
128
|
+
# @see Ashton::Texture#draw
|
129
|
+
def draw(x, y, z, options = {})
|
130
|
+
options = {
|
131
|
+
mode: :add,
|
132
|
+
}.merge! options
|
133
|
+
|
134
|
+
$window.scale @scale do
|
135
|
+
@field.draw x, y, z, options
|
136
|
+
end
|
137
|
+
|
138
|
+
nil
|
139
|
+
end
|
140
|
+
|
141
|
+
# Convert into a nested array of sample values.
|
142
|
+
# @return [Array<Array<Integer>>]
|
143
|
+
def to_a
|
144
|
+
width.times.map do |x|
|
145
|
+
height.times.map do |y|
|
146
|
+
sample_distance x, y
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|