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.
- data/COPYING +504 -0
- data/README +222 -0
- data/glimr-0.1.1.gemspec +21 -0
- data/lib/glimr/renderer/glutwindow.rb +387 -387
- data/lib/glimr/renderer/viewport.rb +352 -349
- data/lib/glimr/widget.rb +1 -0
- data/lib/glimr/widgets/label.rb +120 -91
- data/lib/glimr/widgets/list.rb +67 -9
- data/lib/glimr/widgets/scrollbar.rb +4 -4
- data/setup.rb +1360 -0
- data/tests/integration_tests/test_list.rb +11 -0
- metadata +61 -55
- data/tests/assets/download_progress_meter.png +0 -0
- data/tests/assets/metalwing2.png +0 -0
@@ -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(:
|
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
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
#
|
107
|
-
#
|
108
|
-
|
109
|
-
|
110
|
-
params
|
111
|
-
params[:
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
params
|
141
|
-
|
142
|
-
|
143
|
-
@
|
144
|
-
@
|
145
|
-
|
146
|
-
@
|
147
|
-
collisions
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
@drag_targets
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
collisions.
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
#
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
}
|
307
|
-
collapsed.
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
d.
|
313
|
-
|
314
|
-
d.
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
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
|
+
|