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.
- .geometry_available? ⇒ Boolean
Instance Method Summary collapse
-
#[]=(name, value) ⇒ Object
Set a uniform by name.
-
#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_ivec2(name, x, y) ⇒ Object
Instance Attribute Details
#handle ⇒ Object (readonly)
:nodoc:
142 143 144 |
# File 'lib/sfml/graphics/shader.rb', line 142 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 |
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.
73 74 75 76 77 78 79 80 81 82 83 84 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 |
# File 'lib/sfml/graphics/shader.rb', line 73 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 |
#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.
136 137 138 139 140 |
# File 'lib/sfml/graphics/shader.rb', line 136 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 |