magica_voxel 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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