magica_voxel 0.1.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.
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'matrix'
4
+
5
+ module MagicaVoxel
6
+ # The Frame of Transform
7
+ #
8
+ # @since 0.1.0
9
+ class Frame
10
+ # @param [Hash] attributes
11
+ #
12
+ # @since 0.1.0
13
+ def initialize(attributes)
14
+ @attributes = attributes
15
+ end
16
+
17
+ # Rotation
18
+ #
19
+ # @return [Matrix]
20
+ #
21
+ # @since 0.1.0
22
+ def rotation
23
+ nil # TODO
24
+ end
25
+
26
+ # Translate
27
+ #
28
+ # @return [Vector3]
29
+ #
30
+ # @since 0.1.0
31
+ def translate
32
+ return Vector3.new(0, 0, 0) if @attributes['_t'].nil?
33
+
34
+ x, y, z = @attributes['_t'].split
35
+ @translate ||=
36
+ Vector3.new(x.to_i, y.to_i, z.to_i)
37
+ end
38
+
39
+ # Index
40
+ #
41
+ # @return [Number]
42
+ def index
43
+ return 0 if @attributes['_f'].nil?
44
+
45
+ @index ||= @attributes['_f'].to_i
46
+ end
47
+
48
+ # :nodoc:
49
+ #
50
+ # @since 0.1.0
51
+ def inspect
52
+ "#<MagicaVoxel::Frame index=#{index}, translate=#{translate}>"
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicaVoxel
4
+ # The Chunk type nGRP
5
+ #
6
+ # @since 0.1.0
7
+ class Group < Node
8
+ # @since 0.1.0
9
+ attr_reader :child_ids
10
+
11
+ # :nodoc:
12
+ #
13
+ # @since 0.1.0
14
+ def inspect
15
+ "#<MagicaVoxel::Group id=#{id}, name=#{name}, hidden=#{hidden?}>"
16
+ end
17
+
18
+ private
19
+
20
+ # :nodoc:
21
+ #
22
+ # @since 0.1.0
23
+ def layout
24
+ {
25
+ id: :int32,
26
+ attributes: :dict,
27
+ child_ids: :int32_array
28
+ }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicaVoxel
4
+ # The Chunk type LAYR
5
+ #
6
+ # TODO: Remove dependency on Node
7
+ #
8
+ # @since 0.1.0
9
+ class Layer < Node
10
+ # @since 0.1.0
11
+ attr_reader :reserved_id
12
+
13
+ # :nodoc:
14
+ #
15
+ # @since 0.1.0
16
+ def inspect
17
+ "#<MagicaVoxel::Layer id=#{id}, name=#{name}, hidden=#{hidden?}>"
18
+ end
19
+
20
+ # TODO: Expose Properties
21
+
22
+ private
23
+
24
+ # :nodoc:
25
+ #
26
+ # @since 0.1.0
27
+ def layout
28
+ {
29
+ id: :int32,
30
+ attributes: :dict,
31
+ reversed_id: :int32
32
+ }
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicaVoxel
4
+ # The Chunk type MAIN
5
+ #
6
+ # @since 0.1.0
7
+ class Main < Chunk
8
+ end
9
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicaVoxel
4
+ # The Chunk type MATL
5
+ #
6
+ # @since 0.1.0
7
+ class Material < Chunk
8
+ # @since 0.1.0
9
+ attr_reader :id, :properties
10
+
11
+ # :nodoc:
12
+ #
13
+ # @since 0.1.0
14
+ def inspect
15
+ "#<MagicaVoxel::Material id=#{id}>"
16
+ end
17
+
18
+ # TODO: Expose Properties
19
+
20
+ private
21
+
22
+ # :nodoc:
23
+ #
24
+ # @since 0.1.0
25
+ def layout
26
+ {
27
+ id: :int32,
28
+ properties: :dict
29
+ }
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicaVoxel
4
+ # The Chunk type XYZI
5
+ #
6
+ # @since 0.1.0
7
+ class Model < Chunk
8
+ # @since 0.1.0
9
+ attr_reader :voxels
10
+
11
+ # :nodoc:
12
+ #
13
+ # @return 0.1.0
14
+ def inspect
15
+ "#<MagicaVoxel::Model size=#{voxels.size}>"
16
+ end
17
+
18
+ private
19
+
20
+ # :nodoc:
21
+ #
22
+ # @since 0.1.0
23
+ def layout
24
+ {
25
+ voxels: :voxels
26
+ }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicaVoxel
4
+ # The Node type Chunk
5
+ #
6
+ # @since 0.1.0
7
+ class Node < Chunk
8
+ # @since 0.1.0
9
+ attr_reader :id, :attributes
10
+
11
+ # @return [String] name
12
+ #
13
+ # @since 0.1.0
14
+ def name
15
+ @attributes['_name']
16
+ end
17
+
18
+ # @return [TrueClass|FalseClass] is hidden
19
+ #
20
+ # @since 0.1.0
21
+ def hidden?
22
+ @attributes['_hidden'] == '1'
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicaVoxel
4
+ # The Chunk type NOTE
5
+ #
6
+ # @since 0.1.0
7
+ class Note < Chunk
8
+ # @since 0.1.0
9
+ attr_reader :names
10
+
11
+ private
12
+
13
+ # :nodoc:
14
+ #
15
+ # @since 0.1.0
16
+ def layout
17
+ {
18
+ names: :string_array
19
+ }
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicaVoxel
4
+ # The Chunk type rOBJ
5
+ #
6
+ # @since 0.1.0
7
+ class Object < Chunk
8
+ # @since 0.1.0
9
+ attr_reader :attributes
10
+
11
+ private
12
+
13
+ # :nodoc:
14
+ #
15
+ # @since 0.1.0
16
+ def layout
17
+ {
18
+ attributes: :dict
19
+ }
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicaVoxel
4
+ # The Chunk type RGBA
5
+ #
6
+ # @since 0.1.0
7
+ class Pattle < Chunk
8
+ # @since 0.1.0
9
+ attr_reader :pattle
10
+
11
+ # Get color by index
12
+ #
13
+ # @param id [Number]
14
+ #
15
+ # @return [MagicVoxel::Color]
16
+ #
17
+ # @since 0.1.0
18
+ def [](id)
19
+ @pattle[id]
20
+ end
21
+
22
+ # :nodoc
23
+ #
24
+ # @since 0.1.0
25
+ def inspect
26
+ '#<MagicaVoxel::Pattle>'
27
+ end
28
+
29
+ private
30
+
31
+ # :nodoc:
32
+ #
33
+ # @since 0.1.0
34
+ def layout
35
+ {
36
+ pattle: :pattle
37
+ }
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicaVoxel
4
+ # The Chunk type IMAP
5
+ #
6
+ # @since 0.1.0
7
+ class PattleMap < Chunk
8
+ # @since 0.1.0
9
+ attr_reader :items
10
+
11
+ private
12
+
13
+ # :nodoc:
14
+ #
15
+ # @since 0.1.0
16
+ def layout
17
+ {
18
+ items: :imap
19
+ }
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicaVoxel
4
+ # The Data Reader
5
+ #
6
+ # @since 0.1.0
7
+ class Reader
8
+ class << self
9
+ # Open IO stream
10
+ #
11
+ # @param [IO|String] the stream to read
12
+ #
13
+ # @since 0.1.0
14
+ def open(io)
15
+ io = io.is_a?(IO) ? io : StringIO.new(io)
16
+ yield new(io)
17
+ io.close
18
+ end
19
+ end
20
+ # @param [IO] the stream to read
21
+ #
22
+ # @since 0.1.0
23
+ def initialize(io)
24
+ @io = io
25
+ end
26
+
27
+ # Read int32
28
+ #
29
+ # @return [Number]
30
+ #
31
+ # @since 0.1.0
32
+ def int32
33
+ @io.read(4).unpack1('l')
34
+ end
35
+
36
+ # Read String
37
+ #
38
+ # @return [String]
39
+ #
40
+ # @since 0.1.0
41
+ def string
42
+ @io.read(int32)
43
+ end
44
+
45
+ # Read Dictionary
46
+ #
47
+ # @return [Hash]
48
+ #
49
+ # @since 0.1.0
50
+ def dict
51
+ Hash[*Array.new(int32 * 2).map { string }]
52
+ end
53
+
54
+ # Read Int32 Array
55
+ #
56
+ # @return [Array<Number>]
57
+ #
58
+ # @since 0.1.0
59
+ def int32_array
60
+ Array.new(int32).map { int32 }
61
+ end
62
+
63
+ # Read String Array
64
+ #
65
+ # @return [Array<String>]
66
+ #
67
+ # @since 0.1.0
68
+ def string_array
69
+ Array.new(int32).map { string }
70
+ end
71
+
72
+ # Read Frames
73
+ #
74
+ # @return [Array<MagicaVoxel::Frame>]
75
+ #
76
+ # @since 0.1.0
77
+ def frames
78
+ Array.new(int32).map { Frame.new(dict) }
79
+ end
80
+
81
+ # Read Pattle
82
+ #
83
+ # @return [Array<MagicaVoxel::Color]
84
+ #
85
+ # @since 0.1.0
86
+ def pattle
87
+ Array.new(256).map { rgba }
88
+ end
89
+
90
+ # Read RGBA
91
+ #
92
+ # @return [MagicaVoxel::Color]
93
+ #
94
+ # @since 0.1.0
95
+ def rgba
96
+ r, g, b, a = @io.read(4).unpack('CCCC')
97
+ Color.new(r, g, b, a)
98
+ end
99
+
100
+ # Read Pattle Index MAP
101
+ #
102
+ # @return [Array<Number>]
103
+ #
104
+ # @since 0.1.0
105
+ def imap
106
+ Array.new(256).map { int32 }
107
+ end
108
+
109
+ # Read Voxels
110
+ #
111
+ # @return [Array<MagicaVoxel::Voxel>]
112
+ #
113
+ # @since 0.1.0
114
+ def voxels
115
+ Array.new(int32).map { voxel }
116
+ end
117
+
118
+ # Read Voxel
119
+ #
120
+ # @return [MagicaVoxel::Voxel]
121
+ #
122
+ # @since 0.1.0
123
+ def voxel
124
+ x, y, z, i = @io.read.unpack('cccC')
125
+ Voxel.new(x, y, z, i)
126
+ end
127
+
128
+ # Read Shape's Model
129
+ #
130
+ # @return [MagicaVoxel::Shape::Model]
131
+ #
132
+ # @since 0.1.0
133
+ def shape_model
134
+ Array.new(int32).map { Shape::Model.new(int32, dict) }
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicaVoxel
4
+ # The Chunk type nSHP
5
+ #
6
+ # @since 0.1.0
7
+ class Shape < Node
8
+ # :nodoc:
9
+ class Model
10
+ # @since 0.1.0
11
+ attr_reader :id, :attributes
12
+
13
+ # @param id [Number] the mode id
14
+ # @param attributes [Hash] the model attributes
15
+ #
16
+ # @since 0.1.0
17
+ def initialize(id, attributes)
18
+ @id = id
19
+ @attributes = attributes
20
+ end
21
+ end
22
+
23
+ # @since 0.1.0
24
+ attr_reader :models
25
+
26
+ # :nodoc:
27
+ #
28
+ # @since 0.1.0
29
+ def inspect
30
+ "#<MagicaVoxel::Shape id=#{id}, name=#{name}, hidden=#{hidden?}>"
31
+ end
32
+
33
+ private
34
+
35
+ # :nodoc:
36
+ #
37
+ # @since 0.1.0
38
+ def layout
39
+ {
40
+ id: :int32,
41
+ attributes: :dict,
42
+ models: :shape_model
43
+ }
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicaVoxel
4
+ # The Chunk type SIZE
5
+ #
6
+ # @since 0.1.0
7
+ class Size < Chunk
8
+ # @since 0.1.0
9
+ attr_reader :x, :y, :z
10
+
11
+ # :nodoc:
12
+ #
13
+ # @since 0.1.0
14
+ def inspect
15
+ "#<MagicaVoxel::Size x=#{x}, y=#{y}, z=#{z}>"
16
+ end
17
+
18
+ private
19
+
20
+ # :nodoc:
21
+ #
22
+ # @since 0.1.0
23
+ def layout
24
+ {
25
+ x: :int32,
26
+ y: :int32,
27
+ z: :int32
28
+ }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicaVoxel
4
+ # The Chunk type nTRN
5
+ #
6
+ # @since 0.1.0
7
+ class Transform < Node
8
+ # @since 0.1.0
9
+ attr_reader :child_id, :reserved_id, :layer_id, :frames
10
+
11
+ # :nodoc:
12
+ #
13
+ # @since 0.1.0
14
+ def inspect
15
+ "#<MagicaVoxel::Transform id=#{id}, name=#{name}, hidden=#{hidden?}>"
16
+ end
17
+
18
+ private
19
+
20
+ # :nodoc:
21
+ #
22
+ # @since 0.1.0
23
+ def layout
24
+ {
25
+ id: :int32,
26
+ attributes: :dict,
27
+ child_id: :int32,
28
+ reserved_id: :int32,
29
+ layer_id: :int32,
30
+ frames: :frames
31
+ }
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicaVoxel
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'magica_voxel/version'
4
+ require_relative 'magica_voxel/reader'
5
+ require_relative 'magica_voxel/chunk'
6
+ require_relative 'magica_voxel/main'
7
+ require_relative 'magica_voxel/size'
8
+ require_relative 'magica_voxel/model'
9
+ require_relative 'magica_voxel/pattle'
10
+ require_relative 'magica_voxel/node'
11
+ require_relative 'magica_voxel/transform'
12
+ require_relative 'magica_voxel/frame'
13
+ require_relative 'magica_voxel/group'
14
+ require_relative 'magica_voxel/shape'
15
+ require_relative 'magica_voxel/material'
16
+ require_relative 'magica_voxel/layer'
17
+ require_relative 'magica_voxel/object'
18
+ require_relative 'magica_voxel/camera'
19
+ require_relative 'magica_voxel/note'
20
+ require_relative 'magica_voxel/pattle_map'
21
+ require_relative 'magica_voxel/file'
22
+
23
+ # The MagicaVoxel file parser
24
+ #
25
+ # @since 0.1.0
26
+ module MagicaVoxel
27
+ # The Voxel Data
28
+ #
29
+ # @since 0.1.0
30
+ Voxel = Struct.new(:x, :y, :z, :color)
31
+
32
+ # The Voxel Color
33
+ #
34
+ # @since 0.1.0
35
+ Color = Struct.new(:r, :g, :b, :a)
36
+
37
+ # The Vector3
38
+ #
39
+ # @since 0.1.0
40
+ Vector3 = Struct.new(:x, :y, :z)
41
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/magica_voxel/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'magica_voxel'
7
+ spec.version = MagicaVoxel::VERSION
8
+ spec.authors = ['蒼時弦也']
9
+ spec.email = ['contact@frost.tw']
10
+
11
+ spec.summary = 'The MagicaVoxel reader'
12
+ spec.description = 'The MagicaVoxel reader'
13
+ spec.homepage = 'https://github.com/elct9620/magica_voxel-rb'
14
+ spec.required_ruby_version = '>= 2.5.0'
15
+
16
+ spec.metadata['homepage_uri'] = spec.homepage
17
+ spec.metadata['source_code_uri'] = 'https://github.com/elct9620/magica_voxel-rb'
18
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
23
+ `git ls-files -z`.split("\x0").reject do |f|
24
+ (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
25
+ end
26
+ end
27
+ spec.bindir = 'exe'
28
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ['lib']
30
+
31
+ # Uncomment to register a new dependency of your gem
32
+ # spec.add_dependency "example-gem", "~> 1.0"
33
+
34
+ # For more information and examples about making a new gem, checkout our
35
+ # guide at: https://bundler.io/guides/creating_gem.html
36
+ spec.metadata = {
37
+ 'rubygems_mfa_required' => 'true'
38
+ }
39
+ end