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
data/lib/ashton/shader.rb CHANGED
@@ -1,62 +1,380 @@
1
- require "ashton/base_shader"
2
-
3
1
  module Ashton
4
- class Shader < BaseShader
5
- attr_reader :image
2
+ class Shader
3
+ include Mixins::VersionChecking
4
+
5
+ INVALID_LOCATION = -1
6
+ MIN_OPENGL_VERSION = 2.0 # For GLSL 1.10
6
7
 
7
- shader_path = File.expand_path "../shader", __FILE__
8
- DEFAULT_VERTEX_SOURCE = File.read File.join(shader_path, "default.vert")
9
- DEFAULT_FRAGMENT_SOURCE = File.read File.join(shader_path, "default.frag")
8
+ INCLUDE_PATH = File.expand_path "../shaders/include", __FILE__
9
+ BUILT_IN_SHADER_PATH = File.expand_path "../shaders", __FILE__
10
+ FRAGMENT_EXTENSION = ".frag"
11
+ VERTEX_EXTENSION = ".vert"
12
+
13
+ # List of built-in functions.
14
+ BUILT_IN_FUNCTIONS = Dir[File.join(INCLUDE_PATH, "*.glsl")].map do |filename|
15
+ filename =~ /(\w+)\.glsl/
16
+ $1.to_sym
17
+ end
10
18
 
11
- # Todo: Pass in a filename (String) or name of built-in pp shader (Symbol)
19
+ attr_reader :vertex_source, :fragment_source
20
+
21
+ # Is the shader currently in use?
22
+ def enabled?; !!@previous_program end
23
+ # Is this the currently activated shader program?
24
+ def current?; glGetIntegerv(GL_CURRENT_PROGRAM) == @program end
25
+
26
+ # Instead of passing in source code, a file-name will be loaded or use a symbol to choose a built-in shader.
27
+ #
28
+ # `#include` will be recursively replaced in the source.
12
29
  #
13
- # @option options [String] :vertex Source code for vertex shader.
14
- # @option options [String] :vert equivalent to :vertex
15
- # @option options [String] :fragment Source code for fragment shader.
16
- # @option options [String] :frag equivalent to :fragment
30
+ # * `#include <noise>` will load the built-in shader function, shaders/include/noise.glsl
31
+ # * `#include "/home/spooner/noise.glsl"` will include that file, relative to the current working directory, NOT the source file.
32
+ #
33
+ # @option options :vertex [String, Symbol] (:default) Source code for vertex shader.
34
+ # @option options :vert [String, Symbol] (:default) Equivalent to :vertex
35
+ # @option options :fragment [String, Symbol] (:default) Source code for fragment shader.
36
+ # @option options :frag [String, Symbol] (:default) Equivalent to :fragment
37
+ # @option options :uniforms [Hash] Sets uniforms, as though calling shader[key] = value for each entry (but faster).
17
38
  def initialize(options = {})
18
- @image = nil
39
+ check_opengl_version MIN_OPENGL_VERSION
19
40
 
20
- vertex_source = options[:vertex] || options[:vert] || DEFAULT_VERTEX_SOURCE
21
- fragment_source = options[:fragment] || options[:frag] || DEFAULT_FRAGMENT_SOURCE
41
+ vertex = options[:vertex] || options[:vert] || :default
42
+ fragment = options[:fragment] || options[:frag] || :default
22
43
 
23
- super vertex_source, fragment_source
24
- link
44
+ @vertex_source = process_source vertex, VERTEX_EXTENSION
45
+ @fragment_source = process_source fragment, FRAGMENT_EXTENSION
25
46
 
47
+ @uniform_locations = {}
48
+ @attribute_locations = {}
49
+ @program = nil
50
+ @image = nil
26
51
  @color = [1, 1, 1, 1]
52
+
53
+ # Actually compile and link.
54
+ @vertex = compile GL_VERTEX_SHADER, @vertex_source
55
+ @fragment = compile GL_FRAGMENT_SHADER, @fragment_source
56
+ link
57
+
58
+ # In case we are using '#version 130' or higher, set out own color output.
59
+ begin
60
+ glBindFragDataLocationEXT @program, 0, "out_FragColor"
61
+ rescue NotImplementedError
62
+ # Might fail on an old system, but they will be fine just running GLSL 1.10 or 1.20
63
+ end
64
+
65
+ enable do
66
+ # GL_TEXTURE0 will be activated later. This is the main image texture.
67
+ set_uniform uniform_location("in_Texture", required: false), 0
68
+
69
+ # For multi-textured shaders, we use in_Texture<NUM> instead.
70
+ set_uniform uniform_location("in_Texture0", required: false), 0
71
+ set_uniform uniform_location("in_Texture1", required: false), 1
72
+
73
+ # These are optional, and can be used to check pixel size.
74
+ set_uniform uniform_location("in_WindowWidth", required: false), $window.width
75
+ set_uniform uniform_location("in_WindowHeight", required: false), $window.height
76
+
77
+ # Set uniform values with :uniforms hash.
78
+ if options.has_key? :uniforms
79
+ options[:uniforms].each_pair do |uniform, value|
80
+ self[uniform] = value
81
+ end
82
+ end
83
+ end
27
84
  end
28
85
 
29
- def image=(image)
30
- use do
31
- if image
32
- info = image.gl_tex_info
33
-
34
- # Bind the single texture to 'in_Texture'
35
- glActiveTexture GL_TEXTURE0
36
- glBindTexture GL_TEXTURE_2D, info.tex_name
37
- self["in_Texture"] = 0
38
- raise unless glGetIntegerv(GL_ACTIVE_TEXTURE) == GL_TEXTURE0
39
-
40
- # Ensure that the shader knows to use the texture.
41
- self["in_TextureEnabled"] = true
42
- else
86
+ protected
87
+ # Converts :frog_head to "in_FrogHead"
88
+ def uniform_name_from_symbol(uniform)
89
+ "in_#{uniform.to_s.split("_").map(&:capitalize).join}"
90
+ end
91
+
92
+ public
93
+ # Creates a copy of the shader program, recompiling the source,
94
+ # but not preserving the uniform values.
95
+ def dup
96
+ self.class.new :vertex => @vertex_source, :fragment => @fragment_source
97
+ end
98
+
99
+ public
100
+ # Make this the current shader program. Use with a block or, alternatively, use #enable and #disable separately.
101
+ def enable(z = nil)
102
+ $window.gl z do
103
+ raise ShaderError, "This shader already enabled." if enabled?
104
+ current_shader = glGetIntegerv GL_CURRENT_PROGRAM
105
+ raise ShaderError, "Another shader already enabled." if current_shader > 0
106
+
107
+ @previous_program = current_shader
108
+ glUseProgram @program
109
+ end
110
+
111
+ result = nil
112
+
113
+ if block_given?
114
+ begin
115
+ result = yield self
116
+ ensure
117
+ disable z
118
+ end
119
+ end
120
+
121
+ result
122
+ end
123
+
124
+ # Disable the shader program. Only required if using #enable without a block.
125
+ def disable(z = nil)
126
+ $window.gl z do
127
+ raise ShaderError, "Shader not enabled." unless enabled?
128
+ glUseProgram @previous_program # Disable the shader!
129
+ @previous_program = nil
130
+ end
131
+
132
+ nil
133
+ end
134
+
135
+ public
136
+ # Allow
137
+ # `shader.blob_frequency = 5`
138
+ # to map to
139
+ # `shader["in_BlobFrequency"] = 5`
140
+ # TODO: define specific methods at compile time, based on parsing the source?
141
+ def method_missing(meth, *args, &block)
142
+ if args.size == 1 and meth =~ /^(.+)=$/
143
+ self[$1.to_sym] = args[0]
144
+ else
145
+ super meth, *args, &block
146
+ end
147
+ end
148
+
149
+ public
150
+ # Set the value of a uniform.
151
+ #
152
+ # @param uniform [String, Symbol] If a Symbol, :frog_paste is looked up as "in_FrogPaste", otherwise the Sting is used directly.
153
+ # @param value [Any] Value to set the uniform to
154
+ #
155
+ # @raise ShaderUniformError unless requested uniform is defined in vertex or fragment shaders.
156
+ def []=(uniform, value)
157
+ uniform = uniform_name_from_symbol(uniform) if uniform.is_a? Symbol
158
+
159
+ # Ensure that the program is current before setting values.
160
+ needs_use = !current?
161
+ enable if needs_use
162
+ set_uniform uniform_location(uniform), value
163
+ disable if needs_use
164
+
165
+ value
166
+ end
167
+
168
+ protected
169
+ # Set uniform without trying to force use of the program.
170
+ def set_uniform(location, value)
171
+ raise ShaderUniformError, "Shader uniform #{location.inspect} could not be set, since shader is not current" unless current?
172
+
173
+ return if location == INVALID_LOCATION # Not for end-users :)
174
+
175
+ case value
176
+ when true, GL_TRUE
177
+ glUniform1i location, 1
178
+
179
+ when false, GL_FALSE
180
+ glUniform1i location, 0
181
+
182
+ when Float
43
183
  begin
44
- self["in_TextureEnabled"] = false
184
+ glUniform1f location, value
45
185
  rescue
186
+ glUniform1i location, value.to_i
46
187
  end
188
+
189
+ when Integer
190
+ begin
191
+ glUniform1i location, value
192
+ rescue
193
+ glUniform1f location, value.to_f
194
+ end
195
+
196
+ when Gosu::Color
197
+ glUniform4f location, *value.to_opengl
198
+
199
+ when Array
200
+ size = value.size
201
+
202
+ raise ArgumentError, "Empty array not supported for uniform data" if size.zero?
203
+ raise ArgumentError, "Only support uniforms up to 4 elements" if size > 4
204
+
205
+ case value[0]
206
+ when Float
207
+ begin
208
+ GL.send "glUniform#{size}f", location, *value.map(&:to_f)
209
+ rescue
210
+ GL.send "glUniform#{size}i", location, *value.map(&:to_i)
211
+ end
212
+
213
+ when Integer
214
+ begin
215
+ GL.send "glUniform#{size}i", location, *value.map(&:to_i)
216
+ rescue
217
+ GL.send "glUniform#{size}f", location, *value.map(&:to_f)
218
+ end
219
+
220
+ else
221
+ raise ArgumentError, "Uniform data type not supported for element of type: #{value[0].class}"
222
+ end
223
+
224
+ else
225
+ raise ArgumentError, "Uniform data type not supported for type: #{value.class}"
226
+ end
227
+
228
+ value
229
+ end
230
+
231
+ protected
232
+ def uniform_location(name, options = {})
233
+ options = {
234
+ required: true
235
+ }.merge! options
236
+
237
+ location = @uniform_locations[name]
238
+ if location
239
+ location
240
+ else
241
+ location = glGetUniformLocation @program, name.to_s
242
+ if options[:required] && location == INVALID_LOCATION
243
+ raise ShaderUniformError, "No #{name.inspect} uniform specified in program"
47
244
  end
245
+ @uniform_locations[name] = location
48
246
  end
247
+ end
248
+
249
+ public
250
+ def image=(image)
251
+ raise ShaderError, "Can't set image unless using shader" unless current?
252
+
253
+ if image
254
+ info = image.gl_tex_info
255
+
256
+ glActiveTexture GL_TEXTURE0
257
+ glBindTexture GL_TEXTURE_2D, info.tex_name
258
+ end
259
+
260
+ set_uniform uniform_location("in_TextureEnabled", required: false), !!image
49
261
 
50
262
  @image = image
51
263
  end
52
264
 
265
+ public
53
266
  def color=(color)
54
- raise unless current?
267
+ opengl_color = case color
268
+ when Gosu::Color
269
+ color.to_opengl
270
+ when Integer
271
+ Gosu::Color.new(color).to_opengl
272
+ when Array
273
+ color
274
+ else
275
+ raise TypeError, "Expected Gosu::Color, Integer or opengl float array for color"
276
+ end
55
277
 
56
- opengl_color = color.is_a?(Gosu::Color) ? color.to_opengl : color
278
+ needs_use = !current?
279
+ enable if needs_use
280
+ location = glGetAttribLocation @program, "in_Color"
281
+ glVertexAttrib4f location, *opengl_color unless location == INVALID_LOCATION
282
+ disable if needs_use
57
283
 
58
- glVertexAttrib4f attribute("in_Color"), *opengl_color
59
284
  @color = opengl_color
60
285
  end
286
+
287
+ protected
288
+ def attribute(name)
289
+ location = @attribute_locations[name]
290
+ if location
291
+ location
292
+ else
293
+ location = glGetAttribLocation @program, name.to_s
294
+ raise ShaderAttributeError, "No #{name} attribute specified in program" if location == INVALID_LOCATION
295
+ @attribute_locations[name] = location
296
+ end
297
+ end
298
+
299
+ protected
300
+ def compile(type, source)
301
+ shader = glCreateShader type
302
+ glShaderSource shader, source
303
+ glCompileShader shader
304
+
305
+ unless glGetShaderiv shader, GL_COMPILE_STATUS
306
+ error = glGetShaderInfoLog shader
307
+ error_lines = error.scan(/0\((\d+)\)+/m).map {|num| num.first.to_i }.uniq
308
+
309
+ if type == GL_VERTEX_SHADER
310
+ type_name = "Vertex"
311
+ source = @vertex_source
312
+ else
313
+ type_name = "Fragment"
314
+ source = @fragment_source
315
+ end
316
+
317
+ source_lines = source.split("\n")
318
+ lines = error_lines.map {|i| "#{i.to_s.rjust 3}: #{source_lines[i - 1].rstrip}" }.join "\n"
319
+ raise ShaderCompileError, "#{type_name} shader error: #{glGetShaderInfoLog(shader)}\n#{lines}"
320
+ end
321
+
322
+ shader
323
+ end
324
+
325
+ protected
326
+ def link
327
+ @program = glCreateProgram
328
+ glAttachShader @program, @vertex
329
+ glAttachShader @program, @fragment
330
+ glLinkProgram @program
331
+
332
+ unless glGetProgramiv @program, GL_LINK_STATUS
333
+ raise ShaderLinkError, "Shader link error: #{glGetProgramInfoLog(@program)}"
334
+ end
335
+
336
+ nil
337
+ end
338
+
339
+ protected
340
+ # Symbol => load a built-in
341
+ # Filename => load file
342
+ # Source => use directly.
343
+ #
344
+ # Also recursively replaces #include
345
+ # TODO: What about line numbers getting messed up by #include?
346
+ def process_source(shader, extension)
347
+ source = if shader.is_a? Symbol
348
+ file = File.expand_path "#{shader}#{extension}", BUILT_IN_SHADER_PATH
349
+ unless File.exists? file
350
+ raise ShaderLoadError, "Failed to load built-in shader: #{shader.inspect}"
351
+ end
352
+ File.read file
353
+
354
+ elsif File.exists? shader
355
+ File.read shader
356
+ else
357
+ shader
358
+ end
359
+
360
+ replace_include source
361
+ end
362
+
363
+ protected
364
+ # Recursively replace #include.
365
+ #
366
+ # * Replace '#include <rand>' with the contents of include/rand.glsl
367
+ # * Replace '#include "/home/spooner/my_shader_functions/frog.glsl"' with the contents of that file.
368
+ #
369
+ # @return [String] Source code that has been expanded.
370
+ def replace_include(source)
371
+ source.gsub! /^#include\s+<([^>]*)>/ do
372
+ replace_include File.read(File.expand_path("#{$1}.glsl", INCLUDE_PATH))
373
+ end
374
+
375
+ source.gsub /^#include\s+"([^"]*)"/ do
376
+ replace_include File.read($1)
377
+ end
378
+ end
61
379
  end
62
380
  end
@@ -0,0 +1,41 @@
1
+ #version 110
2
+
3
+ // Bloom filter
4
+ // http://myheroics.wordpress.com/2008/09/04/glsl-bloom-shader/
5
+ //
6
+ // Spooner: Added uniforms for setting bloom intensity.
7
+
8
+ uniform sampler2D in_Texture; // Original in_Texture.
9
+ varying vec2 var_TexCoord; // Pixel to process on this pass
10
+
11
+ uniform float in_GlareSize; // 0.004 is good
12
+ uniform float in_Power; // 0.25 is good
13
+
14
+ void main()
15
+ {
16
+ vec4 sum = vec4(0);
17
+ int i, j;
18
+
19
+ for(i = -4; i < 4; i++)
20
+ {
21
+ for (j = -3; j < 3; j++)
22
+ {
23
+ sum += texture2D(in_Texture, var_TexCoord + vec2(j, i) * in_GlareSize) * in_Power;
24
+ }
25
+ }
26
+
27
+ vec4 base_color = texture2D(in_Texture, var_TexCoord);
28
+
29
+ if (base_color.r < 0.3)
30
+ {
31
+ gl_FragColor = sum * sum * 0.012 + base_color;
32
+ }
33
+ else if(base_color.r < 0.5)
34
+ {
35
+ gl_FragColor = sum * sum * 0.009 + base_color;
36
+ }
37
+ else
38
+ {
39
+ gl_FragColor = sum * sum * 0.0075 + base_color;
40
+ }
41
+ }