inputhookglut.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. # coding: utf-8
  2. """
  3. GLUT Inputhook support functions
  4. """
  5. from __future__ import print_function
  6. #-----------------------------------------------------------------------------
  7. # Copyright (C) 2008-2011 The IPython Development Team
  8. #
  9. # Distributed under the terms of the BSD License. The full license is in
  10. # the file COPYING, distributed as part of this software.
  11. #-----------------------------------------------------------------------------
  12. # GLUT is quite an old library and it is difficult to ensure proper
  13. # integration within IPython since original GLUT does not allow to handle
  14. # events one by one. Instead, it requires for the mainloop to be entered
  15. # and never returned (there is not even a function to exit he
  16. # mainloop). Fortunately, there are alternatives such as freeglut
  17. # (available for linux and windows) and the OSX implementation gives
  18. # access to a glutCheckLoop() function that blocks itself until a new
  19. # event is received. This means we have to setup the idle callback to
  20. # ensure we got at least one event that will unblock the function.
  21. #
  22. # Furthermore, it is not possible to install these handlers without a window
  23. # being first created. We choose to make this window invisible. This means that
  24. # display mode options are set at this level and user won't be able to change
  25. # them later without modifying the code. This should probably be made available
  26. # via IPython options system.
  27. #-----------------------------------------------------------------------------
  28. # Imports
  29. #-----------------------------------------------------------------------------
  30. import os
  31. import sys
  32. import time
  33. import signal
  34. import OpenGL.GLUT as glut
  35. import OpenGL.platform as platform
  36. from timeit import default_timer as clock
  37. #-----------------------------------------------------------------------------
  38. # Constants
  39. #-----------------------------------------------------------------------------
  40. # Frame per second : 60
  41. # Should probably be an IPython option
  42. glut_fps = 60
  43. # Display mode : double buffeed + rgba + depth
  44. # Should probably be an IPython option
  45. glut_display_mode = (glut.GLUT_DOUBLE |
  46. glut.GLUT_RGBA |
  47. glut.GLUT_DEPTH)
  48. glutMainLoopEvent = None
  49. if sys.platform == 'darwin':
  50. try:
  51. glutCheckLoop = platform.createBaseFunction(
  52. 'glutCheckLoop', dll=platform.GLUT, resultType=None,
  53. argTypes=[],
  54. doc='glutCheckLoop( ) -> None',
  55. argNames=(),
  56. )
  57. except AttributeError:
  58. raise RuntimeError(
  59. '''Your glut implementation does not allow interactive sessions'''
  60. '''Consider installing freeglut.''')
  61. glutMainLoopEvent = glutCheckLoop
  62. elif glut.HAVE_FREEGLUT:
  63. glutMainLoopEvent = glut.glutMainLoopEvent
  64. else:
  65. raise RuntimeError(
  66. '''Your glut implementation does not allow interactive sessions. '''
  67. '''Consider installing freeglut.''')
  68. #-----------------------------------------------------------------------------
  69. # Platform-dependent imports and functions
  70. #-----------------------------------------------------------------------------
  71. if os.name == 'posix':
  72. import select
  73. def stdin_ready():
  74. infds, outfds, erfds = select.select([sys.stdin],[],[],0)
  75. if infds:
  76. return True
  77. else:
  78. return False
  79. elif sys.platform == 'win32':
  80. import msvcrt
  81. def stdin_ready():
  82. return msvcrt.kbhit()
  83. #-----------------------------------------------------------------------------
  84. # Callback functions
  85. #-----------------------------------------------------------------------------
  86. def glut_display():
  87. # Dummy display function
  88. pass
  89. def glut_idle():
  90. # Dummy idle function
  91. pass
  92. def glut_close():
  93. # Close function only hides the current window
  94. glut.glutHideWindow()
  95. glutMainLoopEvent()
  96. def glut_int_handler(signum, frame):
  97. # Catch sigint and print the defautl message
  98. signal.signal(signal.SIGINT, signal.default_int_handler)
  99. print('\nKeyboardInterrupt')
  100. # Need to reprint the prompt at this stage
  101. #-----------------------------------------------------------------------------
  102. # Code
  103. #-----------------------------------------------------------------------------
  104. def inputhook_glut():
  105. """Run the pyglet event loop by processing pending events only.
  106. This keeps processing pending events until stdin is ready. After
  107. processing all pending events, a call to time.sleep is inserted. This is
  108. needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
  109. though for best performance.
  110. """
  111. # We need to protect against a user pressing Control-C when IPython is
  112. # idle and this is running. We trap KeyboardInterrupt and pass.
  113. signal.signal(signal.SIGINT, glut_int_handler)
  114. try:
  115. t = clock()
  116. # Make sure the default window is set after a window has been closed
  117. if glut.glutGetWindow() == 0:
  118. glut.glutSetWindow( 1 )
  119. glutMainLoopEvent()
  120. return 0
  121. while not stdin_ready():
  122. glutMainLoopEvent()
  123. # We need to sleep at this point to keep the idle CPU load
  124. # low. However, if sleep to long, GUI response is poor. As
  125. # a compromise, we watch how often GUI events are being processed
  126. # and switch between a short and long sleep time. Here are some
  127. # stats useful in helping to tune this.
  128. # time CPU load
  129. # 0.001 13%
  130. # 0.005 3%
  131. # 0.01 1.5%
  132. # 0.05 0.5%
  133. used_time = clock() - t
  134. if used_time > 10.0:
  135. # print 'Sleep for 1 s' # dbg
  136. time.sleep(1.0)
  137. elif used_time > 0.1:
  138. # Few GUI events coming in, so we can sleep longer
  139. # print 'Sleep for 0.05 s' # dbg
  140. time.sleep(0.05)
  141. else:
  142. # Many GUI events coming in, so sleep only very little
  143. time.sleep(0.001)
  144. except KeyboardInterrupt:
  145. pass
  146. return 0