require 'set' module Ashton module Lighting # Based on Catalin Zima's shader based dynamic shadows system. # http://www.catalinzima.com/2010/07/my-technique-for-the-shader-based-dynamic-2d-shadows/ class Manager include Enumerable attr_accessor :camera_x, :camera_y, :z def each(&block); @lights.each &block end def size; @lights.size end def empty?; @lights.empty? end def width; @shadows.width end def height; @shadows.height end def initialize(options = {}) options = { width: $window.width, height: $window.height, camera_x: 0, camera_y: 0, z: 0, }.merge! options @camera_x, @camera_y = options[:camera_x], options[:camera_y] @z = options[:z] @lights = Set.new @shadows = Ashton::Texture.new options[:width], options[:height] end # @param light [Ashton::LightSource] # @return [Ashton::LightSource] def add(light) raise TypeError unless light.is_a? LightSource @lights << light light end alias_method :<<, :add def remove(light) @lights -= [light] light end # @see Ashton::LightSource#new # # @return [Ashton::LightSource] def create_light(*args) add LightSource.new(*args) end def draw(options = {}) options = { mode: :multiply, }.merge! options @shadows.draw @camera_x, @camera_y, @z, options end def update_shadow_casters(&block) raise ArgumentError, "Requires block" unless block_given? unless empty? # TODO: Need to only render to lights that are on-screen. @lights.each do |light| light.send :render_shadow_casters, &block end # Use each shader on every light, to save setting and un-setting shaders (a bit faster, depending on number of light sources). LightSource.distort_shader.enable do @lights.each {|light| light.send :distort } end LightSource.draw_shadows_shader.enable do @lights.each {|light| light.send :draw_shadows } end LightSource.blur_shader.enable do @lights.each {|light| light.send :blur } end end @shadows.render do |buffer| buffer.clear $window.translate -@camera_x, -@camera_y do @lights.each {|light| light.draw } unless empty? end end nil end end end end