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.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/glimr/renderer/glutwindow.rb', line 80 def initialize(w=400,h=300,title="GlimR - #{$0}",x=nil,y=nil) @viewport = Viewport.new @viewport.background = [1,1,1,1] @viewport.clear_depth_buffer = true @visible = true @display_mode = GLUT::DOUBLE | GLUT::RGB | GLUT::DEPTH @x = x @y = y @viewport.x = 0 @viewport.y = 0 @frame_event = Event.new(:frame) @reshape_event = Event.new(:window_resize) @frame_time = @last_frame_time = Time.now.to_f @frame = @frames_drawn = 0 @title = title @event_queue = {} @mouse_buttons_down = {} @mouse_properties = {} @modifiers = {} reshape(w,h) init_glut end |
Instance Attribute Details
#display_mode ⇒ Object (readonly)
Returns the value of attribute display_mode.
75 76 77 |
# File 'lib/glimr/renderer/glutwindow.rb', line 75 def display_mode @display_mode end |
#frame ⇒ Object (readonly)
Returns the value of attribute frame.
75 76 77 |
# File 'lib/glimr/renderer/glutwindow.rb', line 75 def frame @frame end |
#frames_drawn ⇒ Object (readonly)
Returns the value of attribute frames_drawn.
75 76 77 |
# File 'lib/glimr/renderer/glutwindow.rb', line 75 def frames_drawn @frames_drawn end |
#height ⇒ Object (readonly)
Returns the value of attribute height.
75 76 77 |
# File 'lib/glimr/renderer/glutwindow.rb', line 75 def height @height end |
#title ⇒ Object (readonly)
Returns the value of attribute title.
75 76 77 |
# File 'lib/glimr/renderer/glutwindow.rb', line 75 def title @title end |
#viewport ⇒ Object
Returns the value of attribute viewport.
73 74 75 |
# File 'lib/glimr/renderer/glutwindow.rb', line 73 def @viewport end |
#width ⇒ Object (readonly)
Returns the value of attribute width.
75 76 77 |
# File 'lib/glimr/renderer/glutwindow.rb', line 75 def width @width end |
#window_id ⇒ Object
Returns the value of attribute window_id.
74 75 76 |
# File 'lib/glimr/renderer/glutwindow.rb', line 74 def window_id @window_id end |
#x ⇒ Object (readonly)
Returns the value of attribute x.
75 76 77 |
# File 'lib/glimr/renderer/glutwindow.rb', line 75 def x @x end |
#y ⇒ Object (readonly)
Returns the value of attribute y.
75 76 77 |
# File 'lib/glimr/renderer/glutwindow.rb', line 75 def y @y end |
Class Method Details
.create_window(window) ⇒ Object
Creates a GLUT window with the title and adds it to windows list.
53 54 55 56 57 58 59 60 |
# File 'lib/glimr/renderer/glutwindow.rb', line 53 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.
64 65 66 67 68 |
# File 'lib/glimr/renderer/glutwindow.rb', line 64 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 49 50 |
# File 'lib/glimr/renderer/glutwindow.rb', line 39 def self.next_window GC.enable 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 GC.disable 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
136 137 138 |
# File 'lib/glimr/renderer/glutwindow.rb', line 136 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
132 133 134 |
# File 'lib/glimr/renderer/glutwindow.rb', line 132 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
140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/glimr/renderer/glutwindow.rb', line 140 def heartbeat @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? @frame += 1 end |
#init_glut ⇒ Object
Initialize GLUT state for the window, then ask GLUTWindow class to create the window.
105 106 107 108 |
# File 'lib/glimr/renderer/glutwindow.rb', line 105 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) @viewport.multicast_event(ev) ev = Event.new(:key_up, event_properties) @viewport.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[] @mouse_buttons_down[] = 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
128 129 130 |
# File 'lib/glimr/renderer/glutwindow.rb', line 128 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 window_resize event to the viewport.
113 114 115 116 117 118 119 120 121 |
# File 'lib/glimr/renderer/glutwindow.rb', line 113 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.
124 125 126 |
# File 'lib/glimr/renderer/glutwindow.rb', line 124 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 => @mouse_buttons_down } @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 |