Class: GlimR::GLUTWindow
Overview
The GLUTWindow provides a stand-alone OpenGL context for GlimR.
When rendering, a GLUTWindow first sends a frame event to its viewport, then clears the buffer and tells its viewport to draw itself.
The GLUTWindow is also responsible for mapping GLUT events into GlimR events and sending them to the viewport.
Constant Summary collapse
- MOUSE_BUTTONS =
[:left, :middle, :right, :wheel_up, :wheel_down]
Instance Attribute Summary collapse
-
#display_mode ⇒ Object
readonly
Returns the value of attribute display_mode.
-
#frame ⇒ Object
readonly
Returns the value of attribute frame.
-
#frames_drawn ⇒ Object
readonly
Returns the value of attribute frames_drawn.
-
#height ⇒ Object
readonly
Returns the value of attribute height.
-
#title ⇒ Object
readonly
Returns the value of attribute title.
-
#viewport ⇒ Object
Returns the value of attribute viewport.
-
#width ⇒ Object
readonly
Returns the value of attribute width.
-
#window_id ⇒ Object
Returns the value of attribute window_id.
-
#x ⇒ Object
readonly
Returns the value of attribute x.
-
#y ⇒ Object
readonly
Returns the value of attribute y.
Class Method Summary collapse
-
.create_window(window) ⇒ Object
Creates a GLUT window with the title and adds it to windows list.
-
.current_window ⇒ Object
Id of current GLUT window.
-
.destroy_window(w) ⇒ Object
Destroys the GLUT window w and deletes it from the windows list.
-
.next_window ⇒ Object
Sets the active GLUT window to the next window in order.
-
.window_index ⇒ Object
Index of the current window.
-
.windows ⇒ Object
Array of windows created.
Instance Method Summary collapse
-
#button_box(*a) ⇒ Object
GLUT ButtonBoxFunc.
- #changed? ⇒ Boolean
-
#close(*a) ⇒ Object
Asks GLUTWindow class to destroy the window.
- #damaged? ⇒ Boolean
-
#display ⇒ Object
GLUT DisplayFunc.
-
#entry(enter) ⇒ Object
GLUT EntryFunc.
-
#fullscreen(*a) ⇒ Object
Toggles fullscreen mode.
- #heartbeat ⇒ Object
-
#init_glut ⇒ Object
Initialize GLUT state for the window, then ask GLUTWindow class to create the window.
-
#initialize(w = 400, h = 300, title = "GlimR - #{$0}", x = nil, y = nil) ⇒ GLUTWindow
constructor
Creates a window with width w and height h.
-
#keyboard(key, x, y) ⇒ Object
GLUT KeyboardFunc.
-
#keyhandlers ⇒ Object
Default key handlers.
-
#motion(x, y) ⇒ Object
GLUT MotionFunc.
-
#mouse(button, down, x, y) ⇒ Object
GLUT MouseFunc.
- #need_redraw? ⇒ Boolean
-
#passive_motion(x, y) ⇒ Object
GLUT PassiveMotionFunc.
-
#profiler(*a) ⇒ Object
Enters the profiler, lets run for 5 seconds, then exits.
- #queue_event(evt) ⇒ Object
-
#reshape(w, h) ⇒ Object
GLUT ReshapeFunc.
-
#run ⇒ Object
Enters GLUT.MainLoop.
-
#set_callback_funcs ⇒ Object
Set GLUT callback functions to the object’s methods that have the rubyized name of the corresponding callback function.
-
#special(key, x, y) ⇒ Object
Handles special key presses.
-
#take_screenshot(*a) ⇒ Object
Takes screenshot (not implemented.).
-
#update_coords(x, y, update_modifier_keys = true) ⇒ Object
Updates current mouse coordinates.
-
#update_modifiers ⇒ Object
Gets modifier key states and assigns them to @modifiers-Hash and returns the Hash.
-
#visibility(visible) ⇒ Object
GLUT VisibilityFunc.
-
#window_status(*a) ⇒ Object
GLUT WindowStatusFunc.
Constructor Details
#initialize(w = 400, h = 300, title = "GlimR - #{$0}", x = nil, y = nil) ⇒ GLUTWindow
Creates a window with width w and height h.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/glimr/renderer/glutwindow.rb', line 78 def initialize(w=400,h=300,title="GlimR - #{$0}",x=nil,y=nil) = Viewport.new .background = [1,1,1,1] .clear_depth_buffer = true @visible = true @display_mode = GLUT::DOUBLE | GLUT::RGB | GLUT::DEPTH @x = x @y = y .x = 0 .y = 0 @frame_event = Event.new(:frame) @reshape_event = Event.new(:resize) @frame_time = @last_frame_time = Time.now.to_f @frame = @frames_drawn = 0 @title = title @event_queue = {} = {} @mouse_properties = {} @modifiers = {} reshape(w,h) init_glut end |
Instance Attribute Details
#display_mode ⇒ Object (readonly)
Returns the value of attribute display_mode.
73 74 75 |
# File 'lib/glimr/renderer/glutwindow.rb', line 73 def display_mode @display_mode end |
#frame ⇒ Object (readonly)
Returns the value of attribute frame.
73 74 75 |
# File 'lib/glimr/renderer/glutwindow.rb', line 73 def frame @frame end |
#frames_drawn ⇒ Object (readonly)
Returns the value of attribute frames_drawn.
73 74 75 |
# File 'lib/glimr/renderer/glutwindow.rb', line 73 def frames_drawn @frames_drawn end |
#height ⇒ Object (readonly)
Returns the value of attribute height.
73 74 75 |
# File 'lib/glimr/renderer/glutwindow.rb', line 73 def height @height end |
#title ⇒ Object (readonly)
Returns the value of attribute title.
73 74 75 |
# File 'lib/glimr/renderer/glutwindow.rb', line 73 def title @title end |
#viewport ⇒ Object
Returns the value of attribute viewport.
71 72 73 |
# File 'lib/glimr/renderer/glutwindow.rb', line 71 def end |
#width ⇒ Object (readonly)
Returns the value of attribute width.
73 74 75 |
# File 'lib/glimr/renderer/glutwindow.rb', line 73 def width @width end |
#window_id ⇒ Object
Returns the value of attribute window_id.
72 73 74 |
# File 'lib/glimr/renderer/glutwindow.rb', line 72 def window_id @window_id end |
#x ⇒ Object (readonly)
Returns the value of attribute x.
73 74 75 |
# File 'lib/glimr/renderer/glutwindow.rb', line 73 def x @x end |
#y ⇒ Object (readonly)
Returns the value of attribute y.
73 74 75 |
# File 'lib/glimr/renderer/glutwindow.rb', line 73 def y @y end |
Class Method Details
.create_window(window) ⇒ Object
Creates a GLUT window with the title and adds it to windows list.
51 52 53 54 55 56 57 58 |
# File 'lib/glimr/renderer/glutwindow.rb', line 51 def self.create_window(window) GLUT.InitDisplayMode(window.display_mode) GLUT.InitWindowSize(window.width, window.height) GLUT.InitWindowPosition(window.x, window.y) if window.x and window.y window.window_id = GLUT.CreateWindow window.title windows << window window.window_id end |
.current_window ⇒ Object
Id of current GLUT window.
34 35 36 |
# File 'lib/glimr/renderer/glutwindow.rb', line 34 def self.current_window windows[window_index] end |
.destroy_window(w) ⇒ Object
Destroys the GLUT window w and deletes it from the windows list. Exits if the window in question was the last remaining window.
62 63 64 65 66 |
# File 'lib/glimr/renderer/glutwindow.rb', line 62 def self.destroy_window(w) windows.delete w GLUT.DestroyWindow w.window_id exit if windows.empty? end |
.next_window ⇒ Object
Sets the active GLUT window to the next window in order.
39 40 41 42 43 44 45 46 47 48 |
# File 'lib/glimr/renderer/glutwindow.rb', line 39 def self.next_window if @window_index == 0 slp = 0.033 - (Time.now.to_f - @frame_time) sleep(slp) if slp > 0 @frame_time = Time.now.to_f end @window_index = (window_index + 1)%windows.size GLUT.SetWindow(current_window.window_id) current_window.heartbeat end |
.window_index ⇒ Object
Index of the current window.
24 25 26 |
# File 'lib/glimr/renderer/glutwindow.rb', line 24 def self.window_index @window_index ||= 0 end |
.windows ⇒ Object
Array of windows created.
29 30 31 |
# File 'lib/glimr/renderer/glutwindow.rb', line 29 def self.windows @windows ||= [] end |
Instance Method Details
#button_box(*a) ⇒ Object
GLUT ButtonBoxFunc.
305 306 |
# File 'lib/glimr/renderer/glutwindow.rb', line 305 def (*a) end |
#changed? ⇒ Boolean
134 135 136 |
# File 'lib/glimr/renderer/glutwindow.rb', line 134 def changed? .changed? end |
#close(*a) ⇒ Object
Asks GLUTWindow class to destroy the window.
181 182 183 |
# File 'lib/glimr/renderer/glutwindow.rb', line 181 def close(*a) self.class.destroy_window(self) end |
#damaged? ⇒ Boolean
130 131 132 |
# File 'lib/glimr/renderer/glutwindow.rb', line 130 def damaged? GLUT.LayerGet(GLUT::NORMAL_DAMAGED) == GL::TRUE end |
#display ⇒ Object
GLUT DisplayFunc.
Displays the GLUTWindow. Sleeps to maintain a maximum framerate of 33fps, then displays previously rendered frame. Then sends a frame event to the viewport.
If the GLUTWindow is visible, clears the buffer and tells viewport to draw itself. Finally increments the frame counter.
173 174 175 176 177 178 |
# File 'lib/glimr/renderer/glutwindow.rb', line 173 def display GC.disable .render GLUT.SwapBuffers @frames_drawn += 1 end |
#entry(enter) ⇒ Object
GLUT EntryFunc.
268 269 270 271 272 273 274 275 |
# File 'lib/glimr/renderer/glutwindow.rb', line 268 def entry(enter) @mouse_over_window = (enter == 1) if @mouse_over_window @mouse_x, @mouse_y = @prev_mouse_x, @prev_mouse_y else @mouse_x = @mouse_y = nil end end |
#fullscreen(*a) ⇒ Object
Toggles fullscreen mode.
186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/glimr/renderer/glutwindow.rb', line 186 def fullscreen(*a) if not @fullscreen @fullscreen = %w(X Y WIDTH HEIGHT).map{|cn| GLUT.Get(GLUT.const_get("WINDOW_#{cn}")) } GLUT.FullScreen else x,y,w,h = *@fullscreen GLUT.ReshapeWindow(w,h) GLUT.PositionWindow(x,y) @fullscreen = nil end end |
#heartbeat ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/glimr/renderer/glutwindow.rb', line 138 def heartbeat GC.disable @frame_time = Time.now.to_f @frame_event.time = @frame_time @frame_event.bubbles = false @event_queue.values.each{|evt| .dispatch_event(evt) } @event_queue.clear .multicast_event(@frame_event) GLUT.PostRedisplay if need_redraw? GC.enable @frame += 1 end |
#init_glut ⇒ Object
Initialize GLUT state for the window, then ask GLUTWindow class to create the window.
103 104 105 106 |
# File 'lib/glimr/renderer/glutwindow.rb', line 103 def init_glut self.class.create_window(self) set_callback_funcs end |
#keyboard(key, x, y) ⇒ Object
GLUT KeyboardFunc. Fired when key pressed. Multicasts key_down and key_up.
Note: there is no “Hold button down”-functionality in GLUT.
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
# File 'lib/glimr/renderer/glutwindow.rb', line 343 def keyboard(key, x, y) event_properties = update_coords(x,y).merge(:key => key) ev = Event.new(:key_down, event_properties) .multicast_event(ev) ev = Event.new(:key_up, event_properties) .multicast_event(ev) handler = keyhandlers[key] if @modifiers[:ctrl] and not (@modifiers[:shift] or @modifiers[:alt]) if handler and not (ev.stopped or ev.cancelled) if handler.respond_to? :call handler.call(key, x, y) else __send__(handler, key, x, y) end end end |
#keyhandlers ⇒ Object
Default key handlers.
ESC closes window, f toggles fullscreen, p enters profiler, s takes screenshot.
376 377 378 379 380 381 382 383 |
# File 'lib/glimr/renderer/glutwindow.rb', line 376 def keyhandlers @keyhandlers ||= { 17 => :close, 6 => :fullscreen, 16 => :profiler, 20 => :take_screenshot, } end |
#motion(x, y) ⇒ Object
GLUT MotionFunc. Moving mouse with mouse button depressed.
299 300 301 302 |
# File 'lib/glimr/renderer/glutwindow.rb', line 299 def motion(x,y) event_properties = update_coords(x,y,false) queue_event Event.new(:mouse_move, event_properties) end |
#mouse(button, down, x, y) ⇒ Object
GLUT MouseFunc. Fired when mouse button pressed or released.
318 319 320 321 322 323 324 325 326 |
# File 'lib/glimr/renderer/glutwindow.rb', line 318 def mouse(, down, x, y) down = (down == 0) = MOUSE_BUTTONS[] [] = down event_type = (down ? :mouse_down : :mouse_up) event_properties = update_coords(x,y) event_properties[:button] = queue_event Event.new(event_type, event_properties) end |
#need_redraw? ⇒ Boolean
126 127 128 |
# File 'lib/glimr/renderer/glutwindow.rb', line 126 def need_redraw? @visible and (changed? or damaged?) end |
#passive_motion(x, y) ⇒ Object
GLUT PassiveMotionFunc. Moving mouse without buttons depressed
293 294 295 296 |
# File 'lib/glimr/renderer/glutwindow.rb', line 293 def passive_motion(x,y) event_properties = update_coords(x,y,false) queue_event Event.new(:mouse_move, event_properties) end |
#profiler(*a) ⇒ Object
Enters the profiler, lets run for 5 seconds, then exits.
207 208 209 210 211 212 213 214 |
# File 'lib/glimr/renderer/glutwindow.rb', line 207 def profiler(*a) Thread.new{ puts "Entering profiler" require 'profile' sleep 5 exit } end |
#queue_event(evt) ⇒ Object
153 154 155 156 157 158 159 160 161 162 |
# File 'lib/glimr/renderer/glutwindow.rb', line 153 def queue_event evt if evt.type == :mouse_move and @event_queue[:mouse_move] evt.dx += @event_queue[:mouse_move].dx evt.dy += @event_queue[:mouse_move].dy evt.params[:dx] = evt.dx evt.params[:dy] = evt.dy evt.params[:time] = evt.time = Time.now.to_f end @event_queue[evt.type] = evt end |
#reshape(w, h) ⇒ Object
GLUT ReshapeFunc. Sets viewport width and height to w and h, respectively, and sends a resize event to the viewport.
111 112 113 114 115 116 117 118 119 |
# File 'lib/glimr/renderer/glutwindow.rb', line 111 def reshape(w,h) @width = w @height = h @reshape_event.time = Time.now.to_f @reshape_event.bubbles = false @reshape_event.width = w @reshape_event.height = h .multicast_event(@reshape_event) end |
#run ⇒ Object
Enters GLUT.MainLoop.
122 123 124 |
# File 'lib/glimr/renderer/glutwindow.rb', line 122 def run GLUT.MainLoop end |
#set_callback_funcs ⇒ Object
Set GLUT callback functions to the object’s methods that have the rubyized name of the corresponding callback function. That’s not very clear, is it. Maybe this example sheds some light on it.
GLUT::ReshapeFunc is set to "reshape"-method
GLUT::SpaceballMotionFunc is set to "spaceball_motion"-method
GLUT::MouseFunc is set to "mouse"-method
... and so on for every GLUT method that ends with Func.
If there is no corresponding method (e.g. there’s no “idle”-method), the callback won’t be set.
List of callback names (avoid these in non-callback method names):
ButtonBoxFunc =>
DialsFunc => dials
DisplayFunc => display
EntryFunc => entry
IdleFunc => idle
KeyboardFunc => keyboard
MotionFunc => motion
MouseFunc => mouse
OverlayDisplayFunc =>
PassiveMotionFunc => passive_motion
ReshapeFunc => reshape
SpaceballButtonFunc =>
SpaceballMotionFunc => spaceball_motion
SpaceballRotateFunc => spaceball_rotate
SpecialFunc => special
TabletButtonFunc =>
TabletMotionFunc => tablet_motion
TimerFunc => timer
VisibilityFunc => visibility
WindowStatusFunc => window_status
251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/glimr/renderer/glutwindow.rb', line 251 def set_callback_funcs GLUT.methods.grep(/Func$/).sort.each{|callback_setter_name| # Change FooBarFunc into foo_bar callback_method_name = callback_setter_name[0,1].downcase + callback_setter_name[1..-5]. gsub(/[A-Z]/){|cap| "_" + cap.downcase} if respond_to?(callback_method_name.to_sym) callback_method = method(callback_method_name).to_proc GLUT.__send__(callback_setter_name, callback_method) end } @mouse_over_window = true end |
#special(key, x, y) ⇒ Object
Handles special key presses.
Converts the special key to a symbol by stripping KEY_ off the front and downcasing the remains, e.g. :f1, :left, :right.
Delegates the symbol to #keyboard.
366 367 368 369 370 |
# File 'lib/glimr/renderer/glutwindow.rb', line 366 def special(key, x, y) cn = GLUT.constants.grep(/^KEY_/).find{|k| GLUT.const_get(k) == key} key = cn.sub(/^KEY_/, '').downcase.to_sym keyboard(key, x, y) end |
#take_screenshot(*a) ⇒ Object
Takes screenshot (not implemented.)
201 202 203 |
# File 'lib/glimr/renderer/glutwindow.rb', line 201 def take_screenshot(*a) #screenshot end |
#update_coords(x, y, update_modifier_keys = true) ⇒ Object
Updates current mouse coordinates.
278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/glimr/renderer/glutwindow.rb', line 278 def update_coords(x,y,update_modifier_keys=true) props = { :target => @target, :x => x, :y => y, :dx => (@prev_mouse_x ? x-@prev_mouse_x : 0), :dy => (@prev_mouse_y ? y-@prev_mouse_y : 0), :buttons => } @prev_mouse_x, @prev_mouse_y = x, y @mouse_x, @mouse_y = x, y if @mouse_over_window update_modifiers if update_modifier_keys @mouse_properties = @mouse_properties.merge(props).merge(@modifiers) end |
#update_modifiers ⇒ Object
Gets modifier key states and assigns them to @modifiers-Hash and returns the Hash.
330 331 332 333 334 335 336 |
# File 'lib/glimr/renderer/glutwindow.rb', line 330 def update_modifiers modifier_bitfield = GLUT.GetModifiers GLUT.constants.grep(/^ACTIVE_/).each{|cn| @modifiers[cn[7..-1].downcase.to_sym] = (modifier_bitfield & GLUT.const_get(cn) > 0) } @modifiers end |
#visibility(visible) ⇒ Object
GLUT VisibilityFunc. Toggles window visibility variable based on the argument.
309 310 311 |
# File 'lib/glimr/renderer/glutwindow.rb', line 309 def visibility(visible) @visible = (visible == GLUT::VISIBLE) end |
#window_status(*a) ⇒ Object
GLUT WindowStatusFunc.
314 315 |
# File 'lib/glimr/renderer/glutwindow.rb', line 314 def window_status(*a) end |