wavefront 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []