PageRenderTime 32ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/host/pygletHG/pyglet/gl/base.py

https://github.com/hradec/chemshapes
Python | 386 lines | 168 code | 44 blank | 174 comment | 22 complexity | ca3f850441b590fb0f44b0288500d4a7 MD5 | raw file
  1. #!/usr/bin/python
  2. # $Id:$
  3. import sys as _sys
  4. from pyglet import gl
  5. from pyglet.gl import gl_info
  6. from pyglet.gl import glu_info
  7. class Config(object):
  8. '''Graphics configuration.
  9. A Config stores the preferences for OpenGL attributes such as the
  10. number of auxilliary buffers, size of the colour and depth buffers,
  11. double buffering, stencilling, multi- and super-sampling, and so on.
  12. Different platforms support a different set of attributes, so these
  13. are set with a string key and a value which is integer or boolean.
  14. :Ivariables:
  15. `double_buffer` : bool
  16. Specify the presence of a back-buffer for every color buffer.
  17. `stereo` : bool
  18. Specify the presence of separate left and right buffer sets.
  19. `buffer_size` : int
  20. Total bits per sample per color buffer.
  21. `aux_buffers` : int
  22. The number of auxilliary color buffers.
  23. `sample_buffers` : int
  24. The number of multisample buffers.
  25. `samples` : int
  26. The number of samples per pixel, or 0 if there are no multisample
  27. buffers.
  28. `red_size` : int
  29. Bits per sample per buffer devoted to the red component.
  30. `green_size` : int
  31. Bits per sample per buffer devoted to the green component.
  32. `blue_size` : int
  33. Bits per sample per buffer devoted to the blue component.
  34. `alpha_size` : int
  35. Bits per sample per buffer devoted to the alpha component.
  36. `depth_size` : int
  37. Bits per sample in the depth buffer.
  38. `stencil_size` : int
  39. Bits per sample in the stencil buffer.
  40. `accum_red_size` : int
  41. Bits per pixel devoted to the red component in the accumulation
  42. buffer.
  43. `accum_green_size` : int
  44. Bits per pixel devoted to the green component in the accumulation
  45. buffer.
  46. `accum_blue_size` : int
  47. Bits per pixel devoted to the blue component in the accumulation
  48. buffer.
  49. `accum_alpha_size` : int
  50. Bits per pixel devoted to the alpha component in the accumulation
  51. buffer.
  52. '''
  53. _attribute_names = [
  54. 'double_buffer',
  55. 'stereo',
  56. 'buffer_size',
  57. 'aux_buffers',
  58. 'sample_buffers',
  59. 'samples',
  60. 'red_size',
  61. 'green_size',
  62. 'blue_size',
  63. 'alpha_size',
  64. 'depth_size',
  65. 'stencil_size',
  66. 'accum_red_size',
  67. 'accum_green_size',
  68. 'accum_blue_size',
  69. 'accum_alpha_size',
  70. 'major_version',
  71. 'minor_version',
  72. 'forward_compatible',
  73. 'debug'
  74. ]
  75. major_version = None
  76. minor_version = None
  77. forward_compatible = None
  78. debug = None
  79. def __init__(self, **kwargs):
  80. '''Create a template config with the given attributes.
  81. Specify attributes as keyword arguments, for example::
  82. template = Config(double_buffer=True)
  83. '''
  84. for name in self._attribute_names:
  85. if name in kwargs:
  86. setattr(self, name, kwargs[name])
  87. else:
  88. setattr(self, name, None)
  89. def _requires_gl_3(self):
  90. if self.major_version is not None and self.major_version >= 3:
  91. return True
  92. if self.forward_compatible or self.debug:
  93. return True
  94. return False
  95. def get_gl_attributes(self):
  96. '''Return a list of attributes set on this config.
  97. :rtype: list of tuple (name, value)
  98. :return: All attributes, with unset attributes having a value of
  99. ``None``.
  100. '''
  101. return [(name, getattr(self, name)) for name in self._attribute_names]
  102. def match(self, canvas):
  103. '''Return a list of matching complete configs for the given canvas.
  104. :since: pyglet 1.2
  105. :Parameters:
  106. `canvas` : `Canvas`
  107. Display to host contexts created from the config.
  108. :rtype: list of `CanvasConfig`
  109. '''
  110. raise NotImplementedError('abstract')
  111. def create_context(self, share):
  112. '''Create a GL context that satisifies this configuration.
  113. :deprecated: Use `CanvasConfig.create_context`.
  114. :Parameters:
  115. `share` : `Context`
  116. If not None, a context with which to share objects with.
  117. :rtype: `Context`
  118. :return: The new context.
  119. '''
  120. raise gl.ConfigException(
  121. 'This config cannot be used to create contexts. '
  122. 'Use Config.match to created a CanvasConfig')
  123. def is_complete(self):
  124. '''Determine if this config is complete and able to create a context.
  125. Configs created directly are not complete, they can only serve
  126. as templates for retrieving a supported config from the system.
  127. For example, `pyglet.window.Screen.get_matching_configs` returns
  128. complete configs.
  129. :deprecated: Use ``isinstance(config, CanvasConfig)``.
  130. :rtype: bool
  131. :return: True if the config is complete and can create a context.
  132. '''
  133. return isinstance(self, CanvasConfig)
  134. def __repr__(self):
  135. import pprint
  136. return '%s(%s)' % (self.__class__.__name__,
  137. pprint.pformat(self.get_gl_attributes()))
  138. class CanvasConfig(Config):
  139. '''OpenGL configuration for a particular canvas.
  140. Use `Config.match` to obtain an instance of this class.
  141. :since: pyglet 1.2
  142. :Ivariables:
  143. `canvas` : `Canvas`
  144. The canvas this config is valid on.
  145. '''
  146. def __init__(self, canvas, base_config):
  147. self.canvas = canvas
  148. self.major_version = base_config.major_version
  149. self.minor_version = base_config.minor_version
  150. self.forward_compatible = base_config.forward_compatible
  151. self.debug = base_config.debug
  152. def compatible(self, canvas):
  153. raise NotImplementedError('abstract')
  154. def create_context(self, share):
  155. '''Create a GL context that satisifies this configuration.
  156. :Parameters:
  157. `share` : `Context`
  158. If not None, a context with which to share objects with.
  159. :rtype: `Context`
  160. :return: The new context.
  161. '''
  162. raise NotImplementedError('abstract')
  163. def is_complete(self):
  164. return True
  165. class ObjectSpace(object):
  166. def __init__(self):
  167. # Textures and buffers scheduled for deletion the next time this
  168. # object space is active.
  169. self._doomed_textures = []
  170. self._doomed_buffers = []
  171. class Context(object):
  172. '''OpenGL context for drawing.
  173. Use `CanvasConfig.create_context` to create a context.
  174. :Ivariables:
  175. `object_space` : `ObjectSpace`
  176. An object which is shared between all contexts that share
  177. GL objects.
  178. '''
  179. #: Context share behaviour indicating that objects should not be
  180. #: shared with existing contexts.
  181. CONTEXT_SHARE_NONE = None
  182. #: Context share behaviour indicating that objects are shared with
  183. #: the most recently created context (the default).
  184. CONTEXT_SHARE_EXISTING = 1
  185. # Used for error checking, True if currently within a glBegin/End block.
  186. # Ignored if error checking is disabled.
  187. _gl_begin = False
  188. # gl_info.GLInfo instance, filled in on first set_current
  189. _info = None
  190. # List of (attr, check) for each driver/device-specific workaround that is
  191. # implemented. The `attr` attribute on this context is set to the result
  192. # of evaluating `check(gl_info)` the first time this context is used.
  193. _workaround_checks = [
  194. # GDI Generic renderer on Windows does not implement
  195. # GL_UNPACK_ROW_LENGTH correctly.
  196. ('_workaround_unpack_row_length',
  197. lambda info: info.get_renderer() == 'GDI Generic'),
  198. # Reportedly segfaults in text_input.py example with
  199. # "ATI Radeon X1600 OpenGL Engine"
  200. # glGenBuffers not exported by
  201. # "ATI Radeon X1270 x86/MMX/3DNow!/SSE2"
  202. # glGenBuffers not exported by
  203. # "Intel 965/963 Graphics Media Accelerator"
  204. ('_workaround_vbo',
  205. lambda info: (info.get_renderer().startswith('ATI Radeon X')
  206. or info.get_renderer() ==
  207. 'Intel 965/963 Graphics Media Accelerator')),
  208. # Some ATI cards on OS X start drawing from a VBO before it's written
  209. # to. In these cases pyglet needs to call glFinish() to flush the
  210. # pipeline after updating a buffer but before rendering.
  211. ('_workaround_vbo_finish',
  212. lambda info: ('ATI' in info.get_renderer() and
  213. info.have_version(1, 5) and
  214. _sys.platform == 'darwin')),
  215. ]
  216. def __init__(self, config, context_share=None):
  217. self.config = config
  218. self.context_share = context_share
  219. self.canvas = None
  220. if context_share:
  221. self.object_space = context_share.object_space
  222. else:
  223. self.object_space = ObjectSpace()
  224. def __repr__(self):
  225. return '%s()' % self.__class__.__name__
  226. def attach(self, canvas):
  227. if self.canvas is not None:
  228. self.detach()
  229. if not self.config.compatible(canvas):
  230. raise RuntimeError('Cannot attach %r to %r' % (canvas, self))
  231. self.canvas = canvas
  232. def detach(self):
  233. self.canvas = None
  234. def set_current(self):
  235. if not self.canvas:
  236. raise RuntimeError('Canvas has not been attached')
  237. # XXX not per-thread
  238. gl.current_context = self
  239. # XXX
  240. gl_info.set_active_context()
  241. glu_info.set_active_context()
  242. # Implement workarounds
  243. if not self._info:
  244. self._info = gl_info.GLInfo()
  245. self._info.set_active_context()
  246. for attr, check in self._workaround_checks:
  247. setattr(self, attr, check(self._info))
  248. # Release textures on this context scheduled for deletion
  249. if self.object_space._doomed_textures:
  250. textures = self.object_space._doomed_textures
  251. textures = (gl.GLuint * len(textures))(*textures)
  252. gl.glDeleteTextures(len(textures), textures)
  253. self.object_space._doomed_textures = []
  254. # Release buffers on this context scheduled for deletion
  255. if self.object_space._doomed_buffers:
  256. buffers = self.object_space._doomed_buffers
  257. buffers = (gl.GLuint * len(buffers))(*buffers)
  258. gl.glDeleteBuffers(len(buffers), buffers)
  259. self.object_space._doomed_buffers = []
  260. def destroy(self):
  261. '''Release the context.
  262. The context will not be useable after being destroyed. Each platform
  263. has its own convention for releasing the context and the buffer(s)
  264. that depend on it in the correct order; this should never be called
  265. by an application.
  266. '''
  267. self.detach()
  268. if gl.current_context is self:
  269. gl.current_context = None
  270. gl_info.remove_active_context()
  271. # Switch back to shadow context.
  272. if gl._shadow_window is not None:
  273. gl._shadow_window.switch_to()
  274. def delete_texture(self, texture_id):
  275. '''Safely delete a texture belonging to this context.
  276. Usually, the texture is released immediately using
  277. ``glDeleteTextures``, however if another context that does not share
  278. this context's object space is currently active, the deletion will
  279. be deferred until an appropriate context is activated.
  280. :Parameters:
  281. `texture_id` : int
  282. The OpenGL name of the texture to delete.
  283. '''
  284. if self.object_space is gl.current_context.object_space:
  285. id = gl.GLuint(texture_id)
  286. gl.glDeleteTextures(1, id)
  287. else:
  288. self.object_space._doomed_textures.append(texture_id)
  289. def delete_buffer(self, buffer_id):
  290. '''Safely delete a buffer object belonging to this context.
  291. This method behaves similarly to `delete_texture`, though for
  292. ``glDeleteBuffers`` instead of ``glDeleteTextures``.
  293. :Parameters:
  294. `buffer_id` : int
  295. The OpenGL name of the buffer to delete.
  296. :since: pyglet 1.1
  297. '''
  298. if self.object_space is gl.current_context.object_space and False:
  299. id = gl.GLuint(buffer_id)
  300. gl.glDeleteBuffers(1, id)
  301. else:
  302. self.object_space._doomed_buffers.append(buffer_id)
  303. def get_info(self):
  304. '''Get the OpenGL information for this context.
  305. :since: pyglet 1.2
  306. :rtype: `GLInfo`
  307. '''
  308. return self._info