lib/mittsu/opengl/shader/rbsl_loader.rb
module Mittsu
class OpenGL::Shader
module RBSLLoader
UNIFORM_RGX = /uniform\s+(\S+)\s+(\w+)(|\s+\=\s+(.+));/
COLOR_RGX = /color\(([^\)]*)\)/
class << self
def load_shader(shader, chunks)
shader.lines.flat_map(&:chomp).map{ |line|
if line =~ /(\s*)#include\s+(\w+)/
indentation = $1
chunk_name = $2.to_sym
chunks[chunk_name].lines.map(&:chomp).map{ |l|
"#{indentation}#{l}"
}
else
line
end
}.join("\n") + "\n"
end
def extract_array_contents(str)
/\[([^\]]+)\]/.match(str)[1]
end
def parse_int(str)
str.to_i
end
(2..4).each do |n|
define_method("parse_ivec#{n}") do |str|
str =~ /ivec#{n}\(([^\)]+)\)/
$1.split(',').map(&:strip).map(&:to_i).take(n)
end
end
def parse_float(str)
str.to_f
end
def parse_single_color(values)
if values.length == 1
values = values.map(&:to_i)
else
values = values.map(&:to_f)
end
Color.new(*values)
end
def parse_color(str)
str =~ COLOR_RGX
values = $1.split(',').map(&:strip)
parse_single_color(values)
end
def parse_color_array(str)
str = extract_array_contents(str)
str.scan(COLOR_RGX).map{ |m|
values = m.first.split(',').map(&:strip)
parse_single_color(values)
}
end
def parse_int_array(str)
str = extract_array_contents(str)
str.split(',').map(&:strip).map(&:to_i)
end
def parse_float_array(str)
str = extract_array_contents(str)
str.split(',').map(&:strip).map(&:to_f)
end
[Vector2, Vector3, Vector4].each do |vectorClass|
define_method("parse_vec#{vectorClass::DIMENSIONS}") do |str|
str =~ /vec#{vectorClass::DIMENSIONS}\(([^\)]+)\)/
values = $1.split(',').map(&:strip).map(&:to_f).take(vectorClass::DIMENSIONS)
vectorClass.new(*values)
end
end
(2..4).each do |n|
define_method("parse_ivec#{n}_array") do |str|
str = extract_array_contents(str)
str.scan(/ivec#{n}\(([^\)]+)\)/).map{ |m| m.first.split(',').map(&:strip).map(&:to_i).take(n) }
end
end
[Vector2, Vector3, Vector4].each do |vectorClass|
define_method("parse_vec#{vectorClass::DIMENSIONS}_array") do |str|
str = extract_array_contents(str)
str.scan(/vec#{vectorClass::DIMENSIONS}\(([^\)]+)\)/).map{ |m|
values = m.first.split(',').map(&:strip).map(&:to_f).take(vectorClass::DIMENSIONS)
vectorClass.new(*values)
}
end
end
[Matrix3, Matrix4].each do |matrixClass|
define_method("parse_mat#{matrixClass::DIMENSIONS}") do |str|
str =~ /mat#{matrixClass::DIMENSIONS}\(([^\)]+)\)/
values = $1.split(',').map(&:strip).map(&:to_f).take(matrixClass::DIMENSIONS * matrixClass::DIMENSIONS)
matrixClass.new().tap { |mat| mat.set(*values) }
end
end
[Matrix3, Matrix4].each do |matrixClass|
define_method("parse_mat#{matrixClass::DIMENSIONS}_array") do |str|
str = extract_array_contents(str)
str.scan(/mat#{matrixClass::DIMENSIONS}\(([^\)]+)\)/).map{ |m|
values = m.first.split(',').map(&:strip).map(&:to_f).take(matrixClass::DIMENSIONS * matrixClass::DIMENSIONS)
matrixClass.new().tap { |mat| mat.set(*values) }
}
end
end
def parse_texture(_str)
nil
end
def parse_texture_array(_str)
[]
end
def parse_uniform(uniform)
uniform =~ UNIFORM_RGX
type_str = $1
type = type_str.to_sym
is_array = type_str.end_with?('[]')
name = $2
value_str = $4
value = is_array ? [] : nil
if value_str && !value_str.empty?
value = send("parse_#{type.to_s.gsub(/\[\]/, '_array')}".to_s, value_str)
end
[name, Uniform.new(type, value)]
end
def load_uniforms(uniforms, uniforms_lib)
uniform_strings = nil;
in_uniform = false
uniforms.lines.map(&:strip).each_with_object({}) { |line, hash|
if in_uniform
uniform_strings << line
if line.end_with?(';')
in_uniform = false
name, value = parse_uniform(uniform_strings.join(' '))
hash[name] = value
end
elsif line =~ /#include\s+(\w+)/
uniforms_lib[$1.to_sym].map { |(k, v)| hash[k] = v.clone }
elsif line.start_with?('uniform')
if line.end_with?(';')
name, value = parse_uniform(line)
hash[name] = value
else
in_uniform = true
uniform_strings = [line]
end
end
}
end
end
end
end
end