mirror of
https://github.com/cyberarm/i-mic-fps.git
synced 2025-12-15 15:42:35 +00:00
Restructured Model loading to enable easier implementation of other parsers
This commit is contained in:
@@ -84,9 +84,11 @@ require_relative "lib/game_objects/entities/skydome"
|
|||||||
require_relative "lib/game_objects/entities/terrain"
|
require_relative "lib/game_objects/entities/terrain"
|
||||||
|
|
||||||
require_relative "lib/model"
|
require_relative "lib/model"
|
||||||
require_relative "lib/wavefront/parser"
|
require_relative "lib/model/parser"
|
||||||
require_relative "lib/wavefront/object"
|
require_relative "lib/model/model_object"
|
||||||
require_relative "lib/wavefront/material"
|
require_relative "lib/model/material"
|
||||||
|
|
||||||
|
require_relative "lib/model/parsers/wavefront_parser"
|
||||||
|
|
||||||
require_relative "lib/map_parser"
|
require_relative "lib/map_parser"
|
||||||
require_relative "lib/manifest"
|
require_relative "lib/manifest"
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class IMICFPS
|
|||||||
unless load_model_from_cache
|
unless load_model_from_cache
|
||||||
case @type
|
case @type
|
||||||
when :obj
|
when :obj
|
||||||
@model = IMICFPS::Model.new(file_path: @model_file, parser: Wavefront::Parser)
|
@model = IMICFPS::Model.new(file_path: @model_file)
|
||||||
else
|
else
|
||||||
raise "Unsupported model type, supported models are: #{@supported_models.join(', ')}"
|
raise "Unsupported model type, supported models are: #{@supported_models.join(', ')}"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,14 +10,16 @@ class IMICFPS
|
|||||||
attr_reader :vertex_array_id
|
attr_reader :vertex_array_id
|
||||||
attr_reader :aabb_tree
|
attr_reader :aabb_tree
|
||||||
|
|
||||||
def initialize(file_path:, entity: nil, parser:)
|
def initialize(file_path:, entity: nil)
|
||||||
|
@file_path = file_path
|
||||||
@entity = entity
|
@entity = entity
|
||||||
update if @entity
|
update if @entity
|
||||||
@file_path = file_path
|
|
||||||
@material_file = nil
|
@material_file = nil
|
||||||
@current_object = nil
|
@current_object = nil
|
||||||
@current_material=nil
|
@current_material=nil
|
||||||
@vertex_count = 0
|
@vertex_count = 0
|
||||||
|
|
||||||
@objects = []
|
@objects = []
|
||||||
@materials= {}
|
@materials= {}
|
||||||
@vertices = []
|
@vertices = []
|
||||||
@@ -31,7 +33,7 @@ class IMICFPS
|
|||||||
@bounding_box = BoundingBox.new
|
@bounding_box = BoundingBox.new
|
||||||
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
||||||
|
|
||||||
parse(parser)
|
parse( Model::Parser.find(File.basename(file_path).split(".").last.to_sym) )
|
||||||
|
|
||||||
puts "#{@file_path.split('/').last} took #{((Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)-start_time)/1000.0).round(2)} seconds to parse" if window.config.get(:debug_options, :stats)
|
puts "#{@file_path.split('/').last} took #{((Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)-start_time)/1000.0).round(2)} seconds to parse" if window.config.get(:debug_options, :stats)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
class IMICFPS
|
class IMICFPS
|
||||||
class Wavefront
|
class Model
|
||||||
class Material
|
class Material
|
||||||
attr_accessor :name, :ambient, :diffuse, :specular
|
attr_accessor :name, :ambient, :diffuse, :specular
|
||||||
attr_reader :texture_id
|
attr_reader :texture_id
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
class IMICFPS
|
class IMICFPS
|
||||||
class Wavefront
|
class Model
|
||||||
class Object
|
class ModelObject
|
||||||
attr_reader :name, :vertices, :textures, :normals, :bounding_box, :debug_color
|
attr_reader :name, :vertices, :textures, :normals, :bounding_box, :debug_color
|
||||||
attr_accessor :faces, :scale
|
attr_accessor :faces, :scale
|
||||||
|
|
||||||
30
lib/model/parser.rb
Normal file
30
lib/model/parser.rb
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
class IMICFPS
|
||||||
|
class Model
|
||||||
|
class Parser
|
||||||
|
@@parsers = []
|
||||||
|
|
||||||
|
def self.handles
|
||||||
|
raise NotImplementedError, "Model::Parser#handles must return an array of file extensions that this parser supports"
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.inherited(parser)
|
||||||
|
@@parsers << parser
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.find(file_type)
|
||||||
|
found_parser = @@parsers.find do |parser|
|
||||||
|
parser.handles.include?(file_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
return found_parser
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(model)
|
||||||
|
@model = model
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
180
lib/model/parsers/wavefront_parser.rb
Normal file
180
lib/model/parsers/wavefront_parser.rb
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
class IMICFPS
|
||||||
|
class WavefrontParser < Model::Parser
|
||||||
|
def self.handles
|
||||||
|
[:obj]
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(model)
|
||||||
|
@model = model
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse
|
||||||
|
lines = 0
|
||||||
|
list = File.read(@model.file_path).split("\n")
|
||||||
|
list.each do |line|
|
||||||
|
lines+=1
|
||||||
|
line = line.strip
|
||||||
|
|
||||||
|
array = line.split(' ')
|
||||||
|
case array[0]
|
||||||
|
when 'mtllib'
|
||||||
|
@model.material_file = array[1]
|
||||||
|
parse_mtllib
|
||||||
|
when 'usemtl'
|
||||||
|
set_material(array[1])
|
||||||
|
when 'o'
|
||||||
|
change_object(array[1])
|
||||||
|
when 's'
|
||||||
|
set_smoothing(array[1])
|
||||||
|
when 'v'
|
||||||
|
add_vertex(array)
|
||||||
|
when 'vt'
|
||||||
|
add_texture_coordinate(array)
|
||||||
|
|
||||||
|
when 'vn'
|
||||||
|
add_normal(array)
|
||||||
|
|
||||||
|
when 'f'
|
||||||
|
verts = []
|
||||||
|
uvs = []
|
||||||
|
norms = []
|
||||||
|
array[1..3].each do |f|
|
||||||
|
verts << f.split("/")[0]
|
||||||
|
uvs << f.split("/")[1]
|
||||||
|
norms << f.split("/")[2]
|
||||||
|
end
|
||||||
|
|
||||||
|
face = Face.new
|
||||||
|
face.vertices = []
|
||||||
|
face.uvs = []
|
||||||
|
face.normals = []
|
||||||
|
face.colors = []
|
||||||
|
face.material = material
|
||||||
|
face.smoothing= @model.smoothing
|
||||||
|
|
||||||
|
mat = face.material.diffuse
|
||||||
|
color = Vector.new(mat.red, mat.green, mat.blue)
|
||||||
|
|
||||||
|
verts.each_with_index do |v, index|
|
||||||
|
|
||||||
|
if uvs.first != ""
|
||||||
|
face.vertices << @model.vertices[Integer(v)-1]
|
||||||
|
face.uvs << @model.uvs[Integer(uvs[index])-1]
|
||||||
|
face.normals << @model.normals[Integer(norms[index])-1]
|
||||||
|
face.colors << color
|
||||||
|
else
|
||||||
|
face.vertices << @model.vertices[Integer(v)-1]
|
||||||
|
face.uvs << nil
|
||||||
|
face.normals << @model.normals[Integer(norms[index])-1]
|
||||||
|
face.colors << color
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@model.current_object.faces << face
|
||||||
|
@model.faces << face
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
puts "Total Lines: #{lines}" if $window.config.get(:debug_options, :stats)
|
||||||
|
@model.calculate_bounding_box(@model.vertices, @model.bounding_box)
|
||||||
|
@model.objects.each do |o|
|
||||||
|
@model.calculate_bounding_box(o.vertices, o.bounding_box)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_mtllib
|
||||||
|
file = File.open(@model.file_path.sub(File.basename(@model.file_path), '')+@model.material_file, 'r')
|
||||||
|
file.readlines.each do |line|
|
||||||
|
array = line.strip.split(' ')
|
||||||
|
case array.first
|
||||||
|
when 'newmtl'
|
||||||
|
material = Model::Material.new(array.last)
|
||||||
|
@model.current_material = array.last
|
||||||
|
@model.materials[array.last] = material
|
||||||
|
when 'Ns' # Specular Exponent
|
||||||
|
when 'Ka' # Ambient color
|
||||||
|
@model.materials[@model.current_material].ambient = Color.new(Float(array[1]), Float(array[2]), Float(array[3]))
|
||||||
|
when 'Kd' # Diffuse color
|
||||||
|
@model.materials[@model.current_material].diffuse = Color.new(Float(array[1]), Float(array[2]), Float(array[3]))
|
||||||
|
when 'Ks' # Specular color
|
||||||
|
@model.materials[@model.current_material].specular = Color.new(Float(array[1]), Float(array[2]), Float(array[3]))
|
||||||
|
when 'Ke' # Emissive
|
||||||
|
when 'Ni' # Unknown (Blender Specific?)
|
||||||
|
when 'd' # Dissolved (Transparency)
|
||||||
|
when 'illum' # Illumination model
|
||||||
|
when 'map_Kd' # Diffuse texture
|
||||||
|
texture = File.basename(array[1])
|
||||||
|
texture_path = "#{File.expand_path("../../", @model.file_path)}/textures/#{texture}"
|
||||||
|
@model.materials[@model.current_material].set_texture(texture_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def change_object(name)
|
||||||
|
@model.objects << Model::ModelObject.new(name)
|
||||||
|
@model.current_object = @model.objects.last
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_smoothing(value)
|
||||||
|
if value == "1"
|
||||||
|
@model.smoothing = true
|
||||||
|
else
|
||||||
|
@model.smoothing = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_material(name)
|
||||||
|
@model.current_material = name
|
||||||
|
end
|
||||||
|
|
||||||
|
def material
|
||||||
|
@model.materials[@model.current_material]
|
||||||
|
end
|
||||||
|
|
||||||
|
def faces_count
|
||||||
|
count = 0
|
||||||
|
@model.objects.each {|o| count+=o.faces.count}
|
||||||
|
return count
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_vertex(array)
|
||||||
|
@model.vertex_count+=1
|
||||||
|
vert = nil
|
||||||
|
if array.size == 5
|
||||||
|
vert = Vector.new(Float(array[1]), Float(array[2]), Float(array[3]), Float(array[4]))
|
||||||
|
elsif array.size == 4
|
||||||
|
vert = Vector.new(Float(array[1]), Float(array[2]), Float(array[3]), 1.0)
|
||||||
|
else
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
@model.current_object.vertices << vert
|
||||||
|
@model.vertices << vert
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_normal(array)
|
||||||
|
vert = nil
|
||||||
|
if array.size == 5
|
||||||
|
vert = Vector.new(Float(array[1]), Float(array[2]), Float(array[3]), Float(array[4]))
|
||||||
|
elsif array.size == 4
|
||||||
|
vert = Vector.new(Float(array[1]), Float(array[2]), Float(array[3]), 1.0)
|
||||||
|
else
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
@model.current_object.normals << vert
|
||||||
|
@model.normals << vert
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_texture_coordinate(array)
|
||||||
|
texture = nil
|
||||||
|
if array.size == 4
|
||||||
|
texture = Vector.new(Float(array[1]), 1-Float(array[2]), Float(array[3]))
|
||||||
|
elsif array.size == 3
|
||||||
|
texture = Vector.new(Float(array[1]), 1-Float(array[2]), 1.0)
|
||||||
|
else
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
@model.current_object.textures << texture
|
||||||
|
@model.uvs << texture
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
class IMICFPS
|
|
||||||
class Wavefront
|
|
||||||
class Parser
|
|
||||||
def initialize(model)
|
|
||||||
@model = model
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse
|
|
||||||
lines = 0
|
|
||||||
list = File.read(@model.file_path).split("\n")
|
|
||||||
list.each do |line|
|
|
||||||
lines+=1
|
|
||||||
line = line.strip
|
|
||||||
|
|
||||||
array = line.split(' ')
|
|
||||||
case array[0]
|
|
||||||
when 'mtllib'
|
|
||||||
@model.material_file = array[1]
|
|
||||||
parse_mtllib
|
|
||||||
when 'usemtl'
|
|
||||||
set_material(array[1])
|
|
||||||
when 'o'
|
|
||||||
change_object(array[1])
|
|
||||||
when 's'
|
|
||||||
set_smoothing(array[1])
|
|
||||||
when 'v'
|
|
||||||
add_vertex(array)
|
|
||||||
when 'vt'
|
|
||||||
add_texture_coordinate(array)
|
|
||||||
|
|
||||||
when 'vn'
|
|
||||||
add_normal(array)
|
|
||||||
|
|
||||||
when 'f'
|
|
||||||
verts = []
|
|
||||||
uvs = []
|
|
||||||
norms = []
|
|
||||||
array[1..3].each do |f|
|
|
||||||
verts << f.split("/")[0]
|
|
||||||
uvs << f.split("/")[1]
|
|
||||||
norms << f.split("/")[2]
|
|
||||||
end
|
|
||||||
|
|
||||||
face = Face.new
|
|
||||||
face.vertices = []
|
|
||||||
face.uvs = []
|
|
||||||
face.normals = []
|
|
||||||
face.colors = []
|
|
||||||
face.material = material
|
|
||||||
face.smoothing= @model.smoothing
|
|
||||||
|
|
||||||
mat = face.material.diffuse
|
|
||||||
color = Vector.new(mat.red, mat.green, mat.blue)
|
|
||||||
|
|
||||||
verts.each_with_index do |v, index|
|
|
||||||
|
|
||||||
if uvs.first != ""
|
|
||||||
face.vertices << @model.vertices[Integer(v)-1]
|
|
||||||
face.uvs << @model.uvs[Integer(uvs[index])-1]
|
|
||||||
face.normals << @model.normals[Integer(norms[index])-1]
|
|
||||||
face.colors << color
|
|
||||||
else
|
|
||||||
face.vertices << @model.vertices[Integer(v)-1]
|
|
||||||
face.uvs << nil
|
|
||||||
face.normals << @model.normals[Integer(norms[index])-1]
|
|
||||||
face.colors << color
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@model.current_object.faces << face
|
|
||||||
@model.faces << face
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
puts "Total Lines: #{lines}" if $window.config.get(:debug_options, :stats)
|
|
||||||
@model.calculate_bounding_box(@model.vertices, @model.bounding_box)
|
|
||||||
@model.objects.each do |o|
|
|
||||||
@model.calculate_bounding_box(o.vertices, o.bounding_box)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse_mtllib
|
|
||||||
file = File.open(@model.file_path.sub(File.basename(@model.file_path), '')+@model.material_file, 'r')
|
|
||||||
file.readlines.each do |line|
|
|
||||||
array = line.strip.split(' ')
|
|
||||||
case array.first
|
|
||||||
when 'newmtl'
|
|
||||||
material = Material.new(array.last)
|
|
||||||
@model.current_material = array.last
|
|
||||||
@model.materials[array.last] = material
|
|
||||||
when 'Ns' # Specular Exponent
|
|
||||||
when 'Ka' # Ambient color
|
|
||||||
@model.materials[@model.current_material].ambient = Color.new(Float(array[1]), Float(array[2]), Float(array[3]))
|
|
||||||
when 'Kd' # Diffuse color
|
|
||||||
@model.materials[@model.current_material].diffuse = Color.new(Float(array[1]), Float(array[2]), Float(array[3]))
|
|
||||||
when 'Ks' # Specular color
|
|
||||||
@model.materials[@model.current_material].specular = Color.new(Float(array[1]), Float(array[2]), Float(array[3]))
|
|
||||||
when 'Ke' # Emissive
|
|
||||||
when 'Ni' # Unknown (Blender Specific?)
|
|
||||||
when 'd' # Dissolved (Transparency)
|
|
||||||
when 'illum' # Illumination model
|
|
||||||
when 'map_Kd' # Diffuse texture
|
|
||||||
texture = File.basename(array[1])
|
|
||||||
texture_path = "#{File.expand_path("../../", @model.file_path)}/textures/#{texture}"
|
|
||||||
@model.materials[@model.current_material].set_texture(texture_path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def change_object(name)
|
|
||||||
@model.objects << Object.new(name)
|
|
||||||
@model.current_object = @model.objects.last
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_smoothing(value)
|
|
||||||
if value == "1"
|
|
||||||
@model.smoothing = true
|
|
||||||
else
|
|
||||||
@model.smoothing = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_material(name)
|
|
||||||
@model.current_material = name
|
|
||||||
end
|
|
||||||
|
|
||||||
def material
|
|
||||||
@model.materials[@model.current_material]
|
|
||||||
end
|
|
||||||
|
|
||||||
def faces_count
|
|
||||||
count = 0
|
|
||||||
@model.objects.each {|o| count+=o.faces.count}
|
|
||||||
return count
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_vertex(array)
|
|
||||||
@model.vertex_count+=1
|
|
||||||
vert = nil
|
|
||||||
if array.size == 5
|
|
||||||
vert = Vector.new(Float(array[1]), Float(array[2]), Float(array[3]), Float(array[4]))
|
|
||||||
elsif array.size == 4
|
|
||||||
vert = Vector.new(Float(array[1]), Float(array[2]), Float(array[3]), 1.0)
|
|
||||||
else
|
|
||||||
raise
|
|
||||||
end
|
|
||||||
@model.current_object.vertices << vert
|
|
||||||
@model.vertices << vert
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_normal(array)
|
|
||||||
vert = nil
|
|
||||||
if array.size == 5
|
|
||||||
vert = Vector.new(Float(array[1]), Float(array[2]), Float(array[3]), Float(array[4]))
|
|
||||||
elsif array.size == 4
|
|
||||||
vert = Vector.new(Float(array[1]), Float(array[2]), Float(array[3]), 1.0)
|
|
||||||
else
|
|
||||||
raise
|
|
||||||
end
|
|
||||||
@model.current_object.normals << vert
|
|
||||||
@model.normals << vert
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_texture_coordinate(array)
|
|
||||||
texture = nil
|
|
||||||
if array.size == 4
|
|
||||||
texture = Vector.new(Float(array[1]), 1-Float(array[2]), Float(array[3]))
|
|
||||||
elsif array.size == 3
|
|
||||||
texture = Vector.new(Float(array[1]), 1-Float(array[2]), 1.0)
|
|
||||||
else
|
|
||||||
raise
|
|
||||||
end
|
|
||||||
@model.current_object.textures << texture
|
|
||||||
@model.uvs << texture
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Reference in New Issue
Block a user