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: <<~GLSL)
uniform sampler2D texture;
uniform float time;
void main() {
vec2 uv = gl_TexCoord[0].xy;
uv.x += sin(uv.y * 20.0 + time * 3.0) * 0.02;
gl_FragColor = texture2D(texture, uv) * gl_Color;
}
GLSL
shader[:time] = clock.elapsed.as_seconds
window.draw(sprite, shader: shader)
Uniform types are inferred from the Ruby value:
Float / Integer / Numeric → float (uniform float)
true / false → bool
SFML::Vector2 → vec2
SFML::Vector3 → vec3
SFML::Color → vec4 (normalised RGBA)
SFML::Texture → sampler2D
:current_texture (Symbol) → sampler2D bound to the drawable's own texture
[a, b] → vec2 (floats)
[a, b, c] → vec3
[a, b, c, d] → vec4
Array uniforms (‘uniform vec2 positions;` and friends):
[[x, y], [x, y], ...] → vec2[]
[[x, y, z], ...] → vec3[]
[[x, y, z, w], ...] → vec4[]
[Vector2[a, b], ...] → vec2[] (also accepts Vector2 / Vector3)
Float arrays (‘uniform float weights;`) 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
- .unbind ⇒ Object
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/4` from a Ruby Array of booleans.
-
#set_float_array(name, values) ⇒ Object
Set a ‘uniform float arr;` 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 ‘vec4` uniform from an integer-channel `SFML::Color` (RGBA 0–255).
- #set_ivec2(name, x, y) ⇒ Object
-
#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).
- #set_mat3_array(name, matrices) ⇒ Object
-
#set_mat4(name, matrix) ⇒ Object
Set a ‘uniform mat4` from a 16-element row-major float array.
- #set_mat4_array(name, matrices) ⇒ Object
Instance Attribute Details
#handle ⇒ Object (readonly)
:nodoc:
226 227 228 |
# File 'lib/sfml/graphics/shader.rb', line 226 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.
54 55 56 57 58 59 60 61 |
# File 'lib/sfml/graphics/shader.rb', line 54 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 Error, "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.
64 65 66 67 68 69 |
# File 'lib/sfml/graphics/shader.rb', line 64 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 Error, "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.
74 75 76 77 78 79 80 81 |
# File 'lib/sfml/graphics/shader.rb', line 74 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 Error, "sfShader_createFromStream failed (GLSL compile error?)" if ptr.null? _wrap(ptr) end |
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.
85 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 |
# File 'lib/sfml/graphics/shader.rb', line 85 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))`.
209 |
# File 'lib/sfml/graphics/shader.rb', line 209 def bind = C::Graphics.sfShader_bind(@handle) |
#native_handle ⇒ Object
The OpenGL program ID. Useful for debug printf / interop with raw GL libraries.
215 |
# File 'lib/sfml/graphics/shader.rb', line 215 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.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/sfml/graphics/shader.rb', line 156 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;` 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.
148 149 150 151 152 |
# File 'lib/sfml/graphics/shader.rb', line 148 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`.
135 136 137 |
# File 'lib/sfml/graphics/shader.rb', line 135 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.
221 222 223 224 |
# File 'lib/sfml/graphics/shader.rb', line 221 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
139 140 141 142 143 |
# File 'lib/sfml/graphics/shader.rb', line 139 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).
178 179 180 181 182 183 |
# File 'lib/sfml/graphics/shader.rb', line 178 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
196 197 198 |
# File 'lib/sfml/graphics/shader.rb', line 196 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.
186 187 188 189 190 191 |
# File 'lib/sfml/graphics/shader.rb', line 186 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
200 201 202 |
# File 'lib/sfml/graphics/shader.rb', line 200 def set_mat4_array(name, matrices) _set_mat_array(name, matrices, 16, :sfShader_setMat4UniformArray) end |