1 """Descriptors for texture image units.
2
3 @author: Stephan Wenger
4 @date: 2012-02-29
5 """
6
7 import itertools as _itertools
8
9 import glitter.raw as _gl
10 from glitter.utils import BindableObject, GlitterError
11 from glitter.contexts.proxies import BindingProxy
12
13 -class TextureUnit(BindableObject):
14 """Proxy for a texture unit.
15
16 @warning: For internal use by L{TextureUnitList} only. Do not instantiate
17 or use directly; use the methods of L{TextureUnitList} instead.
18 """
19
20 _binding = "active_texture"
21
22 - def __init__(self, context, _id):
23 super(TextureUnit, self).__init__(context=context)
24 self._context = context
25 self._id = _id
26 self._use_count = 0
27
29 return "GL_TEXTURE%d" % (self._id - _gl.GL_TEXTURE0)
30
32 self._context.active_texture = self
33
34 - def is_available(self):
35 return self._use_count == 0
36
37 texture_binding_1d = BindingProxy(_gl.glBindTexture, [_gl.GL_TEXTURE_1D ])
38 texture_binding_1d_array = BindingProxy(_gl.glBindTexture, [_gl.GL_TEXTURE_1D_ARRAY ])
39 texture_binding_2d = BindingProxy(_gl.glBindTexture, [_gl.GL_TEXTURE_2D ])
40 texture_binding_2d_array = BindingProxy(_gl.glBindTexture, [_gl.GL_TEXTURE_2D_ARRAY ])
41 texture_binding_2d_multisample = BindingProxy(_gl.glBindTexture, [_gl.GL_TEXTURE_2D_MULTISAMPLE ])
42 texture_binding_2d_multisample_array = BindingProxy(_gl.glBindTexture, [_gl.GL_TEXTURE_2D_MULTISAMPLE_ARRAY])
43 texture_binding_3d = BindingProxy(_gl.glBindTexture, [_gl.GL_TEXTURE_3D ])
44 texture_binding_buffer = BindingProxy(_gl.glBindTexture, [_gl.GL_TEXTURE_BUFFER ])
45 texture_binding_cube_map = BindingProxy(_gl.glBindTexture, [_gl.GL_TEXTURE_CUBE_MAP ])
46 texture_binding_rectangle = BindingProxy(_gl.glBindTexture, [_gl.GL_TEXTURE_RECTANGLE ])
47 sampler_binding = BindingProxy(_gl.glBindSampler, ["_unit" ])
48
49 -class TextureUnitList(object):
50 """Proxy for the list of available texture units.
51
52 @warning: C{TextureUnitList}s are created by their respective context only.
53 Do not instantiate them directly. Using the C{TextureUnitList}'s L{bind}
54 and L{release} methods directly is usually not necessary; L{Shader}s bind
55 their textures automatically, and the L{bind<Texture.bind>} method of
56 L{Texture}s is delegated to the C{TextureUnitList}.
57 """
58
59 - def __init__(self, context):
60 self._context = context
61 num_units = context.max_combined_texture_image_units
62 if not 0 < num_units < 4096:
63 raise GlitterError("implausible number of texture units detected; are you sure there is a current OpenGL context?")
64 self._texture_units = [TextureUnit(context, _gl.GL_TEXTURE0 + i) for i in range(num_units)]
65 self._context.active_texture = self[0]
66 self._bound_textures = dict()
67
68 - def __getitem__(self, index):
69 return self._texture_units[index]
70
72 return len(self._texture_units)
73
75 return "[%d texture units]" % len(self)
76
79
80 - def bind(self, texture):
81 """Bind `texture` to a free unit and return the unit id."""
82 if texture in self._bound_textures:
83 unit = self._bound_textures[texture]
84 unit._use_count += 1
85 else:
86 try:
87 unit = _itertools.dropwhile(lambda x: not x.is_available(), self).next()
88 except StopIteration:
89 raise RuntimeError("no free texture units available")
90 setattr(unit, texture._binding, texture)
91 self._bound_textures[texture] = unit
92 unit._use_count = 1
93 return unit._id - _gl.GL_TEXTURE0
94
95 - def release(self, texture):
96 """Unbind `texture`."""
97 unit = self._bound_textures[texture]
98 if unit._use_count == 1:
99 setattr(unit, texture._binding, None)
100 del self._bound_textures[texture]
101 unit._use_count = 0
102 else:
103 unit._use_count -= 1
104