diff --git a/i-mic-fps.rb b/i-mic-fps.rb index a9bb623..c827886 100644 --- a/i-mic-fps.rb +++ b/i-mic-fps.rb @@ -4,7 +4,9 @@ require "glut" require "gosu" # require "wavefront" -require_relative "lib/object" +require_relative "lib/wavefront/model" +require_relative "lib/wavefront/object" +require_relative "lib/wavefront/material" require_relative "lib/window" IMICFPS::Window.new.show diff --git a/lib/object.rb b/lib/object.rb index a1e3a23..3d6309a 100644 --- a/lib/object.rb +++ b/lib/object.rb @@ -1,35 +1,47 @@ class IMICFPS class Object - Vertex = Struct.new("Vertex", :x, :y, :z) + include GL + include GLU + TextureCoordinate = Struct.new(:u, :v, :weight) + Vertex = Struct.new(:x, :y, :z, :weight) + Color = Struct.new(:red, :green, :blue) attr_accessor :vertexes, :texures, :normals, :faces def initialize(object = "objects/cube.obj") - @level = File.open(object, 'r') + @object_path = object + @file = File.open(object, 'r') + @material_file = nil @vertexes = [] @textures = [] @normals = [] @faces = [] parse + @color = Color.new(1.0,1.0,1.0) end def parse - @level.each_line do |line| + @file.each_line do |line| line = line.strip array = line.split(' ') case array[0] + when 'mtllib' + @material_file = array[1] + puts @material_file + parse_mtllib + when 'usemtl' + # PI*(r*r) + set_material(array[1]) + when 'o' + change_object(array[1]) when 'v' - vert = Vertex.new(Float(array[1]), Float(array[2]), Float(array[3])) - @vertexes << vert + add_vertex(array) when 'vt' - p array - # vert = Vertex.new(Float(array[1]), Float(array[2]), Float(array[3])) - # @textures << vert + add_texture_coordinate(array) when 'vn' - vert = Vertex.new(Float(array[1]), Float(array[2]), Float(array[3])) - @normals << vert + add_normal(array) when 'f' vert = [] @@ -46,5 +58,77 @@ class IMICFPS end end end + + def parse_mtllib + file = File.open(@object_path.sub(File.basename(@object_path), '')+@material_file, 'r') + file.readlines.each do |line| + array = line.strip.split(' ') + p array + case array.first + when 'newmtl' + when 'Ns' # Specular Exponent + when 'Ka' # Ambient + when 'Kd' # Diffuse + when 'Ks' # Specular + when 'Ke' # Emissive + when 'Ni' # Unknown (Blender Specific?) + when 'd' # Dissolved (Transparency) + when 'illum' # Illumination model + end + end + end + + def add_vertex(array) + vert = nil + if array.size == 5 + vert = Vertex.new(Float(array[1]), Float(array[2]), Float(array[3]), Float(array[4])) + elsif array.size == 4 + vert = Vertex.new(Float(array[1]), Float(array[2]), Float(array[3]), 1.0) + end + @vertexes << vert + end + + def add_normal(array) + vert = nil + if array.size == 5 + vert = Vertex.new(Float(array[1]), Float(array[2]), Float(array[3]), Float(array[4])) + elsif array.size == 4 + vert = Vertex.new(Float(array[1]), Float(array[2]), Float(array[3]), 1.0) + end + @normals << vert + end + + def add_texture_coordinate(array) + texture = nil + if array.size == 4 + texture = Vertex.new(Float(array[1]), Float(array[2]), Float(array[3])) + elsif array.size == 3 + texture = Vertex.new(Float(array[1]), Float(array[2]), 0.0) + end + @textures << texture + end + + def draw + glEnable(GL_CULL_FACE) + glEnable(GL_COLOR_MATERIAL) + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE) + glBegin(GL_TRIANGLES) # begin drawing model + self.faces.each do |vert| + vertex = vert[0] + normal = vert[1] + + glColor3f(@color.red, @color.green, @color.blue) + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, [@color.red, @color.green, @color.blue, 1.0]) + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, [@color.red, @color.green, @color.blue, 1.0]) + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, [1,1,1,1]) + glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, [10.0]) + + glNormal3f(normal.x, normal.y, normal.z) + glVertex3f(vertex.x, vertex.y, vertex.z) + end + glEnd + glDisable(GL_CULL_FACE) + glDisable(GL_COLOR_MATERIAL) + end end end diff --git a/lib/wavefront/material.rb b/lib/wavefront/material.rb new file mode 100644 index 0000000..00bf882 --- /dev/null +++ b/lib/wavefront/material.rb @@ -0,0 +1,6 @@ +class IMICFPS + class Wavefront + class Material + end + end +end diff --git a/lib/wavefront/model.rb b/lib/wavefront/model.rb new file mode 100644 index 0000000..db46eb8 --- /dev/null +++ b/lib/wavefront/model.rb @@ -0,0 +1,200 @@ +class IMICFPS + class Wavefront + class Model + include GL + include GLU + TextureCoordinate = Struct.new(:u, :v, :weight) + Vertex = Struct.new(:x, :y, :z, :weight) + Color = Struct.new(:red, :green, :blue) + + attr_accessor :objects, :vertexes, :texures, :normals, :faces + + def initialize(object = "objects/cube.obj") + @object_path = object + @file = File.open(object, 'r') + @material_file = nil + @current_object= nil + @vertex_count = 0 + @objects = [] + @color = Color.new(0.5, 0.5, 0.5) + @verts = [] + @norms = [] + parse + vertex_count = 0 + face_count = 0 + @objects.each {|o| face_count+=o.vertexes.count} + puts "vertexes count: #{@vertex_count} Objects: #{face_count}" + form_faces + @objects.each do |o| + puts "LLF-#{o.faces.size}" + end + end + + def draw + glEnable(GL_CULL_FACE) + glEnable(GL_COLOR_MATERIAL) + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE) + glBegin(GL_TRIANGLES) # begin drawing model + @objects.each do |o| + puts "LL..#{o.faces.size}" + o.faces.each do |vert| + vertex = vert[0] + normal = vert[1] + + glColor3f(@color.red, @color.green, @color.blue) + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, [@color.red, @color.green, @color.blue, 1.0]) + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, [@color.red, @color.green, @color.blue, 1.0]) + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, [1,1,1,1]) + glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, [10.0]) + + glNormal3f(normal.x, normal.y, normal.z) + glVertex3f(vertex.x, vertex.y, vertex.z) + end + glEnd + glDisable(GL_CULL_FACE) + glDisable(GL_COLOR_MATERIAL) + end + end + + def parse + lines = 0 + @file.each_line do |line| + lines+=1 + line = line.strip + + array = line.split(' ') + case array[0] + when 'mtllib' + @material_file = array[1] + parse_mtllib + when 'usemtl' + # PI*(r*r) + set_material(array[1]) + when 'o' + change_object(array[1]) + when 'v' + add_vertex(array) + when 'vt' + add_texture_coordinate(array) + + when 'vn' + add_normal(array) + + when 'f' + array[1..3].each do |f| + @verts << f.split("/")[0] + @norms << f.split("/")[2] + end + end + end + + puts "Total Lines: #{lines}" + end + + def parse_mtllib + file = File.open(@object_path.sub(File.basename(@object_path), '')+@material_file, 'r') + file.readlines.each do |line| + array = line.strip.split(' ') + # puts array.join + case array.first + when 'newmtl' + when 'Ns' # Specular Exponent + when 'Ka' # Ambient + when 'Kd' # Diffuse + when 'Ks' # Specular + when 'Ke' # Emissive + when 'Ni' # Unknown (Blender Specific?) + when 'd' # Dissolved (Transparency) + when 'illum' # Illumination model + end + end + end + + def change_object(name) + @objects << Object.new(name) + @current_object = @objects.last + end + + def set_material(name) + # @current_object. + end + + def faces_count + count = 0 + @objects.each {|o| count+=o.faces.count} + return count + end + + def add_vertex(array) + @vertex_count+=1 + vert = nil + if array.size == 5 + vert = Vertex.new(Float(array[1]), Float(array[2]), Float(array[3]), Float(array[4])) + elsif array.size == 4 + vert = Vertex.new(Float(array[1]), Float(array[2]), Float(array[3]), 1.0) + else + raise + end + @current_object.vertexes << vert + end + + def add_normal(array) + vert = nil + if array.size == 5 + vert = Vertex.new(Float(array[1]), Float(array[2]), Float(array[3]), Float(array[4])) + elsif array.size == 4 + vert = Vertex.new(Float(array[1]), Float(array[2]), Float(array[3]), 1.0) + else + raise + end + @current_object.normals << vert + end + + def add_texture_coordinate(array) + texture = nil + if array.size == 4 + texture = Vertex.new(Float(array[1]), Float(array[2]), Float(array[3])) + elsif array.size == 3 + texture = Vertex.new(Float(array[1]), Float(array[2]), 0.0) + else + raise + end + @current_object.textures << texture + end + + def form_faces + @verts.each_with_index do |v, index| + active_object = nil + # Look for active object + search_index = Integer(v)-1 + local_search = 0 + search_object_index = 0 + found = false + @objects.each_with_index do |o, i| + local_search=search_index-i + search_object_index = i + if local_search.between?(local_search, local_search+o.vertexes.count-1) + active_object = o + found = true + break + end + end + + raise "active_object is nil!" if active_object == nil + face = [active_object.vertexes[Integer(v)-local_search-1], active_object.normals[Integer(@norms[index])-1]] + if face.last == nil + p Integer(v)-local_search-1 + p active_object.normals[@norms[index].to_i] + p Integer(@norms[index])-local_search-1 + puts "V: #{active_object.vertexes.count-1}, T: #{Integer(v)-1}" + puts "Vertex: #{v}/#{Integer(v)-1}/#{Integer(v)-local_search-1} + Normal: #{index}/#{Integer(@norms[index])-1}/#{Integer(@norms[index])-local_search-1}" + raise "Bad data!" + end + + active_object.faces << face + end + end + end + end +end diff --git a/lib/wavefront/object.rb b/lib/wavefront/object.rb new file mode 100644 index 0000000..c88575a --- /dev/null +++ b/lib/wavefront/object.rb @@ -0,0 +1,16 @@ +class IMICFPS + class Wavefront + class Object + attr_reader :name + attr_accessor :vertexes, :texures, :normals, :faces + + def initialize(name) + @name = name + @vertexes = [] + @textures = [] + @normals = [] + @faces = [] + end + end + end +end diff --git a/lib/window.rb b/lib/window.rb index 7e6a0f1..ddcab1a 100644 --- a/lib/window.rb +++ b/lib/window.rb @@ -3,19 +3,20 @@ class IMICFPS include GL include GLU include GLUT + Point = Struct.new(:x, :y) def initialize(window_width = 1280, window_height = 800, fullscreen = false) - # super(window_width, window_height, fullscreen) - super(Gosu.screen_width, Gosu.screen_height, true) + super(window_width, window_height, fullscreen) + # super(Gosu.screen_width, Gosu.screen_height, true) $window = self - @level = Object.new("objects/cube.obj") - # @level = Object.new("objects/sponza.obj") - @camera = Object::Vertex.new(0,-1,0) - @camera_target = Object::Vertex.new(0,-1,0) + @model = Wavefront::Model.new("objects/cube.obj") + # @model = Object.new("objects/sponza.obj") + @camera = Wavefront::Model::Vertex.new(0,-1,0) + @camera_target = Wavefront::Model::Vertex.new(0,-1,0) @speed = 0.05 @angle_y = 0 # | @angle_x = 0 # _ - @mouse = Object::Vertex.new(Gosu.screen_width/2,Gosu.screen_height/2,0) + @mouse = Point.new(Gosu.screen_width/2, Gosu.screen_height/2) self.mouse_x, self.mouse_y = Gosu.screen_width/2, Gosu.screen_height/2 @font = Gosu::Font.new(18, name: "DejaVu Sans") @@ -56,10 +57,6 @@ class IMICFPS glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) glEnable(GL_DEPTH_TEST) - glEnable(GL_CULL_FACE) - - glEnable(GL_COLOR_MATERIAL) - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE) # glRotatef(@angle_y,0,1,0) # glRotatef(@angle_x,1,0,0) @@ -68,23 +65,9 @@ class IMICFPS gluLookAt(@camera.x,@camera.y,@camera.z, @angle_x,@angle_y,0, 0,1,0) color = [@c1, @c2, @c3] - glBegin(GL_TRIANGLES) # begin drawing model - @level.faces.each do |vert| - vertex = vert[0] - normal = vert[1] + @model.draw - glColor3f(color[0], color[1], color[2]) - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, [@c1, @c2, @c3, 1.0]) - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, [@c1, @c2, @c3, 1.0]) - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, [1,1,1,1]) - glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, [10.0]) - - glNormal3f(normal.x, normal.y, normal.z) - glVertex3f(vertex.x, vertex.y, vertex.z) - end - glEnd end - @text.split("~").each_with_index do |bit, i| @font.draw(bit.strip, 10, @font.height*i, Float::INFINITY) end @@ -98,11 +81,11 @@ class IMICFPS ~ Angle Y: #{@angle_y} Angle X: #{@angle_x} ~ X:#{@camera.x} Y:#{@camera.y} Z:#{@camera.z} ~ - Mesh Vert Array: #{@level.faces.size} ~ + Model Faces: #{@model.faces_count} ~ Last Frame: #{Gosu.milliseconds-@last_frame_time}ms (#{Gosu.fps} fps)" @last_frame_time = Gosu.milliseconds - # $window.caption = "Gosu OBJ Level - FPS:#{Gosu.fps}" + # $window.caption = "Gosu OBJ object - FPS:#{Gosu.fps}" @angle_x-=Integer(@mouse.x-self.mouse_x) @angle_y-=Integer(@mouse.y-self.mouse_y) @angle_x = @angle_x.clamp(-360, 360)