glimr 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/lib/glimr.rb +2 -0
  2. data/lib/glimr/configurable.rb +37 -0
  3. data/lib/glimr/default_theme/button_bg.png +0 -0
  4. data/lib/glimr/default_theme/button_bg_down.png +0 -0
  5. data/lib/glimr/default_theme/button_cover.png +0 -0
  6. data/lib/glimr/default_theme/button_cover_down.png +0 -0
  7. data/lib/glimr/default_theme/button_focus.png +0 -0
  8. data/lib/glimr/default_theme/checkbox_bg.png +0 -0
  9. data/lib/glimr/default_theme/checkbox_checked_bg.png +0 -0
  10. data/lib/glimr/default_theme/font.ttf +0 -0
  11. data/lib/glimr/default_theme/hscroller_bg.png +0 -0
  12. data/lib/glimr/default_theme/radiobutton_bg.png +0 -0
  13. data/lib/glimr/default_theme/radiobutton_checked_bg.png +0 -0
  14. data/lib/glimr/default_theme/resizer_down.png +0 -0
  15. data/lib/glimr/default_theme/resizer_up.png +0 -0
  16. data/lib/glimr/default_theme/scroll_down_down.png +0 -0
  17. data/lib/glimr/default_theme/scroll_down_up.png +0 -0
  18. data/lib/glimr/default_theme/scroll_hknob_down.png +0 -0
  19. data/lib/glimr/default_theme/scroll_hknob_up.png +0 -0
  20. data/lib/glimr/default_theme/scroll_left_down.png +0 -0
  21. data/lib/glimr/default_theme/scroll_left_up.png +0 -0
  22. data/lib/glimr/default_theme/scroll_right_down.png +0 -0
  23. data/lib/glimr/default_theme/scroll_right_up.png +0 -0
  24. data/lib/glimr/default_theme/scroll_up_down.png +0 -0
  25. data/lib/glimr/default_theme/scroll_up_up.png +0 -0
  26. data/lib/glimr/default_theme/scroll_vknob_down.png +0 -0
  27. data/lib/glimr/default_theme/scroll_vknob_up.png +0 -0
  28. data/lib/glimr/default_theme/text_cursor.png +0 -0
  29. data/lib/glimr/default_theme/text_cursor_insert.png +0 -0
  30. data/lib/glimr/default_theme/text_input_bg.png +0 -0
  31. data/lib/glimr/default_theme/vscroller_bg.png +0 -0
  32. data/lib/glimr/event.rb +41 -0
  33. data/lib/glimr/eventlistener.rb +209 -0
  34. data/lib/glimr/layoutable.rb +520 -0
  35. data/lib/glimr/renderer.rb +2 -0
  36. data/lib/glimr/renderer/camera.rb +63 -0
  37. data/lib/glimr/renderer/geometry.rb +194 -0
  38. data/lib/glimr/renderer/glutwindow.rb +387 -0
  39. data/lib/glimr/renderer/light.rb +43 -0
  40. data/lib/glimr/renderer/material.rb +66 -0
  41. data/lib/glimr/renderer/model.rb +103 -0
  42. data/lib/glimr/renderer/orthoprojection.rb +21 -0
  43. data/lib/glimr/renderer/raw.rb +34 -0
  44. data/lib/glimr/renderer/sceneobject.rb +279 -0
  45. data/lib/glimr/renderer/shader.rb +14 -0
  46. data/lib/glimr/renderer/texture.rb +280 -0
  47. data/lib/glimr/renderer/transform.rb +322 -0
  48. data/lib/glimr/renderer/viewport.rb +349 -0
  49. data/lib/glimr/renderer_core.rb +10 -0
  50. data/lib/glimr/util.rb +247 -0
  51. data/lib/glimr/widget.rb +87 -0
  52. data/lib/glimr/widgets.rb +37 -0
  53. data/lib/glimr/widgets/button.rb +277 -0
  54. data/lib/glimr/widgets/checkbox.rb +82 -0
  55. data/lib/glimr/widgets/container.rb +84 -0
  56. data/lib/glimr/widgets/image.rb +82 -0
  57. data/lib/glimr/widgets/label.rb +91 -0
  58. data/lib/glimr/widgets/layout.rb +227 -0
  59. data/lib/glimr/widgets/list.rb +28 -0
  60. data/lib/glimr/widgets/radiogroup.rb +118 -0
  61. data/lib/glimr/widgets/resizer.rb +31 -0
  62. data/lib/glimr/widgets/scrollable_container.rb +67 -0
  63. data/lib/glimr/widgets/scrollbar.rb +496 -0
  64. data/lib/glimr/widgets/stretchable_image.rb +135 -0
  65. data/lib/glimr/widgets/text_editor.rb +349 -0
  66. data/tests/assets/datatowers_crop.jpg +0 -0
  67. data/tests/assets/download_progress_meter.png +0 -0
  68. data/tests/assets/metalwing2.png +0 -0
  69. data/tests/assets/redhairgreeneyes3.jpg +0 -0
  70. data/tests/demo_apps/spinning_ruby.rb +37 -0
  71. data/tests/integration_tests/run_all.rb +8 -0
  72. data/tests/integration_tests/test_button.rb +22 -0
  73. data/tests/integration_tests/test_checkbox.rb +21 -0
  74. data/tests/integration_tests/test_container.rb +22 -0
  75. data/tests/integration_tests/test_label.rb +12 -0
  76. data/tests/integration_tests/test_layout.rb +43 -0
  77. data/tests/integration_tests/test_radiogroup.rb +16 -0
  78. data/tests/integration_tests/test_renderer.rb +44 -0
  79. data/tests/integration_tests/test_renderer2.rb +36 -0
  80. data/tests/integration_tests/test_scrollable_container.rb +34 -0
  81. data/tests/integration_tests/test_scrollbar.rb +20 -0
  82. data/tests/integration_tests/test_stretchable_image.rb +34 -0
  83. data/tests/integration_tests/test_text_input.rb +20 -0
  84. data/tests/integration_tests/test_zsort.rb +18 -0
  85. data/tests/unit_tests/test_button.rb +93 -0
  86. data/tests/unit_tests/test_checkbox.rb +35 -0
  87. data/tests/unit_tests/test_label.rb +36 -0
  88. data/tests/unit_tests/test_layout.rb +229 -0
  89. data/tests/unit_tests/test_widget.rb +3 -0
  90. metadata +139 -0
@@ -0,0 +1,43 @@
1
+ require 'glimr/renderer/sceneobject'
2
+
3
+
4
+ module GlimR
5
+
6
+
7
+ class Light < SceneObject
8
+
9
+ LIGHTS = GL::constants.grep(/^LIGHT[0-9]+/).map{|l| GL.const_get l }
10
+
11
+ def self.reserve_light_id
12
+ @index ||= 0
13
+ return false if LIGHTS.size <= @index
14
+ l = LIGHTS[@index]
15
+ @index += 1
16
+ l
17
+ end
18
+
19
+ def self.reset_lights
20
+ @index = 0
21
+ LIGHTS.each{|l| Disable(l) }
22
+ end
23
+
24
+ attr_accessor :position, :diffuse, :specular, :ambient
25
+ attr_accessor :constant_attenuation, :linear_attenuation, :quadratic_attenuation
26
+
27
+ def setup
28
+ light_id = self.class.reserve_light_id
29
+ return unless light_id
30
+ Enable(light_id)
31
+ Lightfv(light_id, POSITION, position ) if position
32
+ Lightfv(light_id, DIFFUSE, diffuse ) if diffuse
33
+ Lightfv( light_id, SPECULAR, specular ) if specular
34
+ Lightfv( light_id, AMBIENT, ambient ) if ambient
35
+ Lightf( light_id, CONSTANT_ATTENUATION, constant_attenuation) if constant_attenuation
36
+ Lightf( light_id, LINEAR_ATTENUATION, linear_attenuation) if linear_attenuation
37
+ Lightf( light_id, QUADRATIC_ATTENUATION, quadratic_attenuation) if quadratic_attenuation
38
+ end
39
+
40
+ end
41
+
42
+
43
+ end
@@ -0,0 +1,66 @@
1
+ require 'glimr/renderer/sceneobject'
2
+
3
+
4
+ module GlimR
5
+
6
+
7
+ # A Material node controls OpenGL surface material parameters.
8
+ # It has accessors for ambient, diffuse, specular, shininess and emission.
9
+ #
10
+ # Look up glMaterial and Blinn-Phong shading to find out more.
11
+ #
12
+ class Material < SceneObject
13
+
14
+ touching_accessor :ambient, :diffuse, :specular, :shininess, :emission
15
+
16
+ # The absolute material of a Material is the parent's absolute material
17
+ # merged with the Material.
18
+ def absolute_material
19
+ @__pama ||= (
20
+ pam = parent.absolute_material
21
+ pam.ambient = ambient if ambient
22
+ pam.diffuse = diffuse if diffuse
23
+ pam.specular = specular if specular
24
+ pam.shininess = shininess if shininess
25
+ pam.emission = emission if emission
26
+ pam
27
+ )
28
+ end
29
+
30
+ # Applies the material by calling GL::Material to set the material properties.
31
+ def apply
32
+ Material(FRONT_AND_BACK, AMBIENT, ambient) if ambient
33
+ Material(FRONT_AND_BACK, DIFFUSE, diffuse) if diffuse
34
+ Material(FRONT_AND_BACK, SPECULAR, specular) if specular
35
+ Material(FRONT_AND_BACK, SHININESS, shininess) if shininess
36
+ Material(FRONT_AND_BACK, EMISSION, emission) if emission
37
+ end
38
+
39
+ # Pushes the LIGHTING_BIT to attrib stack.
40
+ def push_state
41
+ PushAttrib(LIGHTING_BIT)
42
+ end
43
+
44
+ # Pops the attrib stack.
45
+ def pop_state
46
+ PopAttrib()
47
+ end
48
+
49
+ # Replaces the instance variables of the Material with
50
+ # the other's.
51
+ def replace!(other)
52
+ @ambient = other.ambient
53
+ @diffuse = other.diffuse
54
+ @specular = other.specular
55
+ @shininess = other.shininess
56
+ @emission = other.emission
57
+ self
58
+ end
59
+
60
+ touching :touch!, :replace!
61
+
62
+ end
63
+
64
+
65
+ end
66
+
@@ -0,0 +1,103 @@
1
+ require 'glimr/renderer/sceneobject'
2
+ require 'glimr/renderer/transform'
3
+ require 'glimr/renderer/texture'
4
+ require 'glimr/renderer/geometry'
5
+ require 'glimr/renderer/material'
6
+ require 'glimr/renderer/shader'
7
+
8
+
9
+ module GlimR
10
+
11
+ # A Model is a convenience SceneObject that
12
+ # has its own transform, material, texture, shader, and geometry.
13
+ #
14
+ # The state nodes are attached to the Model after super initialization
15
+ # and form a five-node subtree ordered like this (from top to bottom):
16
+ # transform - material - texture - shader - geometry.
17
+ #
18
+ # Model delegates many accessors to the corresponding state nodes
19
+ #
20
+ # Example:
21
+ # m = Model.new
22
+ # m.texture.load('foo.jpg')
23
+ # m.position = [10, 20, 30]
24
+ # m.texcoords = make texcoords
25
+ # m.vertices = make vertices
26
+ #
27
+ class Model < SceneObject
28
+
29
+ attr_reader :texture, :geometry, :transform, :material, :shader
30
+
31
+ delegate_accessor :geometry, :type, :vertices, :texcoords, :colors, :normals
32
+ delegate_accessor :transform, :position, :rotation, :scale, :matrix, :x, :y, :z, :angle
33
+ delegate_accessor :material, :ambient, :diffuse, :specular, :shininess, :emission
34
+
35
+ def initialize(*a,&b)
36
+ @transform = Transform.new
37
+ @material = Material.new
38
+ @texture = Texture.new
39
+ @shader = Shader.new
40
+ @geometry = Geometry.new
41
+ super
42
+ attach @material
43
+ @material.attach @texture
44
+ @texture.attach @shader
45
+ @shader.attach @geometry
46
+ end
47
+
48
+ def push_state
49
+ @transform.push_state
50
+ super
51
+ end
52
+
53
+ def pop_state
54
+ @transform.pop_state
55
+ super
56
+ end
57
+
58
+ def apply
59
+ @transform.apply
60
+ super
61
+ end
62
+
63
+ def absolute_transform
64
+ @transform.instance_variable_set :@parent , @parent
65
+ @transform.absolute_transform
66
+ end
67
+
68
+ # Replaces transform with t using Transform#replace!
69
+ # If t is a matrix, creates a Transform with t as the collapsed matrix.
70
+ def transform= t
71
+ unless t.is_a? Transform
72
+ t = Transform.new(:collapsed_matrix => t, :position => nil, :rotation => nil, :scale => nil, :matrix => nil)
73
+ end
74
+ @transform.replace! t
75
+ end
76
+
77
+ # Replaces texture with t. Uses Texture#replace!
78
+ def texture= t
79
+ @texture.replace! t
80
+ end
81
+
82
+ # Replaces geometry with g using Geometry#replace!
83
+ def geometry= g
84
+ @geometry.replace! g
85
+ end
86
+
87
+ # Replaces material with m using Material#replace!
88
+ def material= m
89
+ @material.replace! m
90
+ end
91
+
92
+ # Replaces shader with s using Shader#replace!
93
+ def shader= s
94
+ @shader.replace! s
95
+ end
96
+
97
+ def inspect
98
+ super[0..-2] + "::#{ [@transform, @material, @texture, @shader, @geometry].map{|i|i.inspect[9..-2]}.join("::") }>"
99
+ end
100
+
101
+ end
102
+
103
+ end
@@ -0,0 +1,21 @@
1
+ require 'glimr/renderer/sceneobject'
2
+
3
+
4
+ module GlimR
5
+
6
+ class OrthoProjection < SceneObject
7
+
8
+ attr_accessor :width, :height, :x, :y, :near, :far
9
+
10
+ def apply(x=x, y=y, width=width, height=height)
11
+ MatrixMode(PROJECTION)
12
+ LoadIdentity()
13
+ Ortho(x,width, y,height, near,far)
14
+ MatrixMode(MODELVIEW)
15
+ LoadIdentity()
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+
@@ -0,0 +1,34 @@
1
+ require 'glimr/renderer/sceneobject'
2
+
3
+
4
+ module GlimR
5
+
6
+
7
+ # Raw is a SceneObject that calls its #renderer
8
+ # when applied.
9
+ #
10
+ # Use for doing custom OpenGL calls and such.
11
+ #
12
+ # Raw doesn't work with the Viewport's collapsing #render,
13
+ # so is pretty much useless at the moment.
14
+ #
15
+ # Example:
16
+ #
17
+ # r = Raw.new
18
+ # r.renderer = lambda do
19
+ # puts 'Hi, I was just applied!'
20
+ # end
21
+ #
22
+ class Raw < SceneObject
23
+
24
+ attr_accessor :renderer
25
+
26
+ # Calls #renderer if renderer is set.
27
+ def apply
28
+ renderer.call if renderer
29
+ end
30
+
31
+ end
32
+
33
+
34
+ end
@@ -0,0 +1,279 @@
1
+ require 'glimr/eventlistener'
2
+ require 'glimr/util'
3
+ require 'opengl'
4
+ require 'set'
5
+
6
+
7
+ module GlimR
8
+
9
+
10
+ # The SceneObject is the root class of the GlimR scene graph class hierarchy.
11
+ #
12
+ # A SceneObject may have a parent and children, and usually will.
13
+ # All actual OpenGL state manipulation should be done with its
14
+ # specific subclasses like Transform, Geometry and Texture.
15
+ #
16
+ # The SceneObject is an EventListener, and as such you can tell
17
+ # it to listen and respond to events.
18
+ #
19
+ # SceneObjects also maintain a list of drawable objects underneath them.
20
+ # This is mainly used to speed up rendering by removing the need to traverse
21
+ # the whole scene graph to draw the scene.
22
+ #
23
+ # Example:
24
+ # s = SceneObject.new
25
+ # t = Texture.new
26
+ # s.attach t
27
+ # s.detach t
28
+ #
29
+ class SceneObject
30
+ include GL
31
+ include EventListener
32
+ include Configurable
33
+
34
+ attr_accessor :parent, :children, :viewport, :drawables
35
+ attr_reader :mtime
36
+ touching_accessor :visible
37
+
38
+ def default_config
39
+ super.merge(
40
+ :visible => true,
41
+ :mtime => Time.now.to_f
42
+ )
43
+ end
44
+
45
+ # Configurable initialize.
46
+ def initialize(*arg_hash, &config_block)
47
+ @children = []
48
+ @drawables = Set.new
49
+ super
50
+ end
51
+
52
+ # Returns the viewport or possible parent's viewport.
53
+ def viewport
54
+ @viewport ||= (parent and parent.viewport)
55
+ end
56
+
57
+ # Returns the scene root.
58
+ # This is either the viewport,
59
+ # the parent's scene root if there is no viewport,
60
+ # or self if there is no parent.
61
+ #
62
+ def root
63
+ (viewport || (parent ? parent.root : self))
64
+ end
65
+
66
+ # Sets viewport to vp.
67
+ # Passes viewport change to children.
68
+ #
69
+ def viewport= vp
70
+ if vp != @viewport
71
+ @viewport = vp
72
+ children.each{|c| c.viewport = vp}
73
+ end
74
+ end
75
+
76
+ # Attaches new_children to the scene graph below self.
77
+ def attach(*new_children)
78
+ new_children.each{|c|
79
+ adopt(c)
80
+ }
81
+ end
82
+
83
+ # Attach single child.
84
+ def <<(new_child)
85
+ attach new_child
86
+ self
87
+ end
88
+
89
+ # Detaches children_to_detach from self.
90
+ def detach(*children_to_detach)
91
+ children_to_detach.each{|c|
92
+ orphan(c)
93
+ }
94
+ end
95
+
96
+ # Detaches self from parent if there is a parent.
97
+ def detach_self
98
+ parent.detach(self) if parent
99
+ end
100
+
101
+ # Sets parent to p.
102
+ #
103
+ # Causes viewport to be set to nil and drawables to
104
+ # be added to parent's drawables.
105
+ def parent= new_parent
106
+ #~ if @parent
107
+ #~ puts object_id, "reparenting #{self} from #{@parent} to #{new_parent.inspect}"
108
+ #~ d = @parent
109
+ #~ end
110
+ @parent.remove_drawables drawables if @parent
111
+ @parent = new_parent
112
+ self.viewport = nil
113
+ @parent.add_drawables drawables if @parent
114
+ #~ p [:after, d.drawables] if d
115
+ #~ puts '','' if d
116
+ end
117
+
118
+ # A node is visible if its @visible is true and its parent is visible (if it has a parent.)
119
+ def visible
120
+ @visible and (parent ? parent.visible : true)
121
+ end
122
+
123
+ # Adds d to drawables and parent's drawables.
124
+ def add_drawables(d)
125
+ parent.add_drawables d if parent
126
+ @drawables += d
127
+ end
128
+
129
+ # Removes d from drawables and parent's drawables.
130
+ def remove_drawables(d)
131
+ parent.remove_drawables d if parent
132
+ @drawables -= d
133
+ end
134
+
135
+ # Sets drawables to d and updates parent's drawables.
136
+ def drawables= d
137
+ if (d != @drawables) and parent
138
+ parent.drawables = ((parent.drawables - @drawables) + d)
139
+ end
140
+ @drawables = d
141
+ end
142
+
143
+ # Replaces orig node in scene graph with replacement by
144
+ # Attaching the replacement to orig's parent, and attaching
145
+ # orig's children to replacement.
146
+ #
147
+ # If no replacement is given, removes orig from scenegraph
148
+ # and attaches its children to its parent. If there is no parent or
149
+ # replacement, does nothing.
150
+ #
151
+ def replace_node(orig, replacement=nil)
152
+ return unless orig
153
+ replacement ||= orig.parent
154
+ return unless replacement
155
+ replacement.detach(*orig.children)
156
+ replacement.attach(*orig.children)
157
+ orig.detach(*orig.children)
158
+ orig.parent.attach(replacement) if orig.parent
159
+ orig.detach_self
160
+ end
161
+
162
+ # Renders the SceneObject by pushing state, applying, calling render
163
+ # for each child, and popping state.
164
+ #
165
+ # Not used with collapsing Viewport #render.
166
+ def render(*a)
167
+ push_state
168
+ apply
169
+ children.each{|c| c.render if c.visible }
170
+ pop_state
171
+ end
172
+
173
+ # The collapsed state of a SceneObject is its parent's collapsed state,
174
+ # which fits in with SceneObjects not editing OpenGL state.
175
+ def absolute_transform
176
+ parent.absolute_transform
177
+ end
178
+
179
+ def absolute_transform_for_drawing
180
+ absolute_transform
181
+ end
182
+
183
+ def absolute_material
184
+ #~ unless parent
185
+ #~ puts object_id, geometry.object_id, self, geometry
186
+ #~ ObjectSpace.each_object(Button){|b|
187
+ #~ if b.drawables.include? geometry
188
+ #~ puts b
189
+ #~ p b.drawables.to_a, b.children
190
+ #~ puts
191
+ #~ puts
192
+ #~ cc = b.children.find{|c|
193
+ #~ c.geometry == geometry if c.is_a? Model
194
+ #~ }
195
+ #~ p cc
196
+ #~ end
197
+ #~ }
198
+ #~ end
199
+ parent.absolute_material
200
+ end
201
+
202
+ def absolute_texture
203
+ parent.absolute_texture
204
+ end
205
+
206
+ def absolute_geometry
207
+ parent.absolute_geometry
208
+ end
209
+
210
+ def absolute_shader
211
+ parent.absolute_shader
212
+ end
213
+
214
+ # Applies the SceneObject to OpenGL state.
215
+ # For SceneObject, this is empty.
216
+ def apply
217
+ end
218
+
219
+ # Pushes the relevant OpenGL state stack.
220
+ # Empty for SceneObject.
221
+ def push_state
222
+ end
223
+
224
+ # Pops the relevant OpenGL state stack.
225
+ # Empty for SceneObject.
226
+ def pop_state
227
+ end
228
+
229
+ # Creates a clone of the SceneObject.
230
+ # If deep is set to true, also clones the children.
231
+ # If deep is false, clears children.
232
+ #
233
+ def clone(deep=false)
234
+ c = super()
235
+ if deep
236
+ c.children = []
237
+ c.drawables.clear
238
+ cchildren = c.children.map{|ch| ch.clone(deep) }
239
+ c.attach *cchildren
240
+ else
241
+ c.children = []
242
+ c.drawables.clear
243
+ end
244
+ c.parent = nil
245
+ c
246
+ end
247
+
248
+ def inspect
249
+ "#<#{self.class.name}:#{object_id}>"
250
+ end
251
+
252
+ def touch!(mtime=Time.now.to_f)
253
+ @mtime = mtime
254
+ parent.touch!(@mtime) if parent
255
+ nil
256
+ end
257
+
258
+ private
259
+
260
+ def adopt(c)
261
+ children.push c
262
+ c.parent = self
263
+ c.listener_count.each{|k,v| increment_listener_count k, v }
264
+ touch!
265
+ end
266
+
267
+ def orphan(c)
268
+ if children.include? c
269
+ children.delete c
270
+ c.parent = nil
271
+ c.listener_count.each{|k,v| decrement_listener_count k, v }
272
+ touch!
273
+ end
274
+ end
275
+
276
+ end
277
+
278
+
279
+ end