ray 0.1.1 → 0.2.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.
Files changed (167) hide show
  1. data/README.md +9 -6
  2. data/Rakefile +1 -5
  3. data/ext/audio.c +25 -19
  4. data/ext/audio_source.c +67 -39
  5. data/ext/color.c +19 -19
  6. data/ext/drawable.c +190 -31
  7. data/ext/extconf.rb +16 -14
  8. data/ext/gl.c +310 -30
  9. data/ext/gl_buffer.c +223 -2
  10. data/ext/gl_index_buffer.c +11 -0
  11. data/ext/gl_int_array.c +24 -22
  12. data/ext/gl_vertex.c +84 -49
  13. data/ext/image.c +115 -51
  14. data/ext/image_target.c +58 -10
  15. data/ext/input.c +73 -6
  16. data/ext/mo.c +583 -0
  17. data/ext/mo.h +189 -0
  18. data/ext/music.c +9 -8
  19. data/ext/pixel_bus.c +349 -0
  20. data/ext/polygon.c +68 -45
  21. data/ext/ray.c +1 -0
  22. data/ext/ray.h +19 -1
  23. data/ext/rect.c +9 -47
  24. data/ext/say.h +1 -2
  25. data/ext/say_all.h +6 -0
  26. data/ext/say_audio.h +3 -0
  27. data/ext/say_audio_context.c +1 -4
  28. data/ext/say_basic_type.c +24 -0
  29. data/ext/say_basic_type.h +4 -0
  30. data/ext/say_buffer.c +217 -88
  31. data/ext/say_buffer.h +20 -5
  32. data/ext/say_buffer_renderer.c +10 -7
  33. data/ext/say_buffer_renderer.h +1 -1
  34. data/ext/say_buffer_slice.c +70 -76
  35. data/ext/say_context.c +109 -22
  36. data/ext/say_context.h +14 -0
  37. data/ext/say_drawable.c +113 -25
  38. data/ext/say_drawable.h +23 -2
  39. data/ext/say_error.c +7 -2
  40. data/ext/say_font.c +30 -27
  41. data/ext/say_font.h +3 -6
  42. data/ext/say_get_proc.c +35 -0
  43. data/ext/say_image.c +102 -27
  44. data/ext/say_image.h +11 -4
  45. data/ext/say_image_target.c +88 -34
  46. data/ext/say_image_target.h +3 -2
  47. data/ext/say_index_buffer.c +31 -19
  48. data/ext/say_index_buffer.h +4 -2
  49. data/ext/say_index_buffer_slice.c +78 -70
  50. data/ext/say_music.c +4 -2
  51. data/ext/say_osx.h +3 -2
  52. data/ext/say_osx_context.h +37 -4
  53. data/ext/say_osx_window.h +32 -37
  54. data/ext/say_pixel_bus.c +163 -0
  55. data/ext/say_pixel_bus.h +44 -0
  56. data/ext/say_polygon.c +2 -2
  57. data/ext/say_shader.c +66 -62
  58. data/ext/say_shader.h +2 -0
  59. data/ext/say_sprite.c +1 -2
  60. data/ext/say_target.c +14 -23
  61. data/ext/say_target.h +3 -1
  62. data/ext/say_text.c +45 -7
  63. data/ext/say_text.h +12 -3
  64. data/ext/say_thread.c +13 -6
  65. data/ext/say_thread.h +1 -1
  66. data/ext/say_thread_variable.c +5 -5
  67. data/ext/say_vertex_type.c +79 -41
  68. data/ext/say_vertex_type.h +6 -2
  69. data/ext/say_view.c +10 -31
  70. data/ext/say_view.h +1 -5
  71. data/ext/say_win.h +2 -2
  72. data/ext/say_win_context.h +49 -11
  73. data/ext/say_win_window.h +30 -27
  74. data/ext/say_window.c +3 -3
  75. data/ext/say_x11.h +3 -1
  76. data/ext/say_x11_context.h +64 -10
  77. data/ext/say_x11_window.h +22 -17
  78. data/ext/shader.c +9 -0
  79. data/ext/sprite.c +7 -1
  80. data/ext/target.c +80 -28
  81. data/ext/text.c +43 -1
  82. data/ext/view.c +53 -1
  83. data/ext/window.c +4 -0
  84. data/lib/ray/animation_list.rb +17 -2
  85. data/lib/ray/audio_source.rb +11 -0
  86. data/lib/ray/color.rb +14 -0
  87. data/lib/ray/drawable.rb +23 -0
  88. data/lib/ray/dsl/event.rb +1 -9
  89. data/lib/ray/dsl/event_runner.rb +3 -4
  90. data/lib/ray/dsl/matcher.rb +20 -1
  91. data/lib/ray/effect.rb +116 -0
  92. data/lib/ray/effect/black_and_white.rb +38 -0
  93. data/lib/ray/effect/color_inversion.rb +16 -0
  94. data/lib/ray/effect/generator.rb +145 -0
  95. data/lib/ray/effect/grayscale.rb +32 -0
  96. data/lib/ray/game.rb +25 -5
  97. data/lib/ray/gl/vertex.rb +105 -26
  98. data/lib/ray/helper.rb +5 -0
  99. data/lib/ray/image.rb +54 -13
  100. data/lib/ray/image_target.rb +7 -0
  101. data/lib/ray/matrix.rb +26 -0
  102. data/lib/ray/music.rb +4 -0
  103. data/lib/ray/pixel_bus.rb +22 -0
  104. data/lib/ray/polygon.rb +17 -0
  105. data/lib/ray/pp.rb +28 -0
  106. data/lib/ray/ray.rb +7 -1
  107. data/lib/ray/rect.rb +7 -13
  108. data/lib/ray/scene.rb +24 -5
  109. data/lib/ray/scene_list.rb +9 -0
  110. data/lib/ray/shader.rb +11 -2
  111. data/lib/ray/sound.rb +4 -0
  112. data/lib/ray/sprite.rb +23 -62
  113. data/lib/ray/target.rb +25 -0
  114. data/lib/ray/text.rb +10 -0
  115. data/lib/ray/turtle.rb +9 -3
  116. data/lib/ray/vector.rb +18 -0
  117. data/lib/ray/vertex.rb +6 -0
  118. data/lib/ray/view.rb +22 -0
  119. data/samples/animation/sprite_motion.rb +0 -60
  120. data/samples/audio/{spacial.rb → spatial.rb} +1 -1
  121. data/samples/buffer/buffer.rb +1 -0
  122. data/samples/buffer/index_buffer.rb +2 -0
  123. data/samples/cptn_ruby/cptn_ruby.rb +6 -7
  124. data/samples/effects/effect.rb +39 -0
  125. data/samples/effects/grayscale.rb +27 -0
  126. data/samples/opengl/image.rb +7 -5
  127. data/samples/opengl/instancing.rb +159 -0
  128. data/samples/opengl/instancing.rbc +3231 -0
  129. data/samples/opengl/obj_loader.rb +9 -8
  130. data/samples/opengl/shader.rb +1 -3
  131. data/samples/shaders/geometry.rb +108 -38
  132. data/samples/shaders/geometry.rbc +2074 -0
  133. data/samples/shaders/shape.rb +2 -2
  134. data/samples/starfighter/starfighter.rb +5 -5
  135. data/samples/window/get_pixel.rb +1 -1
  136. data/test/animation_list_test.rb +18 -4
  137. data/test/drawable_test.rb +70 -1
  138. data/test/effect_generator_test.rb +63 -0
  139. data/test/effect_test.rb +61 -0
  140. data/test/game_test.rb +18 -0
  141. data/test/gl_buffer_test.rb +43 -1
  142. data/test/gl_index_buffer_test.rb +5 -0
  143. data/test/gl_vertex_test.rb +28 -1
  144. data/test/image_test.rb +5 -5
  145. data/test/input_test.rb +49 -0
  146. data/test/pixel_bus_test.rb +28 -0
  147. data/test/rect_test.rb +4 -0
  148. data/{samples/_media → test/res}/Beep.wav +0 -0
  149. data/samples/_media/CptnRuby Gem.png b/data/test/res/CptnRuby → Gem.png +0 -0
  150. data/samples/_media/CptnRuby Map.txt b/data/test/res/CptnRuby → Map.txt +0 -0
  151. data/samples/_media/CptnRuby Tileset.png b/data/test/res/CptnRuby → Tileset.png +0 -0
  152. data/{samples/_media → test/res}/CptnRuby.png +0 -0
  153. data/{samples/_media → test/res}/Space.png +0 -0
  154. data/{samples/_media → test/res}/Star.png +0 -0
  155. data/{samples/_media → test/res}/Starfighter.png +0 -0
  156. data/test/res/cube.obj +28 -0
  157. data/test/res/light3d.c +2 -2
  158. data/test/res/stone.png +0 -0
  159. data/test/scene_test.rb +3 -0
  160. data/test/sprite_test.rb +10 -0
  161. data/test/text_test.rb +31 -2
  162. data/test/view_test.rb +13 -1
  163. metadata +38 -17
  164. data/ext/say_array.c +0 -124
  165. data/ext/say_array.h +0 -34
  166. data/ext/say_table.c +0 -86
  167. data/ext/say_table.h +0 -24
@@ -0,0 +1,38 @@
1
+ module Ray
2
+ class Effect
3
+ # A black and white effect. It considers the grayscale level of the image,
4
+ # and sets pixels that are darker than a given value to black, and the
5
+ # others to white.
6
+ class BlackAndWhite < Effect
7
+ effect_name :black_and_white
8
+ attribute :ratio, :vec3
9
+ attribute :value, :float
10
+
11
+ # @param [Ray::Vector3] ratio Default ratio to compute grayscale
12
+ # @param [Float] value Minimal grayscale level of white pixels
13
+ def initialize(value = 0.5, ratio = [0.299, 0.587, 0.114])
14
+ @ratio = ratio
15
+ @value = value
16
+ end
17
+
18
+ # @return [Ray::Vector3] ratio
19
+ attr_accessor :ratio
20
+
21
+ def defaults
22
+ {:ratio => @ratio, :value => @value}
23
+ end
24
+
25
+ def code
26
+ return <<code
27
+ vec4 do_black_and_white(ray_black_and_white args, vec4 color) {
28
+ float gray = dot(color.rgb, args.ratio);
29
+ if (gray > args.value)
30
+ return vec4(1, 1, 1, color.a);
31
+ else
32
+ return vec4(0, 0, 0, color.a);
33
+ }
34
+ code
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,16 @@
1
+ module Ray
2
+ class Effect
3
+ # An effect to invert the color of a pixel. This preserves the alpha component.
4
+ class ColorInversion < Effect
5
+ effect_name :color_inversion
6
+
7
+ def code
8
+ return <<code
9
+ vec4 do_color_inversion(ray_color_inversion args, vec4 color) {
10
+ return vec4(vec3(1, 1, 1) - color.rgb, color.a);
11
+ }
12
+ code
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,145 @@
1
+ module Ray
2
+ class Effect
3
+ class Generator
4
+ include Enumerable
5
+
6
+ # @param [Integer] version GLSL version to use
7
+ # @yield Yields itself if a block is given
8
+ def initialize(version = 110)
9
+ @effects = []
10
+ @version = version
11
+
12
+ if version >= 130
13
+ @input = <<-input
14
+ in vec4 var_Color;
15
+ in vec2 var_TexCoord;
16
+ input
17
+ else
18
+ @input = <<-input
19
+ varying vec4 var_Color;
20
+ varying vec2 var_TexCoord;
21
+ input
22
+ end
23
+
24
+ @uniforms = <<-uniforms
25
+ uniform sampler2D in_Texture;
26
+ uniform bool in_TextureEnabled;
27
+ uniforms
28
+
29
+ @color = "color"
30
+
31
+ @default = <<-default
32
+ /* Apply default value */
33
+ vec4 color;
34
+ if (in_TextureEnabled)
35
+ color = texture#{"2D" if version<130}(in_Texture, var_TexCoord) * var_Color;
36
+ else
37
+ color = var_Color;
38
+ default
39
+
40
+ yield self if block_given?
41
+ end
42
+
43
+ # @param [Array<Ray:::Effect>] effects effects to add to the generator
44
+ def push(*effects)
45
+ @effects.concat effects
46
+ self
47
+ end
48
+
49
+ alias << push
50
+
51
+ def each(&block)
52
+ @effects.each(&block)
53
+ end
54
+
55
+ # @return [Array<Ray::Effect>] All of the effects used by the generator
56
+ attr_reader :effects
57
+ alias to_a effects
58
+
59
+ # @return [Integer] GLSL version number
60
+ attr_reader :version
61
+
62
+ # @return [String] Code defining GLSL input (with varying or in, depending
63
+ # on the GLSL version).
64
+ attr_accessor :input
65
+
66
+ # @return [String] Code defining uniforms
67
+ attr_accessor :uniforms
68
+
69
+ # @return [String] Name of the variable containing the
70
+ # color once the default code is run. "color" by default.
71
+ attr_accessor :color
72
+
73
+ # @return [String] Code to ste the default color. It should apply
74
+ # texturing, for example.
75
+ attr_accessor :default
76
+
77
+ # @return [String] code of the pixel shader
78
+ def code
79
+ str = "#version #@version\n"
80
+ str << "\n"
81
+
82
+ str << input << "\n"
83
+ str << uniforms << "\n"
84
+
85
+
86
+ str << "out vec4 out_FragColor;\n" if version >= 130
87
+ str << "\n"
88
+
89
+ str << "/* Headers */\n"
90
+ each do |effect|
91
+ str << effect.header << "\n"
92
+ end
93
+ str << "\n"
94
+
95
+ str << "/* Structs */\n\n"
96
+ each do |effect|
97
+ str << effect.struct << "\n"
98
+ end
99
+
100
+ str << "/* Effects parameters */\n"
101
+ each do |effect|
102
+ str << "uniform ray_#{effect.name} #{effect.name};\n"
103
+ end
104
+ str << "\n"
105
+
106
+ str << "/* Functions */\n"
107
+ each do |effect|
108
+ str << effect.code << "\n"
109
+ end
110
+
111
+ str << "void main() {\n"
112
+ str << default << "\n"
113
+
114
+ each do |effect|
115
+ str << " if (#{effect.name}.enabled)\n"
116
+ str << " #@color = do_#{effect.name}(#{effect.name}, #@color);\n"
117
+ str << "\n"
118
+ end
119
+
120
+ if version >= 130
121
+ str << " out_FragColor = #@color;\n"
122
+ else
123
+ str << " gl_FragColor = #@color;\n"
124
+ end
125
+
126
+ str << "}\n"
127
+ end
128
+
129
+ # Generates a shader
130
+ # @param [Ray::Shader] shader Shader to compile and apply defaults to
131
+ # @return [Ray::Shader] shader
132
+ def build(shader = Ray::Shader.new)
133
+ shader.compile :frag => StringIO.new(code)
134
+ apply_defaults shader
135
+ shader
136
+ end
137
+
138
+ # Apply generator defaults to a shader
139
+ # @param [Ray::Shader] shader Shader to apply defaults to
140
+ def apply_defaults(shader)
141
+ each { |effect| effect.apply_defaults(shader) }
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,32 @@
1
+ module Ray
2
+ class Effect
3
+ # A grayscale effect. To accomplish it, it computes the dot product of the
4
+ # color by a ratio, and assigns the result to red, green, and blue
5
+ # components. Alpha component is preserved.
6
+ class Grayscale < Effect
7
+ effect_name :grayscale
8
+ attribute :ratio, :vec3
9
+
10
+ # @param [Ray::Vector3] ratio Default ratio
11
+ def initialize(ratio = [0.299, 0.587, 0.114])
12
+ @ratio = ratio
13
+ end
14
+
15
+ # @return [Ray::Vector3] ratio
16
+ attr_accessor :ratio
17
+
18
+ def defaults
19
+ {:ratio => @ratio}
20
+ end
21
+
22
+ def code
23
+ return <<code
24
+ vec4 do_grayscale(ray_grayscale args, vec4 color) {
25
+ float gray = dot(color.rgb, args.ratio);
26
+ return vec4(gray, gray, gray, color.a);
27
+ }
28
+ code
29
+ end
30
+ end
31
+ end
32
+ end
@@ -120,11 +120,31 @@ module Ray
120
120
  @game_scenes.push(scene_name, *args)
121
121
  end
122
122
 
123
- # Pops the last scene.
123
+ # Pops the last scene
124
124
  def pop_scene
125
125
  @game_scenes.pop
126
126
  end
127
127
 
128
+ # Pops scenes while a condition is true
129
+ #
130
+ # @yield [scene] To determine if a scene must be popped.
131
+ # @yieldparam [Ray::Scene] scene The scene that will be popped
132
+ # @yieldreturn [Boolean] True to pop the next scene
133
+ def pop_scene_while
134
+ while yield scenes.current
135
+ scenes.current.pop_scene # ensure exit is set to false
136
+ end
137
+ end
138
+
139
+ # Pops scenes until a condition is met
140
+ #
141
+ # @yield (see #pop_scene_while)
142
+ # @yieldparam scene (see #pop_scene_while)
143
+ # @yieldreturn [Boolean] False to pop the next scene
144
+ def pop_scene_until
145
+ pop_scene_while { |o| !yield(o) }
146
+ end
147
+
128
148
  # Registers a new scene with a given name. the block will be passed
129
149
  # to klass.new.
130
150
  #
@@ -136,6 +156,7 @@ module Ray
136
156
  scene.game = self
137
157
  scene.event_runner = event_runner
138
158
  scene.window = @game_window
159
+ scene.name = name
139
160
  end
140
161
 
141
162
  # @return [Ray::Scene] scene register for a given name
@@ -183,14 +204,17 @@ module Ray
183
204
  @game_scenes.clear
184
205
  end
185
206
 
207
+ # @return [Ray::String]
186
208
  def title
187
209
  @game_title
188
210
  end
189
211
 
212
+ # @return [Ray::SceneList]
190
213
  def scenes
191
214
  @game_scenes
192
215
  end
193
216
 
217
+ # @return [Ray::Window]
194
218
  def window
195
219
  @game_window
196
220
  end
@@ -210,10 +234,6 @@ module Ray
210
234
  scene.event_runner = runner
211
235
  end
212
236
  end
213
-
214
- def inspect
215
- "game(#{title.inspect})"
216
- end
217
237
  end
218
238
 
219
239
  # (see Ray::Game#initialize)
@@ -1,15 +1,51 @@
1
1
  module Ray
2
2
  module GL
3
3
  class Vertex
4
+ include Ray::PP
5
+
4
6
  @vertex_classes = {0 => Ray::Vertex}
5
7
 
8
+ class Instance
9
+ include Ray::PP
10
+
11
+ @instance_classes = {}
12
+
13
+ class << self
14
+ attr_reader :instance_classes
15
+ end
16
+
17
+ def self.layout
18
+ @vertex_instance_layout
19
+ end
20
+
21
+ def to_s
22
+ pairs = []
23
+ self.class.layout.each do |key, _, _, per_instance|
24
+ pairs << "#{key}=#{send(key)}" if per_instance
25
+ end
26
+
27
+ "#<#{self.class} #{pairs.join " "}>"
28
+ end
29
+
30
+ def pretty_print(q)
31
+ attr = []
32
+ self.class.layout.each do |key, _, _, per_instance|
33
+ attr << key if per_instance
34
+ end
35
+
36
+ pretty_print_attributes q, attr
37
+ end
38
+ end
39
+
6
40
  # Creates a new Vertex class with a custom layout. Layout is an array of
7
- # arrays, where each row contains 3 elements:
41
+ # arrays, where each row contains 3 or 4 elements:
8
42
  #
9
43
  # 1. Attribute name in Ruby
10
44
  # 2. Attribute name in GLSL shaders
11
45
  # 3. Attribute type, one of the following symbols: float, int, ubyte,
12
46
  # bool, color, vector2, vector3.
47
+ # 4. Whether the attribute is only accessibel on a per-instance basis (as
48
+ # opposed to per-vertex, which is the default)
13
49
  #
14
50
  # Getters and setters are created for all of the attributes.
15
51
  #
@@ -23,10 +59,13 @@ module Ray
23
59
  # [:bool, "in_Bool", :bool],
24
60
  # [:color, "in_Color", :color],
25
61
  # [:vector2, "in_Vector2", :vector2],
26
- # [:vector3, "in_Vector3", :vector3]
62
+ # [:vector3, "in_Vector3", :vector3],
63
+ #
64
+ # # per-instance data
65
+ # [:instance_color, "magic", :color, true]
27
66
  # ]
28
67
  def self.make(layout)
29
- layout.each do |_, _, type|
68
+ layout.each do |_, _, type, _|
30
69
  unless TypeMap.has_key? type
31
70
  raise ArgumentError, "unknown type in a vertex: #{type.inspect}"
32
71
  end
@@ -40,6 +79,20 @@ module Ray
40
79
  @vertex_type_size = Vertex.size(vtype)
41
80
  @vertex_type_layout = layout
42
81
 
82
+ if layout.any? { |_, _, _, per_instance| per_instance }
83
+ const_set :Instance, Class.new(Ray::GL::Vertex::Instance) {
84
+ @vertex_instance_type_id = vtype
85
+ @vertex_instance_size = Vertex.instance_size(vtype)
86
+ @vertex_instance_layout = layout
87
+
88
+ class << self
89
+ undef instance_classes
90
+ end
91
+
92
+ Vertex.define_layout self, layout, vtype, true
93
+ }
94
+ end
95
+
43
96
  class << self
44
97
  undef make
45
98
  undef make_type
@@ -47,18 +100,51 @@ module Ray
47
100
  undef offset_of
48
101
  end
49
102
 
103
+ Vertex.define_layout self, layout, vtype, false
104
+ end
105
+
106
+ if @vertex_classes[vtype].const_defined? :Instance
107
+ Instance.instance_classes[vtype] = @vertex_classes[vtype]::Instance
108
+ end
109
+
110
+ @vertex_classes[vtype]
111
+ end
112
+
113
+ def self.layout
114
+ @vertex_type_layout
115
+ end
116
+
117
+ def self.default_for(type)
118
+ case type
119
+ when :float, :int, :ubyte then 0
120
+ when :bool then true
121
+ when :vector2 then Ray::Vector2[0, 0]
122
+ when :vector3 then Ray::Vector3[0, 0, 0]
123
+ when :color then Ray::Color.white
124
+ end
125
+ end
126
+
127
+ def self.define_layout(on, layout, vtype, instance = false)
128
+ argument_layout = layout.reject do |_, _, _, per_instance|
129
+ per_instance ^ instance
130
+ end
131
+
132
+ on.class_eval do
50
133
  define_method :initialize do |*args|
51
134
  if args.size > layout.size
52
- raise ArgumentError, "wrong number of arguments: %d for %d",
53
- args.size, layout.size
135
+ msg = "wrong number of arguments: #{args.size} for" <<
136
+ " #{layout.size}"
137
+ raise ArgumentError, msg
54
138
  end
55
139
 
56
- layout.each_with_index do |(attr, _, type), i|
57
- send("#{attr}=", args[i] || default_for(type))
140
+ argument_layout.each_with_index do |(attr, _, type, _), i|
141
+ send("#{attr}=", args[i] || Vertex.default_for(type))
58
142
  end
59
143
  end
60
144
 
61
- layout.each_with_index do |(attr, _, type), i|
145
+ layout.each_with_index do |(attr, _, type, per_instance), i|
146
+ next if per_instance ^ instance
147
+
62
148
  offset = Vertex.offset_of(vtype, i)
63
149
 
64
150
  # Faster than define_method.
@@ -77,29 +163,22 @@ module Ray
77
163
  end
78
164
  end
79
165
 
80
- def self.layout
81
- @vertex_type_layout
82
- end
83
-
84
166
  def to_s
85
- "#<#{self.class} #{pairs}>"
86
- end
167
+ pairs = []
168
+ self.class.layout.each do |key, _, _, per_instance|
169
+ pairs << "#{key}=#{send(key)}" unless per_instance
170
+ end
87
171
 
88
- def pairs
89
- self.class.layout.map { |key, _, _|
90
- "#{key}=#{send(key)}"
91
- }.join " "
172
+ "#<#{self.class} #{pairs.join " "}>"
92
173
  end
93
174
 
94
- private
95
- def default_for(type)
96
- case type
97
- when :float, :int, :ubyte then 0
98
- when :bool then true
99
- when :vector2 then Ray::Vector2[0, 0]
100
- when :vector3 then Ray::Vector3[0, 0, 0]
101
- when :color then Ray::Color.white
175
+ def pretty_print(q)
176
+ attr = []
177
+ self.class.layout.each do |key, _, _, per_instance|
178
+ attr << key unless per_instance
102
179
  end
180
+
181
+ pretty_print_attributes q, attr
103
182
  end
104
183
  end
105
184
  end