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 )
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
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
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
88 """Allow GLUT to process events."""
89 _gl.glutMainLoopEvent()
90
92 """Leave the GLUT main loop."""
93 _gl.glutLeaveMainLoop()
94
98
102
106
110
114
118
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)
196 if old_binding:
197 old_binding._bind()
198 else:
199 context_manager.current_context = self
200
201 super(GlutWindow, self).__init__()
202
203 if hide:
204 self.hide()
205 else:
206 self.show()
207
211
213 if self._id == 0:
214 raise RuntimeError("window has already been destroyed")
215 _gl.glutSetWindow(self._id)
216
220
221 - def post_redisplay(self):
222 with self:
223 _gl.glutPostRedisplay()
224
228
230 with self:
231 _gl.glutLeaveFullScreen()
232
236
240
244
248
252
256
257 @property
261
262 @cursor.setter
266
267 @property
271
272 @property
276
277 @shape.setter
282
283 @property
287
288 @position.setter
293
294 @property
297
298 @property
300 return self._window_title
301
302 @window_title.setter
307
308 @property
310 return self._icon_title
311
312 @icon_title.setter
317
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)
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