1 """Texture classes.
2
3 @todo: Check OpenGL memory layout; do shaders use the same coordinates as C{numpy} does?
4 @todo: Implement depth textures.
5 @todo: Implement C{__getitem__} and C{__setitem__} for subimages (C{glTexSubImage3D}, C{glGetTexImage} with C{format=GL_RED} etc.).
6 @todo: Implement image textures.
7
8 @author: Stephan Wenger
9 @date: 2012-02-29
10 """
11
12 import numpy as _np
13
14 import glitter.raw as _gl
15 from glitter.utils import texture_compare_funcs, texture_compare_modes, texture_min_filters, texture_mag_filters, texture_swizzles, texture_wrapmodes, dtype_to_gl_iformat, dtype_to_gl_format, gl_iformat_to_dtype, gl_iformat_to_dtype, dtype_to_gl_format, gl_iformat_to_gl_type, Datatype, coerce_array, ManagedObject, BindReleaseObject, float32
16
17 -class Texture(ManagedObject, BindReleaseObject):
18 _generate_id = _gl.glGenTextures
19 _delete_id = _gl.glDeleteTextures
20 _db = "textures"
21
22 _ndim = NotImplemented
23 _set = NotImplemented
24
25 compare_funcs = texture_compare_funcs
26 compare_modes = texture_compare_modes
27 min_filters = texture_min_filters
28 mag_filters = texture_mag_filters
29 swizzles = texture_swizzles
30 wrapmodes = texture_wrapmodes
31
33 return self._context.texture_units.bind(self)
34
36 self._context.texture_units.release(self)
37
38 - def __init__(self, data=None, shape=None, dtype=None, mipmap=False, context=None):
39 if any(x is NotImplemented for x in (self._ndim, self._set)):
40 raise TypeError("%s is abstract" % self.__class__.__name__)
41 super(Texture, self).__init__(context=context)
42 self.set_data(data, shape, dtype, mipmap)
43
44 - def __getitem__(self, key):
45 """Return a tuple describing a texture layer.
46
47 This is mainly provided as a convenience notation for binding texture
48 layers to L{Framebuffer}s.
49 """
50
51 return (self, key)
52
55
56 - def set_data(self, data=None, shape=None, dtype=None, level=0, mipmap=False):
57 if data is None:
58 if shape is None:
59 raise ValueError("must specify either data or shape")
60 if dtype is None:
61 dtype = float32
62 else:
63 data = coerce_array(data, dtype)
64 if shape is not None:
65 data = data.reshape(shape)
66 shape = data.shape
67 dtype = Datatype.from_numpy(data.dtype)
68
69 if len(shape) != self._ndim:
70 raise TypeError("shape must be %d-dimensional" % self._ndim)
71
72 _iformat = dtype_to_gl_iformat[dtype, shape[-1]]
73 _format = dtype_to_gl_format[dtype, shape[-1]]
74 _type = dtype._as_gl()
75 _data = data.ctypes if data is not None else _gl.POINTER(_gl.GLvoid)()
76 _gl.glPixelStorei(_gl.GL_UNPACK_ALIGNMENT, 1)
77 with self:
78 args = [self._target, level, _iformat] + list(reversed(shape[:-1])) + [0, _format, _type, _data]
79 self._set(*args)
80 if dtype.is_float():
81 self.min_filter = self.min_filters.LINEAR_MIPMAP_LINEAR if mipmap else self.min_filters.LINEAR
82 self.mag_filter = self.mag_filters.LINEAR
83 else:
84 self.min_filter = self.min_filters.NEAREST
85 self.mag_filter = self.mag_filters.NEAREST
86
87 if mipmap:
88 self.generate_mipmap()
89
90 - def get_data(self, level=0):
91 _data = _np.empty(self.shape, dtype=self.dtype.as_numpy())
92 _gl.glPixelStorei(_gl.GL_PACK_ALIGNMENT, 1)
93 with self:
94 _gl.glGetTexImage(self._target, level, self._format, self._type, _data.ctypes)
95 return _data
96
98 with self:
99 _gl.glGenerateMipmap(self._target)
100
101 @property
103 return self.get_data()
104
105 @data.setter
106 - def data(self, data):
108
109 @property
111 with self:
112 colors = gl_iformat_to_dtype[self._iformat][1]
113 _width = _gl.GLint()
114 _gl.glGetTexLevelParameteriv(self._target, 0, _gl.GL_TEXTURE_WIDTH, _gl.pointer(_width))
115 if self._ndim == 2:
116 return (_width.value, colors)
117 _height = _gl.GLint()
118 _gl.glGetTexLevelParameteriv(self._target, 0, _gl.GL_TEXTURE_HEIGHT, _gl.pointer(_height))
119 if self._ndim == 3:
120 return (_height.value, _width.value, colors)
121 _depth = _gl.GLint()
122 _gl.glGetTexLevelParameteriv(self._target, 0, _gl.GL_TEXTURE_DEPTH, _gl.pointer(_depth))
123 if self._ndim == 4:
124 return (_depth.value, _height.value, _width.value, colors)
125
126 @property
129
130 @property
136
137 @property
140
141 @property
144
145 @property
146 - def base_level(self):
147 _base_level = _gl.GLint()
148 with self:
149 _gl.glGetTexParameterIiv(self._target, _gl.GL_TEXTURE_BASE_LEVEL, _gl.pointer(_base_level))
150 return _base_level.value
151
152 @base_level.setter
153 - def base_level(self, base_level):
154 with self:
155 _gl.glTexParameterIiv(self._target, _gl.GL_TEXTURE_BASE_LEVEL, _gl.pointer(_gl.GLint(base_level)))
156
157 @property
158 - def border_color(self):
159 if self.dtype.is_float():
160 _border_color = (_gl.GLfloat * 4)()
161 with self:
162 _gl.glGetTexParameterfv(self._target, _gl.GL_TEXTURE_BORDER_COLOR, _border_color)
163 elif self.dtype.is_signed():
164 _border_color = (_gl.GLint * 4)()
165 with self:
166 _gl.glGetTexParameterIiv(self._target, _gl.GL_TEXTURE_BORDER_COLOR, _border_color)
167 else:
168 _border_color = (_gl.GLuint * 4)()
169 with self:
170 _gl.glGetTexParameterIuiv(self._target, _gl.GL_TEXTURE_BORDER_COLOR, _border_color)
171 return [_border_color[i] for i in range(4)]
172
173 @border_color.setter
174 - def border_color(self, border_color):
175 if self.dtype.is_float():
176 _border_color = (_gl.GLfloat * 4)()
177 for i, v in zip(range(4), border_color):
178 _border_color[i] = v
179 with self:
180 _gl.glTexParameterfv(self._target, _gl.GL_TEXTURE_BORDER_COLOR, _border_color)
181 elif self.dtype.is_signed():
182 _border_color = (_gl.GLint * 4)()
183 for i, v in zip(range(4), border_color):
184 _border_color[i] = v
185 with self:
186 _gl.glTexParameterIiv(self._target, _gl.GL_TEXTURE_BORDER_COLOR, _border_color)
187 else:
188 _border_color = (_gl.GLuint * 4)()
189 for i, v in zip(range(4), border_color):
190 _border_color[i] = v
191 with self:
192 _gl.glTexParameterIuiv(self._target, _gl.GL_TEXTURE_BORDER_COLOR, _border_color)
193
194 @property
195 - def compare_func(self):
196 _compare_func = _gl.GLenum()
197 with self:
198 _gl.glGetTexParameterIuiv(self._target, _gl.GL_TEXTURE_COMPARE_FUNC, _gl.pointer(_compare_func))
199 return self.compare_funcs[_compare_func.value]
200
201 @compare_func.setter
202 - def compare_func(self, compare_func):
203 _compare_func = _gl.GLenum(self.compare_funcs(compare_func)._value)
204 with self:
205 _gl.glTexParameterIuiv(self._target, _gl.GL_TEXTURE_COMPARE_FUNC, _gl.pointer(_compare_func))
206
207 @property
208 - def compare_mode(self):
209 _compare_mode = _gl.GLenum()
210 with self:
211 _gl.glGetTexParameterIuiv(self._target, _gl.GL_TEXTURE_COMPARE_MODE, _gl.pointer(_compare_mode))
212 return self.compare_modes[_compare_mode.value]
213
214 @compare_mode.setter
215 - def compare_mode(self, compare_mode):
216 _compare_mode = _gl.GLenum(self.compare_modes(compare_mode)._value)
217 with self:
218 _gl.glTexParameterIuiv(self._target, _gl.GL_TEXTURE_COMPARE_MODE, _gl.pointer(_compare_mode))
219
220 @property
222 _immutable_format = _gl.GLenum()
223 with self:
224 _gl.glGetTexParameterIuiv(self._target, _gl.GL_TEXTURE_COMPARE_MODE, _gl.pointer(_immutable_format))
225 return bool(_immutable_format.value)
226
227 @property
228 - def lod_bias(self):
229 _lod_bias = _gl.GLfloat()
230 with self:
231 _gl.glGetTexParameterfv(self._target, _gl.GL_TEXTURE_LOD_BIAS, _gl.pointer(_lod_bias))
232 return _lod_bias.value
233
234 @lod_bias.setter
235 - def lod_bias(self, lod_bias):
236 with self:
237 _gl.glTexParameterfv(self._target, _gl.GL_TEXTURE_LOD_BIAS, _gl.pointer(_gl.GLfloat(lod_bias)))
238
239 @property
240 - def min_filter(self):
241 _min_filter = _gl.GLenum()
242 with self:
243 _gl.glGetTexParameterIuiv(self._target, _gl.GL_TEXTURE_MIN_FILTER, _gl.pointer(_min_filter))
244 return self.min_filters[_min_filter.value]
245
246 @min_filter.setter
247 - def min_filter(self, min_filter):
248 _min_filter = _gl.GLenum(self.min_filters(min_filter)._value)
249 with self:
250 _gl.glTexParameterIuiv(self._target, _gl.GL_TEXTURE_MIN_FILTER, _gl.pointer(_min_filter))
251
252 @property
253 - def mag_filter(self):
254 _mag_filter = _gl.GLenum()
255 with self:
256 _gl.glGetTexParameterIuiv(self._target, _gl.GL_TEXTURE_MAG_FILTER, _gl.pointer(_mag_filter))
257 return self.mag_filters[_mag_filter.value]
258
259 @mag_filter.setter
260 - def mag_filter(self, mag_filter):
261 _mag_filter = _gl.GLenum(self.mag_filters(mag_filter)._value)
262 with self:
263 _gl.glTexParameterIuiv(self._target, _gl.GL_TEXTURE_MAG_FILTER, _gl.pointer(_mag_filter))
264
265 @property
267 _min_lod = _gl.GLint()
268 with self:
269 _gl.glGetTexParameterIiv(self._target, _gl.GL_TEXTURE_MIN_LOD, _gl.pointer(_min_lod))
270 return _min_lod.value
271
272 @min_lod.setter
273 - def min_lod(self, min_lod):
274 with self:
275 _gl.glTexParameterIiv(self._target, _gl.GL_TEXTURE_MIN_LOD, _gl.pointer(_gl.GLint(min_lod)))
276
277 @property
279 _max_lod = _gl.GLint()
280 with self:
281 _gl.glGetTexParameterIiv(self._target, _gl.GL_TEXTURE_MAX_LOD, _gl.pointer(_max_lod))
282 return _max_lod.value
283
284 @max_lod.setter
285 - def max_lod(self, max_lod):
286 with self:
287 _gl.glTexParameterIiv(self._target, _gl.GL_TEXTURE_MAX_LOD, _gl.pointer(_gl.GLint(max_lod)))
288
289 @property
290 - def max_level(self):
291 _max_level = _gl.GLint()
292 with self:
293 _gl.glGetTexParameterIiv(self._target, _gl.GL_TEXTURE_MAX_LEVEL, _gl.pointer(_max_level))
294 return _max_level.value
295
296 @max_level.setter
297 - def max_level(self, max_level):
298 with self:
299 _gl.glTexParameterIiv(self._target, _gl.GL_TEXTURE_MAX_LEVEL, _gl.pointer(_gl.GLint(max_level)))
300
301 @property
302 - def swizzle_r(self):
303 _swizzle_r = _gl.GLenum()
304 with self:
305 _gl.glGetTexParameterIuiv(self._target, _gl.GL_TEXTURE_SWIZZLE_R, _gl.pointer(_swizzle_r))
306 return self.swizzles[_swizzle_r.value]
307
308 @swizzle_r.setter
309 - def swizzle_r(self, swizzle_r):
310 _swizzle_r = _gl.GLenum(self.swizzles(swizzle_r)._value)
311 with self:
312 _gl.glTexParameterIuiv(self._target, _gl.GL_TEXTURE_SWIZZLE_R, _gl.pointer(_swizzle_r))
313
314 @property
315 - def swizzle_g(self):
316 _swizzle_g = _gl.GLenum()
317 with self:
318 _gl.glGetTexParameterIuiv(self._target, _gl.GL_TEXTURE_SWIZZLE_G, _gl.pointer(_swizzle_g))
319 return self.swizzles[_swizzle_g.value]
320
321 @swizzle_g.setter
322 - def swizzle_g(self, swizzle_g):
323 _swizzle_g = _gl.GLenum(self.swizzles(swizzle_g)._value)
324 with self:
325 _gl.glTexParameterIuiv(self._target, _gl.GL_TEXTURE_SWIZZLE_G, _gl.pointer(_swizzle_g))
326
327 @property
328 - def swizzle_b(self):
329 _swizzle_b = _gl.GLenum()
330 with self:
331 _gl.glGetTexParameterIuiv(self._target, _gl.GL_TEXTURE_SWIZZLE_B, _gl.pointer(_swizzle_b))
332 return self.swizzles[_swizzle_b.value]
333
334 @swizzle_b.setter
335 - def swizzle_b(self, swizzle_b):
336 _swizzle_b = _gl.GLenum(self.swizzles(swizzle_b)._value)
337 with self:
338 _gl.glTexParameterIuiv(self._target, _gl.GL_TEXTURE_SWIZZLE_B, _gl.pointer(_swizzle_b))
339
340 @property
341 - def swizzle_a(self):
342 _swizzle_a = _gl.GLenum()
343 with self:
344 _gl.glGetTexParameterIuiv(self._target, _gl.GL_TEXTURE_SWIZZLE_A, _gl.pointer(_swizzle_a))
345 return self.swizzles[_swizzle_a.value]
346
347 @swizzle_a.setter
348 - def swizzle_a(self, swizzle_a):
349 _swizzle_a = _gl.GLenum(self.swizzles(swizzle_a)._value)
350 with self:
351 _gl.glTexParameterIuiv(self._target, _gl.GL_TEXTURE_SWIZZLE_A, _gl.pointer(_swizzle_a))
352
353 @property
354 - def swizzle_rgba(self):
355 _swizzle_rgba = (_gl.GLenum * 4)()
356 with self:
357 _gl.glGetTexParameterIuiv(self._target, _gl.GL_TEXTURE_SWIZZLE_RGBA, _swizzle_rgba)
358 return [self.swizzles[_swizzle_rgba[i]] for i in range(4)]
359
360 @swizzle_rgba.setter
361 - def swizzle_rgba(self, swizzle_rgba):
362 _swizzle_rgba = (_gl.GLenum * 4)()
363 for i, v in zip(range(4), swizzle_rgba):
364 _swizzle_rgba[i] = self.swizzles(v)._value
365 with self:
366 _gl.glTexParameterIuiv(self._target, _gl.GL_TEXTURE_SWIZZLE_RGBA, _swizzle_rgba)
367
368 @property
370 _wrap_s = _gl.GLenum()
371 with self:
372 _gl.glGetTexParameterIuiv(self._target, _gl.GL_TEXTURE_WRAP_S, _gl.pointer(_wrap_s))
373 return self.wrapmodes[_wrap_s.value]
374
375 @wrap_s.setter
376 - def wrap_s(self, wrap_s):
377 _wrap_s = _gl.GLenum(self.wrapmodes(wrap_s)._value)
378 with self:
379 _gl.glTexParameterIuiv(self._target, _gl.GL_TEXTURE_WRAP_S, _gl.pointer(_wrap_s))
380
381 @property
383 _wrap_t = _gl.GLenum()
384 with self:
385 _gl.glGetTexParameterIuiv(self._target, _gl.GL_TEXTURE_WRAP_T, _gl.pointer(_wrap_t))
386 return self.wrapmodes[_wrap_t.value]
387
388 @wrap_t.setter
389 - def wrap_t(self, wrap_t):
390 _wrap_t = _gl.GLenum(self.wrapmodes(wrap_t)._value)
391 with self:
392 _gl.glTexParameterIuiv(self._target, _gl.GL_TEXTURE_WRAP_T, _gl.pointer(_wrap_t))
393
394 @property
396 _wrap_r = _gl.GLenum()
397 with self:
398 _gl.glGetTexParameterIuiv(self._target, _gl.GL_TEXTURE_WRAP_R, _gl.pointer(_wrap_r))
399 return self.wrapmodes[_wrap_r.value]
400
401 @wrap_r.setter
402 - def wrap_r(self, wrap_r):
403 _wrap_r = _gl.GLenum(self.wrapmodes(wrap_r)._value)
404 with self:
405 _gl.glTexParameterIuiv(self._target, _gl.GL_TEXTURE_WRAP_R, _gl.pointer(_wrap_r))
406
407 -class Texture1D(Texture):
408 _target = _gl.GL_TEXTURE_1D
409 _binding = "texture_binding_1d"
410 _ndim = 2
411 _set = _gl.glTexImage1D
412
413 -class Texture2D(Texture):
414 _target = _gl.GL_TEXTURE_2D
415 _binding = "texture_binding_2d"
416 _ndim = 3
417 _set = _gl.glTexImage2D
418
419 -class TextureArray1D(Texture):
420 _target = _gl.GL_TEXTURE_1D_ARRAY
421 _binding = "texture_binding_1d_array"
422 _ndim = 3
423 _set = _gl.glTexImage2D
424
425 -class RectangleTexture(Texture):
426 _target = _gl.GL_TEXTURE_RECTANGLE
427 _binding = "texture_binding_rectangle"
428 _ndim = 3
429 _set = _gl.glTexImage2D
430
431 -class BufferTexture(Texture):
432 """Texture that stores its data in a buffer.
433
434 @todo: Override constructor, C{set_data} and C{get_data}; use C{glTexBuffer}
435 """
436
437 _target = _gl.GL_TEXTURE_BUFFER
438 _binding = "texture_binding_buffer"
439 _ndim = 3
440 _set = _gl.glTexImage2D
441
442 -class CubeMapTexture(Texture):
443 _target = _gl.GL_TEXTURE_CUBE_MAP
444 _binding = "texture_binding_cube_map"
445 _ndim = 3
446 _set = _gl.glTexImage2D
447
449 _target = _gl.GL_TEXTURE_2D_MULTISAMPLE
450 _binding = "texture_binding_2d_multisample"
451 _ndim = 3
452 _set = _gl.glTexImage2D
453
454 -class Texture3D(Texture):
455 _target = _gl.GL_TEXTURE_3D
456 _binding = "texture_binding_3d"
457 _ndim = 4
458 _set = _gl.glTexImage3D
459
460 -class TextureArray2D(Texture):
461 _target = _gl.GL_TEXTURE_2D_ARRAY
462 _binding = "texture_binding_2d_array"
463 _ndim = 4
464 _set = _gl.glTexImage3D
465
467 _target = _gl.GL_TEXTURE_2D_MULTISAMPLE_ARRAY
468 _binding = "texture_binding_2d_multisample_array"
469 _ndim = 4
470 _set = _gl.glTexImage3D
471
472 __all__ = [
473 "Texture",
474 "Texture1D",
475 "Texture2D",
476 "TextureArray1D",
477 "RectangleTexture",
478 "BufferTexture",
479 "CubeMapTexture",
480 "MultisampleTexture2D",
481 "Texture3D",
482 "TextureArray2D",
483 "MultisampleTextureArray2D",
484 ]
485