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()
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()
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()
class Label(object): ''' ''' def __init__(self, text, family='Sans', size=16, bold=False, italic=False, color=(1.0, 1.0, 1.0, 1.0), x=0, y=0, z=0, anchor_x='left', anchor_y='baseline', filename='./Arial.ttf'): self._text = text self._font = get_font(filename, size) self._color = color self._x = x self._y = y self._z = z self._anchor_x = anchor_x self._anchor_y = anchor_y self.build() def build(self): self.vertices = np.zeros(len(self._text) * 4, dtype=[('position', 'f4', 3), ('tex_coord', 'f4', 2), ('color', 'f4', 4)]) self.indices = np.zeros((len(self._text) * 6, ), dtype=np.uint32) prev = None x, y = 0, 0 for i, charcode in enumerate(self._text): glyph = self._font[charcode] kerning = glyph.get_kerning(prev) / 64.0 x0 = int(x + glyph.offset[0] + kerning) y0 = int(y + glyph.offset[1]) x1 = x0 + glyph.size[0] y1 = y0 - glyph.size[1] u0 = glyph.texcoords[0] v0 = glyph.texcoords[1] u1 = glyph.texcoords[2] v1 = glyph.texcoords[3] index = i * 4 indices = [ index, index + 1, index + 2, index, index + 2, index + 3 ] vertices = [[x0, y0, 0], [x0, y1, 0], [x1, y1, 0], [x1, y0, 0]] texcoords = [[u0, v0], [u0, v1], [u1, v1], [u1, v0]] colors = [ self._color, ] * 4 self.indices[i * 6:i * 6 + 6] = indices self.vertices['position'][i * 4:i * 4 + 4] = vertices self.vertices['tex_coord'][i * 4:i * 4 + 4] = texcoords self.vertices['color'][i * 4:i * 4 + 4] = colors x += glyph.advance[0] / 64.0 + kerning y += glyph.advance[1] / 64.0 prev = charcode width = x + glyph.advance[0] / 64.0 + glyph.size[0] if self._anchor_y == 'top': dy = -round(self._font.ascender) elif self._anchor_y == 'center': dy = +round(-self._font.height / 2 - self._font.descender) elif self._anchor_y == 'bottom': dy = -round(self._font.descender) else: dy = 0 if self._anchor_x == 'right': dx = -width / 1.0 elif self._anchor_x == 'center': dx = -width / 2.0 else: dx = 0 self.vertices['position'] += self._x + round(dx), self._y + round( dy), self._z self.buffer = VertexBuffer(self.vertices, self.indices) def draw(self): gl.glDisable(gl.GL_TEXTURE_1D) gl.glEnable(gl.GL_TEXTURE_2D) gl.glDisable(gl.GL_DEPTH_TEST) gl.glBindTexture(gl.GL_TEXTURE_2D, self._font.texid) gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glColor(1, 1, 1, 1) self.buffer.draw(gl.GL_TRIANGLES) def _get_position(self): return self._x, self.y, self._z def _set_position(self, position): x, y = position self.vertices['position'] -= self._x, self._y, 0 self._x, self._y = x, y self.vertices['position'] += x, y, 0 self.vbo.upload() position = property(_get_position, _set_position)
class Label(object): ''' ''' def __init__( self, text, family='Sans', size=16, bold=False, italic=False, color=(1.0, 1.0, 1.0, 1.0), x=0, y=0, z=0, anchor_x='left', anchor_y='baseline', filename='./Arial.ttf'): self._text = text self._font = get_font(filename, size) self._color = color self._x = x self._y = y self._z = z self._anchor_x = anchor_x self._anchor_y = anchor_y self.build() def build(self): self.vertices = np.zeros( len(self._text)*4, dtype = [('position', 'f4',3), ('tex_coord', 'f4',2), ('color', 'f4',4)] ) self.indices = np.zeros( (len(self._text)*6, ), dtype=np.uint32 ) prev = None x,y = 0, 0 for i,charcode in enumerate(self._text): glyph = self._font[charcode] kerning = glyph.get_kerning(prev)/64.0 x0 = int(x + glyph.offset[0] + kerning) y0 = int(y + glyph.offset[1]) x1 = x0 + glyph.size[0] y1 = y0 - glyph.size[1] u0 = glyph.texcoords[0] v0 = glyph.texcoords[1] u1 = glyph.texcoords[2] v1 = glyph.texcoords[3] index = i*4 indices = [index, index+1, index+2, index, index+2, index+3] vertices = [[x0,y0,0],[x0,y1,0],[x1,y1,0], [x1,y0,0]] texcoords = [[u0,v0],[u0,v1],[u1,v1], [u1,v0]] colors = [self._color,]*4 self.indices[i*6:i*6+6] = indices self.vertices['position'][i*4:i*4+4] = vertices self.vertices['tex_coord'][i*4:i*4+4] = texcoords self.vertices['color'][i*4:i*4+4] = colors x += glyph.advance[0]/64.0 + kerning y += glyph.advance[1]/64.0 prev = charcode width = x+glyph.advance[0]/64.0+glyph.size[0] if self._anchor_y == 'top': dy = -round(self._font.ascender) elif self._anchor_y == 'center': dy = +round(-self._font.height/2-self._font.descender) elif self._anchor_y == 'bottom': dy = -round(self._font.descender) else: dy = 0 if self._anchor_x == 'right': dx = -width/1.0 elif self._anchor_x == 'center': dx = -width/2.0 else: dx = 0 self.vertices['position'] += self._x+round(dx), self._y+round(dy), self._z self.buffer = VertexBuffer(self.vertices, self.indices) def draw(self): gl.glDisable (gl.GL_TEXTURE_1D) gl.glEnable( gl.GL_TEXTURE_2D ) gl.glDisable( gl.GL_DEPTH_TEST ) gl.glBindTexture( gl.GL_TEXTURE_2D, self._font.texid ) gl.glEnable( gl.GL_BLEND ) gl.glBlendFunc( gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA ) gl.glColor(1,1,1,1) self.buffer.draw(gl.GL_TRIANGLES) def _get_position(self): return self._x, self.y, self._z def _set_position(self, position): x,y = position self.vertices['position'] -= self._x, self._y, 0 self._x, self._y = x,y self.vertices['position'] += x, y, 0 self.vbo.upload() position = property(_get_position, _set_position)
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()