Package glitter :: Package contexts :: Module glut
[hide private]
[frames] | no frames]

Source Code for Module glitter.contexts.glut

  1  """GLUT context creation and management. 
  2   
  3  @bug: Closing a GLUT window via the window system (not the API) causes bogus error messages and even the occasional segfault. 
  4  @todo: Implement subwindows using C{glutCreateSubWindow} and C{glutGet(GLUT_WINDOW_PARENT)}. 
  5  @todo: Implement menus, font rendering, and geometric object rendering, 
  6  @todo: Fail gracefully (better error message) when context cannot be created, e.g. when opengl 3.2 not available 
  7  @todo: Key constants like C{GLUT_KEY_F1} should be available as an enum. 
  8   
  9  @author: Stephan Wenger 
 10  @date: 2012-02-29 
 11  """ 
 12   
 13  import random as _random 
 14   
 15  import glitter.raw as _gl 
 16  from glitter.utils import Enum 
 17  from glitter.contexts.context import Context 
 18  from glitter.contexts.contextmanager import context_manager 
 19   
 20  _cursors = Enum( 
 21      right_arrow=_gl.GLUT_CURSOR_RIGHT_ARROW, 
 22      left_arrow=_gl.GLUT_CURSOR_LEFT_ARROW, 
 23      info=_gl.GLUT_CURSOR_INFO, 
 24      destroy=_gl.GLUT_CURSOR_DESTROY, 
 25      help=_gl.GLUT_CURSOR_HELP, 
 26      cycle=_gl.GLUT_CURSOR_CYCLE, 
 27      spray=_gl.GLUT_CURSOR_SPRAY, 
 28      wait=_gl.GLUT_CURSOR_WAIT, 
 29      text=_gl.GLUT_CURSOR_TEXT, 
 30      crosshair=_gl.GLUT_CURSOR_CROSSHAIR, 
 31      up_down=_gl.GLUT_CURSOR_UP_DOWN, 
 32      left_right=_gl.GLUT_CURSOR_LEFT_RIGHT, 
 33      top_side=_gl.GLUT_CURSOR_TOP_SIDE, 
 34      bottom_side=_gl.GLUT_CURSOR_BOTTOM_SIDE, 
 35      left_side=_gl.GLUT_CURSOR_LEFT_SIDE, 
 36      right_side=_gl.GLUT_CURSOR_RIGHT_SIDE, 
 37      top_left_corner=_gl.GLUT_CURSOR_TOP_LEFT_CORNER, 
 38      top_right_corner=_gl.GLUT_CURSOR_TOP_RIGHT_CORNER, 
 39      bottom_right_corner=_gl.GLUT_CURSOR_BOTTOM_RIGHT_CORNER, 
 40      bottom_left_corner=_gl.GLUT_CURSOR_BOTTOM_LEFT_CORNER, 
 41      full_crosshair=_gl.GLUT_CURSOR_FULL_CROSSHAIR, 
 42      none=_gl.GLUT_CURSOR_NONE, 
 43      inherit=_gl.GLUT_CURSOR_INHERIT, 
 44  ) 
45 46 -def _func_property(glut_func):
47 import re 48 name = re.match("^glut(.*)Func$", glut_func.__name__).groups()[0] 49 name = re.sub("([a-z0-9])([A-Z])", r"\1_\2", re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name)).lower() 50 private_name = "_%s_func" % name 51 private_c_name = "_%s_func_c" % name 52 53 def getter(self): 54 if not hasattr(self, private_name): 55 setattr(self, private_name, None) 56 return getattr(self, private_name)
57 58 def setter(self, func): 59 ftype = glut_func.argtypes[0] 60 setattr(self, private_c_name, ftype(func) if func is not None else ftype()) 61 setattr(self, private_name, func) 62 with self: 63 glut_func(getattr(self, private_c_name)) 64 65 return property(getter, setter) 66
67 -def initialize(argv=None):
68 """Initialize GLUT. Called automatically on import.""" 69 if argv is None: 70 import sys 71 argv = sys.argv 72 _argc = _gl.c_int(len(argv)) 73 _argv = (_gl.c_char_p * _argc.value)() 74 for i, a in enumerate(argv): 75 _argv[i] = a 76 _gl.glutInit(_gl.pointer(_argc), _argv) 77 argv[:] = [_argv[i] for i in range(_argc.value)]
78
79 -def main_loop():
80 """Enter the GLUT main loop. 81 82 @todo: Avoid destroying a window in C{__del__} that has already been destroyed by closing it; can C{glutCloseFunc} help? 83 """ 84 _gl.glutMainLoop() 85 initialize()
86
87 -def main_loop_event():
88 """Allow GLUT to process events.""" 89 _gl.glutMainLoopEvent()
90
91 -def leave_main_loop():
92 """Leave the GLUT main loop.""" 93 _gl.glutLeaveMainLoop()
94
95 -def get_screen_shape():
96 """Screen height and width in pixels.""" 97 return _gl.glutGet(_gl.GLUT_SCREEN_HEIGHT, _gl.GLUT_SCREEN_WIDTH)
98
99 -def get_screen_shape_mm():
100 """Screen height and width in millimeters.""" 101 return _gl.glutGet(_gl.GLUT_SCREEN_HEIGHT_MM, _gl.GLUT_SCREEN_WIDTH_MM)
102
103 -def get_elapsed_time():
104 """Time in seconds since GLUT was initialized.""" 105 return _gl.glutGet(_gl.GLUT_ELAPSED_TIME) / 1000.0
106
107 -def get_shift_state():
108 """Only available in keyboard, special, and mouse callbacks.""" 109 return _gl.glutGetModifiers(_gl.GLUT_ACTIVE_SHIFT)
110
111 -def get_ctrl_state():
112 """Only available in keyboard, special, and mouse callbacks.""" 113 return _gl.glutGetModifiers(_gl.GLUT_ACTIVE_CTRL)
114
115 -def get_alt_state():
116 """Only available in keyboard, special, and mouse callbacks.""" 117 return _gl.glutGetModifiers(_gl.GLUT_ACTIVE_ALT)
118
119 -class GlutWindow(Context):
120 cursors = _cursors 121
122 - def __init__(self, version=(3, 2), compatibility_profile=False, 123 debug=False, forward_compatible=True, shape=(300, 300), 124 position=(-1, -1), index=False, double=False, accum=False, 125 alpha=False, depth=False, stencil=False, multisample=False, 126 stereo=False, luminance=False, name="", hide=False):
127 """Create a new GLUT window. 128 129 `version` is the OpenGL version to use. It can be either an integer or a (major, minor) tuple. 130 If `compatibility_profile` is `True`, the compatibility profile will be used instead of the core profile. 131 `debug` enables OpenGL debug mode, `forward_compatible` the forward compatibility mode. 132 `shape` and `position` control the initial (height, width) shape and (y, x) position of the window. 133 `index` enables color index mode instead of RGBA. 134 `double` enables double buffering. 135 `accum`, `alpha`, `depth`, and `stencil` enable the corresponding buffers. 136 `multisample` enables multisampling. 137 `stereo` enables stereo buffers. 138 `luminance` enables luminance rendering instead of true RGBA. 139 `name` is the name of the window and its initial title. 140 If `hide` is `True`, the window will initially be hidden. 141 """ 142 143 self._stack = [] 144 145 self._idle_func = None 146 self._display_func = None 147 self._reshape_func = None 148 self._mouse_func = None 149 self._motion_func = None 150 self._keyboard_func = None 151 152 self._timer_funcs = {} 153 def timer_func(value): 154 self._timer_funcs.pop(value)()
155 self._timer_func = _gl.glutTimerFunc.argtypes[1](timer_func) 156 157 self._name = self._window_title = self._icon_title = name 158 159 if hasattr(version, "__iter__"): 160 _gl.glutInitContextVersion(*version) 161 else: 162 _gl.glutInitContextVersion(version, 0) 163 164 _gl.glutInitContextProfile(_gl.GLUT_COMPATIBILITY_PROFILE if compatibility_profile else _gl.GLUT_CORE_PROFILE) 165 166 _gl.glutInitContextFlags( 167 (_gl.GLUT_DEBUG if debug else 0) | 168 (_gl.GLUT_FORWARD_COMPATIBLE if forward_compatible else 0) 169 ) 170 171 height, width = shape 172 _gl.glutInitWindowSize(width, height) 173 174 y, x = position 175 _gl.glutInitWindowPosition(x, y) 176 177 _gl.glutInitDisplayMode( 178 (_gl.GLUT_INDEX if index else _gl.GLUT_RGBA) | 179 (_gl.GLUT_DOUBLE if double else _gl.GLUT_SINGLE) | 180 (_gl.GLUT_ACCUM if accum else 0) | 181 (_gl.GLUT_ALPHA if alpha else 0) | 182 (_gl.GLUT_DEPTH if depth else 0) | 183 (_gl.GLUT_STENCIL if stencil else 0) | 184 (_gl.GLUT_MULTISAMPLE if multisample else 0) | 185 (_gl.GLUT_STEREO if stereo else 0) | 186 (_gl.GLUT_LUMINANCE if luminance else 0) 187 ) 188 189 _gl.glutSetOption(_gl.GLUT_ACTION_ON_WINDOW_CLOSE, _gl.GLUT_ACTION_CONTINUE_EXECUTION) 190 191 if not _gl.glutGet(_gl.GLUT_DISPLAY_MODE_POSSIBLE): 192 raise RuntimeError("display mode not possible") 193 194 old_binding = context_manager.current_context 195 self._id = _gl.glutCreateWindow(self._name) # creating a window changes the current context without the context manager's knowledge 196 if old_binding: 197 old_binding._bind() # rebind the previous context circumventing any caching performed by the context 198 else: 199 context_manager.current_context = self # tell the context manager about the changed binding 200 201 super(GlutWindow, self).__init__() 202 203 if hide: 204 self.hide() 205 else: 206 self.show()
207
208 - def destroy(self):
209 _gl.glutDestroyWindow(self._id) 210 self._id = 0
211
212 - def _bind(self):
213 if self._id == 0: 214 raise RuntimeError("window has already been destroyed") 215 _gl.glutSetWindow(self._id)
216
217 - def swap_buffers(self):
218 with self: 219 _gl.glutSwapBuffers()
220
221 - def post_redisplay(self):
222 with self: 223 _gl.glutPostRedisplay()
224
225 - def full_screen(self):
226 with self: 227 _gl.glutFullScreen()
228
229 - def leave_full_screen(self):
230 with self: 231 _gl.glutLeaveFullScreen()
232
233 - def toggle_full_screen(self):
234 with self: 235 _gl.glutFullScreenToggle()
236
237 - def push(self):
238 with self: 239 _gl.glutPushWindow()
240
241 - def pop(self):
242 with self: 243 _gl.glutPopWindow()
244
245 - def show(self):
246 with self: 247 _gl.glutShowWindow()
248
249 - def hide(self):
250 with self: 251 _gl.glutHideWindow()
252
253 - def iconify(self):
254 with self: 255 _gl.glutIconifyWindow()
256 257 @property
258 - def cursor(self):
259 with self: 260 return GlutWindow.cursors[_gl.glutGet(_gl.GLUT_WINDOW_CURSOR)]
261 262 @cursor.setter
263 - def cursor(self, cursor):
264 with self: 265 _gl.glutSetCursor(cursor._value)
266 267 @property
268 - def num_children(self):
269 with self: 270 return _gl.glutGet(_gl.GLUT_WINDOW_NUM_CHILDREN)
271 272 @property
273 - def shape(self):
274 with self: 275 return _gl.glutGet(_gl.GLUT_WINDOW_HEIGHT), _gl.glutGet(_gl.GLUT_WINDOW_WIDTH)
276 277 @shape.setter
278 - def shape(self, shape):
279 height, width = shape 280 with self: 281 _gl.glutReshapeWindow(width, height)
282 283 @property
284 - def position(self):
285 with self: 286 return _gl.glutGet(_gl.GLUT_WINDOW_Y), _gl.glutGet(_gl.GLUT_WINDOW_X)
287 288 @position.setter
289 - def position(self, position):
290 y, x = position 291 with self: 292 _gl.glutPositionWindow(x, y)
293 294 @property
295 - def name(self):
296 return self._name
297 298 @property
299 - def window_title(self):
300 return self._window_title
301 302 @window_title.setter
303 - def window_title(self, window_title):
304 self._window_title = window_title 305 with self: 306 _gl.glutSetWindowTitle(window_title)
307 308 @property
309 - def icon_title(self):
310 return self._icon_title
311 312 @icon_title.setter
313 - def icon_title(self, icon_title):
314 self._icon_title = icon_title 315 with self: 316 _gl.glutSetIconTitle(icon_title)
317
318 - def add_timer(self, msecs, func):
319 timer_id = _random.randint(0, 1 << 30) 320 while timer_id in self._timer_funcs: 321 timer_id = _random.randint(0, 1 << 30) 322 self._timer_funcs[timer_id] = func 323 _gl.glutTimerFunc(msecs, self._timer_func, timer_id)
324 325 close_callback = _func_property(_gl.glutCloseFunc) 326 display_callback = _func_property(_gl.glutDisplayFunc) 327 entry_callback = _func_property(_gl.glutEntryFunc) 328 idle_callback = _func_property(_gl.glutIdleFunc) # within the callback, current window is not necessarily this window 329 joystick_callback = _func_property(_gl.glutJoystickFunc) 330 keyboard_callback = _func_property(_gl.glutKeyboardFunc) 331 keyboard_up_callback = _func_property(_gl.glutKeyboardUpFunc) 332 menu_destroy_callback = _func_property(_gl.glutMenuDestroyFunc) 333 menu_state_callback = _func_property(_gl.glutMenuStateFunc) 334 menu_status_callback = _func_property(_gl.glutMenuStatusFunc) 335 motion_callback = _func_property(_gl.glutMotionFunc) 336 mouse_callback = _func_property(_gl.glutMouseFunc) 337 mouse_wheel_callback = _func_property(_gl.glutMouseWheelFunc) 338 passive_motion_callback = _func_property(_gl.glutPassiveMotionFunc) 339 reshape_callback = _func_property(_gl.glutReshapeFunc) 340 special_callback = _func_property(_gl.glutSpecialFunc) 341 special_up_callback = _func_property(_gl.glutSpecialUpFunc) 342 visibility_callback = _func_property(_gl.glutVisibilityFunc) 343 window_status_callback = _func_property(_gl.glutWindowStatusFunc) 344 wm_close_callback = _func_property(_gl.glutWMCloseFunc) 345 346 initialize() 347 348 __all__ = [ 349 "main_loop", 350 "main_loop_event", 351 "leave_main_loop", 352 "get_screen_shape", 353 "get_screen_shape_mm", 354 "get_elapsed_time", 355 "get_shift_state", 356 "get_ctrl_state", 357 "get_alt_state", 358 "GlutWindow", 359 ] 360