abstract shader implementation

This commit is contained in:
Matthew Berry 2021-08-01 17:49:20 -07:00
parent 9b0a5536b5
commit 719ca57c64
7 changed files with 61 additions and 39 deletions

View file

@ -5,12 +5,13 @@ require "lib_gl"
require "./controllers/*"
require "./widgets/*"
require "./shaders/*"
class SDLOpenGLImGuiFrontend < Frontend
CONTROLLERS = [StubbedController, GBController, GBAController]
ROM_EXTENSIONS = CONTROLLERS.reduce([] of String) { |acc, controller| acc + controller.extensions }
SCALE = 3
SHADERS = "src/crab/common/shaders"
SHADERS = Path["#{__DIR__}/shaders"]
@controller : Controller
@ -20,7 +21,7 @@ class SDLOpenGLImGuiFrontend < Frontend
@shader_program : UInt32?
@frag_shader_id : UInt32?
@shader_programs : Hash(Controller.class, UInt32)
@shader_programs : Hash(Controller.class, Shader)
@microseconds = 0
@frames = 0
@ -52,17 +53,15 @@ class SDLOpenGLImGuiFrontend < Frontend
)
@gl_context = setup_gl
@shader_programs = Hash.zip(CONTROLLERS, CONTROLLERS.map { |controller| create_shader_program(controller.vertex_shader, controller.fragment_shader) })
@shader_programs = Hash.zip(CONTROLLERS, CONTROLLERS.map { |controller| Shader.new(SHADERS / controller.vertex_shader, SHADERS / controller.fragment_shader)})
shader_program = @shader_programs[@controller.class]
LibGL.use_program(shader_program)
shader_program.use
if stubbed?
@crab_texture, canvas_aspect = texture_from_png("README/crab.png")
window_aspect = @window.width / @window.height
aspect = LibGL.get_uniform_location(shader_program, "aspect")
LibGL.uniform_1f(aspect, window_aspect * canvas_aspect)
scale = LibGL.get_uniform_location(shader_program, "scale")
LibGL.uniform_1f(scale, 0.5)
shader_program.aspect = window_aspect * canvas_aspect
shader_program.scale = 0.5
end
@opengl_info = OpenGLInfo.new
@ -128,7 +127,7 @@ class SDLOpenGLImGuiFrontend < Frontend
LibSDL.set_window_size(@window, @controller.window_width * SCALE, @controller.window_height * SCALE)
LibSDL.set_window_position(@window, LibSDL::WindowPosition::CENTERED, LibSDL::WindowPosition::CENTERED)
LibGL.viewport(0, 0, @window.width, @window.height)
LibGL.use_program(@shader_programs[@controller.class])
@shader_programs[@controller.class].use
LibGL.disable(LibGL::BLEND)
pause(false)
@ -170,10 +169,8 @@ class SDLOpenGLImGuiFrontend < Frontend
end
private def render_game : Nil
aspect = LibGL.get_uniform_location(@shader_programs[@controller.class], "aspect")
LibGL.uniform_1f(aspect, 1)
scale = LibGL.get_uniform_location(@shader_programs[@controller.class], "scale")
LibGL.uniform_1f(scale, 1)
@shader_programs[@controller.class].aspect = 1
@shader_programs[@controller.class].scale = 1
LibGL.bind_texture(LibGL::TEXTURE_2D, @game_texture)
LibGL.tex_image_2d(
@ -305,21 +302,6 @@ class SDLOpenGLImGuiFrontend < Frontend
end
end
private def compile_shader(source : String, type : LibGL::Enum) : UInt32
source_ptr = source.to_unsafe
shader = LibGL.create_shader(type)
LibGL.shader_source(shader, 1, pointerof(source_ptr), nil)
LibGL.compile_shader(shader)
LibGL.get_shader_iv(shader, LibGL::COMPILE_STATUS, out shader_compiled)
if shader_compiled != LibGL::TRUE
LibGL.get_shader_iv(shader, LibGL::INFO_LOG_LENGTH, out log_length)
s = " " * log_length
LibGL.get_shader_info_log(shader, log_length, out _, s) if log_length > 0
abort "Error compiling shader: #{s}"
end
shader
end
private def setup_gl : LibSDL::GLContext
{% if flag?(:darwin) %}
LibSDL.gl_set_attribute(LibSDL::GLattr::SDL_GL_CONTEXT_FLAGS, LibSDL::GLcontextFlag::FORWARD_COMPATIBLE_FLAG)
@ -373,17 +355,6 @@ class SDLOpenGLImGuiFrontend < Frontend
{crab_texture, canvas.height / canvas.width}
end
private def create_shader_program(vertex_shader, fragment_shader : String) : UInt32
shader_program = LibGL.create_program
vert_shader_id = compile_shader(File.read("#{SHADERS}/#{vertex_shader}"), LibGL::VERTEX_SHADER)
frag_shader_id = compile_shader(File.read("#{SHADERS}/#{fragment_shader}"), LibGL::FRAGMENT_SHADER)
LibGL.attach_shader(shader_program, vert_shader_id)
LibGL.attach_shader(shader_program, frag_shader_id)
LibGL.link_program(shader_program)
LibGL.validate_program(shader_program)
shader_program
end
private def setup_imgui : ImGui::ImGuiIO
LibImGuiBackends.gl3wInit

View file

@ -0,0 +1,51 @@
require "lib_gl"
class Shader
@id : UInt32
def initialize(vertex_shader_path : String | Path, fragment_shader_path : String | Path)
@id = LibGL.create_program
vert_shader_id = compile_shader(File.read(vertex_shader_path), LibGL::VERTEX_SHADER)
frag_shader_id = compile_shader(File.read(fragment_shader_path), LibGL::FRAGMENT_SHADER)
LibGL.attach_shader(@id, vert_shader_id)
LibGL.attach_shader(@id, frag_shader_id)
LibGL.link_program(@id)
LibGL.validate_program(@id)
end
def use : Nil
LibGL.use_program(@id)
end
macro method_missing(call)
{% if !call.name.stringify.ends_with?("=") %}
{% raise "#{@type.name}.#{call.name.stringify.id} does not exist" %}
{% elsif call.args.size != 1 %}
{% raise "Call to #{@type.name}.#{call.name.stringify.id} must take one argument" %}
{% end %}
loc = LibGL.get_uniform_location(@id, {{ call.name.stringify[0..-2] }})
case {{call.args[0]}}
when Float then LibGL.uniform_1f(loc, {{call.args[0]}})
when Int then LibGL.uniform_1i(loc, {{call.args[0]}})
when Bool then LibGL.uniform_1i(loc, {{call.args[0]}}.to_unsafe)
else raise "Call to {{@type.name}}.{{call.name.stringify.id}}({{call.args[0]}}) must be of type (Float | Int | Bool)"
end
end
private def compile_shader(source : String, type : LibGL::Enum) : UInt32
source_ptr = source.to_unsafe
shader = LibGL.create_shader(type)
LibGL.shader_source(shader, 1, pointerof(source_ptr), nil)
LibGL.compile_shader(shader)
LibGL.get_shader_iv(shader, LibGL::COMPILE_STATUS, out shader_compiled)
if shader_compiled != LibGL::TRUE
LibGL.get_shader_iv(shader, LibGL::INFO_LOG_LENGTH, out log_length)
s = " " * log_length
LibGL.get_shader_info_log(shader, log_length, out _, s) if log_length > 0
abort "Error compiling shader: #{s}"
end
shader
end
end