##// END OF EJS Templates
Merge branch 'glut-rebased' of git://github.com/fperez/ipython into glut...
Nicolas Rougier -
r4818:89161a5b merge
parent child Browse files
Show More
@@ -0,0 +1,46 b''
1 #!/usr/bin/env python
2 """Simple GLUT example to manually test event loop integration.
3
4 This is meant to run tests manually in ipython as:
5
6 In [5]: %gui glut
7
8 In [6]: %run gui-glut.py
9
10 In [7]: gl.glClearColor(1,1,1,1)
11 """
12
13 #!/usr/bin/env python
14 import sys
15 import OpenGL.GL as gl
16 import OpenGL.GLUT as glut
17
18 def display():
19 gl.glClear (gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
20 glut.glutSwapBuffers()
21
22 def resize(width,height):
23 gl.glViewport(0, 0, width, height+4)
24 gl.glMatrixMode(gl.GL_PROJECTION)
25 gl.glLoadIdentity()
26 gl.glOrtho(0, width, 0, height+4, -1, 1)
27 gl.glMatrixMode(gl.GL_MODELVIEW)
28
29
30 if glut.glutGetWindow() > 0:
31 interactive = True
32 glut.glutInit(sys.argv)
33 glut.glutInitDisplayMode(glut.GLUT_DOUBLE |
34 glut.GLUT_RGBA |
35 glut.GLUT_DEPTH)
36 glut.glutShowWindow()
37 else:
38 glut.glutCreateWindow('gui-glut')
39 interactive = False
40
41 glut.glutDisplayFunc(display)
42 glut.glutReshapeFunc(resize)
43 gl.glClearColor(0,0,0,1)
44
45 if not interactive:
46 glut.glutMainLoop()
@@ -229,8 +229,8 b' class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):'
229 self.load_config_file = lambda *a, **kw: None
229 self.load_config_file = lambda *a, **kw: None
230 self.ignore_old_config=True
230 self.ignore_old_config=True
231
231
232 gui = CaselessStrEnum(('qt','wx','gtk', 'pyglet'), config=True,
232 gui = CaselessStrEnum(('qt', 'wx', 'gtk', 'glut', 'pyglet'), config=True,
233 help="Enable GUI event loop integration ('qt', 'wx', 'gtk', 'pyglet')."
233 help="Enable GUI event loop integration ('qt', 'wx', 'gtk', 'glut', 'pyglet')."
234 )
234 )
235 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'auto'],
235 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'auto'],
236 config=True,
236 config=True,
@@ -19,6 +19,7 b' from IPython.lib.inputhook import ('
19 enable_gtk, disable_gtk,
19 enable_gtk, disable_gtk,
20 enable_qt4, disable_qt4,
20 enable_qt4, disable_qt4,
21 enable_tk, disable_tk,
21 enable_tk, disable_tk,
22 enable_glut, disable_glut,
22 enable_pyglet, disable_pyglet,
23 enable_pyglet, disable_pyglet,
23 set_inputhook, clear_inputhook,
24 set_inputhook, clear_inputhook,
24 current_gui
25 current_gui
@@ -29,6 +29,7 b" GUI_QT4 = 'qt4'"
29 GUI_GTK = 'gtk'
29 GUI_GTK = 'gtk'
30 GUI_TK = 'tk'
30 GUI_TK = 'tk'
31 GUI_OSX = 'osx'
31 GUI_OSX = 'osx'
32 GUI_GLUT = 'glut'
32 GUI_PYGLET = 'pyglet'
33 GUI_PYGLET = 'pyglet'
33
34
34 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
@@ -284,7 +285,207 b' class InputHookManager(object):'
284 """
285 """
285 self.clear_inputhook()
286 self.clear_inputhook()
286
287
288 def enable_glut(self, app=None):
289 """Enable event loop integration with GLUT.
287
290
291 Parameters
292 ----------
293 app : ignored
294 Ignored, it's only a placeholder to keep the call signature of all
295 gui activation methods consistent, which simplifies the logic of
296 supporting magics.
297
298 Notes
299 -----
300
301 This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
302 integrate with terminal based applications like IPython. Due to GLUT
303 limitations, it is currently not possible to start the event loop
304 without first creating a window. You should thus not create another
305 window but use instead the created one. See 'gui-glut.py' in the
306 docs/examples/lib directory.
307
308 The default screen mode is set to:
309
310 glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
311
312 Script integration
313 ------------------
314
315 if glut.glutGetWindow() > 0:
316 interactive = True
317 glut.glutShowWindow()
318 else:
319 interactive = False
320 glut.glutInit(sys.argv)
321 glut.glutInitDisplayMode( glut.GLUT_DOUBLE |
322 glut.GLUT_RGBA |
323 glut.GLUT_DEPTH )
324 ...
325 if not interactive:
326 glut.glutMainLoop()
327 """
328 # GLUT is quite an old library and it is difficult to ensure proper
329 # integration within IPython since original GLUT does not allow to handle
330 # events one by one. Instead, it requires for the mainloop to be entered
331 # and never returned (there is not even a function to exit he
332 # mainloop). Fortunately, there are alternatives such as freeglut
333 # (available for linux and windows) and the OSX implementation gives
334 # access to a glutCheckLoop() function that blocks itself until a new
335 # event is received. This means we have to setup a default timer to
336 # ensure we got at least one event that will unblock the function. We set
337 # a default timer of 60fps.
338 #
339 # Furthermore, it is not possible to install these handlers without a
340 # window being first created. We choose to make this window invisible and
341 # the user is supposed to make it visible when needed (see gui-glut.py in
342 # the docs/examples/lib directory). This means that display mode options
343 # are set at this level and user won't be able to change them later
344 # without modifying the code. This should probably be made available via
345 # IPython options system.
346
347 import OpenGL
348 OpenGL.ERROR_CHECKING = False
349 import OpenGL.GLUT as glut
350 import OpenGL.platform as platform
351 import time
352
353
354 # Frame per second : 60
355 # Should probably be an IPython option
356 glut_fps = 60
357
358
359 # Display mode : double buffeed + rgba + depth
360 # Should probably be an IPython option
361 glut_display_mode = (glut.GLUT_DOUBLE |
362 glut.GLUT_RGBA |
363 glut.GLUT_DEPTH)
364
365 glut_interrupted = False
366
367 def display():
368 ''' Dummy display function '''
369 pass
370
371 def timer(fps):
372 # We should normally set the active window to 1 and post a
373 # redisplay for each window. The problem is that we do not know
374 # how much active windows we have and there is no function in glut
375 # to get that number.
376 # glut.glutSetWindow(1)
377 glut.glutTimerFunc( int(1000.0/fps), timer, fps)
378 glut.glutPostRedisplay()
379
380 def close():
381 glut.glutHideWindow()
382
383 glutMainLoopEvent = None
384 if sys.platform == 'darwin':
385 try:
386 glutCheckLoop = platform.createBaseFunction(
387 'glutCheckLoop', dll=platform.GLUT, resultType=None,
388 argTypes=[],
389 doc='glutCheckLoop( ) -> None',
390 argNames=(),
391 )
392 except AttributeError:
393 raise RuntimeError(
394 '''Your glut implementation does not allow interactive sessions'''
395 '''Consider installing freeglut.''')
396 glutMainLoopEvent = glutCheckLoop
397 elif glut.HAVE_FREEGLUT:
398 glutMainLoopEvent = glut.glutMainLoopEvent
399 else:
400 raise RuntimeError(
401 '''Your glut implementation does not allow interactive sessions. '''
402 '''Consider installing freeglut.''')
403
404 def inputhook_glut():
405 """ Process pending GLUT events only. """
406
407 # We need to protect against a user pressing Control-C when IPython
408 # is idle and this is running. We should trap KeyboardInterrupt and
409 # pass but it does not seem to work with glutMainLoopEvent.
410 # Instead, we setup a signal handler on SIGINT and returns after
411 # having restored the default python SIGINT handler.
412 import signal
413 def handler(signum, frame):
414 signal.signal(signal.SIGINT, signal.default_int_handler)
415 print '\nKeyboardInterrupt'
416 # Need to reprint the prompt at this stage
417
418 signal.signal(signal.SIGINT, handler)
419
420 try:
421 glutMainLoopEvent()
422 except KeyboardInterrupt: # this catch doesn't work for some reasons...
423 pass
424
425 return 0
426
427 if not self._apps.has_key(GUI_GLUT):
428 glut.glutInit(sys.argv)
429 # Display mode should be also an Ipython option since user won't be able
430 # to change it later
431 glut.glutInitDisplayMode(glut_display_mode)
432 glut.glutCreateWindow(sys.argv[0])
433 glut.glutHideWindow()
434 glut.glutWMCloseFunc(close)
435 glut.glutDisplayFunc(display)
436 glut.glutTimerFunc( int(1000.0/glut_fps), timer, glut_fps)
437 else:
438 glut.glutWMCloseFunc(close)
439 glut.glutDisplayFunc(display)
440 glut.glutTimerFunc( int(1000.0/glut_fps), timer, glut_fps)
441
442 self.set_inputhook(inputhook_glut)
443 self._current_gui = GUI_GLUT
444 self._apps[GUI_GLUT] = True
445
446 def disable_glut(self):
447 """Disable event loop integration with glut.
448
449 This sets PyOS_InputHook to NULL and set the display function to a
450 dummy one and set the timer to a dummy timer that will be triggered
451 very far in the future.
452 """
453 import signal
454 import OpenGL
455 OpenGL.ERROR_CHECKING = False
456 import OpenGL.GLUT as glut
457 import OpenGL.platform as platform
458
459 def timer_none(fps):
460 ''' Dummy timer function '''
461 pass
462
463 glutMainLoopEvent = None
464 if sys.platform == 'darwin':
465 try:
466 glutCheckLoop = platform.createBaseFunction(
467 'glutCheckLoop', dll=platform.GLUT, resultType=None,
468 argTypes=[],
469 doc='glutCheckLoop( ) -> None',
470 argNames=(),
471 )
472 except AttributeError:
473 raise RuntimeError(
474 '''Your glut implementation does not allow interactive sessions'''
475 '''Consider installing freeglut.''')
476 glutMainLoopEvent = glutCheckLoop
477 elif glut.HAVE_FREEGLUT:
478 glutMainLoopEvent = glut.glutMainLoopEvent
479 else:
480 raise RuntimeError(
481 '''Your glut implementation does not allow interactive sessions. '''
482 '''Consider installing freeglut.''')
483
484 glut.glutHideWindow() # This is an event to be processed below
485 glutMainLoopEvent()
486 #glut.glutTimerFunc( sys.maxint-1, timer_none, 0)
487 self.clear_inputhook()
488 #signal.signal(signal.SIGINT, signal.default_int_handler)
288
489
289 def enable_pyglet(self, app=None):
490 def enable_pyglet(self, app=None):
290 """Enable event loop integration with pyglet.
491 """Enable event loop integration with pyglet.
@@ -316,7 +517,6 b' class InputHookManager(object):'
316 """
517 """
317 self.clear_inputhook()
518 self.clear_inputhook()
318
519
319
320 def current_gui(self):
520 def current_gui(self):
321 """Return a string indicating the currently active GUI or None."""
521 """Return a string indicating the currently active GUI or None."""
322 return self._current_gui
522 return self._current_gui
@@ -331,6 +531,8 b' enable_gtk = inputhook_manager.enable_gtk'
331 disable_gtk = inputhook_manager.disable_gtk
531 disable_gtk = inputhook_manager.disable_gtk
332 enable_tk = inputhook_manager.enable_tk
532 enable_tk = inputhook_manager.enable_tk
333 disable_tk = inputhook_manager.disable_tk
533 disable_tk = inputhook_manager.disable_tk
534 enable_glut = inputhook_manager.enable_glut
535 disable_glut = inputhook_manager.disable_glut
334 enable_pyglet = inputhook_manager.enable_pyglet
536 enable_pyglet = inputhook_manager.enable_pyglet
335 disable_pyglet = inputhook_manager.disable_pyglet
537 disable_pyglet = inputhook_manager.disable_pyglet
336 clear_inputhook = inputhook_manager.clear_inputhook
538 clear_inputhook = inputhook_manager.clear_inputhook
@@ -371,6 +573,7 b' def enable_gui(gui=None, app=None):'
371 GUI_WX: enable_wx,
573 GUI_WX: enable_wx,
372 GUI_QT: enable_qt4, # qt3 not supported
574 GUI_QT: enable_qt4, # qt3 not supported
373 GUI_QT4: enable_qt4,
575 GUI_QT4: enable_qt4,
576 GUI_GLUT: enable_glut,
374 GUI_PYGLET: enable_pyglet,
577 GUI_PYGLET: enable_pyglet,
375 }
578 }
376 try:
579 try:
General Comments 0
You need to be logged in to leave comments. Login now