module Ray # Effects are used to generate fragment shaders automatically. They represent # one of the transformations applied to the color. # # Effects must generate a structure to store arguments passed to the effect # (structure generation being done through a DSL), and a function to apply the # effect (a call to the #code method returns ) class Effect # @overload effect_name(name) # Sets the name of the effect # @param [String] value # # @overload effect_name # @return [String] Name of the effect def self.effect_name(value = nil) if value @name = value klass = self Ray::Helper.send :define_method, @name do |*args| klass.new(*args) end else @name end end # Adds an attribute to the shader. It is an element of the struct # # @param [String] name Name of the attribute # @param [String] type Type of the attribute. Arrays are written using this # notation: type[count]. def self.attribute(name, type) attributes[name] = type end # @return [Hash] All the attributes of the struct, matched with their type. def self.attributes @attributes ||= {} end # @return [String] Name of the effect def name self.class.effect_name end # @return [String] GLSL code of the struct. def struct str = "struct ray_#{self.class.effect_name} {\n" str << " bool enabled;\n" self.class.attributes.each do |name, type| if type =~ /\A(\w+)\[(\d+)\]\z/ str << " #$1 #{name}[#$2];\n" else str << " #{type} #{name};\n" end end str << "};\n" end # @abstract # # @return [String] Code that must be written *before* the definiton of the # structure. Just returns an empty string by default. def header "" end # @abstract # # @return [String] # Code of the function. This must contain the header of the function. # The name of the function is the name of the effect prepended by # "do_". It is passed a ray_#{effect_name} structure and the color, and is # expected to return the changed color. # # @example # def code # return %{ # vec4 do_some_effect(ray_some_effect arg, vec4 color) { # /* Do magic here. */ # } # } # end def code raise NotImplementedError end # @abstract # # @return [Hash] Default value for each attribute. def defaults {} end # Apply the defaults to a shader. # @param [Ray::Shader] shader def apply_defaults(shader) effect_name = self.class.effect_name shader["#{effect_name}.enabled"] = true defaults.each do |name, value| shader["#{effect_name}.#{name}"] = value end end end end require 'ray/effect/generator' require 'ray/effect/grayscale' require 'ray/effect/color_inversion' require 'ray/effect/black_and_white'