wavefront 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in wavefront.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Misha Conway
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,95 @@
1
+ # Wavefront
2
+
3
+ This is a simple gem for importing and exporting wavefront object files. As it is in it's initial version there are
4
+ some unsupported features that will be coming in future updates. Still, I hope this initial version suffices for
5
+ your most basic wavefront obj needs
6
+
7
+ Here are some of the things it supports importing and exporting:
8
+ -objects
9
+ -groups
10
+ -smoothing groups
11
+ -vertices, normals, and texture coordinates
12
+
13
+ Some additional operations supported are:
14
+ -computing a simple vertex buffer from the wavefront model
15
+
16
+ Some features that are coming in the future
17
+ -ability to compute a vertex/index buffer pair since these will be more optimal than a single giant vertex buffer
18
+ -ability to scale, transform, rotate, and unitize the obj
19
+ -materials (this is a feature I am currently working on, but is not available in the current version)
20
+ -ability to support more than one object. Even though wavefront spec says a file should have only one object,
21
+ there are some 3d modeling tools that export anomalous .obj files and I plan to support them even though
22
+ they are out of spec.
23
+ -parameter space vertices (these are an exotic rarely used feature in the obj format but I plan to support them)
24
+ -higher-order surfaces using several different kinds of interpolation, such as Taylor and B-splines
25
+ (again this is an exotic rarely used feauture in the obj format)
26
+ #############################################################################################################
27
+ #############################################################################################################
28
+ Note: -Let me know if there are any features I should include that are missing from this list.
29
+ -Also please let me know about any bugs or crashes you encounter. My email is MishaAConway@gmail.com.
30
+ If you attach a wavefront model that fails to parse with this gem, I will see what I can do to
31
+ update the code.
32
+
33
+
34
+
35
+
36
+
37
+
38
+ ## Installation
39
+
40
+ Add this line to your application's Gemfile:
41
+
42
+ gem 'wavefront'
43
+
44
+ And then execute:
45
+
46
+ $ bundle
47
+
48
+ Or install it yourself as:
49
+
50
+ $ gem install wavefront
51
+
52
+ ## Usage
53
+
54
+ So here is a little primer. A wavefront object basically contains a single object. This single object contains
55
+ several groups. Each of these groups can contain sub smoothing groups. Both groups and smoothing groups have a
56
+ list of triangles. Each triangle contains three vertices while each vertex contains a position, normal, and
57
+ texture coordinate. I've tried to make it so that the parsed WavefrontFile instance represents this hierarchy
58
+ as much as possible. Now with primer aside, let's go over some sample values we can extract from the
59
+ WavefrontFile instance.
60
+
61
+ w = Wavefront::File.new "my_wavefront_model" (import file, including .obj extension is optional)
62
+ w.export "my_exported_wavefront_model" (export file, including .obj extension is optional)
63
+
64
+ vertex_buffer = w.compute_vertex_buffer (compute an array of vertices from file)
65
+
66
+ w.object (inspect object itself)
67
+ group = w.object.groups.first (grab the first group)
68
+ group.name (see what it's name is)
69
+ smoothing_group = group.smoothing_groups.first (grab the first smoothing group)
70
+ smoothing_group.name (see what it's name is)
71
+ triangles = smoothing_group.triangles (grab triangles from this smoothing group)
72
+ triangle = triangles.first (grab the first triangle)
73
+ vertices = triangle.vertices (get the 3 vertices in this triangle)
74
+ vertex = vertices.first (get the first vertex)
75
+ vertex.position (look at position)
76
+ vertex.normal (look at normal)
77
+ vertex.tex (look at texture coordinate)
78
+
79
+
80
+ This is just the surface of what you can do to explore the parsed wavefront file. When I get more time, I'll try
81
+ to make these usage examples better.
82
+
83
+
84
+ ## Contributing
85
+
86
+ 1. Fork it
87
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
88
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
89
+ 4. Push to the branch (`git push origin my-new-feature`)
90
+ 5. Create new Pull Request
91
+
92
+ or.....
93
+
94
+ Let me know about any issues and send me any wavefront obj models that crash the app so that I can update the gem
95
+ to support them.
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,45 @@
1
+ module Wavefront
2
+ class Group
3
+ attr_reader :name, :triangles, :material, :smoothing_groups
4
+
5
+ def initialize n
6
+ @name = n
7
+ @triangles = []
8
+ @smoothing_groups = []
9
+ end
10
+
11
+ def set_smoothing_group smoothing_group_name
12
+ if smoothing_group_name.nil? || 'off' == smoothing_group_name.to_s || '0' == smoothing_group_name.to_s
13
+ @current_smoothing_group = nil
14
+ else
15
+ @current_smoothing_group = smoothing_groups.find{ |sg| sg.name.to_s == smoothing_group_name.to_s }
16
+ if @current_smoothing_group.nil?
17
+ @current_smoothing_group = SmoothingGroup.new smoothing_group_name
18
+ smoothing_groups << @current_smoothing_group
19
+ end
20
+ end
21
+ end
22
+
23
+ def merge_smoothing_groups!
24
+ set_smoothing_group nil
25
+ smoothing_groups.each { |smoothing_group| triangles += smoothing_group.triangles }
26
+ smoothing_groups.clear
27
+ end
28
+
29
+ def add_triangle triangle
30
+ if @current_smoothing_group
31
+ @current_smoothing_group.add_triangle triangle
32
+ else
33
+ @triangles << triangle
34
+ end
35
+ end
36
+
37
+ def num_faces
38
+ triangles.size + smoothing_groups.map(&:num_faces).inject(:+).to_i
39
+ end
40
+
41
+ def num_vertices
42
+ triangles.size * 3 + smoothing_groups.map(&:num_vertices).inject(:+).to_i
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,26 @@
1
+ module Wavefront
2
+ class SmoothingGroup
3
+ attr_reader :name, :triangles
4
+
5
+ def initialize _name
6
+ @name = _name
7
+ @triangles = []
8
+ end
9
+
10
+ def add_triangle triangle
11
+ @triangles << triangle
12
+ end
13
+
14
+ def num_faces
15
+ triangles.size
16
+ end
17
+
18
+ def num_vertices
19
+ triangles.size * 3
20
+ end
21
+
22
+ def to_s
23
+ "Smoothing Group\n\tNum Faces: #{num_faces}"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ module Wavefront
2
+ class Triangle
3
+ attr_reader :vertices
4
+
5
+ def initialize v
6
+ raise "A triangle can only have three vertices!" if 3 != v.size
7
+ @vertices = v
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ module Wavefront
2
+ class Vec3
3
+ attr_reader :x, :y, :z
4
+
5
+ def initialize *args
6
+ @x = args[0] if args.size > 0
7
+ @y = args[1] if args.size > 1
8
+ @z = args[2] if args.size > 2
9
+ end
10
+
11
+ def to_s
12
+ [x, y, z].compact.join ' '
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ module Wavefront
2
+ class Vertex
3
+ attr_reader :position, :tex, :normal, :position_index, :texture_index, :normal_index
4
+
5
+ def initialize p, uv, n, p_index, t_index, n_index
6
+ @position, @uv, @normal = p, uv, n
7
+ @position_index, @texture_index, @normal_index = p_index, t_index, n_index
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ require "wavefront/version"
2
+ require "vec3"
3
+ require "triangle"
4
+ require "vertex"
5
+ require "smoothing_group"
6
+ require "group"
7
+ require "wavefront_object"
8
+ require "wavefront_file"
9
+
@@ -0,0 +1,3 @@
1
+ module Wavefront
2
+ VERSION = "0.0.5"
3
+ end
@@ -0,0 +1,45 @@
1
+ module Wavefront
2
+ class File
3
+ attr_reader :file_path, :objects
4
+
5
+ def initialize file_path
6
+ @file_path = file_path
7
+ unless /\.obj$/.match @file_path
8
+ @file_path += ".obj"
9
+ end
10
+
11
+ @objects = []
12
+
13
+ file = ::File.new @file_path, 'r'
14
+ while line = file.gets
15
+ components = line.split
16
+ type = components.shift
17
+ if 'o' == type
18
+ name = components.first
19
+ objects << Wavefront::Object.new(name, file)
20
+ end
21
+ end
22
+
23
+ #no object was found so let's create one, rewind back to file, and try parsing again
24
+ if objects.size.zero?
25
+ file.rewind
26
+ objects << Wavefront::Object.new("default", file)
27
+ end
28
+
29
+ file.close
30
+ end
31
+
32
+ def export out_path
33
+ raise "no objects to export!" if objects.size.zero?
34
+ objects.first.export out_path
35
+ end
36
+
37
+ def compute_vertex_buffer
38
+ object.compute_vertex_buffer
39
+ end
40
+
41
+ def object
42
+ objects.first
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,145 @@
1
+ module Wavefront
2
+ class Object
3
+ attr_reader :file, :vertices, :texture_coordinates, :normals, :faces, :groups, :name
4
+
5
+ def initialize name, file
6
+ @name = name
7
+ @file = file
8
+ @vertices, @texture_coordinates, @normals, @faces, @groups = [], [], [], [], []
9
+ parse!
10
+ end
11
+
12
+ def to_s
13
+ s = "Object\n\tName: #{name}\n\tNum Vertices: #{vertices.size}\n\tNum Faces: #{num_faces}"
14
+ unless groups.size.zero?
15
+ s += "\n"
16
+ groups.each do |group|
17
+ s += "\tGroup #{group.name}\n\t\tNum Vertices: #{group.num_vertices}\n\t\tNum Faces: #{group.num_faces}"
18
+ group.smoothing_groups.each do |smoothing_group|
19
+ s += "\n\t\t\tSmoothing Group #{smoothing_group.name}\n\t\t\t\tNum Vertices: #{smoothing_group.num_vertices}\n\t\t\t\tNum Faces: #{smoothing_group.num_faces}"
20
+ end
21
+ end
22
+ end
23
+ s
24
+ end
25
+
26
+ def num_faces
27
+ @num_faces = 0
28
+ groups.each do |g|
29
+ @num_faces += g.num_faces
30
+ end
31
+ @num_faces
32
+ end
33
+
34
+
35
+
36
+
37
+ def export file_name
38
+ unless /\.obj$/.match file_name
39
+ file_name += ".obj"
40
+ end
41
+
42
+ ::File.delete file_name if ::File.exist? file_name
43
+ open file_name, 'a' do |f|
44
+ f.puts "# Exported from Wavefront Ruby Gem Version #{Wavefront::VERSION}"
45
+ f.puts "o #{name}"
46
+ f.puts "##{vertices.size} vertices, #{num_faces} faces"
47
+ vertices.each { |v| f.puts "v #{v}" }
48
+ texture_coordinates.each { |t| f.puts "vt #{t}" }
49
+ normals.each { |n| f.puts "vn #{n}" }
50
+ groups.each do |group|
51
+ f.puts "g ##{group.name}"
52
+ group.triangles.each do |t|
53
+ f.puts 'f ' + t.vertices.map { |v| [v.position_index, v.texture_index, v.normal_index].join '/' }.join(' ')
54
+ end
55
+ group.smoothing_groups.each do |smoothing_group|
56
+ f.puts "s #{smoothing_group.name}"
57
+ smoothing_group.triangles.each do |t|
58
+ f.puts 'f ' + t.vertices.map { |v| [v.position_index, v.texture_index, v.normal_index].join '/' }.join(' ')
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ def compute_vertex_buffer
66
+ vertex_buffer = []
67
+ groups.each do |group|
68
+ group.triangles.each { |t| vertex_buffer << t.vertices }
69
+ group.smoothing_groups.each do |smoothing_group|
70
+ smoothing_group.triangles.each { |t| vertex_buffer << t.vertices }
71
+ end
72
+ end
73
+ vertex_buffer.flatten
74
+ end
75
+
76
+ def compute_vertex_buffer_and_index_buffer
77
+ raise "not yet implemented in version #{Wavefront::VERSION}! will be coming in future versions!"
78
+ vertex_buffer, index_buffer = [], []
79
+
80
+
81
+ {:vertex_buffer => vertex_buffer, :index_buffer => index_buffer}
82
+ end
83
+
84
+ private
85
+ def parse!
86
+ while line = file.gets
87
+ components = line.split
88
+ type = components.shift
89
+ case type
90
+ when 'v'
91
+ vertices << Vec3.new(*components.map(&:to_f))
92
+ when 'vt'
93
+ texture_coordinates << Vec3.new(*components.map(&:to_f))
94
+ when 'vn'
95
+ normals << Vec3.new(*components.map(&:to_f))
96
+ when 'vp'
97
+ #TODO: handle these later
98
+ when 'f'
99
+ triangles = []
100
+ if components.size > 4
101
+ raise "Sorry this version of the gem does not support polygons with more than 4 points. Updates to this gem will fix this issue."
102
+ end
103
+ if components.size == 4
104
+ triangles << triangle_from_face_components(components[0, 3])
105
+ triangles << triangle_from_face_components([components[0], components[2], components[3]])
106
+ elsif components.size == 3
107
+ triangles << triangle_from_face_components(components)
108
+ else
109
+ raise "current version of gem cannot parse triangles with #{components.size} verts!"
110
+ end
111
+ triangles.each { |triangle| @current_group.add_triangle triangle }
112
+ when 'g'
113
+ name = components.first
114
+ @current_group = Group.new name
115
+ groups << @current_group
116
+
117
+ when 's'
118
+ @current_group.set_smoothing_group components.first
119
+ when 'o'
120
+ raise "Wavefront Version #{Wavefront::VERSION} does not support obj files with more than one object. If you encounter such an obj that fails to load, please attach and email to mishaAconway@gmail.com so that I can update the gem to support the file."
121
+ #file.seek -line.size, IO::SEEK_CUR
122
+ #return
123
+ end
124
+ end
125
+ end
126
+
127
+ def triangle_from_face_components face_components
128
+ triangle_vertices = []
129
+ face_components.each do |vertex_str|
130
+ vertex_str_components = vertex_str.split('/').map { |index| index.size > 0 ? index.to_i : nil }
131
+ position_index = vertex_str_components[0]
132
+ tex_index = vertex_str_components[1]
133
+
134
+ normal_index = vertex_str_components[2]
135
+
136
+ position = vertices[position_index]
137
+ tex_coordinate = tex_index ? texture_coordinates[tex_index] : nil
138
+ normal = normals[normal_index]
139
+
140
+ triangle_vertices << Vertex.new(position, tex_coordinate, normal, position_index, tex_index, normal_index)
141
+ end
142
+ Triangle.new triangle_vertices
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'wavefront/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "wavefront"
8
+ gem.version = Wavefront::VERSION
9
+ gem.authors = ["Misha Conway"]
10
+ gem.email = ["MishaAConway@gmail.com"]
11
+ gem.description = %q{Wavefront parser and exporter}
12
+ gem.summary = %q{Wavefront parser and exporter}
13
+ gem.homepage = "https://github.com/MishaConway/wavefront-ruby"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wavefront
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Misha Conway
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-07 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Wavefront parser and exporter
15
+ email:
16
+ - MishaAConway@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - Gemfile
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - lib/group.rb
27
+ - lib/smoothing_group.rb
28
+ - lib/triangle.rb
29
+ - lib/vec3.rb
30
+ - lib/vertex.rb
31
+ - lib/wavefront.rb
32
+ - lib/wavefront/version.rb
33
+ - lib/wavefront_file.rb
34
+ - lib/wavefront_object.rb
35
+ - wavefront.gemspec
36
+ homepage: https://github.com/MishaConway/wavefront-ruby
37
+ licenses: []
38
+ post_install_message:
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ none: false
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ none: false
54
+ requirements: []
55
+ rubyforge_project:
56
+ rubygems_version: 1.8.24
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: Wavefront parser and exporter
60
+ test_files: []