Class: SFML::Shader
- Inherits:
-
Object
- Object
- SFML::Shader
- Defined in:
- lib/sfml/graphics/shader.rb
Overview
A GLSL shader. Build one from a vertex and/or fragment source (either
a file path or a literal source string), then set uniforms with
bracket assignment and pass it to draw via the shader: kwarg:
shader = SFML::Shader.from_source(fragment: "uniform sampler2D texture;\nuniform float time;\nvoid main() {\n vec2 uv = gl_TexCoord[0].xy;\n uv.x += sin(uv.y * 20.0 + time * 3.0) * 0.02;\n gl_FragColor = texture2D(texture, uv) * gl_Color;\n}\n")
shader[:time] = clock.elapsed.as_seconds
window.draw(sprite, shader: shader)
Uniform types are inferred from the Ruby value:
Float / Integer / Numeric
Array uniforms (uniform vec2 positions[8]; and friends):
[[x, y], [x, y], ...]
Float arrays (uniform float weights[N];) are ambiguous with vec3
at length 3, so use the explicit #set_float_array setter.
Need an int / bvec / matrix uniform? Use #set_int, #set_ivec2,
etc. — they exist for completeness.
Instance Attribute Summary collapse
-
#handle ⇒ Object
readonly
:nodoc:.
Class Method Summary collapse
-
.available? ⇒ Boolean
Class-level: is GLSL available on the current GPU at all?.
-
.from_file(vertex: nil, geometry: nil, fragment: nil) ⇒ Object
Build a shader from one or more source files.
-
.from_source(vertex: nil, geometry: nil, fragment: nil) ⇒ Object
Build a shader directly from GLSL source strings.
-
.from_stream(vertex: nil, geometry: nil, fragment: nil) ⇒ Object
Build a shader from one or more IO-like streams (any object answering read/seek/pos/size).
-
.geometry_available? ⇒ Boolean
Returns the self.
-
.unbind ⇒ Object
Returns the self.
Instance Method Summary collapse
-
#[]=(name, value) ⇒ Object
Set a uniform by name.
-
#bind ⇒ Object
Bind this shader as the active GL program.
-
#native_handle ⇒ Object
The OpenGL program ID.
-
#set_bvec(name, *components) ⇒ Object
Set a
uniform bvec2/3/4from a Ruby Array of booleans. -
#set_float_array(name, values) ⇒ Object
Set a
uniform float arr[N];from a plain Ruby array of numbers. -
#set_int(name, value) ⇒ Object
Explicit integer setters when a uniform really is
uniform int n. -
#set_int_color(name, color) ⇒ Object
Set a
vec4uniform from an integer-channelSFML::Color(RGBA 0–255). -
#set_ivec2(name, x, y) ⇒ Object
Returns the ivec2.
-
#set_mat3(name, matrix) ⇒ Object
Set a
uniform mat3from a 9-element row-major float array (or an SFML::Transform — its 3×3 matrix is read directly). -
#set_mat3_array(name, matrices) ⇒ Object
Set a
uniform mat3 arr[N];/uniform mat4 arr[N];from a list of matrices (each a 9- or 16-element flat array, or an SFML::Transform for mat3). -
#set_mat4(name, matrix) ⇒ Object
Set a
uniform mat4from a 16-element row-major float array. -
#set_mat4_array(name, matrices) ⇒ Object
Returns the mat4 array.
Instance Attribute Details
#handle ⇒ Object (readonly)
:nodoc:
230 231 232 |
# File 'lib/sfml/graphics/shader.rb', line 230 def handle @handle end |
Class Method Details
.available? ⇒ Boolean
Class-level: is GLSL available on the current GPU at all?
44 45 46 |
# File 'lib/sfml/graphics/shader.rb', line 44 def self.available? C::Graphics.sfShader_isAvailable end |
.from_file(vertex: nil, geometry: nil, fragment: nil) ⇒ Object
Build a shader from one or more source files. Any of vertex / geometry / fragment may be omitted; at least one must be present.
55 56 57 58 59 60 61 62 |
# File 'lib/sfml/graphics/shader.rb', line 55 def self.from_file(vertex: nil, geometry: nil, fragment: nil) _check_at_least_one(vertex, geometry, fragment) ptr = C::Graphics.sfShader_createFromFile( vertex&.to_s, geometry&.to_s, fragment&.to_s, ) raise ShaderError, "sfShader_createFromFile failed (compile error or missing file?)" if ptr.null? _wrap(ptr) end |
.from_source(vertex: nil, geometry: nil, fragment: nil) ⇒ Object
Build a shader directly from GLSL source strings.
65 66 67 68 69 70 |
# File 'lib/sfml/graphics/shader.rb', line 65 def self.from_source(vertex: nil, geometry: nil, fragment: nil) _check_at_least_one(vertex, geometry, fragment) ptr = C::Graphics.sfShader_createFromMemory(vertex, geometry, fragment) raise ShaderError, "sfShader_createFromMemory failed (GLSL compile error?)" if ptr.null? _wrap(ptr) end |
.from_stream(vertex: nil, geometry: nil, fragment: nil) ⇒ Object
Build a shader from one or more IO-like streams (any object answering read/seek/pos/size). Useful when shader source lives inside an archive or a network resource.
75 76 77 78 79 80 81 82 |
# File 'lib/sfml/graphics/shader.rb', line 75 def self.from_stream(vertex: nil, geometry: nil, fragment: nil) _check_at_least_one(vertex, geometry, fragment) streams = [vertex, geometry, fragment].map { |io| io && SFML::InputStream.new(io) } ptrs = streams.map { |s| s ? s.to_ptr : nil } ptr = C::Graphics.sfShader_createFromStream(*ptrs) raise ShaderError, "sfShader_createFromStream failed (GLSL compile error?)" if ptr.null? _wrap(ptr) end |
.geometry_available? ⇒ Boolean
Returns the self.
49 50 51 |
# File 'lib/sfml/graphics/shader.rb', line 49 def self.geometry_available? C::Graphics.sfShader_isGeometryAvailable end |
.unbind ⇒ Object
Returns the self.
215 |
# File 'lib/sfml/graphics/shader.rb', line 215 def self.unbind = C::Graphics.sfShader_bind(nil) |
Instance Method Details
#[]=(name, value) ⇒ Object
Set a uniform by name. Dispatches to the right CSFML setter based on the Ruby value's type — see the class-level docs for the table.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/sfml/graphics/shader.rb', line 86 def []=(name, value) n = name.to_s case value when true, false C::Graphics.sfShader_setBoolUniform(@handle, n, value) when Integer C::Graphics.sfShader_setFloatUniform(@handle, n, value.to_f) when Numeric C::Graphics.sfShader_setFloatUniform(@handle, n, value.to_f) when Vector2 v = C::System::Vector2f.new v[:x] = value.x.to_f; v[:y] = value.y.to_f C::Graphics.sfShader_setVec2Uniform(@handle, n, v) when Vector3 v = C::System::Vector3f.new v[:x] = value.x.to_f; v[:y] = value.y.to_f; v[:z] = value.z.to_f C::Graphics.sfShader_setVec3Uniform(@handle, n, v) when Color C::Graphics.sfShader_setColorUniform(@handle, n, value.to_native) when Texture C::Graphics.sfShader_setTextureUniform(@handle, n, value.handle) when :current_texture C::Graphics.sfShader_setCurrentTextureUniform(@handle, n) when Array raise ArgumentError, "Shader uniform array must not be empty" if value.empty? first = value.first if first.is_a?(Array) || first.is_a?(Vector2) || first.is_a?(Vector3) _set_vec_array_uniform(n, value) else case value.length when 2 then self[name] = Vector2.new(*value) when 3 then self[name] = Vector3.new(*value) when 4 v = C::Graphics::GlslVec4.new v[:x] = value[0].to_f; v[:y] = value[1].to_f v[:z] = value[2].to_f; v[:w] = value[3].to_f C::Graphics.sfShader_setVec4Uniform(@handle, n, v) else raise ArgumentError, "Shader uniform array must be length 2, 3, or 4 (got #{value.length})" end end else raise ArgumentError, "Shader uniform value must be Numeric, Vector2/3, Color, Texture, " \ "Array of 2-4 numbers, or :current_texture (got #{value.class})" end end |
#bind ⇒ Object
Bind this shader as the active GL program. Useful when you
want to issue raw GL draw calls under SFML's context. Pair
with Shader.unbind to restore SFML's default. Most users
don't need this — just pass the shader to target.draw(..., render_states: SFML::RenderStates.new(shader: self)).
212 |
# File 'lib/sfml/graphics/shader.rb', line 212 def bind = C::Graphics.sfShader_bind(@handle) |
#native_handle ⇒ Object
The OpenGL program ID. Useful for debug printf / interop with raw GL libraries.
219 |
# File 'lib/sfml/graphics/shader.rb', line 219 def native_handle = C::Graphics.sfShader_getNativeHandle(@handle) |
#set_bvec(name, *components) ⇒ Object
Set a uniform bvec2/3/4 from a Ruby Array of booleans. Length
picks the dimensionality.
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/sfml/graphics/shader.rb', line 158 def set_bvec(name, *components) flat = components.flatten case flat.length when 2 s = C::Graphics::GlslBvec2.new s[:x] = !!flat[0]; s[:y] = !!flat[1] C::Graphics.sfShader_setBvec2Uniform(@handle, name.to_s, s) when 3 s = C::Graphics::GlslBvec3.new s[:x] = !!flat[0]; s[:y] = !!flat[1]; s[:z] = !!flat[2] C::Graphics.sfShader_setBvec3Uniform(@handle, name.to_s, s) when 4 s = C::Graphics::GlslBvec4.new s[:x] = !!flat[0]; s[:y] = !!flat[1]; s[:z] = !!flat[2]; s[:w] = !!flat[3] C::Graphics.sfShader_setBvec4Uniform(@handle, name.to_s, s) else raise ArgumentError, "bvec uniform must have 2, 3, or 4 components (got #{flat.length})" end end |
#set_float_array(name, values) ⇒ Object
Set a uniform float arr[N]; from a plain Ruby array of numbers.
Float arrays can't be inferred via []= because they'd collide
with the vec3 case at length 3.
150 151 152 153 154 |
# File 'lib/sfml/graphics/shader.rb', line 150 def set_float_array(name, values) buf = FFI::MemoryPointer.new(:float, values.length) buf.write_array_of_float(values.map(&:to_f)) C::Graphics.sfShader_setFloatUniformArray(@handle, name.to_s, buf, values.length) end |
#set_int(name, value) ⇒ Object
Explicit integer setters when a uniform really is uniform int n.
136 137 138 |
# File 'lib/sfml/graphics/shader.rb', line 136 def set_int(name, value) C::Graphics.sfShader_setIntUniform(@handle, name.to_s, Integer(value)) end |
#set_int_color(name, color) ⇒ Object
Set a vec4 uniform from an integer-channel SFML::Color
(RGBA 0–255). Equivalent to writing [c.r/255, ..., c.a/255]
by hand into a vec4 — the CSFML helper does the divide for
you.
225 226 227 228 |
# File 'lib/sfml/graphics/shader.rb', line 225 def set_int_color(name, color) raise ArgumentError, "expected SFML::Color" unless color.is_a?(Color) C::Graphics.sfShader_setIntColorUniform(@handle, name.to_s, color.to_native) end |
#set_ivec2(name, x, y) ⇒ Object
Returns the ivec2.
141 142 143 144 145 |
# File 'lib/sfml/graphics/shader.rb', line 141 def set_ivec2(name, x, y) v = C::System::Vector2i.new v[:x] = Integer(x); v[:y] = Integer(y) C::Graphics.sfShader_setIvec2Uniform(@handle, name.to_s, v) end |
#set_mat3(name, matrix) ⇒ Object
Set a uniform mat3 from a 9-element row-major float array (or
an SFML::Transform — its 3×3 matrix is read directly).
180 181 182 183 184 185 |
# File 'lib/sfml/graphics/shader.rb', line 180 def set_mat3(name, matrix) values = _coerce_matrix(matrix, 9, "mat3") mat = C::Graphics::GlslMat3.new values.each_with_index { |v, i| mat[:array][i] = v } C::Graphics.sfShader_setMat3Uniform(@handle, name.to_s, mat.pointer) end |
#set_mat3_array(name, matrices) ⇒ Object
Set a uniform mat3 arr[N]; / uniform mat4 arr[N]; from a
list of matrices (each a 9- or 16-element flat array, or an
SFML::Transform for mat3).
198 199 200 |
# File 'lib/sfml/graphics/shader.rb', line 198 def set_mat3_array(name, matrices) _set_mat_array(name, matrices, 9, :sfShader_setMat3UniformArray) end |
#set_mat4(name, matrix) ⇒ Object
Set a uniform mat4 from a 16-element row-major float array.
188 189 190 191 192 193 |
# File 'lib/sfml/graphics/shader.rb', line 188 def set_mat4(name, matrix) values = _coerce_matrix(matrix, 16, "mat4") mat = C::Graphics::GlslMat4.new values.each_with_index { |v, i| mat[:array][i] = v } C::Graphics.sfShader_setMat4Uniform(@handle, name.to_s, mat.pointer) end |
#set_mat4_array(name, matrices) ⇒ Object
Returns the mat4 array.
203 204 205 |
# File 'lib/sfml/graphics/shader.rb', line 203 def set_mat4_array(name, matrices) _set_mat_array(name, matrices, 16, :sfShader_setMat4UniformArray) end |