##// END OF EJS Templates
Add GLUT input hook
Thomas Kluyver -
Show More
@@ -0,0 +1,141 b''
1 """GLUT Input hook for interactive use with prompt_toolkit
2 """
3 from __future__ import print_function
4
5
6 # GLUT is quite an old library and it is difficult to ensure proper
7 # integration within IPython since original GLUT does not allow to handle
8 # events one by one. Instead, it requires for the mainloop to be entered
9 # and never returned (there is not even a function to exit he
10 # mainloop). Fortunately, there are alternatives such as freeglut
11 # (available for linux and windows) and the OSX implementation gives
12 # access to a glutCheckLoop() function that blocks itself until a new
13 # event is received. This means we have to setup the idle callback to
14 # ensure we got at least one event that will unblock the function.
15 #
16 # Furthermore, it is not possible to install these handlers without a window
17 # being first created. We choose to make this window invisible. This means that
18 # display mode options are set at this level and user won't be able to change
19 # them later without modifying the code. This should probably be made available
20 # via IPython options system.
21
22 import sys
23 import time
24 import signal
25 import OpenGL.GLUT as glut
26 import OpenGL.platform as platform
27 from timeit import default_timer as clock
28
29 # Frame per second : 60
30 # Should probably be an IPython option
31 glut_fps = 60
32
33 # Display mode : double buffeed + rgba + depth
34 # Should probably be an IPython option
35 glut_display_mode = (glut.GLUT_DOUBLE |
36 glut.GLUT_RGBA |
37 glut.GLUT_DEPTH)
38
39 glutMainLoopEvent = None
40 if sys.platform == 'darwin':
41 try:
42 glutCheckLoop = platform.createBaseFunction(
43 'glutCheckLoop', dll=platform.GLUT, resultType=None,
44 argTypes=[],
45 doc='glutCheckLoop( ) -> None',
46 argNames=(),
47 )
48 except AttributeError:
49 raise RuntimeError(
50 '''Your glut implementation does not allow interactive sessions'''
51 '''Consider installing freeglut.''')
52 glutMainLoopEvent = glutCheckLoop
53 elif glut.HAVE_FREEGLUT:
54 glutMainLoopEvent = glut.glutMainLoopEvent
55 else:
56 raise RuntimeError(
57 '''Your glut implementation does not allow interactive sessions. '''
58 '''Consider installing freeglut.''')
59
60
61 def glut_display():
62 # Dummy display function
63 pass
64
65 def glut_idle():
66 # Dummy idle function
67 pass
68
69 def glut_close():
70 # Close function only hides the current window
71 glut.glutHideWindow()
72 glutMainLoopEvent()
73
74 def glut_int_handler(signum, frame):
75 # Catch sigint and print the defaultipyt message
76 signal.signal(signal.SIGINT, signal.default_int_handler)
77 print('\nKeyboardInterrupt')
78 # Need to reprint the prompt at this stage
79
80 # Initialisation code
81 glut.glutInit( sys.argv )
82 glut.glutInitDisplayMode( glut_display_mode )
83 # This is specific to freeglut
84 if bool(glut.glutSetOption):
85 glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
86 glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
87 glut.glutCreateWindow( b'ipython' )
88 glut.glutReshapeWindow( 1, 1 )
89 glut.glutHideWindow( )
90 glut.glutWMCloseFunc( glut_close )
91 glut.glutDisplayFunc( glut_display )
92 glut.glutIdleFunc( glut_idle )
93
94
95 def inputhook(context):
96 """Run the pyglet event loop by processing pending events only.
97
98 This keeps processing pending events until stdin is ready. After
99 processing all pending events, a call to time.sleep is inserted. This is
100 needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
101 though for best performance.
102 """
103 # We need to protect against a user pressing Control-C when IPython is
104 # idle and this is running. We trap KeyboardInterrupt and pass.
105
106 signal.signal(signal.SIGINT, glut_int_handler)
107
108 try:
109 t = clock()
110
111 # Make sure the default window is set after a window has been closed
112 if glut.glutGetWindow() == 0:
113 glut.glutSetWindow( 1 )
114 glutMainLoopEvent()
115 return 0
116
117 while not context.input_is_ready():
118 glutMainLoopEvent()
119 # We need to sleep at this point to keep the idle CPU load
120 # low. However, if sleep to long, GUI response is poor. As
121 # a compromise, we watch how often GUI events are being processed
122 # and switch between a short and long sleep time. Here are some
123 # stats useful in helping to tune this.
124 # time CPU load
125 # 0.001 13%
126 # 0.005 3%
127 # 0.01 1.5%
128 # 0.05 0.5%
129 used_time = clock() - t
130 if used_time > 10.0:
131 # print 'Sleep for 1 s' # dbg
132 time.sleep(1.0)
133 elif used_time > 0.1:
134 # Few GUI events coming in, so we can sleep longer
135 # print 'Sleep for 0.05 s' # dbg
136 time.sleep(0.05)
137 else:
138 # Many GUI events coming in, so sleep only very little
139 time.sleep(0.001)
140 except KeyboardInterrupt:
141 pass
@@ -1,51 +1,51 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """Simple GLUT example to manually test event loop integration.
2 """Simple GLUT example to manually test event loop integration.
3
3
4 This is meant to run tests manually in ipython as:
4 This is meant to run tests manually in ipython as:
5
5
6 In [5]: %gui glut
6 In [5]: %gui glut
7
7
8 In [6]: %run gui-glut.py
8 In [6]: %run gui-glut.py
9
9
10 In [7]: gl.glClearColor(1,1,1,1)
10 In [7]: gl.glClearColor(1,1,1,1)
11 """
11 """
12
12
13 #!/usr/bin/env python
13 #!/usr/bin/env python
14 import sys
14 import sys
15 import OpenGL.GL as gl
15 import OpenGL.GL as gl
16 import OpenGL.GLUT as glut
16 import OpenGL.GLUT as glut
17
17
18 def close():
18 def close():
19 glut.glutDestroyWindow(glut.glutGetWindow())
19 glut.glutDestroyWindow(glut.glutGetWindow())
20
20
21 def display():
21 def display():
22 gl.glClear (gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
22 gl.glClear (gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
23 glut.glutSwapBuffers()
23 glut.glutSwapBuffers()
24
24
25 def resize(width,height):
25 def resize(width,height):
26 gl.glViewport(0, 0, width, height+4)
26 gl.glViewport(0, 0, width, height+4)
27 gl.glMatrixMode(gl.GL_PROJECTION)
27 gl.glMatrixMode(gl.GL_PROJECTION)
28 gl.glLoadIdentity()
28 gl.glLoadIdentity()
29 gl.glOrtho(0, width, 0, height+4, -1, 1)
29 gl.glOrtho(0, width, 0, height+4, -1, 1)
30 gl.glMatrixMode(gl.GL_MODELVIEW)
30 gl.glMatrixMode(gl.GL_MODELVIEW)
31
31
32 if glut.glutGetWindow() > 0:
32 if glut.glutGetWindow() > 0:
33 interactive = True
33 interactive = True
34 glut.glutInit(sys.argv)
34 glut.glutInit(sys.argv)
35 glut.glutInitDisplayMode(glut.GLUT_DOUBLE |
35 glut.glutInitDisplayMode(glut.GLUT_DOUBLE |
36 glut.GLUT_RGBA |
36 glut.GLUT_RGBA |
37 glut.GLUT_DEPTH)
37 glut.GLUT_DEPTH)
38 else:
38 else:
39 interactive = False
39 interactive = False
40
40
41 glut.glutCreateWindow('gui-glut')
41 glut.glutCreateWindow(b'gui-glut')
42 glut.glutDisplayFunc(display)
42 glut.glutDisplayFunc(display)
43 glut.glutReshapeFunc(resize)
43 glut.glutReshapeFunc(resize)
44 # This is necessary on osx to be able to close the window
44 # This is necessary on osx to be able to close the window
45 # (else the close button is disabled)
45 # (else the close button is disabled)
46 if sys.platform == 'darwin' and not bool(glut.HAVE_FREEGLUT):
46 if sys.platform == 'darwin' and not bool(glut.HAVE_FREEGLUT):
47 glut.glutWMCloseFunc(close)
47 glut.glutWMCloseFunc(close)
48 gl.glClearColor(0,0,0,1)
48 gl.glClearColor(0,0,0,1)
49
49
50 if not interactive:
50 if not interactive:
51 glut.glutMainLoop()
51 glut.glutMainLoop()
General Comments 0
You need to be logged in to leave comments. Login now