コード例 #1
0
ファイル: collection.py プロジェクト: gabr1e11/GLSL-Examples
    def upload(self):

        # Update uniform index for all objects
        # TODO: vectorize
        for i in range(len(self.objects)):
            _,vstart,vend,_,_,_,_ = self.objects[i]
            self.vertices_data[vstart:vend]['index'] = i/float(len(self.uniforms_data))

        VertexBuffer.upload(self)

        if not self._uniforms_id:
            self._uniforms_id = gl.glGenTextures(1)
        gl.glActiveTexture( gl.GL_TEXTURE0 )
        gl.glPixelStorei( gl.GL_UNPACK_ALIGNMENT, 1 )
        gl.glPixelStorei( gl.GL_PACK_ALIGNMENT, 1 )
        gl.glBindTexture( gl.GL_TEXTURE_2D, self._uniforms_id )
        gl.glTexParameterf( gl.GL_TEXTURE_2D,
                            gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST )
        gl.glTexParameterf( gl.GL_TEXTURE_2D,
                           gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST )
        gl.glTexParameterf( gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE )
        gl.glTexParameterf( gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE )

        data = self.uniforms_data.view(np.float32)
        self.uniforms_shape = data.shape[1]//4, data.shape[0]
        gl.glTexImage2D( gl.GL_TEXTURE_2D, 0, gl.GL_RGBA32F_ARB,
                         data.shape[1]//4, data.shape[0], 0, gl.GL_RGBA, gl.GL_FLOAT, data )
コード例 #2
0
ファイル: collection.py プロジェクト: vispy/experimental
    def upload(self):

        # Update uniform index for all objects
        # TODO: vectorize
        for i in range(len(self.objects)):
            _, vstart, vend, _, _, _, _ = self.objects[i]
            self.vertices_data[vstart:vend]['index'] = i / float(
                len(self.uniforms_data))

        VertexBuffer.upload(self)

        if not self._uniforms_id:
            self._uniforms_id = gl.glGenTextures(1)
        gl.glActiveTexture(gl.GL_TEXTURE0)
        gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1)
        gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1)
        gl.glBindTexture(gl.GL_TEXTURE_2D, self._uniforms_id)
        gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER,
                           gl.GL_NEAREST)
        gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER,
                           gl.GL_NEAREST)
        gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S,
                           gl.GL_CLAMP_TO_EDGE)
        gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T,
                           gl.GL_CLAMP_TO_EDGE)

        data = self.uniforms_data.view(np.float32)
        self.uniforms_shape = data.shape[1] // 4, data.shape[0]
        gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA32F_ARB,
                        data.shape[1] // 4, data.shape[0], 0, gl.GL_RGBA,
                        gl.GL_FLOAT, data)
コード例 #3
0
ファイル: grid.py プロジェクト: changcunyuan/gl-agg
class Grid(object):

    def __init__(self,
                 major_lines        = (1.00, 1.00, 0.75),
                 major_lines_color  = (0.75, 0.75, 0.75, 1.00),
                 major_ticks        = (5.00, 5.00, 1.50),
                 major_ticks_color  = (0.00, 0.00, 0.00, 1.00),
                 minor_lines        = (0.10, 0.10, 0.25),
                 minor_lines_color  = (0.75, 0.75, 0.75, 1.00),
                 minor_ticks        = (2.50, 2.50, 1.00),
                 minor_ticks_color  = (0.00, 0.00, 0.00, 1.00) ):
        self._major_lines          = np.array(major_lines)
        self._major_lines_color    = np.array(major_lines_color)
        self._major_ticks          = np.array(major_ticks)
        self._major_ticks_color    = np.array(major_ticks_color)
        self._minor_lines          = np.array(minor_lines)
        self._minor_lines_color    = np.array(minor_lines_color)
        self._minor_ticks          = np.array(minor_ticks)
        self._minor_ticks_color    = np.array(minor_ticks_color)

        vert = open('./grid.vert').read()
        frag = open('./grid.frag').read()
        self._shader = Shader(vert,frag)
        self._transform = 0.0,0.0,100.0,0.0

        w,h = 512,512
        vertices = np.array( [ ((0, 0), (0,0)),
                               ((w, 0), (w,0)),
                               ((w, h), (w,h)),
                               ((0, h), (0,h)) ],
                             dtype = [('position','f4',2), ('tex_coord','f4',2)] )
        vertices['position'] += .315,.315
        indices = np.array( [0,1,2, 0,2,3 ], dtype=np.uint32 )
        self._buffer = VertexBuffer(vertices,indices)


    def set_transforms(self, transforms):
        """ """

        self._transform = transforms


    def update(self):
        """ """

        _,_,w,h = gl.glGetIntegerv(gl.GL_VIEWPORT)
        self._buffer.vertices['position'][0] = 0, 0
        self._buffer.vertices['position'][1] = w, 0
        self._buffer.vertices['position'][2] = w, h
        self._buffer.vertices['position'][3] = 0, h
        self._buffer.vertices['position'] += .315, .315
        self._buffer.vertices['tex_coord'][0] = 0, 0
        self._buffer.vertices['tex_coord'][1] = w, 0
        self._buffer.vertices['tex_coord'][2] = w, h
        self._buffer.vertices['tex_coord'][3] = 0, h
        self._buffer.upload()


    def draw(self):

        x,y,scale,rotation = self._transform
        _,_,w,h = gl.glGetIntegerv(gl.GL_VIEWPORT)

        shader = self._shader
        shader.bind()
        shader.uniformf( 'size',               w,h)
        shader.uniformf( 'offset',             x,y)

        x,y,t   = self._major_lines
        r,g,b,a = self._major_lines_color
        shader.uniformf( 'major_lines',        x*scale, y*scale, max(t,1.0) )
        shader.uniformf( 'major_lines_color',  r,g,b,a*min(t,1.0) )

        x,y,t   = self._major_ticks
        r,g,b,a = self._major_ticks_color
        shader.uniformf( 'major_ticks',        x,y,max(t,1.0) )
        shader.uniformf( 'major_ticks_color',  r,g,b,a*min(t,1.0) )

        x,y,t   = self._minor_lines
        r,g,b,a = self._minor_lines_color
        shader.uniformf( 'minor_lines',        x*scale, y*scale, max(t,1.0) )
        shader.uniformf( 'minor_lines_color',  r,g,b,a*min(t,1.0) )

        x,y,t   = self._minor_ticks
        r,g,b,a = self._minor_ticks_color
        shader.uniformf( 'minor_ticks',        x,y,max(t,1.0) )
        shader.uniformf( 'minor_ticks_color',  r,g,b,a*min(t,1.0) )

        self._buffer.draw( gl.GL_TRIANGLES )
        shader.unbind()
コード例 #4
0
ファイル: collection.py プロジェクト: x2nie/gl-agg
class Collection(object):

    join = {'miter': 0, 'round': 1, 'bevel': 2}

    caps = {
        '': 0,
        'none': 0,
        '.': 0,
        'round': 1,
        ')': 1,
        '(': 1,
        'o': 1,
        'triangle in': 2,
        '<': 2,
        'triangle out': 3,
        '>': 3,
        'square': 4,
        '=': 4,
        'butt': 4,
        '|': 5
    }

    # ---------------------------------
    def __init__(self, vtype, utype):
        self.dash_atlas = None

        # Convert types to lists (in case they were already dtypes) such that
        # we can append new fields
        vtype = eval(str(np.dtype(vtype)))
        utype = eval(str(np.dtype(utype)))

        # We add a uniform index to access uniform data from texture
        vtype.append(('a_index', 'f4'))

        # Check if given utype is made of float32 only
        rutype = dtype_reduce(utype)
        if type(rutype[0]) is not str or rutype[2] != 'float32':
            raise CollectionError(
                "Uniform type cannot de reduced to float32 only")
        else:
            count = rutype[1]
            size = count // 4
            if count % 4:
                size += 1
                utype.append(('unnused', 'f4', size * 4 - count))
            count = size * 4
            self.utype = utype
        self._vbuffer = VertexBuffer(vtype)
        self._ubuffer = DynamicBuffer(utype)
        self._ubuffer_id = 0
        self._ubuffer_shape = [0, count]

        self._dirty = True

    # ---------------------------------
    def __len__(self):
        return len(self._vbuffer)

    # ---------------------------------
    def __getitem__(self, key):
        V = self._vbuffer.vertices[key]
        I = self._vbuffer.indices[key]
        U = self._ubuffer[key]
        return Item(self, key, V, I, U)

    # ---------------------------------
    def __delitem__(self, key):
        start, end = self._vbuffer.vertices.range(key)
        del self._vbuffer[key]
        del self._ubuffer[key]
        self._vbuffer.vertices.data['a_index'][start:] -= 1
        self._vbuffer._dirty = True
        self._dirty = True

    # ---------------------------------
    def get_vertices(self):
        return self._vbuffer.vertices

    vertices = property(get_vertices)

    # ---------------------------------
    def get_indices(self):
        return self._vbuffer.indices

    indices = property(get_indices)

    # ---------------------------------
    def get_uniforms(self):
        return self._ubuffer

    uniforms = property(get_uniforms)

    # ---------------------------------
    def __getattr__(self, name):
        if hasattr(self, '_ubuffer'):
            buffer = object.__getattribute__(self, '_ubuffer')
            if name in buffer.dtype.names:
                return buffer.data[name]
        return object.__getattribute__(self, name)

    # ---------------------------------
    def __setattr__(self, name, value):
        object.__setattr__(self, name, value)
        if hasattr(self, '_ubuffer'):
            buffer = object.__getattribute__(self, '_ubuffer')
            if name in buffer.dtype.names:
                buffer.data[name] = value
                # buffer._dirty = True
                object.__setattr__(self, '_dirty', True)
        object.__setattr__(self, name, value)

    # ---------------------------------
    def clear(self):
        self._vbuffer.clear()
        self._ubuffer.clear()
        self._dirty = True

    # ---------------------------------
    def append(self, vertices, indices, uniforms):
        vertices = np.array(vertices).astype(self._vbuffer.vertices.dtype)
        indices = np.array(indices).astype(self._vbuffer.indices.dtype)
        uniforms = np.array(uniforms).astype(self._ubuffer.dtype)
        vertices['a_index'] = len(self)
        self._vbuffer.append(vertices, indices)
        self._ubuffer.append(uniforms)
        self._ubuffer_shape[0] = len(self)
        self._dirty = True

    # ---------------------------------
    def upload(self):

        if not self._dirty:
            return

        self._vbuffer.upload()

        gl.glActiveTexture(gl.GL_TEXTURE0)
        data = self._ubuffer.data.view(np.float32)
        shape = self._ubuffer_shape
        if not self._ubuffer_id:
            self._ubuffer_id = gl.glGenTextures(1)

            gl.glBindTexture(gl.GL_TEXTURE_2D, self._ubuffer_id)
            gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1)
            gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1)
            gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER,
                               gl.GL_NEAREST)
            gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER,
                               gl.GL_NEAREST)
            gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S,
                               gl.GL_CLAMP_TO_EDGE)
            gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T,
                               gl.GL_CLAMP_TO_EDGE)
            gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_BASE_LEVEL, 0)
            gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAX_LEVEL, 0)
            gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA32F, shape[1] // 4,
                            shape[0], 0, gl.GL_RGBA, gl.GL_FLOAT, data)

        gl.glActiveTexture(gl.GL_TEXTURE0)
        gl.glBindTexture(gl.GL_TEXTURE_2D, self._ubuffer_id)
        gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA32F, shape[1] // 4,
                        shape[0], 0, gl.GL_RGBA, gl.GL_FLOAT, data)
        #gl.glTexSubImage2D( gl.GL_TEXTURE_2D,0, 0, 0, shape[1]//4, shape[0],
        #                    gl.GL_RGBA, gl.GL_FLOAT, data);
        self._dirty = False

    # ---------------------------------
    def bake(self, vertices):
        raise NotImplemented

    # ---------------------------------
    def draw(self):
        if self._dirty:
            self.upload()

        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
        gl.glEnable(gl.GL_BLEND)
        _, _, width, height = gl.glGetIntegerv(gl.GL_VIEWPORT)
        P = orthographic(0, width, 0, height, -1, +1)
        V = np.eye(4).astype(np.float32)
        M = np.eye(4).astype(np.float32)

        shader = self.shader
        shader.bind()
        gl.glActiveTexture(gl.GL_TEXTURE0)
        shader.uniformi('u_uniforms', 0)
        gl.glBindTexture(gl.GL_TEXTURE_2D, self._ubuffer_id)
        if self.dash_atlas:
            gl.glActiveTexture(gl.GL_TEXTURE1)
            shader.uniformi('u_dash_atlas', 1)
            gl.glBindTexture(gl.GL_TEXTURE_2D, self.dash_atlas.texture_id)
        shader.uniform_matrixf('u_M', M)
        shader.uniform_matrixf('u_V', V)
        shader.uniform_matrixf('u_P', P)
        shape = self._ubuffer_shape
        shader.uniformf('u_uniforms_shape', shape[1] // 4, shape[0])
        self._vbuffer.draw()
        shader.unbind()
コード例 #5
0
ファイル: collection.py プロジェクト: Eric89GXL/gl-agg
class Collection(object):

    join = { 'miter' : 0,
             'round' : 1,
             'bevel' : 2 }

    caps = { ''             : 0,
             'none'         : 0,
             '.'            : 0,
             'round'        : 1,
             ')'            : 1,
             '('            : 1,
             'o'            : 1,
             'triangle in'  : 2,
             '<'            : 2,
             'triangle out' : 3,
             '>'            : 3,
             'square'       : 4,
             '='            : 4,
             'butt'         : 4,
             '|'            : 5 }


    # ---------------------------------
    def __init__(self, vtype, utype):
        self.dash_atlas = None

        # Convert types to lists (in case they were already dtypes) such that
        # we can append new fields
        vtype = eval(str(np.dtype(vtype)))
        utype = eval(str(np.dtype(utype)))

        # We add a uniform index to access uniform data from texture
        vtype.append( ('a_index', 'f4') )

        # Check if given utype is made of float32 only
        rutype = dtype_reduce(utype)
        if type(rutype[0]) is not str or rutype[2] != 'float32':
            raise CollectionError("Uniform type cannot de reduced to float32 only")
        else:
            count = rutype[1]
            size = count//4
            if count % 4:
                size += 1
                utype.append(('unnused', 'f4', size*4-count))
            count = size*4
            self.utype = utype
        self._vbuffer = VertexBuffer(vtype)
        self._ubuffer = DynamicBuffer( utype )
        self._ubuffer_id = 0
        self._ubuffer_shape = [0,count]

        self._dirty = True

    # ---------------------------------
    def __len__(self):
        return len(self._vbuffer)


    # ---------------------------------
    def __getitem__(self, key):
        V = self._vbuffer.vertices[key]
        I = self._vbuffer.indices[key]
        U = self._ubuffer[key]
        return Item(self, key, V, I, U)


    # ---------------------------------
    def __delitem__(self, key):
        start,end = self._vbuffer.vertices.range(key)
        del self._vbuffer[key]
        del self._ubuffer[key]
        self._vbuffer.vertices.data['a_index'][start:] -= 1
        self._vbuffer._dirty = True
        self._dirty = True


    # ---------------------------------
    def get_vertices(self):
        return self._vbuffer.vertices
    vertices = property(get_vertices)


    # ---------------------------------
    def get_indices(self):
        return self._vbuffer.indices
    indices = property(get_indices)


    # ---------------------------------
    def get_uniforms(self):
        return self._ubuffer
    uniforms = property(get_uniforms)


    # ---------------------------------
    def __getattr__(self, name):
        if hasattr(self, '_ubuffer'):
            buffer = object.__getattribute__(self,'_ubuffer')
            if name in buffer.dtype.names:
                return buffer.data[name]
        return object.__getattribute__(self,name)


    # ---------------------------------
    def __setattr__(self, name, value):
        object.__setattr__(self, name, value)
        if hasattr(self, '_ubuffer'):
            buffer = object.__getattribute__(self,'_ubuffer')
            if name in buffer.dtype.names:
                buffer.data[name] = value
                # buffer._dirty = True
                object.__setattr__(self, '_dirty', True)
        object.__setattr__(self, name, value)


    # ---------------------------------
    def clear(self):
        self._vbuffer.clear()
        self._ubuffer.clear()
        self._dirty = True


    # ---------------------------------
    def append(self, vertices, indices, uniforms):
        vertices = np.array(vertices).astype(self._vbuffer.vertices.dtype)
        indices  = np.array(indices).astype(self._vbuffer.indices.dtype)
        uniforms = np.array(uniforms).astype(self._ubuffer.dtype)
        vertices['a_index'] = len(self)
        self._vbuffer.append( vertices, indices)
        self._ubuffer.append( uniforms )
        self._ubuffer_shape[0] = len(self)
        self._dirty = True


    # ---------------------------------
    def upload(self):

        if not self._dirty:
            return

        self._vbuffer.upload()

        gl.glActiveTexture( gl.GL_TEXTURE0 )
        data = self._ubuffer.data.view(np.float32)
        shape = self._ubuffer_shape
        if not self._ubuffer_id:
            self._ubuffer_id = gl.glGenTextures(1)

            gl.glBindTexture( gl.GL_TEXTURE_2D, self._ubuffer_id )
            gl.glPixelStorei( gl.GL_UNPACK_ALIGNMENT, 1 )
            gl.glPixelStorei( gl.GL_PACK_ALIGNMENT, 1 )
            gl.glTexParameterf( gl.GL_TEXTURE_2D,
                                gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST )
            gl.glTexParameterf( gl.GL_TEXTURE_2D,
                                gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST )
            gl.glTexParameterf( gl.GL_TEXTURE_2D,
                                gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE )
            gl.glTexParameterf( gl.GL_TEXTURE_2D,
                                gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE )
            gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_BASE_LEVEL, 0)
            gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAX_LEVEL, 0)
            gl.glTexImage2D( gl.GL_TEXTURE_2D, 0, gl.GL_RGBA32F,
                             shape[1]//4, shape[0], 0, gl.GL_RGBA, gl.GL_FLOAT, data )

        gl.glActiveTexture( gl.GL_TEXTURE0 )
        gl.glBindTexture( gl.GL_TEXTURE_2D, self._ubuffer_id )
        gl.glTexImage2D( gl.GL_TEXTURE_2D, 0, gl.GL_RGBA32F,
                         shape[1]//4, shape[0], 0, gl.GL_RGBA, gl.GL_FLOAT, data )
        #gl.glTexSubImage2D( gl.GL_TEXTURE_2D,0, 0, 0, shape[1]//4, shape[0],
        #                    gl.GL_RGBA, gl.GL_FLOAT, data);
        self._dirty = False


    # ---------------------------------
    def bake(self, vertices):
        raise NotImplemented


    # ---------------------------------
    def draw(self):
        if self._dirty:
            self.upload()

        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
        gl.glEnable(gl.GL_BLEND)
        _,_,width,height = gl.glGetIntegerv( gl.GL_VIEWPORT )
        P = orthographic( 0, width, 0, height, -1, +1 )
        V = np.eye(4).astype( np.float32 )
        M = np.eye(4).astype( np.float32 )

        shader = self.shader
        shader.bind()
        gl.glActiveTexture( gl.GL_TEXTURE0 )
        shader.uniformi( 'u_uniforms', 0 )
        gl.glBindTexture( gl.GL_TEXTURE_2D, self._ubuffer_id )
        if self.dash_atlas:
            gl.glActiveTexture( gl.GL_TEXTURE1 )
            shader.uniformi('u_dash_atlas', 1)
            gl.glBindTexture( gl.GL_TEXTURE_2D, self.dash_atlas.texture_id )
        shader.uniform_matrixf( 'u_M', M )
        shader.uniform_matrixf( 'u_V', V )
        shader.uniform_matrixf( 'u_P', P )
        shape = self._ubuffer_shape
        shader.uniformf( 'u_uniforms_shape', shape[1]//4, shape[0])
        self._vbuffer.draw( )
        shader.unbind()
コード例 #6
0
class Collection(object):

    # ---------------------------------
    def __init__(self, vtype, utype):
        # Convert types to lists (in case they were already dtypes) such that
        # we can append new fields
        vtype = eval(str(np.dtype(vtype)))
        utype = eval(str(np.dtype(utype)))

        # We add a uniform index to access uniform data from texture
        vtype.append( ('a_index', 'f4') )

        # Check if given utype is made of float32 only
        rutype = dtype_reduce(utype)
        if type(rutype[0]) is not str or rutype[2] != 'float32':
            raise CollectionError("Uniform type cannot de reduced to float32 only")
        else:
            count = rutype[1]
            count2 = int(math.pow(2, math.ceil(math.log(count, 2))))
            if (count2 - count) > 0:
                utype.append(('unused', 'f4', count2-count))
            self._count = count2
            self.utype = utype
        
        self._vbuffer = VertexBuffer(vtype)
        self._ubuffer = DynamicBuffer( utype )
        self._ubuffer_id = 0
        self._max_texture_size = gl.glGetInteger(gl.GL_MAX_TEXTURE_SIZE)
        self._compute_ushape(1)
        self._ubuffer.reserve( self._ushape[1] / (count/4) )
        self._dirty = True


    # ---------------------------------
    def _compute_ushape(self, size=1):
        max_texsize = self._max_texture_size
        cols = max_texsize//(self._count/4)
        rows = (size // cols)+1
        self._ushape = rows, cols*(self._count/4), self._count


    # ---------------------------------
    def __len__(self):
        return len(self._vbuffer)


    # ---------------------------------
    def __getitem__(self, key):
        V = self._vbuffer.vertices[key]
        I = self._vbuffer.indices[key]
        U = self._ubuffer[key]
        return Item(self, key, V, I, U)


    # ---------------------------------
    def __delitem__(self, key):
        start,end = self._vbuffer.vertices.range(key)
        del self._vbuffer[key]
        del self._ubuffer[key]
        self._vbuffer.vertices.data['a_index'][start:] -= 1
        self._vbuffer._dirty = True
        self._dirty = True



    # ---------------------------------
    def get_vbuffer(self):
        return self._vbuffer
    vbuffer = property(get_vbuffer)

    # ---------------------------------
    def get_vertices(self):
        return self._vbuffer.vertices
    vertices = property(get_vertices)


    # ---------------------------------
    def get_indices(self):
        return self._vbuffer.indices
    indices = property(get_indices)


    # ---------------------------------
    def get_uniforms(self):
        return self._ubuffer
    uniforms = property(get_uniforms)


    # ---------------------------------
    def get_attributes(self):
        return self._vbuffer._attributes
    attributes = property(get_attributes)


    # ---------------------------------
    def __getattr__(self, name):
        if hasattr(self, '_ubuffer'):
            buffer = object.__getattribute__(self,'_ubuffer')
            if name in buffer.dtype.names:
                return buffer.data[name]
        return object.__getattribute__(self,name)


    # ---------------------------------
    def __setattr__(self, name, value):
        object.__setattr__(self, name, value)
        if hasattr(self, '_ubuffer'):
            buffer = object.__getattribute__(self,'_ubuffer')
            if name in buffer.dtype.names:
                buffer.data[name] = value
                # buffer._dirty = True
                object.__setattr__(self, '_dirty', True)
        object.__setattr__(self, name, value)


    # ---------------------------------
    def clear(self):
        self._vbuffer.clear()
        self._ubuffer.clear()
        self._dirty = True


    # ---------------------------------
    def append(self, vertices, indices, uniforms, splits=None):
        vertices = np.array(vertices).astype(self._vbuffer.vertices.dtype)
        indices  = np.array(indices).astype(self._vbuffer.indices.dtype)
        uniforms = np.array(uniforms).astype(self._ubuffer.dtype)

        if splits is None:
            vertices['a_index'] = len(self)
            self._vbuffer.append( vertices, indices )
            self._ubuffer.append( uniforms )
            self._compute_ushape(len(self))
        elif len(splits) == 2:
            vsize,isize = splits[0], splits[1]
            if (vertices.size % vsize) != 0:
                raise( RuntimeError,
                       "Cannot split vertices data into %d pieces" % vsize)
            if (indices.size % isize) != 0:
                raise( RuntimeError,
                       "Cannot split indices data into %d pieces" % vsize)
            vcount = vertices.size//vsize
            icount = indices.size//isize
            ucount = uniforms.size
            n = ucount
            if vcount != icount or vcount != ucount:
                raise( RuntimeError,
                       "Vertices/indices/uniforms cannot be split")
            vertices['a_index'] = len(self)+np.repeat(np.arange(n),vsize)
            self._vbuffer.append( vertices, indices, (vsize,isize))
            self._ubuffer.append( uniforms )
            self._compute_ushape(len(self))
        else:
            raise(RuntimeError, "Splits argument not understood")
        self._dirty = True


    # ---------------------------------
    def upload(self):

        if not self._dirty:
            return
        self._vbuffer.upload()
        self.upload_uniforms()
        self._dirty = False


    # ---------------------------------
    def upload_uniforms(self):

        gl.glActiveTexture( gl.GL_TEXTURE0 )
        data = self._ubuffer.data.view(np.float32)
        shape = self._ushape

        if not self._ubuffer_id:
            self._ubuffer_id = gl.glGenTextures(1)

            gl.glBindTexture( gl.GL_TEXTURE_2D, self._ubuffer_id )
            gl.glPixelStorei( gl.GL_UNPACK_ALIGNMENT, 1 )
            gl.glPixelStorei( gl.GL_PACK_ALIGNMENT, 1 )
            gl.glTexParameterf( gl.GL_TEXTURE_2D,
                                gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST )
            gl.glTexParameterf( gl.GL_TEXTURE_2D,
                                gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST )
            gl.glTexParameterf( gl.GL_TEXTURE_2D,
                                gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE )
            gl.glTexParameterf( gl.GL_TEXTURE_2D,
                                gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE )
            gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_BASE_LEVEL, 0)
            gl.glTexParameterf(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAX_LEVEL, 0)
            gl.glTexImage2D( gl.GL_TEXTURE_2D, 0, gl.GL_RGBA32F,
                             shape[1], shape[0], 0, gl.GL_RGBA, gl.GL_FLOAT, data )
        gl.glActiveTexture( gl.GL_TEXTURE0 )
        gl.glBindTexture( gl.GL_TEXTURE_2D, self._ubuffer_id )
        gl.glTexImage2D( gl.GL_TEXTURE_2D, 0, gl.GL_RGBA32F,
                         shape[1], shape[0], 0, gl.GL_RGBA, gl.GL_FLOAT, data )


    # ---------------------------------
    def draw(self, mode=gl.GL_TRIANGLES, uniforms = {}):
        if self._dirty:
            self.upload()
        shader = self.shader
        shader.bind()
        gl.glActiveTexture( gl.GL_TEXTURE0 )
        shader.uniformi( 'u_uniforms', 0 )
        gl.glBindTexture( gl.GL_TEXTURE_2D, self._ubuffer_id )
        for name,value in uniforms.items():
            shader.uniform(name, value)
        shader.uniformf('u_uniforms_shape', *self._ushape)
        self._vbuffer.draw(mode)
        shader.unbind()