ashton 0.0.1alpha → 0.0.2alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. data/LICENSE +21 -21
  2. data/README.md +95 -68
  3. data/Rakefile +41 -23
  4. data/examples/bloom_example.rb +59 -0
  5. data/examples/lighting_example.rb +127 -0
  6. data/examples/media/SmallStar.png +0 -0
  7. data/examples/media/Starfighter.png +0 -0
  8. data/examples/media/simple.png +0 -0
  9. data/examples/noise_example.rb +94 -0
  10. data/examples/outline_example.rb +86 -0
  11. data/examples/particle_emitter_example.rb +114 -0
  12. data/examples/pixelate_example.rb +51 -49
  13. data/examples/pixelated_texture_example.rb +69 -0
  14. data/examples/radial_blur_example.rb +60 -62
  15. data/examples/shader_image_example.rb +74 -41
  16. data/examples/{shockwave2_example.rb → shockwave_example.rb} +74 -75
  17. data/examples/stencil_shader_example.rb +104 -0
  18. data/examples/{framebuffer_example.rb → texture_render_example.rb} +53 -49
  19. data/examples/{tv_screen_and_noise_example.rb → tv_screen_and_static_example.rb} +59 -59
  20. data/ext/ashton/GLee.c +18170 -0
  21. data/ext/ashton/GLee.h +17647 -0
  22. data/ext/ashton/ashton.c +42 -0
  23. data/ext/ashton/ashton.h +31 -0
  24. data/ext/ashton/color.c +45 -0
  25. data/ext/ashton/color.h +25 -0
  26. data/ext/ashton/common.h +41 -0
  27. data/ext/ashton/extconf.rb +42 -0
  28. data/ext/ashton/fast_math.c +30 -0
  29. data/ext/ashton/fast_math.h +30 -0
  30. data/ext/ashton/font.c +8 -0
  31. data/ext/ashton/font.h +16 -0
  32. data/ext/ashton/gosu.c +18 -0
  33. data/ext/ashton/gosu.h +19 -0
  34. data/ext/ashton/image.c +8 -0
  35. data/ext/ashton/image.h +16 -0
  36. data/ext/ashton/particle_emitter.c +788 -0
  37. data/ext/ashton/particle_emitter.h +171 -0
  38. data/ext/ashton/pixel_cache.c +237 -0
  39. data/ext/ashton/pixel_cache.h +58 -0
  40. data/ext/ashton/shader.c +9 -0
  41. data/ext/ashton/shader.h +16 -0
  42. data/ext/ashton/texture.c +442 -0
  43. data/ext/ashton/texture.h +63 -0
  44. data/ext/ashton/window.c +8 -0
  45. data/ext/ashton/window.h +16 -0
  46. data/lib/ashton.rb +38 -26
  47. data/lib/ashton/1.9/ashton.so +0 -0
  48. data/lib/ashton/gosu_ext/color.rb +24 -11
  49. data/lib/ashton/gosu_ext/font.rb +58 -0
  50. data/lib/ashton/gosu_ext/gosu_module.rb +16 -0
  51. data/lib/ashton/gosu_ext/image.rb +95 -31
  52. data/lib/ashton/gosu_ext/window.rb +78 -35
  53. data/lib/ashton/image_stub.rb +32 -36
  54. data/lib/ashton/lighting/light_source.rb +146 -0
  55. data/lib/ashton/lighting/manager.rb +98 -0
  56. data/lib/ashton/mixins/version_checking.rb +23 -0
  57. data/lib/ashton/particle_emitter.rb +87 -0
  58. data/lib/ashton/pixel_cache.rb +24 -0
  59. data/lib/ashton/shader.rb +353 -35
  60. data/lib/ashton/shaders/bloom.frag +41 -0
  61. data/lib/ashton/shaders/color_inversion.frag +11 -0
  62. data/lib/ashton/{post_process → shaders}/contrast.frag +16 -16
  63. data/lib/ashton/{shader → shaders}/default.frag +22 -19
  64. data/lib/ashton/{shader → shaders}/default.vert +13 -13
  65. data/lib/ashton/shaders/fade.frag +14 -0
  66. data/lib/ashton/shaders/grayscale.frag +15 -0
  67. data/lib/ashton/shaders/include/classicnoise2d.glsl +113 -0
  68. data/lib/ashton/shaders/include/classicnoise3d.glsl +177 -0
  69. data/lib/ashton/shaders/include/classicnoise4d.glsl +302 -0
  70. data/lib/ashton/{include/simplex.glsl → shaders/include/noise2d.glsl} +70 -63
  71. data/lib/ashton/shaders/include/noise3d.glsl +102 -0
  72. data/lib/ashton/shaders/include/noise4d.glsl +128 -0
  73. data/lib/ashton/shaders/include/rand.glsl +5 -0
  74. data/lib/ashton/shaders/lighting/distort.frag +57 -0
  75. data/lib/ashton/shaders/lighting/draw_shadows.frag +60 -0
  76. data/lib/ashton/shaders/lighting/shadow_blur.frag +60 -0
  77. data/lib/ashton/shaders/mezzotint.frag +22 -0
  78. data/lib/ashton/shaders/multitexture2.vert +19 -0
  79. data/lib/ashton/shaders/outline.frag +45 -0
  80. data/lib/ashton/{post_process → shaders}/pixelate.frag +48 -48
  81. data/lib/ashton/shaders/radial_blur.frag +63 -0
  82. data/lib/ashton/shaders/sepia.frag +26 -0
  83. data/lib/ashton/{post_process/shockwave2.frag → shaders/shockwave.frag} +38 -35
  84. data/lib/ashton/shaders/signed_distance_field.frag +80 -0
  85. data/lib/ashton/{post_process/noise.frag → shaders/static.frag} +25 -27
  86. data/lib/ashton/shaders/stencil.frag +27 -0
  87. data/lib/ashton/shaders/tv_screen.frag +23 -0
  88. data/lib/ashton/signed_distance_field.rb +151 -0
  89. data/lib/ashton/texture.rb +186 -0
  90. data/lib/ashton/version.rb +2 -2
  91. data/lib/ashton/window_buffer.rb +16 -0
  92. data/spec/ashton/ashton_spec.rb +22 -0
  93. data/spec/ashton/gosu_ext/color_spec.rb +34 -0
  94. data/spec/ashton/gosu_ext/font_spec.rb +57 -0
  95. data/spec/ashton/gosu_ext/gosu_spec.rb +11 -0
  96. data/spec/ashton/gosu_ext/image_spec.rb +66 -0
  97. data/spec/ashton/gosu_ext/window_spec.rb +71 -0
  98. data/spec/ashton/image_stub_spec.rb +46 -0
  99. data/spec/ashton/particle_emitter_spec.rb +123 -0
  100. data/spec/ashton/pixel_cache_spec.rb +153 -0
  101. data/spec/ashton/shader_spec.rb +152 -0
  102. data/spec/ashton/signed_distance_field_spec.rb +163 -0
  103. data/spec/ashton/texture_spec.rb +347 -0
  104. data/spec/helper.rb +12 -0
  105. metadata +159 -28
  106. data/examples/output/README.txt +0 -1
  107. data/lib/ashton/base_shader.rb +0 -172
  108. data/lib/ashton/framebuffer.rb +0 -183
  109. data/lib/ashton/post_process.rb +0 -83
  110. data/lib/ashton/post_process/default.vert +0 -9
  111. data/lib/ashton/post_process/fade.frag +0 -11
  112. data/lib/ashton/post_process/mezzotint.frag +0 -24
  113. data/lib/ashton/post_process/radial_blur.frag +0 -31
  114. data/lib/ashton/post_process/sepia.frag +0 -19
  115. data/lib/ashton/post_process/shockwave.frag +0 -40
  116. data/lib/ashton/post_process/tv_screen.frag +0 -32
@@ -1,27 +1,25 @@
1
- #version 110
2
-
3
- // Rather poor quality noise generation, but better than nothing and sort of looks like TV static a bit.
4
-
5
- uniform sampler2D in_Texture;
6
-
7
- uniform int in_WindowWidth; // Not used.
8
- uniform int in_WindowHeight; // Not used.
9
-
10
- uniform float in_Intensity;
11
- uniform float in_T;
12
-
13
- varying vec2 var_TexCoord;
14
-
15
- float rand(vec2 co) {
16
- return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);
17
- }
18
-
19
- void main() {
20
- vec4 color = texture2D(in_Texture, var_TexCoord);
21
-
22
- vec4 influence = min(color, 1.0 - color);
23
-
24
- float noise = 1.0 - 2.0 * rand(var_TexCoord + float(in_T));
25
-
26
- gl_FragColor = color + in_Intensity * influence * noise;
27
- }
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
@@ -0,0 +1,186 @@
1
+ module Ashton
2
+ class Texture
3
+ include Mixins::VersionChecking
4
+
5
+ DEFAULT_DRAW_COLOR = Gosu::Color::WHITE
6
+ VALID_DRAW_MODES = [:alpha_blend, :add, :multiply, :replace]
7
+
8
+ class << self
9
+ # [Boolean] Whether or not to pixelate (rather than smooth) on #draw
10
+ attr_writer :pixelated
11
+ # [Boolean] Whether or not to pixelate (rather than smooth) on #draw. Set true when Gosu::enable_undocumented_retrofication called.
12
+ def pixelated?; @pixelated end
13
+ end
14
+ self.pixelated = false
15
+
16
+ # [Boolean] Is this texture being rendered to currently?
17
+ def rendering?; @rendering end
18
+
19
+ # @overload initialize(image)
20
+ # Create a texture from a Gosu::Image
21
+ #
22
+ # @see Image#to_texture
23
+ # @param image [Gosu::Image]
24
+ #
25
+ # @overload initialize(blob, width, height)
26
+ # Create a texture from a binary blob.
27
+ #
28
+ # @param blob [String]
29
+ # @param width [Integer]
30
+ # @param height [Integer]
31
+ #
32
+ # @overload initialize(width, height)
33
+ # Create a blank (transparent) texture.
34
+ #
35
+ # @param width [Integer]
36
+ # @param height [Integer]
37
+ def initialize(*args)
38
+ case args.size
39
+ when 1
40
+ # Create from Gosu::Image
41
+ image = args[0]
42
+ raise TypeError, "Expected Gosu::Image" unless image.is_a? Gosu::Image
43
+ initialize_ image.width, image.height, nil
44
+
45
+ render do
46
+ # TODO: Ideally we'd draw the image in replacement mode, but Gosu doesn't support that.
47
+ $window.gl do
48
+ info = image.gl_tex_info
49
+ glEnable GL_TEXTURE_2D
50
+ glBindTexture GL_TEXTURE_2D, info.tex_name
51
+ glEnable GL_BLEND
52
+ glBlendFunc GL_ONE, GL_ZERO
53
+
54
+ glBegin GL_QUADS do
55
+ glTexCoord2d info.left, info.top
56
+ glVertex2d 0, height # BL
57
+
58
+ glTexCoord2d info.left, info.bottom
59
+ glVertex2d 0, 0 # TL
60
+
61
+ glTexCoord2d info.right, info.bottom
62
+ glVertex2d width, 0 # TR
63
+
64
+ glTexCoord2d info.right, info.top
65
+ glVertex2d width, height # BR
66
+ end
67
+ end
68
+ end
69
+
70
+ when 2
71
+ # Create blank image.
72
+ width, height = *args
73
+ initialize_ width, height, nil
74
+ clear
75
+
76
+ when 3
77
+ # Create from blob - create a Gosu image first.
78
+ blob, width, height = *args
79
+ raise ArgumentError, "Blob data is not of expected size" if blob.length != width * height * 4
80
+ initialize_ width, height, blob
81
+
82
+ else
83
+ raise ArgumentError, "Expected 1, 2 or 3 parameters."
84
+ end
85
+
86
+ @rendering = false
87
+ end
88
+
89
+ public
90
+ # Clears the buffer, optionally to a specific color.
91
+ #
92
+ # @option options :color [Gosu::Color, Array<Float>] (transparent)
93
+ def clear(options = {})
94
+ options = {
95
+ color: [0.0, 0.0, 0.0, 0.0],
96
+ }.merge! options
97
+
98
+ color = options[:color]
99
+ color = color.to_opengl if color.is_a? Gosu::Color
100
+
101
+ glBindFramebufferEXT GL_FRAMEBUFFER_EXT, fbo_id unless rendering?
102
+
103
+ glDisable GL_BLEND # Need to replace the alpha too.
104
+ glClearColor *color
105
+ glClear GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
106
+ glEnable GL_BLEND
107
+
108
+ glBindFramebufferEXT GL_FRAMEBUFFER_EXT, 0 unless rendering?
109
+
110
+ nil
111
+ end
112
+
113
+ public
114
+ # Enable the texture to use (e.g. to draw or convert it).
115
+ def render
116
+ raise ArgumentError, "Block required" unless block_given?
117
+ raise Error, "Can't nest rendering" if rendering?
118
+
119
+ $window.flush # Ensure that any drawing _before_ the render block is drawn to screen, rather than into the buffer.
120
+
121
+ render_
122
+
123
+ @rendering = true
124
+
125
+ # Project onto the texture itself, using Gosu (inverted) coordinates.
126
+ glPushMatrix
127
+ glMatrixMode GL_PROJECTION
128
+ glLoadIdentity
129
+ glViewport 0, 0, width, height
130
+ glOrtho 0, width, height, 0, -1, 1
131
+
132
+ begin
133
+ yield self
134
+ ensure
135
+ $window.flush # Force all the drawing to draw now!
136
+ glBindFramebufferEXT GL_FRAMEBUFFER_EXT, 0
137
+
138
+ @rendering = false
139
+
140
+ glPopMatrix
141
+
142
+ cache.refresh # Force lazy reloading of the cache.
143
+ end
144
+
145
+ self
146
+ end
147
+
148
+ # @!method draw(x, y, z, options = {})
149
+ # Draw the Texture.
150
+ #
151
+ # This is not as versatile as converting the Texture into a Gosu::Image and then
152
+ # drawing it, but it is many times faster, so use it when you are updating the buffer
153
+ # every frame, rather than just composing an image.
154
+ #
155
+ # Drawing in Gosu orientation will be flipped in standard OpenGL and visa versa.
156
+ #
157
+ # @param x [Number] Top left corner x.
158
+ # @param y [Number] Top left corner y.
159
+ # @param z [Number] Z-order (can be nil to draw immediately)
160
+ #
161
+ # @option options :shader [Ashton::Shader] Shader to apply to drawing.
162
+ # @option options :color [Gosu::Color] (Gosu::Color::WHITE) Color to apply to the drawing.
163
+ # @option options :mode [Symbol] (:alpha_blend) :alpha_blend, :add, :multiply, :replace
164
+ # @option options :multitexture [Texture] A texture to be used in a multi-texturing shader.
165
+ # @option options :pixelated [Boolean] (true if Gosu::enable_undocumented_retrofication ever called) Pixelate, rather than smooth, when zoomed out.
166
+
167
+ public
168
+ # Convert the current contents of the buffer into a Gosu::Image
169
+ #
170
+ # @option options :caching [Boolean] (true) TexPlay behaviour.
171
+ # @option options :tileable [Boolean] (false) Standard Gosu behaviour.
172
+ # @option options :rect [Array<Integer>] ([0, 0, width, height]) Rectangular area of buffer to use to create the image [x, y, w, h]
173
+ def to_image(*args)
174
+ cache.to_image *args
175
+ end
176
+
177
+ def dup
178
+ # Create a new texture and draw self into it.
179
+ new_texture = Texture.new width, height
180
+ new_texture.render do
181
+ draw 0, 0, 0, mode: :replace
182
+ end
183
+ new_texture
184
+ end
185
+ end
186
+ end
@@ -1,3 +1,3 @@
1
- module Ashton
2
- VERSION = "0.0.1alpha"
1
+ module Ashton
2
+ VERSION = "0.0.2alpha"
3
3
  end