diff --git a/i-mic-fps.rb b/i-mic-fps.rb index 948d199..4f7dcb1 100644 --- a/i-mic-fps.rb +++ b/i-mic-fps.rb @@ -21,6 +21,12 @@ when :OPENGL_PLATFORM_MACOSX OpenGL.load_lib("libGL.dylib", "/System/Library/Frameworks/OpenGL.framework/Libraries") GLU.load_lib("libGLU.dylib", "/System/Library/Frameworks/OpenGL.framework/Libraries") when :OPENGL_PLATFORM_LINUX + # Black magic to get GLSL 3.30 support on older Intel hardware + if `glxinfo | egrep "OpenGL vendor|OpenGL renderer"`.include?("Intel") + ENV["MESA_GL_VERSION_OVERRIDE"] = "3.3" + ENV["MESA_GLSL_VERSION_OVERRIDE"] = "330" + end + gl_library_path = nil if File.exist?("/usr/lib/x86_64-linux-gnu/libGL.so") # Ubuntu (Debian) @@ -63,6 +69,9 @@ if RUBY_VERSION < "2.5.0" end include CyberarmEngine +include OpenGL +include GLU + require_relative "lib/version" require_relative "lib/constants" require_relative "lib/common_methods" @@ -111,9 +120,6 @@ require_relative "lib/wavefront/model" require_relative "lib/window" -MODEL_METER_SCALE = 1.0 # Objects exported from blender using the default or meter object scale will be close to 1 GL unit - - if ARGV.join.include?("--profile") begin require "ruby-prof" diff --git a/lib/common_methods.rb b/lib/common_methods.rb index e9538be..aafef05 100644 --- a/lib/common_methods.rb +++ b/lib/common_methods.rb @@ -42,5 +42,14 @@ class IMICFPS def fill(color = Gosu::Color::WHITE) draw_rect(0, 0, window.width, window.height, color) end + + def handleGlError + e = glGetError() + if e != GL_NO_ERROR + $stderr.puts "OpenGL error detected by handler at: #{caller[0]}" + $stderr.puts " #{gluErrorString(e)} (#{e})\n" + exit + end + end end end diff --git a/lib/constants.rb b/lib/constants.rb index 0593a0b..d1b5835 100644 --- a/lib/constants.rb +++ b/lib/constants.rb @@ -5,4 +5,7 @@ class IMICFPS Point = Struct.new(:x, :y) Color = Struct.new(:red, :green, :blue, :alpha) Face = Struct.new(:vertices, :uvs, :normals, :colors, :material, :smoothing) + + # Objects exported from blender using the default or meter object scale will be close to 1 GL unit + MODEL_METER_SCALE = 1.0 end \ No newline at end of file diff --git a/lib/objects/camera.rb b/lib/objects/camera.rb index 11e2d96..3272001 100644 --- a/lib/objects/camera.rb +++ b/lib/objects/camera.rb @@ -1,8 +1,6 @@ class IMICFPS class Camera include CommonMethods - include OpenGL - include GLU attr_accessor :field_of_view, :pitch, :yaw, :roll, :mouse_sensitivity attr_reader :entity, :position diff --git a/lib/objects/entity.rb b/lib/objects/entity.rb index 8f3fd2b..386e619 100644 --- a/lib/objects/entity.rb +++ b/lib/objects/entity.rb @@ -3,8 +3,6 @@ class IMICFPS # A game object is any renderable thing class Entity - include OpenGL - include GLU include CommonMethods attr_accessor :scale, :visible, :renderable, :backface_culling @@ -104,13 +102,5 @@ class IMICFPS def normalize_bounding_box @bound_model.model.bounding_box.normalize(self) end - - def handleGlError - e = glGetError() - if e != GL_NO_ERROR - $stderr.puts "OpenGL error in: #{gluErrorString(e)} (#{e})\n" - exit - end - end end end diff --git a/lib/objects/light.rb b/lib/objects/light.rb index 95aa299..a8b366a 100644 --- a/lib/objects/light.rb +++ b/lib/objects/light.rb @@ -1,6 +1,5 @@ class IMICFPS class Light - include OpenGL attr_reader :ambient, :diffuse, :specular, :position, :light_id attr_accessor :x, :y, :z, :intensity def initialize(x:,y:,z:, game_state:, diff --git a/lib/renderer/bounding_box_renderer.rb b/lib/renderer/bounding_box_renderer.rb index 0a26cb4..31d80c2 100644 --- a/lib/renderer/bounding_box_renderer.rb +++ b/lib/renderer/bounding_box_renderer.rb @@ -1,8 +1,5 @@ class IMICFPS class BoundingBoxRenderer - include OpenGL - include GLU - attr_reader :bounding_boxes, :vertex_count def initialize(game_state:) @game_state = game_state @@ -11,14 +8,6 @@ class IMICFPS @vertex_count = 0 end - def handleGlError - e = glGetError() - if e != GL_NO_ERROR - $stderr.puts "OpenGL error in: #{gluErrorString(e)} (#{e})\n" - exit - end - end - def create_bounding_box(object, box, color = nil, mesh_object_id) color ||= object.debug_color diff --git a/lib/renderer/opengl_renderer.rb b/lib/renderer/opengl_renderer.rb index 486c27b..f2c4b83 100644 --- a/lib/renderer/opengl_renderer.rb +++ b/lib/renderer/opengl_renderer.rb @@ -1,19 +1,6 @@ class IMICFPS class OpenGLRenderer include CommonMethods - include OpenGL - include GLU - - def initialize - end - - def handleGlError - e = glGetError() - if e != GL_NO_ERROR - $stderr.puts "OpenGL error in: #{gluErrorString(e)} (#{e})\n" - exit - end - end def draw_object(object) handleGlError @@ -28,12 +15,12 @@ class IMICFPS handleGlError - if Shader.available?("lighting") - Shader.use("lighting") do |shader| - glUniform3f(shader.attribute_location("SunLight"), 1.0, 1.0, 1.0) + if Shader.available?("default") + Shader.use("default") do |shader| + glUniform3f(shader.attribute_location("worldPosition"), object.position.x, object.position.y, object.position.z) handleGlError - draw_mesh(object.model) + draw_model(object.model) object.draw end else @@ -47,6 +34,28 @@ class IMICFPS handleGlError end + def draw_model(model) + glBindVertexArray(model.vertex_array_id) + glBindBuffer(GL_ARRAY_BUFFER, model.vertices_buffer_id) + glEnableVertexAttribArray(0) + glEnableVertexAttribArray(1) + glEnableVertexAttribArray(2) + glEnableVertexAttribArray(3) + glEnableVertexAttribArray(4) + + glDrawArrays(GL_TRIANGLES, 0, model.vertices.count) + window.number_of_vertices+=model.vertices.size + + glDisableVertexAttribArray(4) + glDisableVertexAttribArray(3) + glDisableVertexAttribArray(2) + glDisableVertexAttribArray(1) + glDisableVertexAttribArray(0) + + glBindBuffer(GL_ARRAY_BUFFER, 0) + glBindVertexArray(0) + end + def draw_mesh(model) model.objects.each_with_index do |o, i| glEnable(GL_CULL_FACE) if model.entity.backface_culling diff --git a/lib/renderer/renderer.rb b/lib/renderer/renderer.rb index 83b9c5a..2e19d0c 100644 --- a/lib/renderer/renderer.rb +++ b/lib/renderer/renderer.rb @@ -1,8 +1,6 @@ class IMICFPS class Renderer include CommonMethods - include OpenGL - include GLU attr_reader :opengl_renderer, :bounding_box_renderer @@ -28,14 +26,6 @@ class IMICFPS # @bounding_box_renderer.bounding_boxes.clear end - def handleGlError - e = glGetError() - if e != GL_NO_ERROR - $stderr.puts "OpenGL error in: #{gluErrorString(e)} (#{e})\n" - exit - end - end - def finalize # cleanup end end diff --git a/lib/states/game_states/game.rb b/lib/states/game_states/game.rb index 959817b..bea5025 100644 --- a/lib/states/game_states/game.rb +++ b/lib/states/game_states/game.rb @@ -1,8 +1,5 @@ class IMICFPS class Game < GameState - include OpenGL - include GLU - def setup @collision_manager = CollisionManager.new(game_state: self) @renderer = Renderer.new(game_state: self) diff --git a/lib/states/game_states/loading_state.rb b/lib/states/game_states/loading_state.rb index 3f3cf95..2537f05 100644 --- a/lib/states/game_states/loading_state.rb +++ b/lib/states/game_states/loading_state.rb @@ -15,7 +15,7 @@ class IMICFPS add_asset(:model, "base", "tree") add_asset(:model, "base", "biped") - add_asset(:shader, nil, "lighting") + add_asset(:shader, nil, "default") @act = false @cycled = false diff --git a/lib/wavefront/material.rb b/lib/wavefront/material.rb index c73c7e4..df7e4f1 100644 --- a/lib/wavefront/material.rb +++ b/lib/wavefront/material.rb @@ -1,7 +1,6 @@ class IMICFPS class Wavefront class Material - include OpenGL attr_accessor :name, :ambient, :diffuse, :specular attr_reader :texture_id def initialize(name) diff --git a/lib/wavefront/model.rb b/lib/wavefront/model.rb index dd97cbb..c7eb2ad 100644 --- a/lib/wavefront/model.rb +++ b/lib/wavefront/model.rb @@ -5,7 +5,6 @@ require_relative "material" class IMICFPS class Wavefront class Model - include OpenGL include CommonMethods include Parser @@ -14,8 +13,9 @@ class IMICFPS attr_accessor :scale, :entity attr_reader :position, :bounding_box, :textured_material - attr_reader :vertices_buffer + attr_reader :vertices_buffer_id attr_reader :vertices_buffer_data + attr_reader :vertices_buffer_size attr_reader :vertex_array_id attr_reader :aabb_tree @@ -45,8 +45,8 @@ class IMICFPS puts "#{@file_path.split('/').last} took #{((Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)-start_time)/1000.0).round(2)} seconds to parse" if $debug.get(:stats) allocate_gl_objects - populate_buffers - # populate_arrays + populate_vertex_buffer + configure_vao @objects.each {|o| @vertex_count+=o.vertices.size} @objects.each_with_index do |o, i| @@ -61,7 +61,9 @@ class IMICFPS end end + start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) build_collision_tree + puts " Building mesh collision tree took #{((Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)-start_time)/1000.0).round(2)} seconds" if $debug.get(:stats) end def allocate_gl_objects @@ -73,15 +75,17 @@ class IMICFPS @vertex_array_id = buffer.unpack('L2').first # Allocate buffers for future use - @vertices_buffer = nil + @vertices_buffer_id = nil buffer = " " * 4 glGenBuffers(1, buffer) - @vertices_buffer = buffer.unpack('L2').first + @vertices_buffer_id = buffer.unpack('L2').first end - def populate_buffers + def populate_vertex_buffer + @vertices_buffer_size = 0 @vertices_buffer_data = [] + model_has_texture = @materials.any? { |id, mat| mat.texture_id != nil } verts = [] colors = [] @@ -93,8 +97,11 @@ class IMICFPS verts << face.vertices.map { |vert| [vert.x, vert.y, vert.z] } colors << face.colors.map { |vert| [vert.x, vert.y, vert.z] } norms << face.normals.map { |vert| [vert.x, vert.y, vert.z, vert.weight] } - uvs << face.uvs.map { |vert| [vert.x, vert.y, vert.z] } if face.material.texture_id - tex_ids << face.material.texture_id if face.material.texture_id + + if model_has_texture + uvs << face.uvs.map { |vert| [vert.x, vert.y, vert.z] } + tex_ids << face.material.texture_id ? face.material.texture_id : -1 + end end verts.each_with_index do |vert, i| @@ -105,18 +112,57 @@ class IMICFPS @vertices_buffer_data << tex_ids[i] if tex_ids.size > 0 end + data_size = 0 + data_size += Fiddle::SIZEOF_FLOAT * 3 * verts.size + data_size += Fiddle::SIZEOF_FLOAT * 3 * colors.size + data_size += Fiddle::SIZEOF_FLOAT * 4 * norms.size + data_size += Fiddle::SIZEOF_FLOAT * 3 * uvs.size + data_size += Fiddle::SIZEOF_INT * 1 * tex_ids.size + + @vertices_buffer_size = data_size + data = @vertices_buffer_data.flatten.pack("f*") - glBindBuffer(GL_ARRAY_BUFFER, @vertices_buffer) - glBufferData(GL_ARRAY_BUFFER, Fiddle::SIZEOF_FLOAT * @vertices_buffer_data.size, data, GL_STATIC_DRAW) + glBindBuffer(GL_ARRAY_BUFFER, @vertices_buffer_id) + glBufferData(GL_ARRAY_BUFFER, @vertices_buffer_size, data, GL_STATIC_DRAW) glBindBuffer(GL_ARRAY_BUFFER, 0) end - def populate_arrays + def configure_vao + glBindBuffer(GL_ARRAY_BUFFER, @vertices_buffer_id) glBindVertexArray(@vertex_array_id) - glBindBuffer(GL_ARRAY_BUFFER, @vertices_buffer) - glBindVertexArray(0) + + glEnableVertexAttribArray(0) + glEnableVertexAttribArray(1) + glEnableVertexAttribArray(2) + glEnableVertexAttribArray(3) + glEnableVertexAttribArray(4) + + # index, size, type, normalized, stride, pointer + # vertices (positions) + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, Fiddle::SIZEOF_FLOAT * 3, nil) + handleGlError + # colors + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, Fiddle::SIZEOF_FLOAT * (3 + 3), nil) + handleGlError + # normals + glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, Fiddle::SIZEOF_FLOAT * (4 + 3 + 3), nil) + handleGlError + # uvs + glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, Fiddle::SIZEOF_FLOAT * (3 + 4 + 3 + 3), nil) + handleGlError + # texture ids + glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, Fiddle::SIZEOF_FLOAT + (Fiddle::SIZEOF_FLOAT * (3 + 4 + 3 + 3)), nil) + handleGlError + + glDisableVertexAttribArray(4) + glDisableVertexAttribArray(3) + glDisableVertexAttribArray(2) + glDisableVertexAttribArray(1) + glDisableVertexAttribArray(0) + glBindBuffer(GL_ARRAY_BUFFER, 0) + glBindVertexArray(0) end def build_collision_tree diff --git a/shaders/fragment/default.glsl b/shaders/fragment/default.glsl new file mode 100644 index 0000000..f6627bc --- /dev/null +++ b/shaders/fragment/default.glsl @@ -0,0 +1,10 @@ +# version 330 + +in vec3 outColor; +in vec4 outNormal; +in vec3 outUV; +in float outTextureID; + +void main() { + gl_FragColor = vec4(outColor, 1.0); +} \ No newline at end of file diff --git a/shaders/fragment/lighting.glsl b/shaders/fragment/lighting.glsl deleted file mode 100644 index e8569e0..0000000 --- a/shaders/fragment/lighting.glsl +++ /dev/null @@ -1,7 +0,0 @@ -# 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/default.glsl b/shaders/vertex/default.glsl new file mode 100644 index 0000000..d81d831 --- /dev/null +++ b/shaders/vertex/default.glsl @@ -0,0 +1,24 @@ +# version 330 + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inColor; +layout(location = 2) in vec4 inNormal; +layout(location = 3) in vec3 inUV; +layout(location = 4) in float inTextureID; + +out vec3 outColor; +out vec4 outNormal; +out vec3 outUV; +out float outTextureID; + +uniform vec3 worldPosition; + +void main() { + // projection * view * model * + outColor = inColor; + outNormal= inNormal; + outUV = inUV; + outTextureID = inTextureID; + + gl_Position = vec4(worldPosition + inPosition, 1.0); +} \ No newline at end of file diff --git a/shaders/vertex/lighting.glsl b/shaders/vertex/lighting.glsl deleted file mode 100644 index 2af6e81..0000000 --- a/shaders/vertex/lighting.glsl +++ /dev/null @@ -1,9 +0,0 @@ -# version 330 - -layout(location = 0) in vec3 vert; -uniform vec3 position; - -void main() { - // projection * view * model * - gl_Position = vec4(vert+position, 1.0); -} \ No newline at end of file