This file is indexed.

/usr/share/pyshared/pymt/texture.py is in python-pymt 0.5.1-0ubuntu3.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
'''
Texture: abstraction to handle GL texture, and region
'''

__all__ = ('Texture', 'TextureRegion')

import os
import re
from array import array
from pymt import pymt_logger
import OpenGL
from OpenGL.GL import GL_RGBA, GL_UNSIGNED_BYTE, GL_TEXTURE_MIN_FILTER, \
        GL_TEXTURE_MAG_FILTER, GL_TEXTURE_WRAP_T, GL_TEXTURE_WRAP_S, \
        GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_RECTANGLE_ARB, \
        GL_CLAMP_TO_EDGE, GL_LINEAR_MIPMAP_LINEAR, GL_GENERATE_MIPMAP, \
        GL_TRUE, GL_LINEAR, GL_UNPACK_ALIGNMENT, GL_BGR, GL_BGRA, GL_RGB, \
        glEnable, glDisable, glBindTexture, glTexParameteri, glTexImage2D, \
        glTexSubImage2D, glFlush, glGenTextures, glDeleteTextures, \
        GLubyte, glPixelStorei
from OpenGL.GL.NV.texture_rectangle import glInitTextureRectangleNV
from OpenGL.GL.ARB.texture_rectangle import glInitTextureRectangleARB
from OpenGL.extensions import hasGLExtension

# for a specific bug in 3.0.0, about deletion of framebuffer.
# same hack as FBO :(
OpenGLversion = tuple(int(re.match('^(\d+)', i).groups()[0]) \
                      for i in OpenGL.__version__.split('.'))
if OpenGLversion < (3, 0, 1):
    try:
        import numpy
        have_numpy = True
    except Exception:
        have_numpy = False


def _nearest_pow2(v):
    # From http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
    # Credit: Sean Anderson
    v -= 1
    v |= v >> 1
    v |= v >> 2
    v |= v >> 4
    v |= v >> 8
    v |= v >> 16
    return v + 1

def _is_pow2(v):
    # http://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
    return (v & (v - 1)) == 0

#
# Releasing texture through GC is problematic
# GC can happen in a middle of glBegin/glEnd
# So, to prevent that, call the _texture_release
# at flip time.
_texture_release_list = []
def _texture_release(*largs):
    global _texture_release_list
    for texture_id in _texture_release_list:
        # try/except are here to prevent an error like this :
        # Exception TypeError: "'NoneType' object is not callable"
        # in <bound method Texture.__del__ of <pymt.texture.Texture
        # object at 0x3a1acb0>> ignored
        #
        # It occured only when leaving the application.
        # So, maybe numpy or pyopengl is unloaded, and have weird things happen.
        #
        try:
            if OpenGLversion < (3, 0, 1) and have_numpy:
                glDeleteTextures(numpy.array(texture_id))
            else:
                glDeleteTextures(texture_id)
        except:
            pass

    # let the list to 0
    _texture_release_list = []

class Texture(object):
    '''Handle a OpenGL texture. This class can be used to create simple texture
    or complex texture based on ImageData.'''

    __slots__ = ('tex_coords', '_width', '_height', '_target', '_id', '_mipmap',
                '_gl_wrap', '_gl_min_filter', '_gl_mag_filter', '_rectangle')

    _has_bgr = None
    _has_bgr_tested = False
    _has_texture_nv = None
    _has_texture_arb = None

    def __init__(self, width, height, target, texid, mipmap=False, rectangle=False):
        self.tex_coords     = (0., 0., 1., 0., 1., 1., 0., 1.)
        self._width         = width
        self._height        = height
        self._target        = target
        self._id            = texid
        self._mipmap        = mipmap
        self._gl_wrap       = None
        self._gl_min_filter = None
        self._gl_mag_filter = None
        self._rectangle     = rectangle

    def __del__(self):
        # Add texture deletion outside GC call.
        # This case happen if some texture have been not deleted
        # before application exit...
        if _texture_release_list is not None:
            _texture_release_list.append(self.id)

    @property
    def mipmap(self):
        '''Return True if the texture have mipmap enabled (readonly)'''
        return self._mipmap

    @property
    def rectangle(self):
        '''Return True if the texture is a rectangle texture (readonly)'''
        return self._rectangle

    @property
    def id(self):
        '''Return the OpenGL ID of the texture (readonly)'''
        return self._id

    @property
    def target(self):
        '''Return the OpenGL target of the texture (readonly)'''
        return self._target

    @property
    def width(self):
        '''Return the width of the texture (readonly)'''
        return self._width

    @property
    def height(self):
        '''Return the height of the texture (readonly)'''
        return self._height

    def flip_vertical(self):
        '''Flip tex_coords for vertical displaying'''
        a, b, c, d, e, f, g, h = self.tex_coords
        self.tex_coords = (g, h, e, f, c, d, a, b)

    def get_region(self, x, y, width, height):
        '''Return a part of the texture, from (x,y) with (width,height)
        dimensions'''
        return TextureRegion(x, y, width, height, self)

    def bind(self):
        '''Bind the texture to current opengl state'''
        glBindTexture(self.target, self.id)

    def enable(self):
        '''Do the appropriate glEnable()'''
        glEnable(self.target)

    def disable(self):
        '''Do the appropriate glDisable()'''
        glDisable(self.target)

    def _get_min_filter(self):
        return self._gl_min_filter
    def _set_min_filter(self, x):
        if x == self._gl_min_filter:
            return
        self.bind()
        glTexParameteri(self.target, GL_TEXTURE_MIN_FILTER, x)
        self._gl_min_filter = x
    min_filter = property(_get_min_filter, _set_min_filter,
                          doc='''Get/set the GL_TEXTURE_MIN_FILTER property''')

    def _get_mag_filter(self):
        return self._gl_mag_filter
    def _set_mag_filter(self, x):
        if x == self._gl_mag_filter:
            return
        self.bind()
        glTexParameteri(self.target, GL_TEXTURE_MAG_FILTER, x)
        self._gl_mag_filter = x
    mag_filter = property(_get_mag_filter, _set_mag_filter,
                          doc='''Get/set the GL_TEXTURE_MAG_FILTER property''')

    def _get_wrap(self):
        return self._gl_wrap
    def _set_wrap(self, wrap):
        if wrap == self._gl_wrap:
            return
        self.bind()
        glTexParameteri(self.target, GL_TEXTURE_WRAP_S, wrap)
        glTexParameteri(self.target, GL_TEXTURE_WRAP_T, wrap)
    wrap = property(_get_wrap, _set_wrap,
                    doc='''Get/set the GL_TEXTURE_WRAP_S,T property''')

    @staticmethod
    def create(width, height, format=GL_RGBA, rectangle=False, mipmap=False):
        '''Create a texture based on size.'''
        target = GL_TEXTURE_2D
        if rectangle:
            if _is_pow2(width) and _is_pow2(height):
                rectangle = False
            else:
                rectangle = False

                try:
                    if Texture._has_texture_nv is None:
                        Texture._has_texture_nv = glInitTextureRectangleNV()
                    if Texture._has_texture_nv:
                        target = GL_TEXTURE_RECTANGLE_NV
                        rectangle = True
                except Exception:
                    pass

                try:
                    if Texture._has_texture_arb is None:
                        Texture._has_texture_arb = glInitTextureRectangleARB()
                    if not rectangle and Texture._has_texture_arb:
                        target = GL_TEXTURE_RECTANGLE_ARB
                        rectangle = True
                except Exception:
                    pass

                if not rectangle:
                    pymt_logger.debug(
                        'Texture: Missing support for rectangular texture')
                else:
                    # Can't do mipmap with rectangle texture
                    mipmap = False

        if rectangle:
            texture_width = width
            texture_height = height
        else:
            texture_width = _nearest_pow2(width)
            texture_height = _nearest_pow2(height)

        texid = glGenTextures(1)
        texture = Texture(texture_width, texture_height, target, texid,
                          mipmap=mipmap)

        texture.bind()
        texture.wrap        = GL_CLAMP_TO_EDGE
        if mipmap:
            texture.min_filter  = GL_LINEAR_MIPMAP_LINEAR
            #texture.mag_filter  = GL_LINEAR_MIPMAP_LINEAR
            glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE)
        else:
            texture.min_filter  = GL_LINEAR
            texture.mag_filter  = GL_LINEAR

        if not Texture.is_gl_format_supported(format):
            format = Texture.convert_gl_format(format)

        data = (GLubyte * texture_width * texture_height *
                Texture.gl_format_size(format))()
        glTexImage2D(target, 0, format, texture_width, texture_height, 0,
                     format, GL_UNSIGNED_BYTE, data)

        if rectangle:
            texture.tex_coords = \
                (0., 0., width, 0., width, height, 0., height)

        glFlush()

        if texture_width == width and texture_height == height:
            return texture

        return texture.get_region(0, 0, width, height)

    @staticmethod
    def create_from_data(im, rectangle=True, mipmap=False):
        '''Create a texture from an ImageData class'''

        format = Texture.mode_to_gl_format(im.mode)

        texture = Texture.create(im.width, im.height,
                                 format, rectangle=rectangle,
                                 mipmap=mipmap)
        if texture is None:
            return None

        texture.blit_data(im)

        return texture

    def blit_data(self, im, pos=(0, 0)):
        '''Replace a whole texture with a image data'''
        self.blit_buffer(im.data, size=(im.width, im.height),
                         mode=im.mode, pos=pos)

    def blit_buffer(self, buffer, size=None, mode='RGB', format=None,
                    pos=(0, 0), buffertype=GL_UNSIGNED_BYTE):
        '''Blit a buffer into a texture.

        :Parameters:
            `buffer` : str
                Image data
            `size` : tuple, default to texture size
                Size of the image (width, height)
            `mode` : str, default to 'RGB'
                Image mode, can be one of RGB, RGBA, BGR, BGRA
            `format` : glconst, default to None
                if format is passed, it will be used instead of mode
            `pos` : tuple, default to (0, 0)
                Position to blit in the texture
            `buffertype` : glglconst, default to GL_UNSIGNED_BYTE
                Type of the data buffer
        '''
        if size is None:
            size = self.size
        if format is None:
            format = self.mode_to_gl_format(mode)
        target = self.target
        glBindTexture(target, self.id)
        glEnable(target)

        # activate 1 alignement, of window failed on updating weird size
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1)

        # need conversion ?
        pdata, format = self._convert_buffer(buffer, format)

        # transfer the new part of texture
        glTexSubImage2D(target, 0, pos[0], pos[1],
                        size[0], size[1], format,
                        buffertype, pdata)

        glFlush()
        glDisable(target)

    @staticmethod
    def has_bgr():
        if not Texture._has_bgr_tested:
            pymt_logger.warning('Texture: BGR/BGRA format is not supported by'
                                'your graphic card')
            pymt_logger.warning('Texture: Software conversion will be done to'
                                'RGB/RGBA')
            Texture._has_bgr = hasGLExtension('GL_EXT_bgra')
            Texture._has_bgr_tested = True
        return Texture._has_bgr

    @staticmethod
    def is_gl_format_supported(format):
        if format in (GL_BGR, GL_BGRA):
            return not Texture.has_bgr()
        return True

    @staticmethod
    def convert_gl_format(format):
        if format == GL_BGR:
            return GL_RGB
        elif format == GL_BGRA:
            return GL_RGBA
        return format

    def _convert_buffer(self, data, format):
        # check if format is supported by user
        ret_format = format
        ret_buffer = data

        # BGR / BGRA conversion not supported by hardware ?
        if not Texture.is_gl_format_supported(format):
            if format == GL_BGR:
                ret_format = GL_RGB
                a = array('b', data)
                a[0::3], a[2::3] = a[2::3], a[0::3]
                ret_buffer = a.tostring()
            elif format == GL_BGRA:
                ret_format = GL_RGBA
                a = array('b', data)
                a[0::4], a[2::4] = a[2::4], a[0::4]
                ret_buffer = a.tostring()
            else:
                pymt_logger.critical('Texture: non implemented'
                                     '%s texture conversion' % str(format))
                raise Exception('Unimplemented texture conversion for %s' %
                                str(format))
        return ret_buffer, ret_format

    @property
    def size(self):
        return (self.width, self.height)

    @staticmethod
    def mode_to_gl_format(format):
        if format == 'RGBA':
            return GL_RGBA
        elif format == 'BGRA':
            return GL_BGRA
        elif format == 'BGR':
            return GL_BGR
        else:
            return GL_RGB

    @staticmethod
    def gl_format_size(format):
        if format in (GL_RGB, GL_BGR):
            return 3
        elif format in (GL_RGBA, GL_BGRA):
            return 4
        raise Exception('Unsupported format size <%s>' % str(format))

    def __str__(self):
        return '<Texture size=(%d, %d)>' % self.size


class TextureRegion(Texture):
    '''Handle a region of a Texture class. Useful for non power-of-2
    texture handling.'''

    __slots__ = ('x', 'y', 'owner')

    def __init__(self, x, y, width, height, origin):
        super(TextureRegion, self).__init__(
            width, height, origin.target, origin.id)
        self.x = x
        self.y = y
        self.owner = origin

        # recalculate texture coordinate
        origin_u1 = origin.tex_coords[0]
        origin_v1 = origin.tex_coords[1]
        origin_u2 = origin.tex_coords[2]
        origin_v2 = origin.tex_coords[5]
        scale_u = origin_u2 - origin_u1
        scale_v = origin_v2 - origin_v1
        u1 = x / float(origin.width) * scale_u + origin_u1
        v1 = y / float(origin.height) * scale_v + origin_v1
        u2 = (x + width) / float(origin.width) * scale_u + origin_u1
        v2 = (y + height) / float(origin.height) * scale_v + origin_v1
        self.tex_coords = (u1, v1, u2, v1, u2, v2, u1, v2)

    def __del__(self):
        # don't use self of owner !
        pass

if 'PYMT_DOC' not in os.environ:
    from pymt.clock import getClock

    # install tick to release texture every 200ms
    getClock().schedule_interval(_texture_release, 0.2)