From 4d8638d81c71a1abcb2ed4abbe9b33cc1ab60922 Mon Sep 17 00:00:00 2001 From: Cyberarm Date: Mon, 10 Dec 2018 18:50:25 -0600 Subject: [PATCH] Added shader support, removed unused debugging puts statements and fixed Gosu Font.draw deprecation warning. --- i-mic-fps.rb | 3 + lib/managers/shader_manager.rb | 12 +++ lib/objects/game_objects/camera.rb | 14 +-- lib/objects/game_objects/terrain.rb | 2 - lib/objects/model_loader.rb | 2 +- lib/objects/text.rb | 18 ++-- lib/renderer/opengl_renderer.rb | 22 ++++- lib/renderer/shader.rb | 112 ++++++++++++++++++++++++ lib/states/game_states/loading_state.rb | 5 +- lib/wavefront/material.rb | 2 +- lib/wavefront/model.rb | 23 +++-- shaders/fragment/lighting.glsl | 7 ++ shaders/vertex/lighting.glsl | 8 ++ 13 files changed, 201 insertions(+), 29 deletions(-) create mode 100644 lib/managers/shader_manager.rb create mode 100644 lib/renderer/shader.rb create mode 100644 shaders/fragment/lighting.glsl create mode 100644 shaders/vertex/lighting.glsl diff --git a/i-mic-fps.rb b/i-mic-fps.rb index 90a1201..3d141f6 100644 --- a/i-mic-fps.rb +++ b/i-mic-fps.rb @@ -42,10 +42,13 @@ end $debug = ARGV.join.include?("--debug") ? true : false require_relative "lib/common_methods" +require_relative "lib/managers/shader_manager" require_relative "lib/managers/object_manager" require_relative "lib/managers/light_manager" +require_relative "lib/managers/network_manager" require_relative "lib/renderer/renderer" +require_relative "lib/renderer/shader" require_relative "lib/renderer/opengl_renderer" require_relative "lib/renderer/bounding_box_renderer" diff --git a/lib/managers/shader_manager.rb b/lib/managers/shader_manager.rb new file mode 100644 index 0000000..b63fc13 --- /dev/null +++ b/lib/managers/shader_manager.rb @@ -0,0 +1,12 @@ +class IMICFPS + class ShaderManager + SHADERS = {} + def self.add_shader(name, shader) + SHADERS[name] = shader + end + + def self.shader(name) + SHADERS[name] + end + end +end \ No newline at end of file diff --git a/lib/objects/game_objects/camera.rb b/lib/objects/game_objects/camera.rb index 9a95885..421dc92 100644 --- a/lib/objects/game_objects/camera.rb +++ b/lib/objects/game_objects/camera.rb @@ -77,13 +77,13 @@ class IMICFPS glMatrixMode(GL_MODELVIEW) # The modelview matrix is where object information is stored. glLoadIdentity - if $debug && @game_object - glBegin(GL_LINES) - glColor3f(1,0,0) - glVertex3f(@x, @y, @z) - glVertex3f(@game_object.x, @game_object.y, @game_object.z) - glEnd - end + # if $debug && @game_object + # glBegin(GL_LINES) + # glColor3f(1,0,0) + # glVertex3f(@x, @y, @z) + # glVertex3f(@game_object.x, @game_object.y, @game_object.z) + # glEnd + # end end def update diff --git a/lib/objects/game_objects/terrain.rb b/lib/objects/game_objects/terrain.rb index e505cf2..428d4b4 100644 --- a/lib/objects/game_objects/terrain.rb +++ b/lib/objects/game_objects/terrain.rb @@ -19,8 +19,6 @@ class IMICFPS @nearest_vertex_lookup[x_slot][y_slot] = [] unless @nearest_vertex_lookup[x_slot][y_slot] @nearest_vertex_lookup[x_slot][y_slot] << vert end - - p model.faces.first end def height_at(vertex, max_distance = Float::INFINITY) diff --git a/lib/objects/model_loader.rb b/lib/objects/model_loader.rb index 0ddb28e..fd3f78c 100644 --- a/lib/objects/model_loader.rb +++ b/lib/objects/model_loader.rb @@ -37,7 +37,7 @@ class IMICFPS if CACHE[@type].is_a?(Hash) if CACHE[@type][@file_path] @model = CACHE[@type][@file_path]#.dup # Don't know why, but adding .dup improves performance with Sponza (1 fps -> 20 fps) - puts "Used cached model for: #{@file_path.split('/').last}" + # puts "Used cached model for: #{@file_path.split('/').last}" found = true end end diff --git a/lib/objects/text.rb b/lib/objects/text.rb index b0cd6c7..6571ebe 100644 --- a/lib/objects/text.rb +++ b/lib/objects/text.rb @@ -75,20 +75,20 @@ class Text # _color = Gosu::Color.rgba(@color.red, @color.green, @color.blue, @shadow_alpha) if @shadow_alpha <= @color.alpha # _color = Gosu::Color.rgba(@color.red, @color.green, @color.blue, @color.alpha) unless @shadow_alpha <= @color.alpha _color = Gosu::Color::BLACK - @textobject.draw(@text, @x-@shadow_size, @y, @z, @factor_x, @factor_y, _color) - @textobject.draw(@text, @x-@shadow_size, @y-@shadow_size, @z, @factor_x, @factor_y, _color) + @textobject.draw_text(@text, @x-@shadow_size, @y, @z, @factor_x, @factor_y, _color) + @textobject.draw_text(@text, @x-@shadow_size, @y-@shadow_size, @z, @factor_x, @factor_y, _color) - @textobject.draw(@text, @x, @y-@shadow_size, @z, @factor_x, @factor_y, _color) - @textobject.draw(@text, @x+@shadow_size, @y-@shadow_size, @z, @factor_x, @factor_y, _color) + @textobject.draw_text(@text, @x, @y-@shadow_size, @z, @factor_x, @factor_y, _color) + @textobject.draw_text(@text, @x+@shadow_size, @y-@shadow_size, @z, @factor_x, @factor_y, _color) - @textobject.draw(@text, @x, @y+@shadow_size, @z, @factor_x, @factor_y, _color) - @textobject.draw(@text, @x-@shadow_size, @y+@shadow_size, @z, @factor_x, @factor_y, _color) + @textobject.draw_text(@text, @x, @y+@shadow_size, @z, @factor_x, @factor_y, _color) + @textobject.draw_text(@text, @x-@shadow_size, @y+@shadow_size, @z, @factor_x, @factor_y, _color) - @textobject.draw(@text, @x+@shadow_size, @y, @z, @factor_x, @factor_y, _color) - @textobject.draw(@text, @x+@shadow_size, @y+@shadow_size, @z, @factor_x, @factor_y, _color) + @textobject.draw_text(@text, @x+@shadow_size, @y, @z, @factor_x, @factor_y, _color) + @textobject.draw_text(@text, @x+@shadow_size, @y+@shadow_size, @z, @factor_x, @factor_y, _color) end - @textobject.draw(@text, @x, @y, @z, @factor_x, @factor_y, @color) + @textobject.draw_markup(@text, @x, @y, @z, @factor_x, @factor_y, @color) end def update; end diff --git a/lib/renderer/opengl_renderer.rb b/lib/renderer/opengl_renderer.rb index 2d30296..1f48975 100644 --- a/lib/renderer/opengl_renderer.rb +++ b/lib/renderer/opengl_renderer.rb @@ -27,9 +27,17 @@ class IMICFPS handleGlError - draw_mesh(object.model) - object.draw - + if ShaderManager.shader("lighting") + ShaderManager.shader("lighting").use do |shader| + handleGlError + draw_mesh(object.model) + object.draw + end + else + handleGlError + draw_mesh(object.model) + object.draw + end handleGlError glPopMatrix @@ -56,21 +64,29 @@ class IMICFPS glColorPointer(3, GL_FLOAT, 0, o.flattened_materials) glNormalPointer(GL_FLOAT, 0, o.flattened_normals) + # glBindBuffer(GL_ARRAY_BUFFER, model.vertices_buffer) + # glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0) + if $debug # This is kinda expensive glDisable(GL_LIGHTING) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) glPolygonOffset(2, 0.5) glLineWidth(3) + glDrawArrays(GL_TRIANGLES, 0, o.flattened_vertices_size/4) + glLineWidth(1) glPolygonOffset(0, 0) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glEnable(GL_LIGHTING) + glDrawArrays(GL_TRIANGLES, 0, o.flattened_vertices_size/4) else glDrawArrays(GL_TRIANGLES, 0, o.flattened_vertices_size/4) end + # glBindBuffer(GL_ARRAY_BUFFER, 0) + glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_COLOR_ARRAY) glDisableClientState(GL_NORMAL_ARRAY) diff --git a/lib/renderer/shader.rb b/lib/renderer/shader.rb new file mode 100644 index 0000000..ac601dd --- /dev/null +++ b/lib/renderer/shader.rb @@ -0,0 +1,112 @@ +class IMICFPS + # Ref: https://github.com/vaiorabbit/ruby-opengl/blob/master/sample/OrangeBook/brick.rb + class Shader + include OpenGL + + def initialize(name:, vertex_file:, fragment_file:) + @name = name + @vertex_file = vertex_file + @fragment_file = fragment_file + @compiled = false + + @error_buffer_size = 1024 + + create_shaders + compile_shaders + + if @compiled + ShaderManager.add_shader(@name, self) + else + puts "FAILED to compile shader: #{@name}", "" + end + end + + def shader_files_exist? + File.exists?(@vertex_file) && File.exists?(@fragment_file) + end + + def create_shaders + return unless shader_files_exist? + + @vertex = glCreateShader(GL_VERTEX_SHADER) + @fragment = glCreateShader(GL_FRAGMENT_SHADER) + + source = [File.read(@vertex_file)].pack('p') + size = [File.size(@vertex_file)].pack('I') + glShaderSource(@vertex, 1, source, size) + + source = [File.read(@fragment_file)].pack('p') + size = [File.size(@fragment_file)].pack('I') + glShaderSource(@fragment, 1, source, size) + end + + def compile_shaders + return unless shader_files_exist? + + glCompileShader(@vertex) + buffer = ' ' + glGetShaderiv(@vertex, GL_COMPILE_STATUS, buffer) + compiled = buffer.unpack('L')[0] + + if compiled == 0 + log = ' ' * @error_buffer_size + glGetShaderInfoLog(@vertex, @error_buffer_size, nil, log) + puts "Vertex Shader InfoLog:\n#{log.strip}\n" + puts "Shader Compiled status: #{compiled}" + puts + end + + glCompileShader(@fragment) + buffer = ' ' + 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 "Fragment Shader InfoLog:\n#{log.strip}\n" + puts "Shader Compiled status: #{compiled}" + puts + end + + @program = glCreateProgram + glAttachShader(@program, @vertex) + glAttachShader(@program, @fragment) + glLinkProgram(@program) + + buffer = ' ' + glGetProgramiv(@program, GL_LINK_STATUS, buffer) + linked = buffer.unpack('L')[0] + + if linked == 0 + log = ' ' * @error_buffer_size + glGetProgramInfoLog(@program, @error_buffer_size, nil, log) + puts "Program InfoLog:\n#{log.strip}\n" + end + + @compiled = linked == 0 ? false : true + end + + # Returns the location of a uniform variable + def variable(variable) + loc = glGetUniformLocation(@program, variable) + if (loc == -1) + puts "Shader:\"#{@name}\" No such uniform named #{variable}" + end + return loc + end + + def use(&block) + return unless compiled? + glUseProgram(@program) + + block.call(self) if block + + glUseProgram(0) + end + + def compiled? + @compiled + end + end +end \ No newline at end of file diff --git a/lib/states/game_states/loading_state.rb b/lib/states/game_states/loading_state.rb index b65f80a..8deac7a 100644 --- a/lib/states/game_states/loading_state.rb +++ b/lib/states/game_states/loading_state.rb @@ -14,6 +14,9 @@ class IMICFPS add_asset(:obj, "objects/tree.obj") add_asset(:obj, "objects/biped.obj") + # Currently broken + # Shader.new(name: "lighting", vertex_file: "shaders/vertex/lighting.glsl", fragment_file: "shaders/fragment/lighting.glsl") + @act = false @cycled = false @@ -31,7 +34,7 @@ class IMICFPS end def update - puts (@asset_index.to_f/@assets.count) + # puts (@asset_index.to_f/@assets.count) @percentage.text = "#{((@asset_index.to_f/@assets.count)*100.0).round}%" @act = true if @cycled diff --git a/lib/wavefront/material.rb b/lib/wavefront/material.rb index 4717632..77759db 100644 --- a/lib/wavefront/material.rb +++ b/lib/wavefront/material.rb @@ -14,7 +14,7 @@ class IMICFPS end def set_texture(texture_path) - puts "#{name} texture #{texture_path}" + # puts "#{name} texture #{texture_path}" @texture = Gosu::Image.new(texture_path, retro: false) array_of_pixels = @texture.to_blob diff --git a/lib/wavefront/model.rb b/lib/wavefront/model.rb index 77bdc51..111396f 100644 --- a/lib/wavefront/model.rb +++ b/lib/wavefront/model.rb @@ -13,7 +13,9 @@ class IMICFPS attr_accessor :objects, :materials, :vertices, :texures, :normals, :faces attr_accessor :x, :y, :z, :scale, :game_object attr_reader :bounding_box, :model_has_texture, :textured_material - attr_reader :normals_buffer, :colors_buffer, :vertices_buffer + + attr_reader :normals_buffer, :uvs_buffer, :vertices_buffer + attr_reader :vertices_buffer_data, :uvs_buffer_data, :normals_buffer_data def initialize(file_path:, game_object: nil) @game_object = game_object @@ -40,7 +42,7 @@ class IMICFPS buffer = " " * 4 glGenBuffers(1, buffer) - @colors_buffer = buffer.unpack('L2').first + @uvs_buffer = buffer.unpack('L2').first buffer = " " * 4 glGenBuffers(1, buffer) @@ -48,7 +50,9 @@ class IMICFPS @bounding_box = BoundingBox.new(0,0,0, 0,0,0) start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) + parse + puts "#{@file_path.split('/').last} took #{((Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)-start_time)/1000.0).round(2)} seconds to parse" # populate_buffers @@ -69,12 +73,21 @@ class IMICFPS end def populate_buffers - glBindBuffer(GL_ARRAY_BUFFER, @normals_buffer) - glBufferData(GL_ARRAY_BUFFER, @vertices.size, @vertices.flatten.pack("f*"), GL_STATIC_DRAW) + @vertices_buffer_data = @vertices.map {|vert| [vert.x, vert.y, vert.z]}.flatten.pack("f*") + @uvs_buffer_data = @uvs.map {|uv| [uv.x, uv.y, uv.z]}.flatten.pack("f*") + @normals_buffer_data = @normals.map {|norm| [norm.x, norm.y, norm.z, norm.weight]}.flatten.pack("f*") - glBindBuffer(GL_ARRAY_BUFFER, @colors_buffer) glBindBuffer(GL_ARRAY_BUFFER, @vertices_buffer) + glBufferData(GL_ARRAY_BUFFER, @vertices.size, @vertices_buffer_data, GL_STATIC_DRAW) + glBindBuffer(GL_ARRAY_BUFFER, 0) + glBindBuffer(GL_ARRAY_BUFFER, @uvs_buffer) + glBufferData(GL_ARRAY_BUFFER, @uvs.size, @uvs_buffer_data, GL_STATIC_DRAW) + glBindBuffer(GL_ARRAY_BUFFER, 0) + + glBindBuffer(GL_ARRAY_BUFFER, @normals_buffer) + glBufferData(GL_ARRAY_BUFFER, @normals.size, @normals_buffer_data, GL_STATIC_DRAW) + glBindBuffer(GL_ARRAY_BUFFER, 0) end def update diff --git a/shaders/fragment/lighting.glsl b/shaders/fragment/lighting.glsl new file mode 100644 index 0000000..e8569e0 --- /dev/null +++ b/shaders/fragment/lighting.glsl @@ -0,0 +1,7 @@ +# version 150 + +out vec4 frag_colour; + +void main() { + frag_colour = vec4(0.5, 0.0, 0.5, 1.0); +} \ No newline at end of file diff --git a/shaders/vertex/lighting.glsl b/shaders/vertex/lighting.glsl new file mode 100644 index 0000000..9a35f61 --- /dev/null +++ b/shaders/vertex/lighting.glsl @@ -0,0 +1,8 @@ +# version 150 +# extension GL_ARB_explicit_attrib_location : enable + +layout(location = 0) in vec3 vert; + +void main() { + gl_Position = vec4(vert, 1.0); +} \ No newline at end of file