ashton 0.0.1alpha → 0.0.2alpha

Sign up to get free protection for your applications and to get access to all the features.
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
+ }