glimr 0.1.0 → 0.1.1

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.
@@ -1,349 +1,352 @@
1
- require 'glimr/renderer/sceneobject'
2
- require 'glimr/renderer/material'
3
- require 'glimr/renderer/texture'
4
- require 'glimr/renderer/camera'
5
- require 'glimr/renderer/transform'
6
-
7
-
8
- module GlimR
9
-
10
- # Viewport is a scene graph root node and takes care of
11
- # drawing its subtree and mapping mouse events to
12
- # its child nodes.
13
- #
14
- class Viewport < SceneObject
15
-
16
- attr_accessor :width, :height, :x, :y, :camera
17
- touching_accessor :clear_depth_buffer, :background
18
-
19
- def default_config
20
- super.merge(
21
- :click_time => 0.3,
22
- :click_radius => 4,
23
- :background => nil,
24
- :clear_depth_buffer => false,
25
- :camera => Camera.new,
26
- :x => 0, :y => 0, :width => 1, :height => 1
27
- )
28
- end
29
-
30
- def initialize(*a,&b)
31
- @down_x = 0
32
- @down_y = 0
33
- @old_collisions = []
34
- @mouse_down_collisions = []
35
- @drag_targets = {}
36
- super
37
- add_event_listener(:mouse_move, :mouse_move_handler, true)
38
- add_event_listener(:click, :click_handler, true)
39
- add_event_listener(:mouse_down, :mouse_down_handler, true)
40
- add_event_listener(:mouse_up, :mouse_up_handler, true)
41
- add_event_listener(:resize, :resize_handler, true)
42
- end
43
-
44
- # Acts as root node for dispatched events
45
- def event_root
46
- true
47
- end
48
-
49
- def min_x
50
- @x
51
- end
52
-
53
- def max_x
54
- viewport_width
55
- end
56
-
57
- def min_y
58
- @y
59
- end
60
-
61
- def max_y
62
- viewport_height
63
- end
64
-
65
- def viewport_x
66
- if parent
67
- abs_x = @x + parent.absolute_transform.flatten[12]
68
- else
69
- @x
70
- end
71
- end
72
-
73
- def viewport_y
74
- if parent
75
- abs_y = @y + parent.absolute_transform.flatten[13]
76
- parent.viewport.height - abs_y - @height
77
- else
78
- -@y
79
- end
80
- end
81
-
82
- def viewport_width
83
- if parent
84
- @width * parent.absolute_transform.flatten[0]
85
- else
86
- @width
87
- end
88
- end
89
-
90
- def viewport_height
91
- if parent
92
- @height * parent.absolute_transform.flatten[5]
93
- else
94
- @height
95
- end
96
- end
97
-
98
- def resize_handler(o,e)
99
- if !parent
100
- self.width = e.width
101
- self.height = e.height
102
- end
103
- end
104
-
105
- # Tracks mouse pointer position and sends hover, mouse_out, and mouse_over
106
- # -events to nodes interacting with the mouse pointer.
107
- #
108
- def mouse_move_handler(o,e)
109
- params = e.params.clone
110
- params[:x] += x
111
- params[:y] += y
112
- if Vector[@down_x - params[:x], @down_y - params[:y]].r > @click_radius
113
- @click_valid = false
114
- end
115
- duc = drawables_under_cursor(e)
116
- collisions = duc.map{|rx,ry,c| c }
117
- (@old_collisions - collisions).each{|oc|
118
- evt = Event.new(:mouse_out,
119
- params.merge(:sender => self, :target => oc))
120
- oc.dispatch_event(evt)
121
- }
122
- (collisions - @old_collisions).each{|oc|
123
- evt = Event.new(:mouse_over,
124
- params.merge(:sender => self, :target => oc))
125
- oc.dispatch_event(evt)
126
- }
127
- @old_collisions = collisions
128
- children.each{|c|
129
- c.multicast_event(Event.new(:mouse_move, params))
130
- }
131
- @drag_targets.each{|k,t|
132
- t.dispatch_event(Event.new(:drag, params.merge(:button => k)))
133
- }
134
- e.phase = :bubble
135
- end
136
-
137
- def mouse_down_handler(o,e)
138
- params = e.params.clone
139
- params[:x] += x
140
- params[:y] += y
141
- @down_x = params[:x]
142
- @down_y = params[:y]
143
- @click_valid = true
144
- @down_time = Time.now.to_f
145
- collisions = drawables_under_cursor(e)
146
- @mouse_down_collisions = collisions.map{|rx,ry,c| c }
147
- collisions.each{|rx, ry, c|
148
- evt = Event.new(:mouse_down,
149
- e.params.merge(:sender => self, :target => c, :rx => rx, :ry => ry))
150
- c.dispatch_event(evt)
151
- }
152
- if collisions.first
153
- @drag_targets[e.button] = collisions.first[2]
154
- else
155
- @drag_targets.delete(e.button)
156
- end
157
- e.phase = :bubble
158
- end
159
-
160
- def mouse_up_handler(o,e)
161
- params = e.params.clone
162
- params[:x] += x
163
- params[:y] += y
164
- if Vector[@down_x - params[:x], @down_y - params[:y]].r > @click_radius or (Time.now.to_f - @down_time) > @click_time
165
- @click_valid = false
166
- end
167
- children.each{|c|
168
- c.multicast_event(Event.new(:mouse_up, params))
169
- }
170
- if @click_valid or @drag_targets[e.button]
171
- collisions = drawables_under_cursor(e)
172
- if @click_valid
173
- collisions.each{|rx,ry,c|
174
- if @mouse_down_collisions.include? c
175
- evt = Event.new(:click, params.merge(:sender => self, :rx => rx, :ry => ry))
176
- c.dispatch_event(evt)
177
- end
178
- break
179
- }
180
- end
181
- if @drag_targets[e.button]
182
- if collisions.first
183
- @drag_targets[e.button].dispatch_event(
184
- Event.new(
185
- :drop,
186
- params.merge(:drop_target => collisions.first[2], :rx => collisions.first[0], :ry => collisions.first[1])
187
- )
188
- )
189
- end
190
- @drag_targets.delete(e.button)
191
- end
192
- end
193
- @mouse_down_collisions.clear
194
- e.phase = :bubble
195
- end
196
-
197
- def click_handler(o,e)
198
- e.phase = :bubble
199
- end
200
-
201
- def drawables_under_cursor(e)
202
- collapsed = (@drawables - [self])
203
- collisions = collapsed.map{|d|
204
- collides?( d, e.x, e.y ) if d.visible
205
- }.compact
206
- collisions.sort_by{|c| -c[2].absolute_transform.flatten[14] } # reverse z-sort
207
- end
208
-
209
- # Tests if the coordinates ex and ey fall within the rectangle of drawable d.
210
- def collides?( d, ex, ey )
211
- MatrixMode MODELVIEW
212
- PushMatrix()
213
- LoadIdentity()
214
- MultMatrix(d.absolute_transform_for_drawing)
215
- Translate(-ex,-ey,0)
216
- camatrix = GetDoublev(MODELVIEW_MATRIX)
217
- PopMatrix()
218
- if (camatrix[3][0]+d.min_x+d.max_x >= d.min_x and camatrix[3][0]+d.min_x+d.max_x <= d.max_x and
219
- camatrix[3][1]+d.min_y+d.max_y >= d.min_y and camatrix[3][1]+d.min_y+d.max_y <= d.max_y)
220
- [-camatrix[3][0], -camatrix[3][1], d] # return relative x & y -coordinates and the drawable
221
- else
222
- nil
223
- end
224
- end
225
-
226
- # Draws the viewport drawables using painter's algorithm.
227
- def render
228
- apply
229
- end
230
-
231
- # The absolute state of a viewport is empty starter state.
232
- # This to provide the SceneObject absolute state methods
233
- # a starting point.
234
- #
235
- def absolute_transform
236
- camera.absolute_transform
237
- end
238
-
239
- # Behave like a square when going through drawing list.
240
- def absolute_transform_for_drawing
241
- parent.absolute_transform
242
- end
243
-
244
- def absolute_material
245
- Material.new
246
- end
247
-
248
- def absolute_texture
249
- Texture.new
250
- end
251
-
252
- def absolute_geometry
253
- Geometry.new
254
- end
255
-
256
- def absolute_shader
257
- Shader.new
258
- end
259
-
260
- def changed?
261
- @last_frame_time != @mtime
262
- end
263
-
264
- # Applies viewport to OpenGL state, scissor to viewport,
265
- # enable blending and apply camera.
266
- def apply
267
- @last_frame_time = @mtime
268
- apply_clip
269
- clear_viewport
270
- apply_camera
271
- apply_blend
272
- draw_drawables
273
- end
274
-
275
- def apply_clip
276
- Viewport(viewport_x, viewport_y, viewport_width, viewport_height)
277
- Enable SCISSOR_TEST
278
- Scissor(viewport_x, viewport_y, viewport_width, viewport_height)
279
- end
280
-
281
- def clear_viewport
282
- if background
283
- GL.ClearColor(*background)
284
- GL.Clear(GL::COLOR_BUFFER_BIT)
285
- GL.Clear(GL::DEPTH_BUFFER_BIT) if clear_depth_buffer
286
- end
287
- end
288
-
289
- def apply_blend
290
- Enable GL::BLEND
291
- BlendFunc(GL::SRC_ALPHA, GL::ONE_MINUS_SRC_ALPHA)
292
- end
293
-
294
- def apply_camera
295
- if camera
296
- camera.viewport = self
297
- camera.apply
298
- end
299
- end
300
-
301
- # Draws the viewport drawables using painter's algorithm.
302
- def draw_drawables
303
- collapsed = (@drawables).find_all{|d| d.visible }
304
- collapsed = collapsed.sort_by{|d|
305
- d.absolute_transform.flatten[14]
306
- }
307
- collapsed.each{|d|
308
- PushAttrib( TEXTURE_BIT | LIGHTING_BIT )
309
- LoadMatrix(d.absolute_transform_for_drawing)
310
- d.absolute_texture.apply
311
- d.absolute_material.apply
312
- d.push_state
313
- d.apply
314
- d.pop_state
315
- PopAttrib()
316
- if d.is_a? Viewport
317
- apply_clip
318
- apply_camera
319
- end
320
- }
321
- end
322
-
323
- # The viewport of a Viewport is the Viewport itself.
324
- def viewport
325
- self
326
- end
327
-
328
- # Viewport presents only itself to its parent.
329
- def drawables
330
- Set.new + [self]
331
- end
332
-
333
- # Width per height aspect of the viewport.
334
- def aspect
335
- width.to_f / height
336
- end
337
-
338
- private
339
-
340
- def adopt(c)
341
- super
342
- c.viewport = self
343
- end
344
-
345
- end
346
-
347
- end
348
-
349
-
1
+ require 'glimr/renderer/sceneobject'
2
+ require 'glimr/renderer/material'
3
+ require 'glimr/renderer/texture'
4
+ require 'glimr/renderer/camera'
5
+ require 'glimr/renderer/transform'
6
+
7
+
8
+ module GlimR
9
+
10
+ # Viewport is a scene graph root node and takes care of
11
+ # drawing its subtree and mapping mouse events to
12
+ # its child nodes.
13
+ #
14
+ class Viewport < SceneObject
15
+
16
+ attr_accessor :width, :height, :x, :y, :camera
17
+ touching_accessor :clear_depth_buffer, :background
18
+
19
+ def default_config
20
+ super.merge(
21
+ :click_time => 0.3,
22
+ :click_radius => 4,
23
+ :background => nil,
24
+ :clear_depth_buffer => false,
25
+ :camera => Camera.new,
26
+ :x => 0, :y => 0, :width => 1, :height => 1
27
+ )
28
+ end
29
+
30
+ def initialize(*a,&b)
31
+ @down_x = 0
32
+ @down_y = 0
33
+ @old_collisions = []
34
+ @mouse_down_collisions = []
35
+ @drag_targets = {}
36
+ super
37
+ add_event_listener(:mouse_move, :mouse_move_handler, true)
38
+ add_event_listener(:click, :click_handler, true)
39
+ add_event_listener(:mouse_down, :mouse_down_handler, true)
40
+ add_event_listener(:mouse_up, :mouse_up_handler, true)
41
+ add_event_listener(:window_resize, :resize_handler, true)
42
+ end
43
+
44
+ # Acts as root node for dispatched events
45
+ def event_root
46
+ true
47
+ end
48
+
49
+ def min_x
50
+ @x
51
+ end
52
+
53
+ def max_x
54
+ viewport_width
55
+ end
56
+
57
+ def min_y
58
+ @y
59
+ end
60
+
61
+ def max_y
62
+ viewport_height
63
+ end
64
+
65
+ def viewport_x
66
+ if parent
67
+ abs_x = @x + parent.absolute_transform.flatten[12]
68
+ else
69
+ @x
70
+ end
71
+ end
72
+
73
+ def viewport_y
74
+ if parent
75
+ abs_y = @y + parent.absolute_transform.flatten[13]
76
+ parent.viewport.height - abs_y - @height
77
+ else
78
+ -@y
79
+ end
80
+ end
81
+
82
+ def viewport_width
83
+ if parent
84
+ @width * parent.absolute_transform.flatten[0]
85
+ else
86
+ @width
87
+ end
88
+ end
89
+
90
+ def viewport_height
91
+ if parent
92
+ @height * parent.absolute_transform.flatten[5]
93
+ else
94
+ @height
95
+ end
96
+ end
97
+
98
+ def resize_handler(o,e)
99
+ if !parent
100
+ self.width = e.width
101
+ self.height = e.height
102
+ multicast_event(Event.new(:resize, e.params))
103
+ end
104
+ end
105
+
106
+ # Tracks mouse pointer position and sends hover, mouse_out, and mouse_over
107
+ # -events to nodes interacting with the mouse pointer.
108
+ #
109
+ def mouse_move_handler(o,e)
110
+ params = e.params.clone
111
+ params[:x] += x
112
+ params[:y] += y
113
+ if Vector[@down_x - params[:x], @down_y - params[:y]].r > @click_radius
114
+ @click_valid = false
115
+ end
116
+ duc = drawables_under_cursor(e)
117
+ collisions = duc.map{|rx,ry,c| c }
118
+ (collisions - @old_collisions).each{|oc|
119
+ evt = Event.new(:mouse_over,
120
+ params.merge(:sender => self, :target => oc))
121
+ oc.dispatch_event(evt)
122
+ }
123
+ (@old_collisions - collisions).each{|oc|
124
+ evt = Event.new(:mouse_out,
125
+ params.merge(:sender => self, :target => oc))
126
+ oc.dispatch_event(evt)
127
+ }
128
+ @old_collisions = collisions
129
+ children.each{|c|
130
+ c.multicast_event(Event.new(:mouse_move, params))
131
+ }
132
+ @drag_targets.each{|k,t|
133
+ t.dispatch_event(Event.new(:drag, params.merge(:button => k)))
134
+ }
135
+ e.phase = :bubble
136
+ end
137
+
138
+ def mouse_down_handler(o,e)
139
+ mouse_move_handler o, e if !parent
140
+ params = e.params.clone
141
+ params[:x] += x
142
+ params[:y] += y
143
+ @down_x = params[:x]
144
+ @down_y = params[:y]
145
+ @click_valid = true
146
+ @down_time = Time.now.to_f
147
+ collisions = drawables_under_cursor(e)
148
+ @mouse_down_collisions = collisions.map{|rx,ry,c| c }
149
+ collisions.each{|rx, ry, c|
150
+ evt = Event.new(:mouse_down,
151
+ e.params.merge(:sender => self, :target => c, :rx => rx, :ry => ry))
152
+ c.dispatch_event(evt)
153
+ }
154
+ if collisions.first
155
+ @drag_targets[e.button] = collisions.first[2]
156
+ else
157
+ @drag_targets.delete(e.button)
158
+ end
159
+ e.phase = :bubble
160
+ end
161
+
162
+ def mouse_up_handler(o,e)
163
+ mouse_move_handler o, e if !parent
164
+ params = e.params.clone
165
+ params[:x] += x
166
+ params[:y] += y
167
+ if Vector[@down_x - params[:x], @down_y - params[:y]].r > @click_radius or (Time.now.to_f - @down_time) > @click_time
168
+ @click_valid = false
169
+ end
170
+ children.each{|c|
171
+ c.multicast_event(Event.new(:mouse_up, params))
172
+ }
173
+ if @click_valid or @drag_targets[e.button]
174
+ collisions = drawables_under_cursor(e)
175
+ if @click_valid
176
+ collisions.each{|rx,ry,c|
177
+ if @mouse_down_collisions.include? c
178
+ evt = Event.new(:click, params.merge(:sender => self, :rx => rx, :ry => ry))
179
+ c.dispatch_event(evt)
180
+ end
181
+ break
182
+ }
183
+ end
184
+ if @drag_targets[e.button]
185
+ if collisions.first
186
+ @drag_targets[e.button].dispatch_event(
187
+ Event.new(
188
+ :drop,
189
+ params.merge(:drop_target => collisions.first[2], :rx => collisions.first[0], :ry => collisions.first[1])
190
+ )
191
+ )
192
+ end
193
+ @drag_targets.delete(e.button)
194
+ end
195
+ end
196
+ @mouse_down_collisions.clear
197
+ e.phase = :bubble
198
+ end
199
+
200
+ def click_handler(o,e)
201
+ e.phase = :bubble
202
+ end
203
+
204
+ def drawables_under_cursor(e)
205
+ collapsed = (@drawables - [self])
206
+ collisions = collapsed.map{|d|
207
+ collides?( d, e.x, e.y ) if d.visible
208
+ }.compact
209
+ collisions.sort_by{|c| -c[2].absolute_transform.flatten[14] } # reverse z-sort
210
+ end
211
+
212
+ # Tests if the coordinates ex and ey fall within the rectangle of drawable d.
213
+ def collides?( d, ex, ey )
214
+ MatrixMode MODELVIEW
215
+ PushMatrix()
216
+ LoadIdentity()
217
+ MultMatrix(d.absolute_transform_for_drawing)
218
+ Translate(-ex,-ey,0)
219
+ camatrix = GetDoublev(MODELVIEW_MATRIX)
220
+ PopMatrix()
221
+ if (camatrix[3][0]+d.min_x+d.max_x >= d.min_x and camatrix[3][0]+d.min_x+d.max_x <= d.max_x and
222
+ camatrix[3][1]+d.min_y+d.max_y >= d.min_y and camatrix[3][1]+d.min_y+d.max_y <= d.max_y)
223
+ [-camatrix[3][0], -camatrix[3][1], d] # return relative x & y -coordinates and the drawable
224
+ else
225
+ nil
226
+ end
227
+ end
228
+
229
+ # Draws the viewport drawables using painter's algorithm.
230
+ def render
231
+ apply
232
+ end
233
+
234
+ # The absolute state of a viewport is empty starter state.
235
+ # This to provide the SceneObject absolute state methods
236
+ # a starting point.
237
+ #
238
+ def absolute_transform
239
+ camera.absolute_transform
240
+ end
241
+
242
+ # Behave like a square when going through drawing list.
243
+ def absolute_transform_for_drawing
244
+ parent.absolute_transform
245
+ end
246
+
247
+ def absolute_material
248
+ Material.new
249
+ end
250
+
251
+ def absolute_texture
252
+ Texture.new
253
+ end
254
+
255
+ def absolute_geometry
256
+ Geometry.new
257
+ end
258
+
259
+ def absolute_shader
260
+ Shader.new
261
+ end
262
+
263
+ def changed?
264
+ @last_frame_time != @mtime
265
+ end
266
+
267
+ # Applies viewport to OpenGL state, scissor to viewport,
268
+ # enable blending and apply camera.
269
+ def apply
270
+ @last_frame_time = @mtime
271
+ apply_clip
272
+ clear_viewport
273
+ apply_camera
274
+ apply_blend
275
+ draw_drawables
276
+ end
277
+
278
+ def apply_clip
279
+ Viewport(viewport_x, viewport_y, viewport_width, viewport_height)
280
+ Enable SCISSOR_TEST
281
+ Scissor(viewport_x, viewport_y, viewport_width, viewport_height)
282
+ end
283
+
284
+ def clear_viewport
285
+ if background
286
+ GL.ClearColor(*background)
287
+ GL.Clear(GL::COLOR_BUFFER_BIT)
288
+ GL.Clear(GL::DEPTH_BUFFER_BIT) if clear_depth_buffer
289
+ end
290
+ end
291
+
292
+ def apply_blend
293
+ Enable GL::BLEND
294
+ BlendFunc(GL::SRC_ALPHA, GL::ONE_MINUS_SRC_ALPHA)
295
+ end
296
+
297
+ def apply_camera
298
+ if camera
299
+ camera.viewport = self
300
+ camera.apply
301
+ end
302
+ end
303
+
304
+ # Draws the viewport drawables using painter's algorithm.
305
+ def draw_drawables
306
+ collapsed = (@drawables).find_all{|d| d.visible }
307
+ collapsed = collapsed.sort_by{|d|
308
+ d.absolute_transform.flatten[14]
309
+ }
310
+ collapsed.each{|d|
311
+ PushAttrib( TEXTURE_BIT | LIGHTING_BIT )
312
+ LoadMatrix(d.absolute_transform_for_drawing)
313
+ d.absolute_texture.apply
314
+ d.absolute_material.apply
315
+ d.push_state
316
+ d.apply
317
+ d.pop_state
318
+ PopAttrib()
319
+ if d.is_a? Viewport
320
+ apply_clip
321
+ apply_camera
322
+ end
323
+ }
324
+ end
325
+
326
+ # The viewport of a Viewport is the Viewport itself.
327
+ def viewport
328
+ self
329
+ end
330
+
331
+ # Viewport presents only itself to its parent.
332
+ def drawables
333
+ Set.new + [self]
334
+ end
335
+
336
+ # Width per height aspect of the viewport.
337
+ def aspect
338
+ width.to_f / height
339
+ end
340
+
341
+ private
342
+
343
+ def adopt(c)
344
+ super
345
+ c.viewport = self
346
+ end
347
+
348
+ end
349
+
350
+ end
351
+
352
+