def set_program(camera, lights, fog, material, object)
      @_used_texture_units = 0
      if material.needs_update?
        deallocate_material(material) if material.program

        material.init(lights, fog, object, self)
        material.needs_update = false
      end

      if material.morph_targets
        if !object.morph_target_influences
          object.morph_target_influences = Array.new(@max_morph_targets) # Float32Array
        end
      end

      refresh_program = false
      refresh_material = false
      refresh_lights = false

      program = material.program
      program_uniforms = program.uniforms
      material_uniforms = material.shader[:uniforms]

      if program.id != @_current_program
        glUseProgram(program.program)
        @_current_program = program.id

        refresh_program = true
        refresh_material = true
        refresh_lights = true
      end

      if material.id != @_current_material_id
        refresh_lights = true if @_current_material_id == -1
        @_current_material_id = material.id

        refresh_material = true
      end

      if refresh_program || camera != @_current_camera
        @_current_camera = camera
        update_camera_uniforms(program_uniforms, camera, material)
      end

      if material.skinning
        # TODO: when skinning is implemented. Then also refactor
        # if object.bind_matrix && !program_uniforms['bindMatrix'].nil?
        #   glUniformMatrix4fv(program_uniforms['bindMatrix'], GL_FALSE, object.bind_matrix.elements)
        # end
        #
        # if object.bind_matrix_inverse && !program_uniforms['bindMatrixInverse'].nil?
        #   glUniformMatrix4fv(program_uniforms['bindMatrixInverse'], GL_FALSE, object.bind_matrix_inverse.elements)
        # end
        #
        # if @_supports_bone_textures && object.skeleton && object.skeleton.use_vertex_texture
        #   if !program_uniforms['boneTexture'].nil?
        #     texture_unit = get_texture_unit
        #
        #     glUniform1i(program_uniforms['boneTexture'], texture_unit)
        #     object.skeleton.bone_texture.set(texture_unit, self)
        #   end
        #
        #   if !program_uniforms['boneTextureWidth'].nil?
        #     glUniform1i(program_uniforms['boneTextureWidth'], object.skeleton.bone_texture_width)
        #   end
        #
        #   if !program_uniforms['boneTextureHeight'].nil?
        #     glUniform1i(program_uniforms['boneTextureHeight'], object.skeleton.bone_texture_height)
        #   end
        # elsif object.skeleton && object.skeleton.bone_matrices
        #   if !program_uniforms['boneGlobalMatrices'].nil?
        #     glUniformMatrix4fv(program_uniforms['boneGlobalMatrices'], GL_FALSE, object.skeleton.bone_matrices)
        #   end
        # end
      end

      if refresh_material
        # TODO: when fog is implemented
        # refresh_uniforms_fog(material_uniforms, fog) if fog && material.fog

        if material.needs_lights?
          if @light_renderer.lights_need_update
            refresh_lights = true
            @light_renderer.setup(lights)
          end

          if refresh_lights
            OpenGLHelper.refresh_uniforms_lights(material_uniforms, @light_renderer.cache)
          end

          OpenGLHelper.mark_uniforms_lights_needs_update(material_uniforms, refresh_lights)
        end

        material.refresh_uniforms(material_uniforms)

        # TODO: when all of these things exist
        # when LineDashedMaterial
        #   refresh_uniforms_line(material_uniforms, material)
        #   refresh_uniforms_dash(material_uniforms, material)
        # when MeshDepthMaterial
        #   material_uniforms.m_near.value = camera.near
        #   material_uniforms.m_far.value = camera.far
        #   material_uniforms.opacity.value = material.opacity
        # when MeshNormalMaterial
        #   material_uniforms.opactity.value = material.opacity

        if object.receive_shadow && !material.shadow_pass
          OpenGLHelper.refresh_uniforms_shadow(material_uniforms, lights)
        end

        load_uniforms_generic(material.uniforms_list)
      end

      object.load_uniforms_matrices(program_uniforms)

      if !program_uniforms['modelMatrix'].nil?
        glUniformMatrix4fv(program_uniforms['modelMatrix'], 1, GL_FALSE, array_to_ptr_easy(object.matrix_world.elements))
      end

      program
    end
def set_program(camera, lights, fog, material, object)
      @_used_texture_units = 0
      if material.needs_update?
        deallocate_material(material) if material.program

        material.init(lights, fog, object, self)
        material.needs_update = false
      end

      if material.morph_targets
        if !object.morph_target_influences
          object.morph_target_influences = Array.new(@max_morph_targets) # Float32Array
        end
      end

      refresh_program = false
      refresh_material = false
      refresh_lights = false

      program = material.program
      program_uniforms = program.uniforms
      material_uniforms = material.shader[:uniforms]

      if program.id != @_current_program
        glUseProgram(program.program)
        @_current_program = program.id

        refresh_program = true
        refresh_material = true
        refresh_lights = true
      end

      if material.id != @_current_material_id
        refresh_lights = true if @_current_material_id == -1
        @_current_material_id = material.id

        refresh_material = true
      end

      if refresh_program || camera != @_current_camera
        @_current_camera = camera
        update_camera_uniforms(program_uniforms, camera, material)
      end

      if material.skinning
        # TODO: when skinning is implemented. Then also refactor
        # if object.bind_matrix && !program_uniforms['bindMatrix'].nil?
        #   glUniformMatrix4fv(program_uniforms['bindMatrix'], GL_FALSE, object.bind_matrix.elements)
        # end
        #
        # if object.bind_matrix_inverse && !program_uniforms['bindMatrixInverse'].nil?
        #   glUniformMatrix4fv(program_uniforms['bindMatrixInverse'], GL_FALSE, object.bind_matrix_inverse.elements)
        # end
        #
        # if @_supports_bone_textures && object.skeleton && object.skeleton.use_vertex_texture
        #   if !program_uniforms['boneTexture'].nil?
        #     texture_unit = get_texture_unit
        #
        #     glUniform1i(program_uniforms['boneTexture'], texture_unit)
        #     object.skeleton.bone_texture.set(texture_unit, self)
        #   end
        #
        #   if !program_uniforms['boneTextureWidth'].nil?
        #     glUniform1i(program_uniforms['boneTextureWidth'], object.skeleton.bone_texture_width)
        #   end
        #
        #   if !program_uniforms['boneTextureHeight'].nil?
        #     glUniform1i(program_uniforms['boneTextureHeight'], object.skeleton.bone_texture_height)
        #   end
        # elsif object.skeleton && object.skeleton.bone_matrices
        #   if !program_uniforms['boneGlobalMatrices'].nil?
        #     glUniformMatrix4fv(program_uniforms['boneGlobalMatrices'], GL_FALSE, object.skeleton.bone_matrices)
        #   end
        # end
      end

      if refresh_material
        # TODO: when fog is implemented
        # refresh_uniforms_fog(material_uniforms, fog) if fog && material.fog

        if material.needs_lights?
          if @light_renderer.lights_need_update
            refresh_lights = true
            @light_renderer.setup(lights)
          end

          if refresh_lights
            OpenGLHelper.refresh_uniforms_lights(material_uniforms, @light_renderer.cache)
          end

          OpenGLHelper.mark_uniforms_lights_needs_update(material_uniforms, refresh_lights)
        end

        material.refresh_uniforms(material_uniforms)

        # TODO: when all of these things exist
        # when LineDashedMaterial
        #   refresh_uniforms_line(material_uniforms, material)
        #   refresh_uniforms_dash(material_uniforms, material)
        # when MeshDepthMaterial
        #   material_uniforms.m_near.value = camera.near
        #   material_uniforms.m_far.value = camera.far
        #   material_uniforms.opacity.value = material.opacity
        # when MeshNormalMaterial
        #   material_uniforms.opactity.value = material.opacity

        if object.receive_shadow && !material.shadow_pass
          OpenGLHelper.refresh_uniforms_shadow(material_uniforms, lights)
        end

        load_uniforms_generic(material.uniforms_list)
      end

      object.load_uniforms_matrices(program_uniforms)

      if !program_uniforms['modelMatrix'].nil?
        glUniformMatrix4fv(program_uniforms['modelMatrix'], 1, GL_FALSE, array_to_ptr_easy(object.matrix_world.elements))
      end

      program
    end
FIXME: refactor