class Scaled(Widget): def __init__(self, **kwargs): super(Scaled, self).__init__(**kwargs) self.elements = [] self.pointsize = 5 # this multiplies by two according to kivy docs with self.canvas: self._fbo = Fbo(size=self.size) self._rect = Rectangle(texture=self._fbo.texture) with self._fbo: Color(1, 1, 1) self._fborect = Rectangle(size=self._fbo.size) Color(0, 0, 1) self._points = Point(pointsize=self.pointsize) self._fbo.add_reload_observer(self._clear_fbo) self.bind(pos=self._update_rect, size=self._update_rect) def drawpoint(self, x, y): self.elements.append([x, y]) self._points.add_point(x, y) def draw(self, matrix): self._points.points = [] self._clear_fbo() for point in matrix: x = int(point[0] * (self.pointsize * 2) + self.pointsize) y = int(point[1] * (self.pointsize * 2) + self.pointsize) self.drawpoint(x, y) # RELOADING THE BUFFER AT ANY CHANGE def _clear_fbo(self, fbo=None): ''' This will reload the framebufferer either by the call of the observer or by the deletion of a point''' if fbo is None: fbo = self._fbo fbo.bind() fbo.clear_buffer() fbo.add(Color(1, 1, 1)) fbo.add(self._fborect) fbo.add(Color(0, 0, 1)) fbo.add(self._points) fbo.release() def _update_rect(self, instance, value): self._fbo.size = instance.size self._fborect.size = instance.size self._rect.size = instance.size self._rect.pos = instance.pos self._rect.texture = self._fbo.texture
class Scaled(Widget): def __init__(self, **kwargs): super(Scaled, self).__init__(**kwargs) self.elements = [] self.pointsize = 5 # this multiplies by two according to kivy docs with self.canvas: self._fbo = Fbo(size=self.size) self._rect = Rectangle(texture=self._fbo.texture) with self._fbo: Color(1, 1, 1) self._fborect = Rectangle(size=self._fbo.size) Color(0, 0, 1) self._points = Point(pointsize=self.pointsize) self._fbo.add_reload_observer(self._clear_fbo) self.bind(pos=self._update_rect, size=self._update_rect) def drawpoint(self, x, y): self.elements.append([x, y]) self._points.add_point(x, y) def draw(self, matrix): self._points.points = [] self._clear_fbo() for point in matrix: x = int(point[0] * (self.pointsize * 2) + self.pointsize) y = int(point[1] * (self.pointsize * 2) + self.pointsize) self.drawpoint(x, y) # RELOADING THE BUFFER AT ANY CHANGE def _clear_fbo(self, fbo=None): """ This will reload the framebufferer either by the call of the observer or by the deletion of a point""" if fbo is None: fbo = self._fbo fbo.bind() fbo.clear_buffer() fbo.add(Color(1, 1, 1)) fbo.add(self._fborect) fbo.add(Color(0, 0, 1)) fbo.add(self._points) fbo.release() def _update_rect(self, instance, value): self._fbo.size = instance.size self._fborect.size = instance.size self._rect.size = instance.size self._rect.pos = instance.pos self._rect.texture = self._fbo.texture
class GLWindow(BoxLayout): texture = ObjectProperty(None, allownone=True) def __init__(self, **kwargs): self.mesh_data = MeshData() self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=(10, 10), compute_normal_mat=True) self.fbo.add_reload_observer(self.populate_fbo) with self.fbo: ClearColor(0, 0, 0, 0) ClearBuffers() self.populate_fbo(self.fbo) super(GLWindow, self).__init__(**kwargs) Clock.schedule_interval(self.update_glsl, 1 / 60.) def populate_fbo(self, fbo): Logger.info("Setting up FBO") with self.canvas: fbo.shader.source = resource_find('simple.glsl') fbo['diffuse_light'] = (1.0, 1.0, 0.8) fbo['ambient_light'] = (0.8, 0.8, 0.8) with fbo: self.cb = Callback(self.setup_gl_context) PushMatrix() BindTexture(source='testure.jpg', index=1) UpdateNormalMatrix() Translate(0, 0, -3) self.rot = Rotate(1, 0, 1, 0) # self.show_axis() self.make_pretty_dots() PopMatrix() self.cb = Callback(self.reset_gl_context) fbo['texture1'] = 1 def update_glsl(self, *largs): asp = self.size[0] / float(self.size[1]) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) model = Matrix().look_at(0.0, 0.0, 0.25, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) with self.canvas: self.fbo.shader.source = resource_find('simple.glsl') self.fbo['projection_mat'] = proj self.fbo['modelview_mat'] = model self.rot.angle += -1 self.texture = self.fbo.texture with self.fbo: BindTexture(source='testure.jpg', index=1) def setup_gl_context(self, *args): glEnable(GL_DEPTH_TEST) def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def on_size(self, instance, value): Logger.info('resize') self.fbo.size = value self.texture = self.fbo.texture def show_axis(self): Color(1, 1, 0, 1) #Yellow Mesh( vertices=[ -1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0.8, 0.1, 0, 1, 1, 0, 0, 0, 0.8, -0.1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0.8, 0, -0.1, 1, 1, 0, 0, 0, 0.8, 0, 0.1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, ], indices=[0, 1, 2, 3, 4, 5, 6, 7], fmt=self.mesh_data.vertex_format, mode='line_strip', ) Color(1, 0, 1, 1) # purple Mesh( vertices=[ 0, 0, -1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0.1, 0, 0.8, 0, 1, 1, 0, 0, -0.1, 0, 0.8, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, -0.1, 0.8, 0, 1, 1, 0, 0, 0, 0.1, 0.8, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, ], indices=[0, 1, 2, 3, 4, 5, 6, 7], fmt=self.mesh_data.vertex_format, mode='line_strip', ) Color(0, 1, 1, 1) # Baby Blue Mesh( vertices=[ 0, -1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0.1, 0.8, 0, 1, 1, 0, 0, 0, -0.1, 0.8, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0.8, -0.1, 1, 1, 0, 0, 0, 0, 0.8, 0.1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, ], indices=[0, 1, 2, 3, 4, 5, 6, 7], fmt=self.mesh_data.vertex_format, mode='line_strip', ) def make_pretty_dots(self): points_per_side = 50 points = [] for idx in range(points_per_side): v = -1.0 + ((2.0 / points_per_side) * float(idx)) tex = idx / float(points_per_side) print("TEX: {}".format(str(tex))) points.append([[v, -1.0, -1.0, v, -1.0, -1.0, tex, 0.0], [v, -1.0, 1.0, v, -1.0, 1.0, tex, 0.0], [v, 1.0, -1.0, v, 1.0, -1.0, tex, 1.0], [v, 1.0, 1.0, v, 1.0, 1.0, tex, 1.0], [-1.0, v, -1.0, -1.0, v, -1.0, 0.0, tex], [-1.0, v, 1.0, -1.0, v, 1.0, 0.0, tex], [1.0, v, -1.0, 1.0, v, -1.0, 1.0, tex], [1.0, v, 1.0, 1.0, v, 1.0, 1.0, tex], [-1.0, -1.0, v, -1.0, -1.0, v, tex, tex], [-1.0, 1.0, v, -1.0, 1.0, v, tex, tex], [1.0, -1.0, v, 1.0, -1.0, v, tex, tex], [1.0, 1.0, v, 1.0, 1.0, v, tex, tex]], ) points = np.array(points).flatten() Color(1, 1, 1, 1) Mesh( vertices=points, indices=[i for i in range(len(points) / 8)], fmt=self.mesh_data.vertex_format, mode='points', )
class FragmentCompute: def __init__(self, fs, length1, length2 = 1): size = (length1, length2) # it doesn't look like we can use float textures on mobile kivy, but people sometimes interconvert floats with 32bit rgba in shaders. # we would then have 3 shaders or texture rows or such, for x coord, y coord, angle, etc #Logger.info('float: ' + str(gl.getExtension('OES_texture_float'))) texture = Texture.create( size = size, #bufferfmt = 'float' ) self._fbo = Fbo( size = size, texture = texture, vs = default_vs, fs = header_fs + fs, ) # these matrices are to transform # window coordinates into data # coordinates centermat = Matrix() centermat.translate(-.5,-.5,-.5) idxscale = 1.0 / 255.0; idxmat = Matrix() idxmat.scale(idxscale, idxscale, idxscale) self._fbo['frag_coord2idx'] = idxmat.multiply(centermat) ratiomat = Matrix() ratiomat.scale(1.0 / length1, 1.0 / length2, 1.0) self._fbo['frag_coord2ratio'] = ratiomat self._texture_bindings = {} self._fbo.add_reload_observer(self._populate_fbo) self._populate_fbo(self._fbo) def texture(self): return self._fbo.texture def download(self): ## cgl requires cython, ## but glReadPixels is used in ## fbo.py, and could be used to ## get RGB instead of RGBA, since ## A is presently drawn blended, ## and maybe save a memory copy. #width, height = self._fbo.size #data = array('B', [1] * width * height * 4) #self._fbo.bind() #cgl.cgl.glPixelStorei(GL_PACK_ALIGNMENT, 1) #cgl.cgl.glReadPixels(0, 0, width, height, cgl.GL_RGB, cgl.GL_UNSIGNED_BYTE, data) #self._fbo.release() #return data return bytearray(self._fbo.pixels) def compute(self): self._rectangle.texture = self._fbo.texture self._fbo.draw() return self def __setitem__(self, name, value): if isinstance(value, Texture): if name in self._texture_bindings: index, oldvalue = self._texture_bindings[name] else: index = len(self._texture_bindings) + 1 self._texture_bindings[name] = (index, value) self._fbo[name] = index self._fbo.clear() self._populate_fbo(self._fbo) else: self._fbo[name] = value def _populate_fbo(self, fbo): with fbo: for index, texture in self._texture_bindings.values(): BindTexture(index = index, texture = texture) Callback(self._set_blend_mode) self._rectangle = Rectangle(size = self._fbo.size) Callback(self._unset_blend_mode) # opaque blend mode provides for use of the alpha channel for data def _set_blend_mode(self, instruction = None): gl.glBlendFunc(gl.GL_ONE, gl.GL_ZERO); gl.glBlendFuncSeparate(gl.GL_ONE, gl.GL_ZERO, gl.GL_ONE, gl.GL_ZERO); def _unset_blend_mode(self, instruction = None): gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA); gl.glBlendFuncSeparate(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA, gl.GL_ONE, gl.GL_ONE);
class ObjectRenderer(BoxLayout): texture = ObjectProperty(None, allownone=True) mesh_mode = BooleanProperty(False) def __init__(self, **kwargs): self.lock = Lock() self.gl_depth = -3 self.mesh_data = MeshData() self.mesh_data.vertices = np.array([0, 0, 0, 0, 0, 0, 0, 0]) self.mesh_data.indices = np.array([0]) self.points = None self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=(10, 10), compute_normal_mat=True) self.fbo.add_reload_observer(self.populate_fbo) with self.fbo: ClearColor(1, 1, 1, 1) ClearBuffers() self.populate_fbo(self.fbo) super(ObjectRenderer, self).__init__(**kwargs) Clock.schedule_interval(self.update_glsl, 1 / 10.) def on_size(self, instance, value): size = (max(1, value[0]), max(1, value[1])) self.fbo.size = size self.texture = self.fbo.texture def setup_gl_context(self, *args): glEnable(GL_DEPTH_TEST) def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def clear(self): if hasattr(self, 'model_texture'): self.mesh_data.vertices = np.array([0, 0, 0, 0, 0, 0, 0, 0]) self.mesh_data.indices = np.array([0]) del self.model_texture def update_texture(self, texture): if not hasattr(self, 'model_texture'): self.model_texture = texture self.populate_fbo(self.fbo) def update_glsl(self, *largs): # self.fbo.shader.source = resource_find('simple.glsl') asp = max(10, self.size[0]) / max(10, float(self.size[1])) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) model = Matrix().look_at( 0.0, 0.0, 0.0, 0.0, 0.0, -3.0, 0.0, 1.0, 0.0) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) with self.canvas: self.fbo['projection_mat'] = proj self.fbo['modelview_mat'] = model self.mesh.vertices = self.mesh_data.vertices self.mesh.indices = self.mesh_data.indices self.rot.angle += -3 def update_mesh(self, points): self.points = points points = np.array(points)[::8] points = points.flatten() self.mesh_data.vertices = points indicies = np.arange(len(points) // 8) if self.mesh_mode: idx = [] y = 0 x = 0 z = 0 for pos in range(1, len(indicies)): if points[(indicies[pos] * 8) + 2] > z: A = indicies[pos - 1] B = indicies[pos] idx.extend([A, B]) (x,y,z) = points[(indicies[pos] * 8) : (indicies[pos] * 8 ) + 3] self.mesh_data.indices = idx self.mesh.mode = 'lines' else: self.mesh_data.indices = indicies self.mesh.mode = 'points' def populate_fbo(self, fbo): with self.canvas: fbo.shader.source = resource_find('simple.glsl') fbo['diffuse_light'] = (1.0, 1.0, 0.8) fbo['ambient_light'] = (0.5, 0.5, 0.5) with fbo: self.cb = Callback(self.setup_gl_context) PushMatrix() if hasattr(self, 'model_texture'): BindTexture(texture=self.model_texture, index=1) Translate(0, 1, self.gl_depth + 1) self.rot = Rotate(0, 0, 1, 0) UpdateNormalMatrix() Color(1, 1, 1, 1) self.mesh = Mesh( vertices=self.mesh_data.vertices, indices=self.mesh_data.indices, fmt=self.mesh_data.vertex_format, mode=self.mesh_data.mode, ) PopMatrix() self.cb = Callback(self.reset_gl_context) fbo['texture1'] = 1 def show_axis(self): Color(1, 1, 0, 1) #Yellow Mesh( vertices=[ -1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0.8, 0.1, 0, 1, 1, 0, 0, 0, 0.8, -0.1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0.8, 0, -0.1, 1, 1, 0, 0, 0, 0.8, 0, 0.1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, ], indices=[0, 1, 2, 3, 4, 5, 6, 7], fmt=self.mesh_data.vertex_format, mode='line_strip', ) Color(1, 0, 1, 1) # purple Mesh( vertices=[ 0, 0, -1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0.1, 0, 0.8, 0, 1, 1, 0, 0, -0.1, 0, 0.8, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, -0.1, 0.8, 0, 1, 1, 0, 0, 0, 0.1, 0.8, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, ], indices=[0, 1, 2, 3, 4, 5, 6, 7], fmt=self.mesh_data.vertex_format, mode='line_strip', ) Color(0, 1, 1, 1) # Baby Blue Mesh( vertices=[ 0, -1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0.1, 0.8, 0, 1, 1, 0, 0, 0, -0.1, 0.8, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0.8, -0.1, 1, 1, 0, 0, 0, 0, 0.8, 0.1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, ], indices=[0, 1, 2, 3, 4, 5, 6, 7], fmt=self.mesh_data.vertex_format, mode='line_strip', ) def on_mesh_mode(self, instance, value): self.update_mesh(self.points)
class Grid( Widget ): point_size = NumericProperty(10) def __init__(self, **kwargs): super(Grid, self).__init__(**kwargs) # Which elements exist in the grid in the normalized coordinates self.elements = [] # If active, it can't be modified self.active = False # To the canvas, we add the FrameBufferObject and the rect to show it with self.canvas: self.fbo = Fbo(size=self.size) self.rect = Rectangle(texture=self.fbo.texture) # Color(1,0,0) # self.rect = Rectangle(size = self.size, pos = self.pos) # To the FrameBufferObject I set the color and add the point list with self.fbo: Color(1,1,1) self.points = Point( pointsize=self.point_size ) # add some observers to the fbo, changes for the point_size (grid # resizing) and widget resizing self.fbo.add_reload_observer(self._populate_fbo) self.bind( point_size = self._reshape ) self.bind( size = self._update_rect, pos = self._update_rect ) def on_touch_down(self, touch): ''' Handle adding/removing points when the grid is not active''' if not self.active and self.collide_point(*touch.pos): # Move to a 0,0 from where the widget starts x = touch.x - self.x y = touch.y - self.y self.add_point( [x,y] ) return True return super(Grid, self).on_touch_down(touch) def normalize(self, coords): ''' normalization of coordinates, it will transform any given point in the widget to its corresponding normalized coords ''' # TODO: Create a picture to describe what are the normalized coordinates if type(coords) is tuple: coords = list(coords) if type(coords) is list: for ind in range(len(coords)): coords[ind] = int( coords[ind] // ( self.points.pointsize * 2 ) ) return coords else: return int( coords // ( self.points.pointsize * 2 ) ) def adjust(self, coords): ''' adjustment of a normalized coordinate to the real coordinate using the current point size as a guide ''' if type(coords) is tuple: coords = list(coords) if type(coords) is list: for ind in range(len(coords)): coords[ind] = int( coords[ind] * ( self.points.pointsize * 2 ) + self.points.pointsize ) return coords else: return int( coords * ( self.points.pointsize * 2 ) + self.points.pointsize ) def add_point(self, point, redraw=True): ''' method to add a point to the grid if it doesn't exist if it's there, remove it''' point = self.normalize(point) if point in self.elements: where = self.elements.index( point ) # Steal the reference to the vector of points points = self.points.points self.points.points = [] # Clean the desired point del(points[where*2]) del(points[where*2]) # Reassign the property for the context to know (kivy weird things) self.points.points = points # Remove from the historical del(self.elements[where]) # Redraw if asked for if redraw: self._populate_fbo(self.fbo) else: # add the normalized coords to the element list # it has to be copied because the adjust method will modify # the elements in points self.elements.append(point[:]) # add the point to the visible points using the adjusted coordinates # the * leading self.adjust is to unpack the resulting array self.points.add_point( *self.adjust(point) ) # print(self.elements) def next(self, instance): if len(self.elements) == 0: return # calculate the survivors nextgen = automaton.survivors(self.elements) # print(nextgen) # calculate any possible newborns nextgen += automaton.births(self.elements) # print(nextgen) # replace the current elements self.elements = nextgen # The vector comes with minivectors within, which is fine for the # list of elements but doesn't work for the adjustment of points in # the screen nextgen = [ i for cell in nextgen for i in cell ] # adjust the elements to the actual coordinates nextgen = self.adjust( nextgen ) # assign the vector back self.points.points = nextgen # redraw self._populate_fbo() def clear(self, instance): self.elements = [] self.points.points = [] self._populate_fbo() # RELOADING THE BUFFER AT ANY CHANGE def _populate_fbo(self, fbo = None): ''' This will reload the framebufferer either by the call of the observer or by the deletion of a point''' if fbo is None: fbo = self.fbo fbo.bind() fbo.clear_buffer() fbo.add(self.points) fbo.release() def _reshape(self, instance, value): # There are no elements if len(self.elements) == 0: # We just update the points to be drawn self.points.pointsize = self.point_size # If we do have elements else: # steal the reference to the vector points = self.points.points self.points.points = [] # normalize using current value points = self.normalize( points ) # reassing the value self.points.pointsize = self.point_size # adjust using new value points = self.adjust( points ) # assign the vector back self.points.points = points # redraw self._populate_fbo() # REDRAWING THE FBO AND THE def _update_rect( self, instance, value ): self.fbo.size = instance.size self.rect.size = instance.size self.rect.pos = instance.pos self.rect.texture = self.fbo.texture
class Pad(Widget): scaled = ListProperty() def __init__(self, **kwargs): super(Pad, self).__init__(**kwargs) # Which elements exist in the grid in the normalized coordinates self.elements = [] self.oldxy = None with self.canvas: self._fbo = Fbo(size=self.size) self._rect = Rectangle(texture=self._fbo.texture) with self._fbo: Color(1, 1, 1) self._fborect = Rectangle(size=self._fbo.size) Color(1, 0, 0) self._fbo.add_reload_observer(self._clear_fbo) self.bind(pos=self._update_rect, size=self._update_rect) def on_touch_down(self, touch): if self.collide_point(*touch.pos): # let's hold the mouse touch.grab(self) self.elements = [] self._clear_fbo() x = round(touch.x - self.x) y = round(touch.y - self.y) # and keep the position self.oldxy = [x, y] return True return super(Pad, self).on_touch_down(touch) def on_touch_move(self, touch): if self.collide_point(*touch.pos): x = round(touch.x - self.x) y = round(touch.y - self.y) self.drawline([x, y]) # and keep the position self.oldxy = [x, y] return True return super(Pad, self).on_touch_move(touch) def on_touch_up(self, touch): if touch.grab_current is self: touch.ungrab(self) # print('elements', self.elements) # try: with misc.timeit() as t: self.reducematrix() # finally: print('Matrix reduction and redraw') self.oldxy = None return True return super(Pad, self).on_touch_up(touch) def drawline(self, newxy): if newxy not in self.elements: self.elements.append(newxy) with self._fbo: Line(points=self.oldxy + newxy, width=1) def reducematrix(self): self.matrix = [] minx = None maxx = None miny = None maxy = None with misc.timeit() as t: for i in range(len(self.elements) - 1): # all but last # take the current origin = self.elements[i] # and the next point = self.elements[i + 1] # and get all pixels in between points = misc.allpoints(origin, point) for p in points: if p not in self.matrix: if minx is None or p[0] < minx: minx = p[0] if maxx is None or p[0] > maxx: maxx = p[0] if miny is None or p[1] < miny: miny = p[1] if maxy is None or p[1] > maxy: maxy = p[1] self.matrix.append(p) print('- Calc all points') # ajust to the minimum coord for p in self.matrix: p[0] = p[0] - minx p[1] = p[1] - miny # print('matrix', self.matrix) if maxx is not None: size = max(maxx - minx, maxy - miny) # print(' minx', minx, 'miny', miny, 'maxx', maxx, 'maxy', maxy, 'size', size) else: size = self.width with misc.timeit() as t: self.scaled = misc.scalematrix(self.matrix, (size, size), (15, 15)) # finally: print('- Scale matrix') # print('scaled', self.scaled) # RELOADING THE BUFFER AT ANY CHANGE def _clear_fbo(self, fbo=None): ''' This will reload the framebufferer either by the call of the observer or by the deletion of a point''' if fbo is None: fbo = self._fbo fbo.bind() fbo.clear_buffer() fbo.add(Color(1, 1, 1)) fbo.add(self._fborect) fbo.add(Color(1, 0, 0)) fbo.release() def _update_rect(self, instance, value): self._fbo.size = instance.size self._fborect.size = instance.size self._rect.size = instance.size self._rect.pos = instance.pos self._rect.texture = self._fbo.texture
class GLWindow(BoxLayout): texture = ObjectProperty(None, allownone=True) def __init__(self, **kwargs): self.mesh_data = MeshData() self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=(10, 10), compute_normal_mat=True) self.fbo.add_reload_observer(self.populate_fbo) with self.fbo: ClearColor(0, 0, 0, 0) ClearBuffers() self.populate_fbo(self.fbo) super(GLWindow, self).__init__(**kwargs) Clock.schedule_interval(self.update_glsl, 1 / 60.) def populate_fbo(self, fbo): Logger.info("Setting up FBO") with self.canvas: fbo.shader.source = resource_find('simple.glsl') fbo['diffuse_light'] = (1.0, 1.0, 0.8) fbo['ambient_light'] = (0.8, 0.8, 0.8) with fbo: self.cb = Callback(self.setup_gl_context) PushMatrix() BindTexture(source='testure.jpg', index=1) UpdateNormalMatrix() Translate(0,0,-3) self.rot = Rotate(1,0,1,0) # self.show_axis() self.make_pretty_dots() PopMatrix() self.cb = Callback(self.reset_gl_context) fbo['texture1'] = 1 def update_glsl(self, *largs): asp = self.size[0] / float(self.size[1]) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) model = Matrix().look_at( 0.0, 0.0, 0.25, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0) with self.canvas: self.fbo.shader.source = resource_find('simple.glsl') self.fbo['projection_mat'] = proj self.fbo['modelview_mat'] = model self.rot.angle += -1 self.texture = self.fbo.texture with self.fbo: BindTexture(source='testure.jpg', index=1) def setup_gl_context(self, *args): glEnable(GL_DEPTH_TEST) def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def on_size(self, instance, value): Logger.info('resize') self.fbo.size = value self.texture = self.fbo.texture def show_axis(self): Color(1, 1, 0, 1) #Yellow Mesh( vertices=[ -1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0.8, 0.1, 0, 1, 1, 0, 0, 0, 0.8, -0.1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0.8, 0, -0.1, 1, 1, 0, 0, 0, 0.8, 0, 0.1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, ], indices=[0, 1, 2, 3, 4, 5, 6, 7], fmt=self.mesh_data.vertex_format, mode='line_strip', ) Color(1, 0, 1, 1) # purple Mesh( vertices=[ 0, 0, -1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0.1, 0, 0.8, 0, 1, 1, 0, 0, -0.1, 0, 0.8, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, -0.1, 0.8, 0, 1, 1, 0, 0, 0, 0.1, 0.8, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, ], indices=[0, 1, 2, 3, 4, 5, 6, 7], fmt=self.mesh_data.vertex_format, mode='line_strip', ) Color(0, 1, 1, 1) # Baby Blue Mesh( vertices=[ 0, -1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0.1, 0.8, 0, 1, 1, 0, 0, 0, -0.1, 0.8, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0.8, -0.1, 1, 1, 0, 0, 0, 0, 0.8, 0.1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, ], indices=[0, 1, 2, 3, 4, 5, 6, 7], fmt=self.mesh_data.vertex_format, mode='line_strip', ) def make_pretty_dots(self): points_per_side = 50 points = [] for idx in range(points_per_side): v = -1.0 + ((2.0 / points_per_side) * float(idx)) tex = idx / float(points_per_side) print ("TEX: {}".format(str(tex)) ) points.append( [ [ v, -1.0, -1.0, v, -1.0, -1.0, tex, 0.0], [ v, -1.0, 1.0, v, -1.0, 1.0, tex, 0.0], [ v, 1.0, -1.0, v, 1.0, -1.0, tex, 1.0], [ v, 1.0, 1.0, v, 1.0, 1.0, tex, 1.0], [ -1.0, v, -1.0, -1.0, v, -1.0, 0.0, tex], [ -1.0, v, 1.0, -1.0, v, 1.0, 0.0, tex], [ 1.0, v, -1.0, 1.0, v, -1.0, 1.0, tex], [ 1.0, v, 1.0, 1.0, v, 1.0, 1.0, tex], [ -1.0, -1.0, v, -1.0, -1.0, v, tex, tex], [ -1.0, 1.0, v, -1.0, 1.0, v, tex, tex], [ 1.0, -1.0, v, 1.0, -1.0, v, tex, tex], [ 1.0, 1.0, v, 1.0, 1.0, v, tex, tex]], ) points = np.array(points).flatten() Color(1,1,1,1) Mesh( vertices=points, indices=[i for i in range(len(points) / 8)], fmt=self.mesh_data.vertex_format, mode='points', )
class Pad(Widget): scaled = ListProperty() def __init__(self, **kwargs): super(Pad, self).__init__(**kwargs) # Which elements exist in the grid in the normalized coordinates self.elements = [] self.oldxy = None with self.canvas: self._fbo = Fbo(size=self.size) self._rect = Rectangle(texture=self._fbo.texture) with self._fbo: Color(1, 1, 1) self._fborect = Rectangle(size=self._fbo.size) Color(1, 0, 0) self._fbo.add_reload_observer(self._clear_fbo) self.bind(pos=self._update_rect, size=self._update_rect) def on_touch_down(self, touch): if self.collide_point(*touch.pos): # let's hold the mouse touch.grab(self) self.elements = [] self._clear_fbo() x = round(touch.x - self.x) y = round(touch.y - self.y) # and keep the position self.oldxy = [x, y] return True return super(Pad, self).on_touch_down(touch) def on_touch_move(self, touch): if self.collide_point(*touch.pos): x = round(touch.x - self.x) y = round(touch.y - self.y) self.drawline([x, y]) # and keep the position self.oldxy = [x, y] return True return super(Pad, self).on_touch_move(touch) def on_touch_up(self, touch): if touch.grab_current is self: touch.ungrab(self) # print('elements', self.elements) # try: with misc.timeit() as t: self.reducematrix() # finally: print("Matrix reduction and redraw") self.oldxy = None return True return super(Pad, self).on_touch_up(touch) def drawline(self, newxy): if newxy not in self.elements: self.elements.append(newxy) with self._fbo: Line(points=self.oldxy + newxy, width=1) def reducematrix(self): self.matrix = [] minx = None maxx = None miny = None maxy = None with misc.timeit() as t: for i in range(len(self.elements) - 1): # all but last # take the current origin = self.elements[i] # and the next point = self.elements[i + 1] # and get all pixels in between points = misc.allpoints(origin, point) for p in points: if p not in self.matrix: if minx is None or p[0] < minx: minx = p[0] if maxx is None or p[0] > maxx: maxx = p[0] if miny is None or p[1] < miny: miny = p[1] if maxy is None or p[1] > maxy: maxy = p[1] self.matrix.append(p) print("- Calc all points") # ajust to the minimum coord for p in self.matrix: p[0] = p[0] - minx p[1] = p[1] - miny # print('matrix', self.matrix) if maxx is not None: size = max(maxx - minx, maxy - miny) # print(' minx', minx, 'miny', miny, 'maxx', maxx, 'maxy', maxy, 'size', size) else: size = self.width with misc.timeit() as t: self.scaled = misc.scalematrix(self.matrix, (size, size), (15, 15)) # finally: print("- Scale matrix") # print('scaled', self.scaled) # RELOADING THE BUFFER AT ANY CHANGE def _clear_fbo(self, fbo=None): """ This will reload the framebufferer either by the call of the observer or by the deletion of a point""" if fbo is None: fbo = self._fbo fbo.bind() fbo.clear_buffer() fbo.add(Color(1, 1, 1)) fbo.add(self._fborect) fbo.add(Color(1, 0, 0)) fbo.release() def _update_rect(self, instance, value): self._fbo.size = instance.size self._fborect.size = instance.size self._rect.size = instance.size self._rect.pos = instance.pos self._rect.texture = self._fbo.texture