Class: Ashton::Shader
- Inherits:
-
Object
- Object
- Ashton::Shader
- Includes:
- Mixins::VersionChecking
- Defined in:
- lib/ashton/shader.rb
Constant Summary collapse
- INVALID_LOCATION =
-1
- MIN_OPENGL_VERSION =
For GLSL 1.10
2.0
- INCLUDE_PATH =
File. "../shaders/include", __FILE__
- BUILT_IN_SHADER_PATH =
File. "../shaders", __FILE__
- FRAGMENT_EXTENSION =
".frag"
- VERTEX_EXTENSION =
".vert"
- BUILT_IN_FUNCTIONS =
List of built-in functions.
Dir[File.join(INCLUDE_PATH, "*.glsl")].map do |filename| filename =~ /(\w+)\.glsl/ $1.to_sym end
Instance Attribute Summary collapse
-
#fragment_source ⇒ Object
readonly
Returns the value of attribute fragment_source.
-
#vertex_source ⇒ Object
readonly
Returns the value of attribute vertex_source.
Instance Method Summary collapse
-
#[]=(uniform, value) ⇒ Object
Set the value of a uniform.
- #color=(color) ⇒ Object
-
#current? ⇒ Boolean
Is this the currently activated shader program?.
-
#disable(z = nil) ⇒ Object
Disable the shader program.
-
#dup ⇒ Object
Creates a copy of the shader program, recompiling the source, but not preserving the uniform values.
-
#enable(z = nil) ⇒ Object
Make this the current shader program.
-
#enabled? ⇒ Boolean
Is the shader currently in use?.
- #image=(image) ⇒ Object
-
#initialize(options = {}) ⇒ Shader
constructor
Instead of passing in source code, a file-name will be loaded or use a symbol to choose a built-in shader.
-
#method_missing(meth, *args, &block) ⇒ Object
Allow ‘shader.blob_frequency = 5` to map to `shader = 5` TODO: define specific methods at compile time, based on parsing the source?.
Methods included from Mixins::VersionChecking
#check_opengl_extension, #check_opengl_version
Constructor Details
#initialize(options = {}) ⇒ Shader
Instead of passing in source code, a file-name will be loaded or use a symbol to choose a built-in shader.
‘#include` will be recursively replaced in the source.
-
‘#include <noise>` will load the built-in shader function, shaders/include/noise.glsl
-
‘#include “/home/spooner/noise.glsl”` will include that file, relative to the current working directory, NOT the source file.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/ashton/shader.rb', line 39 def initialize( = {}) check_opengl_version MIN_OPENGL_VERSION vertex = [:vertex] || [:vert] || :default fragment = [:fragment] || [:frag] || :default @vertex_source = process_source vertex, VERTEX_EXTENSION @fragment_source = process_source fragment, FRAGMENT_EXTENSION @uniform_locations = {} @attribute_locations = {} @program = nil @previous_program = nil @image = nil @color = [1, 1, 1, 1] # Actually compile and link. @vertex = compile Gl::GL_VERTEX_SHADER, @vertex_source @fragment = compile Gl::GL_FRAGMENT_SHADER, @fragment_source link # In case we are using '#version 130' or higher, set out own color output. begin Gl.glBindFragDataLocationEXT @program, 0, "out_FragColor" rescue NotImplementedError # Might fail on an old system, but they will be fine just running GLSL 1.10 or 1.20 end enable do # GL_TEXTURE0 will be activated later. This is the main image texture. set_uniform uniform_location("in_Texture", required: false), 0 # For multi-textured shaders, we use in_Texture<NUM> instead. set_uniform uniform_location("in_Texture0", required: false), 0 set_uniform uniform_location("in_Texture1", required: false), 1 # These are optional, and can be used to check pixel size. set_uniform uniform_location("in_WindowWidth", required: false), $window.width set_uniform uniform_location("in_WindowHeight", required: false), $window.height # Set uniform values with :uniforms hash. if .has_key? :uniforms [:uniforms].each_pair do |uniform, value| self[uniform] = value end end end end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(meth, *args, &block) ⇒ Object
Allow
`shader.blob_frequency = 5`
to map to
`shader["in_BlobFrequency"] = 5`
TODO: define specific methods at compile time, based on parsing the source?
144 145 146 147 148 149 150 |
# File 'lib/ashton/shader.rb', line 144 def method_missing(meth, *args, &block) if args.size == 1 and meth =~ /^(.+)=$/ self[$1.to_sym] = args[0] else super meth, *args, &block end end |
Instance Attribute Details
#fragment_source ⇒ Object (readonly)
Returns the value of attribute fragment_source.
19 20 21 |
# File 'lib/ashton/shader.rb', line 19 def fragment_source @fragment_source end |
#vertex_source ⇒ Object (readonly)
Returns the value of attribute vertex_source.
19 20 21 |
# File 'lib/ashton/shader.rb', line 19 def vertex_source @vertex_source end |
Instance Method Details
#[]=(uniform, value) ⇒ Object
Set the value of a uniform.
159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/ashton/shader.rb', line 159 def []=(uniform, value) uniform = uniform_name_from_symbol(uniform) if uniform.is_a? Symbol # Ensure that the program is current before setting values. needs_use = !current? enable if needs_use set_uniform uniform_location(uniform), value disable if needs_use value end |
#color=(color) ⇒ Object
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
# File 'lib/ashton/shader.rb', line 272 def color=(color) opengl_color = case color when Gosu::Color color.to_opengl when Integer Gosu::Color.new(color).to_opengl when Array color else raise TypeError, "Expected Gosu::Color, Integer or opengl float array for color" end needs_use = !current? enable if needs_use location = Gl.glGetAttribLocation @program, "in_Color" Gl.glVertexAttrib4f location, *opengl_color unless location == INVALID_LOCATION disable if needs_use @color = opengl_color end |
#current? ⇒ Boolean
Is this the currently activated shader program?
25 |
# File 'lib/ashton/shader.rb', line 25 def current?; Gl.glGetIntegerv(Gl::GL_CURRENT_PROGRAM) == @program end |
#disable(z = nil) ⇒ Object
Disable the shader program. Only required if using #enable without a block.
128 129 130 131 132 133 134 135 136 |
# File 'lib/ashton/shader.rb', line 128 def disable(z = nil) $window.gl z do raise ShaderError, "Shader not enabled." unless enabled? Gl.glUseProgram @previous_program # Disable the shader! @previous_program = nil end nil end |
#dup ⇒ Object
Creates a copy of the shader program, recompiling the source, but not preserving the uniform values.
98 99 100 |
# File 'lib/ashton/shader.rb', line 98 def dup self.class.new :vertex => @vertex_source, :fragment => @fragment_source end |
#enable(z = nil) ⇒ Object
Make this the current shader program. Use with a block or, alternatively, use #enable and #disable separately.
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/ashton/shader.rb', line 104 def enable(z = nil) $window.gl z do raise ShaderError, "This shader already enabled." if enabled? current_shader = Gl.glGetIntegerv GL::GL_CURRENT_PROGRAM raise ShaderError, "Another shader already enabled." if current_shader > 0 @previous_program = current_shader Gl.glUseProgram @program end result = nil if block_given? begin result = yield self ensure disable z end end result end |
#enabled? ⇒ Boolean
Is the shader currently in use?
22 |
# File 'lib/ashton/shader.rb', line 22 def enabled?; !!@previous_program end |
#image=(image) ⇒ Object
256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
# File 'lib/ashton/shader.rb', line 256 def image=(image) raise ShaderError, "Can't set image unless using shader" unless current? if image info = image.gl_tex_info Gl.glActiveTexture Gl::GL_TEXTURE0 Gl.glBindTexture Gl::GL_TEXTURE_2D, info.tex_name end set_uniform uniform_location("in_TextureEnabled", required: false), !!image @image = image end |