glimr 0.1.0 → 0.1.1

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