rgltf 1.0.0
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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +270 -0
- data/Rakefile +10 -0
- data/benchmark/accessors.rb +26 -0
- data/benchmark/compare.rb +28 -0
- data/benchmark/sample_assets.rb +61 -0
- data/examples/README.md +23 -0
- data/examples/build_triangle.rb +40 -0
- data/examples/convert.rb +24 -0
- data/examples/inspect.rb +27 -0
- data/lib/rgltf/accessor_reader.rb +142 -0
- data/lib/rgltf/buffer_resolver.rb +95 -0
- data/lib/rgltf/builder/accessor_data.rb +40 -0
- data/lib/rgltf/builder/accessors.rb +130 -0
- data/lib/rgltf/builder/component_builders.rb +89 -0
- data/lib/rgltf/builder/document_properties.rb +32 -0
- data/lib/rgltf/builder/materials.rb +132 -0
- data/lib/rgltf/builder.rb +176 -0
- data/lib/rgltf/document.rb +159 -0
- data/lib/rgltf/errors.rb +10 -0
- data/lib/rgltf/extension.rb +79 -0
- data/lib/rgltf/extensions/khr_lights_punctual.rb +101 -0
- data/lib/rgltf/extensions/khr_materials_emissive_strength.rb +29 -0
- data/lib/rgltf/extensions/khr_materials_unlit.rb +19 -0
- data/lib/rgltf/extensions/khr_texture_transform.rb +42 -0
- data/lib/rgltf/glb.rb +71 -0
- data/lib/rgltf/properties/accessor.rb +142 -0
- data/lib/rgltf/properties/animation.rb +96 -0
- data/lib/rgltf/properties/asset.rb +15 -0
- data/lib/rgltf/properties/base.rb +45 -0
- data/lib/rgltf/properties/buffer.rb +50 -0
- data/lib/rgltf/properties/buffer_view.rb +18 -0
- data/lib/rgltf/properties/camera.rb +50 -0
- data/lib/rgltf/properties/image.rb +48 -0
- data/lib/rgltf/properties/material.rb +95 -0
- data/lib/rgltf/properties/mesh.rb +67 -0
- data/lib/rgltf/properties/node.rb +135 -0
- data/lib/rgltf/properties/sampler.rb +35 -0
- data/lib/rgltf/properties/scene.rb +14 -0
- data/lib/rgltf/properties/skin.rb +25 -0
- data/lib/rgltf/properties/texture.rb +19 -0
- data/lib/rgltf/properties.rb +17 -0
- data/lib/rgltf/validation/accessors.rb +205 -0
- data/lib/rgltf/validation/animations.rb +184 -0
- data/lib/rgltf/validation/buffers.rb +95 -0
- data/lib/rgltf/validation/cameras.rb +76 -0
- data/lib/rgltf/validation/context.rb +133 -0
- data/lib/rgltf/validation/images_materials.rb +159 -0
- data/lib/rgltf/validation/meshes.rb +214 -0
- data/lib/rgltf/validation/root_asset_extensions.rb +134 -0
- data/lib/rgltf/validation/scenes_nodes.rb +141 -0
- data/lib/rgltf/validation/skins.rb +94 -0
- data/lib/rgltf/validator.rb +53 -0
- data/lib/rgltf/version.rb +5 -0
- data/lib/rgltf/writer/buffer_merger.rb +72 -0
- data/lib/rgltf/writer/default_omitter.rb +51 -0
- data/lib/rgltf/writer/extension_serializer.rb +64 -0
- data/lib/rgltf/writer.rb +95 -0
- data/lib/rgltf.rb +133 -0
- data/tasks/sample_assets.rake +115 -0
- metadata +104 -0
data/lib/rgltf/writer.rb
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rgltf
|
|
4
|
+
class Writer
|
|
5
|
+
def initialize(document, validate: true)
|
|
6
|
+
@document = document
|
|
7
|
+
@validate = validate
|
|
8
|
+
return unless validate
|
|
9
|
+
|
|
10
|
+
result = Validator.validate(document)
|
|
11
|
+
return if result.errors.empty?
|
|
12
|
+
|
|
13
|
+
raise ValidationError, result.errors.map { |issue| "#{issue.path}: #{issue.message}" }.join('; ')
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_glb
|
|
17
|
+
json, binary = serialized_payload
|
|
18
|
+
json.fetch('buffers', []).each { |buffer| buffer.delete('uri') }
|
|
19
|
+
GLB.write(JSON.generate(json), binary.empty? ? nil : binary)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def write_glb(path)
|
|
23
|
+
File.binwrite(path, to_glb)
|
|
24
|
+
path
|
|
25
|
+
rescue Errno::EACCES, Errno::ENOENT => e
|
|
26
|
+
raise MissingResourceError, e.message
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def write_gltf(path, embed: false)
|
|
30
|
+
json, binary = serialized_payload
|
|
31
|
+
unless binary.empty?
|
|
32
|
+
if embed
|
|
33
|
+
json.fetch('buffers').first['uri'] = data_uri(binary)
|
|
34
|
+
else
|
|
35
|
+
extension = File.extname(path)
|
|
36
|
+
basename = File.basename(path, extension)
|
|
37
|
+
bin_path = File.join(File.dirname(path), "#{basename}.bin")
|
|
38
|
+
File.binwrite(bin_path, binary)
|
|
39
|
+
json.fetch('buffers').first['uri'] = File.basename(bin_path)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
File.write(path, JSON.pretty_generate(json) << "\n")
|
|
43
|
+
path
|
|
44
|
+
rescue Errno::EACCES, Errno::ENOENT => e
|
|
45
|
+
raise MissingResourceError, e.message
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def serialized_payload
|
|
51
|
+
copies = {}
|
|
52
|
+
json = deep_copy(@document.raw_json, copies)
|
|
53
|
+
owners = property_owners
|
|
54
|
+
ExtensionSerializer.new(@document, copies).apply!(owners)
|
|
55
|
+
DefaultOmitter.apply!(owners, copies)
|
|
56
|
+
binary = BufferMerger.new(@document).merge!(json)
|
|
57
|
+
validate_serialized!(json) if @validate
|
|
58
|
+
[json, binary]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def property_owners
|
|
62
|
+
roots = [@document.asset, *@document.class::COLLECTIONS.keys.flat_map do |key|
|
|
63
|
+
@document.public_send(key == 'bufferViews' ? :buffer_views : key)
|
|
64
|
+
end]
|
|
65
|
+
roots.flat_map { |owner| collect_owners(owner) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def collect_owners(owner)
|
|
69
|
+
[owner, *owner.nested_properties.flat_map { |child| collect_owners(child) }]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def deep_copy(value, copies)
|
|
73
|
+
copy = case value
|
|
74
|
+
when Hash then value.to_h { |key, child| [key, deep_copy(child, copies)] }
|
|
75
|
+
when Array then value.map { |child| deep_copy(child, copies) }
|
|
76
|
+
when String then value.dup
|
|
77
|
+
else value
|
|
78
|
+
end
|
|
79
|
+
copies[value.object_id] = copy if value.is_a?(Hash)
|
|
80
|
+
copy
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def data_uri(binary)
|
|
84
|
+
"data:application/octet-stream;base64,#{[binary].pack('m0')}"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def validate_serialized!(json)
|
|
88
|
+
result = Validator.validate(json)
|
|
89
|
+
return if result.errors.empty?
|
|
90
|
+
|
|
91
|
+
message = result.errors.map { |issue| "#{issue.path}: #{issue.message}" }.join('; ')
|
|
92
|
+
raise ValidationError, message
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
data/lib/rgltf.rb
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
require_relative 'rgltf/version'
|
|
6
|
+
require_relative 'rgltf/errors'
|
|
7
|
+
require_relative 'rgltf/glb'
|
|
8
|
+
require_relative 'rgltf/extension'
|
|
9
|
+
require_relative 'rgltf/buffer_resolver'
|
|
10
|
+
require_relative 'rgltf/accessor_reader'
|
|
11
|
+
require_relative 'rgltf/properties'
|
|
12
|
+
require_relative 'rgltf/document'
|
|
13
|
+
require_relative 'rgltf/extensions/khr_materials_unlit'
|
|
14
|
+
require_relative 'rgltf/extensions/khr_texture_transform'
|
|
15
|
+
require_relative 'rgltf/extensions/khr_lights_punctual'
|
|
16
|
+
require_relative 'rgltf/extensions/khr_materials_emissive_strength'
|
|
17
|
+
require_relative 'rgltf/validator'
|
|
18
|
+
require_relative 'rgltf/writer/default_omitter'
|
|
19
|
+
require_relative 'rgltf/writer/extension_serializer'
|
|
20
|
+
require_relative 'rgltf/writer/buffer_merger'
|
|
21
|
+
require_relative 'rgltf/writer'
|
|
22
|
+
require_relative 'rgltf/builder'
|
|
23
|
+
|
|
24
|
+
module Rgltf
|
|
25
|
+
class << self
|
|
26
|
+
def load(source, base_dir: nil, **options)
|
|
27
|
+
data, inferred_base_dir, inferred_format = read_source(source)
|
|
28
|
+
base_dir ||= inferred_base_dir
|
|
29
|
+
|
|
30
|
+
if inferred_format == :glb
|
|
31
|
+
raise FormatError, 'not a GLB (bad magic)' unless glb?(data)
|
|
32
|
+
|
|
33
|
+
load_glb(data, base_dir:, **options)
|
|
34
|
+
elsif glb?(data)
|
|
35
|
+
load_glb(data, base_dir:, **options)
|
|
36
|
+
else
|
|
37
|
+
load_json(data, base_dir:, **options)
|
|
38
|
+
end
|
|
39
|
+
rescue Errno::ENOENT, Errno::EACCES => e
|
|
40
|
+
raise MissingResourceError, e.message
|
|
41
|
+
rescue Error
|
|
42
|
+
raise
|
|
43
|
+
rescue StandardError => e
|
|
44
|
+
raise FormatError, "could not load glTF: #{e.message}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def load_glb(data, base_dir: nil, **options)
|
|
48
|
+
json, bin = GLB.read(binary_string(data))
|
|
49
|
+
load_json(json, base_dir:, glb_bin: bin, **options)
|
|
50
|
+
rescue Error
|
|
51
|
+
raise
|
|
52
|
+
rescue StandardError => e
|
|
53
|
+
raise FormatError, "could not load GLB: #{e.message}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def load_json(json, base_dir: nil, buffers: nil, glb_bin: nil, lazy: true,
|
|
57
|
+
extensions: default_extensions, validate: false,
|
|
58
|
+
strict_extensions: true)
|
|
59
|
+
parsed = json.is_a?(Hash) ? deep_copy(json) : JSON.parse(string_data(json))
|
|
60
|
+
validate_before_build!(parsed, supplied_buffers: buffers) if validate
|
|
61
|
+
Document.new(
|
|
62
|
+
parsed,
|
|
63
|
+
base_dir:,
|
|
64
|
+
supplied_buffers: buffers,
|
|
65
|
+
glb_bin:,
|
|
66
|
+
lazy:,
|
|
67
|
+
extension_registry: extensions,
|
|
68
|
+
validate:,
|
|
69
|
+
strict_extensions:
|
|
70
|
+
)
|
|
71
|
+
rescue JSON::ParserError => e
|
|
72
|
+
raise FormatError, "invalid glTF JSON: #{e.message}"
|
|
73
|
+
rescue FormatError => e
|
|
74
|
+
raise ValidationError, e.message if validate
|
|
75
|
+
|
|
76
|
+
raise
|
|
77
|
+
rescue Error
|
|
78
|
+
raise
|
|
79
|
+
rescue StandardError => e
|
|
80
|
+
raise FormatError, "could not load glTF JSON: #{e.message}"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def read_source(source)
|
|
86
|
+
return [source.read, nil, nil] if source.respond_to?(:read)
|
|
87
|
+
|
|
88
|
+
value = string_data(source)
|
|
89
|
+
stripped = value.lstrip
|
|
90
|
+
return [value, nil, nil] if glb?(value.b) || stripped.start_with?('{', '[')
|
|
91
|
+
|
|
92
|
+
format = :glb if File.extname(value).casecmp?('.glb')
|
|
93
|
+
[File.binread(value), File.dirname(File.expand_path(value)), format]
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def string_data(value)
|
|
97
|
+
return value.to_str if value.respond_to?(:to_str)
|
|
98
|
+
|
|
99
|
+
raise ArgumentError, 'expected a path, String, or IO-like object'
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def binary_string(value)
|
|
103
|
+
string_data(value).b
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def glb?(data)
|
|
107
|
+
data.bytesize >= 4 && data.byteslice(0, 4).unpack1('L<') == GLB::MAGIC
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def deep_copy(value)
|
|
111
|
+
Marshal.load(Marshal.dump(value))
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def validate_before_build!(json, supplied_buffers: nil)
|
|
115
|
+
result = Validator.validate(json)
|
|
116
|
+
errors = filter_supplied_buffer_errors(result.errors, supplied_buffers)
|
|
117
|
+
return if errors.empty?
|
|
118
|
+
|
|
119
|
+
message = errors.map { |issue| "#{issue.path}: #{issue.message}" }.join('; ')
|
|
120
|
+
raise ValidationError, message
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def filter_supplied_buffer_errors(errors, supplied_buffers)
|
|
124
|
+
return errors unless supplied_buffers
|
|
125
|
+
|
|
126
|
+
resolver = BufferResolver.new(base_dir: nil, supplied_buffers:)
|
|
127
|
+
errors.reject do |issue|
|
|
128
|
+
match = %r{\Abuffers/(\d+)\z}.match(issue.path) if issue.code == :missing_buffer
|
|
129
|
+
match && resolver.send(:supplied?, match[1].to_i)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'rake'
|
|
5
|
+
|
|
6
|
+
namespace :sample_assets do
|
|
7
|
+
SHA = '2bac6f8c57bf471df0d2a1e8a8ec023c7801dddf'
|
|
8
|
+
URL = 'https://github.com/KhronosGroup/glTF-Sample-Assets.git'
|
|
9
|
+
DEFAULT_PATH = File.expand_path('../tmp/gltf-sample-assets', __dir__)
|
|
10
|
+
|
|
11
|
+
desc 'Clone and verify the pinned Khronos glTF-Sample-Assets revision'
|
|
12
|
+
task :fetch do
|
|
13
|
+
destination = ENV.fetch('GLTF_SAMPLE_ASSETS', DEFAULT_PATH)
|
|
14
|
+
managed = File.expand_path(destination) == DEFAULT_PATH
|
|
15
|
+
checkout = SampleAssetsCheckout.new(destination, URL, SHA)
|
|
16
|
+
managed ? checkout.prepare_managed : checkout.verify_custom
|
|
17
|
+
puts "glTF-Sample-Assets ready at #{destination} (#{SHA})"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
desc 'Run the explicit and full pinned sample-asset acceptance suites'
|
|
21
|
+
task :verify do
|
|
22
|
+
root = ENV.fetch('GLTF_SAMPLE_ASSETS', nil)
|
|
23
|
+
abort 'GLTF_SAMPLE_ASSETS must point to a pinned checkout' if root.nil? || root.empty?
|
|
24
|
+
|
|
25
|
+
sh({ 'GLTF_SAMPLE_ASSETS' => File.expand_path(root) }, 'bundle', 'exec', 'rspec',
|
|
26
|
+
'spec/sample_assets_spec.rb', 'spec/sample_assets_full_spec.rb')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class SampleAssetsCheckout
|
|
30
|
+
def initialize(destination, url, sha)
|
|
31
|
+
@destination = destination
|
|
32
|
+
@url = url
|
|
33
|
+
@sha = sha
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def prepare_managed
|
|
37
|
+
clone_fresh unless usable_repository?
|
|
38
|
+
refresh unless commit_available?
|
|
39
|
+
return checkout if checkout_successful?
|
|
40
|
+
|
|
41
|
+
clone_fresh
|
|
42
|
+
checkout
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def verify_custom
|
|
46
|
+
raise "custom sample-assets path is not a git repository: #{@destination}" unless usable_repository?
|
|
47
|
+
|
|
48
|
+
dirty = capture('git', '-C', @destination, 'status', '--porcelain').strip
|
|
49
|
+
raise "custom sample-assets checkout must be clean: #{@destination}" unless dirty.empty?
|
|
50
|
+
|
|
51
|
+
actual = capture('git', '-C', @destination, 'rev-parse', 'HEAD').strip
|
|
52
|
+
raise "custom sample-assets checkout must be at #{@sha}, got #{actual}" unless actual == @sha
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def usable_repository?
|
|
58
|
+
return false unless File.directory?(File.join(@destination, '.git'))
|
|
59
|
+
|
|
60
|
+
system('git', '-C', @destination, 'rev-parse', '--is-inside-work-tree',
|
|
61
|
+
out: File::NULL, err: File::NULL)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def commit_available?
|
|
65
|
+
system('git', '-C', @destination, 'cat-file', '-e', "#{@sha}^{commit}",
|
|
66
|
+
out: File::NULL, err: File::NULL)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def refresh
|
|
70
|
+
remove_stale_locks
|
|
71
|
+
run 'git', '-C', @destination, 'fetch', '--depth', '1', '--force', 'origin', @sha
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def checkout
|
|
75
|
+
run 'git', '-C', @destination, 'checkout', '--detach', '--force', @sha
|
|
76
|
+
actual = capture('git', '-C', @destination, 'rev-parse', 'HEAD').strip
|
|
77
|
+
raise "sample-assets revision mismatch: #{actual}" unless actual == @sha
|
|
78
|
+
|
|
79
|
+
run 'git', '-C', @destination, 'submodule', 'update', '--init', '--recursive', '--depth', '1'
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def checkout_successful?
|
|
83
|
+
remove_stale_locks
|
|
84
|
+
system('git', '-C', @destination, 'checkout', '--detach', '--force', @sha,
|
|
85
|
+
out: File::NULL, err: File::NULL)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def clone_fresh
|
|
89
|
+
temporary = "#{@destination}.new-#{Process.pid}"
|
|
90
|
+
FileUtils.rm_rf(temporary)
|
|
91
|
+
FileUtils.mkdir_p(File.dirname(@destination))
|
|
92
|
+
run 'git', 'clone', '--filter=blob:none', '--no-checkout', @url, temporary
|
|
93
|
+
run 'git', '-C', temporary, 'fetch', '--depth', '1', '--force', 'origin', @sha
|
|
94
|
+
FileUtils.rm_rf(@destination)
|
|
95
|
+
FileUtils.mv(temporary, @destination)
|
|
96
|
+
ensure
|
|
97
|
+
FileUtils.rm_rf(temporary) if temporary && File.exist?(temporary)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def remove_stale_locks
|
|
101
|
+
Dir[File.join(@destination, '.git', '**', '*.lock')].each { |path| FileUtils.rm_f(path) }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def run(*command)
|
|
105
|
+
raise "command failed: #{command.join(' ')}" unless system(*command)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def capture(*command)
|
|
109
|
+
IO.popen(command, &:read)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
desc 'Clone and verify the pinned Khronos glTF sample assets'
|
|
115
|
+
task sample_assets: 'sample_assets:fetch'
|
metadata
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rgltf
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Yudai Takada
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: Loads and writes glTF 2.0 and GLB with GPU-ready packed binary accessors.
|
|
13
|
+
email:
|
|
14
|
+
- t.yudai92@gmail.com
|
|
15
|
+
executables: []
|
|
16
|
+
extensions: []
|
|
17
|
+
extra_rdoc_files: []
|
|
18
|
+
files:
|
|
19
|
+
- LICENSE.txt
|
|
20
|
+
- README.md
|
|
21
|
+
- Rakefile
|
|
22
|
+
- benchmark/accessors.rb
|
|
23
|
+
- benchmark/compare.rb
|
|
24
|
+
- benchmark/sample_assets.rb
|
|
25
|
+
- examples/README.md
|
|
26
|
+
- examples/build_triangle.rb
|
|
27
|
+
- examples/convert.rb
|
|
28
|
+
- examples/inspect.rb
|
|
29
|
+
- lib/rgltf.rb
|
|
30
|
+
- lib/rgltf/accessor_reader.rb
|
|
31
|
+
- lib/rgltf/buffer_resolver.rb
|
|
32
|
+
- lib/rgltf/builder.rb
|
|
33
|
+
- lib/rgltf/builder/accessor_data.rb
|
|
34
|
+
- lib/rgltf/builder/accessors.rb
|
|
35
|
+
- lib/rgltf/builder/component_builders.rb
|
|
36
|
+
- lib/rgltf/builder/document_properties.rb
|
|
37
|
+
- lib/rgltf/builder/materials.rb
|
|
38
|
+
- lib/rgltf/document.rb
|
|
39
|
+
- lib/rgltf/errors.rb
|
|
40
|
+
- lib/rgltf/extension.rb
|
|
41
|
+
- lib/rgltf/extensions/khr_lights_punctual.rb
|
|
42
|
+
- lib/rgltf/extensions/khr_materials_emissive_strength.rb
|
|
43
|
+
- lib/rgltf/extensions/khr_materials_unlit.rb
|
|
44
|
+
- lib/rgltf/extensions/khr_texture_transform.rb
|
|
45
|
+
- lib/rgltf/glb.rb
|
|
46
|
+
- lib/rgltf/properties.rb
|
|
47
|
+
- lib/rgltf/properties/accessor.rb
|
|
48
|
+
- lib/rgltf/properties/animation.rb
|
|
49
|
+
- lib/rgltf/properties/asset.rb
|
|
50
|
+
- lib/rgltf/properties/base.rb
|
|
51
|
+
- lib/rgltf/properties/buffer.rb
|
|
52
|
+
- lib/rgltf/properties/buffer_view.rb
|
|
53
|
+
- lib/rgltf/properties/camera.rb
|
|
54
|
+
- lib/rgltf/properties/image.rb
|
|
55
|
+
- lib/rgltf/properties/material.rb
|
|
56
|
+
- lib/rgltf/properties/mesh.rb
|
|
57
|
+
- lib/rgltf/properties/node.rb
|
|
58
|
+
- lib/rgltf/properties/sampler.rb
|
|
59
|
+
- lib/rgltf/properties/scene.rb
|
|
60
|
+
- lib/rgltf/properties/skin.rb
|
|
61
|
+
- lib/rgltf/properties/texture.rb
|
|
62
|
+
- lib/rgltf/validation/accessors.rb
|
|
63
|
+
- lib/rgltf/validation/animations.rb
|
|
64
|
+
- lib/rgltf/validation/buffers.rb
|
|
65
|
+
- lib/rgltf/validation/cameras.rb
|
|
66
|
+
- lib/rgltf/validation/context.rb
|
|
67
|
+
- lib/rgltf/validation/images_materials.rb
|
|
68
|
+
- lib/rgltf/validation/meshes.rb
|
|
69
|
+
- lib/rgltf/validation/root_asset_extensions.rb
|
|
70
|
+
- lib/rgltf/validation/scenes_nodes.rb
|
|
71
|
+
- lib/rgltf/validation/skins.rb
|
|
72
|
+
- lib/rgltf/validator.rb
|
|
73
|
+
- lib/rgltf/version.rb
|
|
74
|
+
- lib/rgltf/writer.rb
|
|
75
|
+
- lib/rgltf/writer/buffer_merger.rb
|
|
76
|
+
- lib/rgltf/writer/default_omitter.rb
|
|
77
|
+
- lib/rgltf/writer/extension_serializer.rb
|
|
78
|
+
- tasks/sample_assets.rake
|
|
79
|
+
homepage: https://github.com/ydah/rgltf
|
|
80
|
+
licenses:
|
|
81
|
+
- MIT
|
|
82
|
+
metadata:
|
|
83
|
+
homepage_uri: https://github.com/ydah/rgltf
|
|
84
|
+
source_code_uri: https://github.com/ydah/rgltf
|
|
85
|
+
changelog_uri: https://github.com/ydah/rgltf/releases
|
|
86
|
+
rubygems_mfa_required: 'true'
|
|
87
|
+
rdoc_options: []
|
|
88
|
+
require_paths:
|
|
89
|
+
- lib
|
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
91
|
+
requirements:
|
|
92
|
+
- - ">="
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: 3.1.0
|
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
|
+
requirements:
|
|
97
|
+
- - ">="
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: '0'
|
|
100
|
+
requirements: []
|
|
101
|
+
rubygems_version: 4.0.6
|
|
102
|
+
specification_version: 4
|
|
103
|
+
summary: Pure Ruby glTF 2.0 loader and writer
|
|
104
|
+
test_files: []
|