mirror of
https://github.com/cyberarm/cyberarm_engine.git
synced 2025-12-16 21:22:33 +00:00
Refactored Shader to duplicate code in shader compilation step, added support for @include preprocessor in shaders
This commit is contained in:
@@ -3,6 +3,7 @@ module CyberarmEngine
|
|||||||
class Shader
|
class Shader
|
||||||
include OpenGL
|
include OpenGL
|
||||||
@@shaders = {}
|
@@shaders = {}
|
||||||
|
PREPROCESSOR_CHARACTER = "@"
|
||||||
|
|
||||||
def self.add(name, instance)
|
def self.add(name, instance)
|
||||||
@@shaders[name] = instance
|
@@shaders[name] = instance
|
||||||
@@ -54,10 +55,11 @@ module CyberarmEngine
|
|||||||
end
|
end
|
||||||
|
|
||||||
attr_reader :name, :program
|
attr_reader :name, :program
|
||||||
def initialize(name:, vertex: "shaders/default.vert", fragment:)
|
def initialize(name:, includes_dir: nil, vertex: "shaders/default.vert", fragment:)
|
||||||
|
raise "Shader name can not be blank" if name.length == 0
|
||||||
|
|
||||||
@name = name
|
@name = name
|
||||||
@vertex_file = vertex
|
@includes_dir = includes_dir
|
||||||
@fragment_file = fragment
|
|
||||||
@compiled = false
|
@compiled = false
|
||||||
|
|
||||||
@program = nil
|
@program = nil
|
||||||
@@ -65,74 +67,110 @@ module CyberarmEngine
|
|||||||
@error_buffer_size = 1024
|
@error_buffer_size = 1024
|
||||||
@variable_missing = {}
|
@variable_missing = {}
|
||||||
|
|
||||||
raise ArgumentError, "Shader files not found: #{@vertex_file} or #{@fragment_file}" unless shader_files_exist?
|
@data = {shaders: {}}
|
||||||
|
|
||||||
create_shaders
|
unless shader_files_exist?(vertex: vertex, fragment: fragment)
|
||||||
compile_shaders
|
raise ArgumentError, "Shader files not found: #{vertex} or #{fragment}"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_shader(type: :vertex, source: File.read(vertex))
|
||||||
|
create_shader(type: :fragment, source: File.read(fragment))
|
||||||
|
|
||||||
|
compile_shader(type: :vertex)
|
||||||
|
compile_shader(type: :fragment)
|
||||||
|
link_shaders
|
||||||
|
|
||||||
# Only add shader if it successfully compiles
|
# Only add shader if it successfully compiles
|
||||||
if @compiled
|
if @compiled
|
||||||
|
puts "compiled!"
|
||||||
|
puts "Compiled shader: #{@name}"
|
||||||
Shader.add(@name, self)
|
Shader.add(@name, self)
|
||||||
else
|
else
|
||||||
puts "FAILED to compile shader: #{@name}", ""
|
warn "FAILED to compile shader: #{@name}", ""
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def shader_files_exist?
|
def shader_files_exist?(vertex:, fragment:)
|
||||||
File.exist?(@vertex_file) && File.exist?(@fragment_file)
|
File.exist?(vertex) && File.exist?(fragment)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_shaders
|
def create_shader(type:, source:)
|
||||||
@vertex = glCreateShader(GL_VERTEX_SHADER)
|
_shader = nil
|
||||||
@fragment = glCreateShader(GL_FRAGMENT_SHADER)
|
|
||||||
|
|
||||||
source = [File.read(@vertex_file)].pack('p')
|
case type
|
||||||
size = [File.size(@vertex_file)].pack('I')
|
when :vertex
|
||||||
glShaderSource(@vertex, 1, source, size)
|
_shader = glCreateShader(GL_VERTEX_SHADER)
|
||||||
|
when :fragment
|
||||||
|
_shader = glCreateShader(GL_FRAGMENT_SHADER)
|
||||||
|
else
|
||||||
|
warn "Unsupported shader type: #{type.inspect}"
|
||||||
|
end
|
||||||
|
|
||||||
source = [File.read(@fragment_file)].pack('p')
|
processed_source = preprocess_source(source: source)
|
||||||
size = [File.size(@fragment_file)].pack('I')
|
|
||||||
glShaderSource(@fragment, 1, source, size)
|
_source = [processed_source].pack("p")
|
||||||
|
_size = [processed_source.length].pack("I")
|
||||||
|
glShaderSource(_shader, 1, _source, _size)
|
||||||
|
|
||||||
|
@data[:shaders][type] =_shader
|
||||||
end
|
end
|
||||||
|
|
||||||
def compile_shaders
|
def preprocess_source(source:)
|
||||||
return unless shader_files_exist?
|
lines = source.lines
|
||||||
|
|
||||||
glCompileShader(@vertex)
|
lines.each_with_index do |line, i|
|
||||||
|
if line.start_with?(PREPROCESSOR_CHARACTER)
|
||||||
|
preprocessor = line.strip.split(" ")
|
||||||
|
lines.delete(line)
|
||||||
|
|
||||||
|
case preprocessor.first
|
||||||
|
when "@include"
|
||||||
|
raise ArgumentError, "Shader preprocessor include directory was not given for shader #{@name}" unless @includes_dir
|
||||||
|
|
||||||
|
preprocessor[1..preprocessor.length - 1].join.scan(/"([^"]*)"/).flatten.each do |file|
|
||||||
|
source = File.read("#{@includes_dir}/#{file}.glsl")
|
||||||
|
|
||||||
|
lines.insert(i, source)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
warn "Unsupported preprocessor #{preprocessor.first} for #{@name}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
lines.join
|
||||||
|
end
|
||||||
|
|
||||||
|
def compile_shader(type:)
|
||||||
|
_compiled = false
|
||||||
|
_shader = @data[:shaders][type]
|
||||||
|
raise ArgumentError, "No shader for #{type.inspect}" unless _shader
|
||||||
|
|
||||||
|
glCompileShader(_shader)
|
||||||
buffer = ' '
|
buffer = ' '
|
||||||
glGetShaderiv(@vertex, GL_COMPILE_STATUS, buffer)
|
glGetShaderiv(_shader, GL_COMPILE_STATUS, buffer)
|
||||||
compiled = buffer.unpack('L')[0]
|
compiled = buffer.unpack('L')[0]
|
||||||
|
|
||||||
if compiled == 0
|
if compiled == 0
|
||||||
log = ' ' * @error_buffer_size
|
log = ' ' * @error_buffer_size
|
||||||
glGetShaderInfoLog(@vertex, @error_buffer_size, nil, log)
|
glGetShaderInfoLog(_shader, @error_buffer_size, nil, log)
|
||||||
puts "Shader Error: Program \"#{@name}\""
|
puts "Shader Error: Program \"#{@name}\""
|
||||||
puts " Vectex Shader InfoLog:", " #{log.strip.split("\n").join("\n ")}\n\n"
|
puts " #{type.to_s.capitalize} Shader InfoLog:", " #{log.strip.split("\n").join("\n ")}\n\n"
|
||||||
puts " Shader Compiled status: #{compiled}"
|
puts " Shader Compiled status: #{compiled}"
|
||||||
puts " NOTE: assignment of uniforms in shaders is illegal!"
|
puts " NOTE: assignment of uniforms in shaders is illegal!"
|
||||||
puts
|
puts
|
||||||
return
|
else
|
||||||
|
_compiled = true
|
||||||
end
|
end
|
||||||
|
|
||||||
glCompileShader(@fragment)
|
return _compiled
|
||||||
buffer = ' '
|
end
|
||||||
glGetShaderiv(@fragment, GL_COMPILE_STATUS, buffer)
|
|
||||||
compiled = buffer.unpack('L')[0]
|
|
||||||
|
|
||||||
if compiled == 0
|
|
||||||
log = ' ' * @error_buffer_size
|
|
||||||
glGetShaderInfoLog(@fragment, @error_buffer_size, nil, log)
|
|
||||||
puts "Shader Error: Program \"#{@name}\""
|
|
||||||
puts " Fragment Shader InfoLog:", " #{log.strip.split("\n").join("\n ")}\n\n"
|
|
||||||
puts " Shader Compiled status: #{compiled}"
|
|
||||||
puts " NOTE: assignment of uniforms in shader is not allowed."
|
|
||||||
puts
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
|
def link_shaders
|
||||||
@program = glCreateProgram
|
@program = glCreateProgram
|
||||||
glAttachShader(@program, @vertex)
|
@data[:shaders].values.each do |_shader|
|
||||||
glAttachShader(@program, @fragment)
|
glAttachShader(@program, _shader)
|
||||||
|
end
|
||||||
glLinkProgram(@program)
|
glLinkProgram(@program)
|
||||||
|
|
||||||
buffer = ' '
|
buffer = ' '
|
||||||
@@ -221,4 +259,4 @@ module CyberarmEngine
|
|||||||
glUniform4f(attr_loc, *value.to_a)
|
glUniform4f(attr_loc, *value.to_a)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user