def fbo_create(self, size, tex=None): if tex is None: tex = Texture.create(size=size, colorfmt='rgba', bufferfmt='ubyte') tex.mag_filter = 'nearest' tex.min_filter = 'nearest' if self.fbo is None: self.fbo = Fbo(size=size, texture=tex) self.fbo.texture.mag_filter = 'nearest' self.fbo.texture.min_filter = 'nearest' else: self.fbo = Fbo(size=size, texture=tex) self.fbo.texture.mag_filter = 'nearest' self.fbo.texture.min_filter = 'nearest' tool_tex = Texture.create(size=size, colorfmt='rgba', bufferfmt='ubyte') tool_tex.mag_filter = 'nearest' tool_tex.min_filter = 'nearest' if self.tool_fbo is None: self.tool_fbo = Fbo(size=size, texture=tool_tex) self.tool_fbo.texture.mag_filter = 'nearest' self.tool_fbo.texture.min_filter = 'nearest' else: self.tool_fbo = Fbo(size=size, texture=tool_tex) self.tool_fbo.texture.mag_filter = 'nearest' self.tool_fbo.texture.min_filter = 'nearest' return self.fbo
class Renderer(Widget): def __init__(self, **kw): self.shader_file = kw.pop("shader_file", None) self.canvas = Canvas() super(Renderer, self).__init__(**kw) with self.canvas: self._viewport = Rectangle(size=self.size, pos=self.pos) self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True) self._config_fbo() self.texture = self.fbo.texture self.camera = None self.scene = None def _config_fbo(self): # set shader file here self.fbo.shader.source = self.shader_file or \ os.path.join(kivy3_path, "default.glsl") with self.fbo: Callback(self._setup_gl_context) PushMatrix() # instructions set for all instructions self._instructions = InstructionGroup() PopMatrix() Callback(self._reset_gl_context) def _setup_gl_context(self, *args): glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() def _reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def render(self, scene, camera): self.scene = scene self.camera = camera self.camera.bind_to(self) self._instructions.add(scene.as_instructions()) Clock.schedule_once(self._update_matrices, -1) def on_size(self, instance, value): self.fbo.size = value self._viewport.texture = self.fbo.texture self._viewport.size = value self._update_matrices() def on_texture(self, instance, value): self._viewport.texture = value def _update_matrices(self, dt=None): if self.camera: self.fbo['projection_mat'] = self.camera.projection_matrix self.fbo['modelview_mat'] = self.camera.modelview_matrix else: raise RendererError("Camera is not defined for renderer") def set_clear_color(self, color): self.fbo.clear_color = color
def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas.before: Callback(self._set_blend_func) self.fbo_texture = Texture.create(size=self.size, colorfmt='rgba',) self.fbo_texture.mag_filter='nearest' with self.canvas: #self.cbs = Callback(self.prepare_canvas) self.fbo = Fbo(size=self.size, texture=self.fbo_texture) #Color(1, 1, 1, 0) #self.fbo_rect = Rectangle() with self.fbo: ClearColor(0.0, 0.0, 0.0, 0.0) ClearBuffers() self.fbo_rect = Rectangle(size=self.size) #self.fbo.shader.source = resource_find('./kivy3dgui/gles2.0/shaders/invert.glsl') #with self.fbo.after: # self.cbr = Callback(self.reset_gl_context) # PopMatrix() with self.canvas.before: Callback(self._set_blend_func) # wait that all the instructions are in the canvas to set texture self.texture = self.fbo.texture super(FboFloatLayout, self).__init__(**kwargs)
def refbo(self): tex = Texture.create(size=self.fbo.texture.size, colorfmt='rgba', bufferfmt='ubyte') self.fbo = Fbo(size=tex.size, texture=tex) self.fbo.texture.mag_filter = 'nearest' self.fbo.texture.min_filter = 'nearest' self.fbo.draw() self.canvas.ask_update()
def __init__(self, **kwargs): # self.canvas = RenderContext(compute_normal_mat=True) # self.canvas.shader.source = resource_find('simple.glsl') self.canvas = Canvas() self.scene = ObjFileLoader(resource_find("testnurbs.obj")) self.meshes = [] with self.canvas: self.fbo = Fbo( size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0.0, 0.0, 0.0, 0.0) ) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find("simple.glsl") # self.texture = self.fbo.texture super(Renderer, self).__init__(**kwargs) with self.fbo: # ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) Clock.schedule_interval(self.update_scene, 1 / 60.0) self._touches = []
def texture_get_data(texture): size = texture.size fbo = Fbo(size=texture.size, texture=texture) fbo.draw() fbo.bind() data = glReadPixels(0, 0, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE) fbo.release() return data
def texture_to_pil_image(texture): size = texture.size fbo = Fbo(size=texture.size, texture=texture) fbo.draw() fbo.bind() data = glReadPixels(0, 0, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE) fbo.release() im = PILImage.fromstring('RGBA', size, data) return im
def on_parent(self, *args): if not self.canvas: Clock.schedule_once(self.on_parent, 0) return if not hasattr(self, '_fbo'): with self.canvas: self._fbo = Fbo(size=self.size) self._fbo.add_reload_observer(self.redraw) self._translate = Translate(x=self.x, y=self.y) self._rectangle = Rectangle(texture=self._fbo.texture, size=self.size) self.rebind_children()
def merged_texture_from_zip(filename): textures_list = textures_list_from_zip(filename) fbo = Fbo(size=textures_list[0].size) fbo.bind() with fbo: for texture in textures_list: Rectangle(texture=texture) fbo.release() fbo.draw() return fbo.texture
def _redraw(self, *args): if not self._ffplayer: return next_frame = self._next_frame if not next_frame: return img, pts = next_frame if img.get_size() != self._size or self._texture is None: self._size = w, h = img.get_size() if self._out_fmt == 'yuv420p': w2 = int(w / 2) h2 = int(h / 2) self._tex_y = Texture.create(size=(w, h), colorfmt='luminance') self._tex_u = Texture.create(size=(w2, h2), colorfmt='luminance') self._tex_v = Texture.create(size=(w2, h2), colorfmt='luminance') self._fbo = fbo = Fbo(size=self._size) with fbo: BindTexture(texture=self._tex_u, index=1) BindTexture(texture=self._tex_v, index=2) Rectangle(size=fbo.size, texture=self._tex_y) fbo.shader.fs = VideoFFPy.YUV_RGB_FS fbo['tex_y'] = 0 fbo['tex_u'] = 1 fbo['tex_v'] = 2 self._texture = fbo.texture else: self._texture = Texture.create(size=self._size, colorfmt='rgba') # XXX FIXME # self.texture.add_reload_observer(self.reload_buffer) self._texture.flip_vertical() self.dispatch('on_load') if self._texture: if self._out_fmt == 'yuv420p': dy, du, dv, _ = img.to_memoryview() if dy and du and dv: self._tex_y.blit_buffer(dy, colorfmt='luminance') self._tex_u.blit_buffer(du, colorfmt='luminance') self._tex_v.blit_buffer(dv, colorfmt='luminance') self._fbo.ask_update() self._fbo.draw() else: self._texture.blit_buffer(img.to_memoryview()[0], colorfmt='rgba') self.dispatch('on_frame')
def widget_save_canvas(widget, filename, format): parent = widget.parent if parent: parent.remove_widget(widget) size = (int(widget.size[0]), int(widget.size[1])) texture = Texture.create(size=widget.size, colorfmt='rgba') fbo = Fbo(size=widget.size, texture=texture) fbo.add(widget.canvas) fbo.draw() fbo.bind() data = glReadPixels(0, 0, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE) fbo.release() im = PILImage.fromstring('RGBA', size, data) im = im.transpose(PILImage.FLIP_TOP_BOTTOM) im.save(filename, format) if parent: parent.add_widget(widget) return True
def __init__(self, **kwargs): self.canvas = Canvas() self.scene = ObjFileLoader(resource_find("brain.obj")) self.meshes = [] with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self.viewport = Rectangle(size=self.size, pos=(0, -150)) self.fbo.shader.source = resource_find('simple.glsl') super(Renderer, self).__init__(**kwargs) with self.fbo: self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context)
class Graph(Image): def __init__(self, colors=(Color(1, 0, 1)), *args, **kwargs): if 'height' not in kwargs: kwargs['height'] = 32 self.fbo = Fbo() with self.fbo: Color(1, 1, 1) self.fboscrollrect = Rectangle(pos=(-1, 0)) Color(0, 0, 0) self.fboclearrect = Rectangle() self.points = [] self.colors = [] for color in colors: self.colors.append(Color(*color.rgba)) self.points.append(Point(points=(), pointsize=0.5)) super().__init__(*args, **kwargs) @staticmethod def to2pow(x): return 1 << (int(x) - 1).bit_length() def on_size(self, instance, size): self.fbo.size = (*(self.to2pow(v) for v in size), ) self.fboscrollrect.size = self.fbo.size self.fboclearrect.pos = (self.fbo.size[0] - 1, 0) self.fboclearrect.size = (1, self.fbo.size[1]) # this quick call to draw while the old texture is still attached stretches the old image instead of # preserving it at the proper scale, but at least it keeps the old data visible in some manner self.fbo.draw() self.fboscrollrect.texture = self.fbo.texture self.fboscrollrect.tex_coords = self.fbo.texture.tex_coords self.texture = self.fbo.texture def add(self, *values): for point, value in zip(self.points, values): point.points = (self.fbo.size[0] - 0.5, (value + 1) / 2 * self.fbo.size[1]) self.fbo.draw() self.canvas.ask_update()
def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find( join(dirname(__file__), 'simple.glsl')) super(ObjectRenderer, self).__init__(**kwargs)
def render_widget(self, widget): # create an FBO to render the widget to self.tmp_fbo = Fbo(size = self.size) self.tmp_fbo.add(ClearColor(0,0,0,0)) self.tmp_fbo.add(ClearBuffers()) self.tmp_fbo.add(widget.canvas) self.tmp_fbo.draw() # render a rectangle in the main fbo containing the content from the widget with self.fbo: Color(1,1,1,1) Rectangle(texture=self.tmp_fbo.texture, size=self.tmp_fbo.size)
def __init__(self, mc: "MpfMc", name: str, config: dict) -> None: """Initialise DMD.""" self.mc = mc self.name = name self.mc.log.info('Initializing DMD') self.config = self._get_validated_config(config) self.source = self.mc.displays[self.config['source_display']] self.prev_data = None # put the widget canvas on a Fbo texture = Texture.create(size=self.source.size, colorfmt='rgb') self.fbo = Fbo(size=self.source.size, texture=texture) self.effect_widget = EffectWidget() effect_list = list() effect_list.append(FlipVerticalEffect()) if self.config['brightness'] != 1.0: if not 0.0 <= self.config['brightness'] <= 1.0: raise ValueError("DMD brightness value should be between 0.0 " "and 1.0. Yours is {}".format( self.config['brightness'])) effect_list.append(GainEffect(gain=self.config['brightness'])) if self.config['gamma'] != 1.0: effect_list.append(GammaEffect(gamma=self.config['gamma'])) self.effect_widget.effects = effect_list self.effect_widget.size = self.source.size self.fbo.add(self.effect_widget.canvas) self._set_dmd_fps()
def _setup_fbo(self, element, settings): """Setup FBO for a display.""" if element not in self.machine.displays: raise AssertionError( "Display {} not found. Please create it to use display_light_player." .format(element)) source = self.machine.displays[element] # put the widget canvas on a Fbo texture = Texture.create(size=source.size, colorfmt='rgb') fbo = Fbo(size=source.size, texture=texture) effect_widget = EffectWidget() effect_list = list() effect_widget.effects = effect_list effect_widget.size = source.size fbo.add(effect_widget.canvas) return [fbo, effect_widget, source, settings, True]
def __init__(self, **kw): self.shader_file = kw.pop("shader_file", None) self.canvas = Canvas() super(Renderer, self).__init__(**kw) with self.canvas: self._viewport = Rectangle(size=self.size, pos=self.pos) self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True) self._config_fbo() self.texture = self.fbo.texture self.camera = None self.scene = None
def texture_add_to_zip(texture, zip_object, entry_name): size = texture.size fbo = Fbo(size=texture.size, texture=texture) fbo.draw() fbo.bind() if format == 'BMP': data = glReadPixels(0, 0, size[0], size[1], GL_RGB, GL_UNSIGNED_BYTE) else: data = glReadPixels(0, 0, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE) fbo.release() zip_object.writestr(entry_name, data)
def export(self, wid, *largs): fbo = Fbo(size=wid.size, with_stencilbuffer=True) with fbo: ClearColor(1, 1, 1, 1) ClearBuffers() #Scale(1, -1, 1) #Translate(-self.x, -self.y - self.height, 0) fbo.add(wid.canvas) fbo.draw() img = fbo.texture img.save('test.png') fbo.remove(wid.canvas)
def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=self.size) self.fbo_color = Color(1, 1, 1, 1) self.fbo_rect = Rectangle() with self.fbo: ClearColor(0, 0, 0, 0) ClearBuffers() # wait that all the instructions are in the canvas to set texture self.texture = self.fbo.texture super(FboFloatLayout, self).__init__(**kwargs)
def _setup_fbo(self, element, settings, context): """Setup FBO for a display.""" if element not in self.machine.displays: raise AssertionError( "Display {} not found. Please create it to use display_light_player." .format(element)) source = self.machine.displays[element] # put the widget canvas on a Fbo texture = Texture.create(size=source.size, colorfmt='rgba') fbo = Fbo(size=source.size, texture=texture) effect_widget = RelativeLayout() effect_widget.size = source.size fbo.add(effect_widget.canvas) with source.canvas: callback = Callback(partial(self._trigger_render, context, element)) return [ fbo, effect_widget, source, settings, True, True, True, callback ]
def __init__(self, filename=None, onload=None, maxtexsize=(1024, 1024), **kwargs): if maxtexsize == None: maxtexsize = (1024, 1024) self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=maxtexsize) self.fbo.add_reload_observer(self.updateFbo) self.border_image = CoreImage('data/shadow32.png') self.img_texture = Texture.create(size=(16, 16), colorfmt="rgba") self.alpha = 0 self.fbo_texture = self.fbo.texture super(Picture, self).__init__(**kwargs) self.loadImage(filename, onload)
def __init__(self, **kwargs): LOP, dm = initFiles() #self.canvas = RenderContext(compute_normal_mat=True) #self.canvas.shader.source = resource_find('simple.glsl') self.canvas = Canvas() self.scene = ObjFileLoader(resource_find("testnurbs.obj")) self.LOP = LOP self.dm = dm self.meshes = [] self.panCamera = False # KEITH EDIT self.pause = True # KEITH EDIT with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find('simple.glsl') #self.texture = self.fbo.texture # *&Y*&Y*&YH*&Y*&Y*&Y*Y&* # Keith: This allows keyboard interaction # http://stackoverflow.com/questions/22137786/ self._keyboard = Window.request_keyboard(None, self) if not self._keyboard: return self._keyboard.bind(on_key_down=self.on_keyboard_down) # *&Y*&Y*&YH*&Y*&Y*&Y*Y&* super(NSpect, self).__init__(**kwargs) with self.fbo: #ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene(self.LOP, dm) PopMatrix() self.cb = Callback(self.reset_gl_context) Clock.schedule_interval(self.update_scene, 1 / 60.) self._touches = []
def texture_save(texture, filename, format=None): size = texture.size fbo = Fbo(size=texture.size, texture=texture) fbo.draw() fbo.bind() if format == 'BMP': data = glReadPixels(0, 0, size[0], size[1], GL_RGB, GL_UNSIGNED_BYTE) else: data = glReadPixels(0, 0, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE) fbo.release() if format == 'BMP': im = PILImage.fromstring('RGB', size, data) else: im = PILImage.fromstring('RGBA', size, data) im = im.transpose(PILImage.FLIP_TOP_BOTTOM) im.save(filename)
def create_image(self): parent = self.parent if parent: canvas_parent_index = parent.canvas.indexof(self.canvas) if canvas_parent_index > -1: parent.canvas.remove(self.canvas) fbo = Fbo(size=self.size, with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Scale(1, -1, 1) Translate(-self.x, -self.y - self.height, 0) fbo.add(self.canvas) fbo.draw() image = Image.frombytes('RGBA', list(map(int, self.size)), fbo.texture.pixels, 'raw', 'RGBA', 0, 1) fbo.remove(self.canvas) if parent is not None and canvas_parent_index > -1: parent.canvas.insert(canvas_parent_index, self.canvas) return image
def screenshot(widget, filename='output.png', region=None): if widget.parent is not None: canvas_parent_index = widget.parent.canvas.indexof(widget.canvas) widget.parent.canvas.remove(widget.canvas) fbo = Fbo(size=widget.size) with fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Translate(-widget.x, -widget.y, 0) fbo.add(widget.canvas) fbo.draw() fbo.texture.save(filename) fbo.remove(widget.canvas) if widget.parent is not None: widget.parent.canvas.insert(canvas_parent_index, widget.canvas) return True
def __init__(self, filename=None, onload=None, maxtexsize=(1024, 1024), **kwargs): if maxtexsize == None: maxtexsize = (1024, 1024) self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=maxtexsize) self.fbo.add_reload_observer(self.updateFbo) self.border_image = CoreImage("data/shadow32.png") self.img_texture = Texture.create(size=(16, 16), colorfmt="rgba") self.alpha = 0 self.fbo_texture = self.fbo.texture super(Picture, self).__init__(**kwargs) self.loadImage(filename, onload)
def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas: self.fbo = Fbo( size=self.size, with_depthbuffer=True, ) self.fbo_color = Color(1, 1, 1, 1) self.viewport = Rectangle( pos=self.pos, size=self.size, ) with self.fbo: ClearColor(0, 0, 0, 0) ClearBuffers() self.texture = self.fbo.texture super(TransparentLayout, self).__init__(**kwargs)
def screenshot_texture(widget, factory_func): if widget.parent is not None: canvas_parent_index = widget.parent.canvas.indexof(widget.canvas) widget.parent.canvas.remove(widget.canvas) fbo = Fbo(size=widget.size) with fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Translate(-widget.x, -widget.y, 0) fbo.add(widget.canvas) fbo.draw() result = factory_func(fbo.texture) fbo.remove(widget.canvas) if widget.parent is not None: widget.parent.canvas.insert(canvas_parent_index, widget.canvas) return result
def update_img(self, img, force=False): ''' Updates the screen with a new image. :Parameters: `img`: :class:`~ffpyplayer.pic.Image` instance The image to be displayed. ''' from ffpyplayer.tools import get_best_pix_fmt from ffpyplayer.pic import SWScale if img is None: return img_fmt = img.get_pixel_format() self.image_size = img_w, img_h = img.get_size() update = force if self._iw != img_w or self._ih != img_h: update = True if img_fmt not in ('yuv420p', 'rgba', 'rgb24', 'gray', 'bgr24', 'bgra'): swscale = self._swscale if img_fmt != self._sw_src_fmt or swscale is None or update: ofmt = get_best_pix_fmt( img_fmt, ( 'yuv420p', 'rgba', 'rgb24', 'gray', 'bgr24', 'bgra')) self._swscale = swscale = SWScale( iw=img_w, ih=img_h, ifmt=img_fmt, ow=0, oh=0, ofmt=ofmt) self._sw_src_fmt = img_fmt img = swscale.scale(img) img_fmt = img.get_pixel_format() w, h = self.available_size or self.size if (not w) or not h: self.img = img return if self._fmt != img_fmt: self._fmt = img_fmt self._kivy_ofmt = { 'yuv420p': 'yuv420p', 'rgba': 'rgba', 'rgb24': 'rgb', 'gray': 'luminance', 'bgr24': 'bgr', 'bgra': 'bgra'}[img_fmt] update = True if update or w != self._last_w or h != self._last_h or \ self.rotation != self._last_rotation: if self.scale_to_image: rotation = self.rotation rot = self.rotation * math.pi / 180 rot_w = abs(img_w * math.cos(rot)) + abs(img_h * math.sin(rot)) rot_h = abs(img_h * math.cos(rot)) + abs(img_w * math.sin(rot)) scalew, scaleh = w / rot_w, h / rot_h scale = min(min(scalew, scaleh), 1) self.transform = Matrix() self.rotation = rotation self.apply_transform(Matrix().scale(scale, scale, 1), post_multiply=True) self.pos = 0, 0 self._iw, self._ih = img_w, img_h self._last_h = h self._last_w = w self._last_rotation = self.rotation self.img = img kivy_ofmt = self._kivy_ofmt if update: self.canvas.remove_group(str(self) + 'image_display') if kivy_ofmt == 'yuv420p': w2 = int(img_w / 2) h2 = int(img_h / 2) self._tex_y = Texture.create(size=(img_w, img_h), colorfmt='luminance') self._tex_u = Texture.create(size=(w2, h2), colorfmt='luminance') self._tex_v = Texture.create(size=(w2, h2), colorfmt='luminance') with self.canvas: self._fbo = fbo = Fbo(size=(img_w, img_h), group=str(self) + 'image_display') with fbo: BindTexture(texture=self._tex_u, index=1) BindTexture(texture=self._tex_v, index=2) Rectangle(size=fbo.size, texture=self._tex_y) fbo.shader.fs = BufferImage._YUV_RGB_FS fbo['tex_y'] = 0 fbo['tex_u'] = 1 fbo['tex_v'] = 2 tex = self.img_texture = fbo.texture fbo.add_reload_observer(self.reload_buffer) else: tex = self.img_texture = Texture.create( size=(img_w, img_h), colorfmt=kivy_ofmt) tex.add_reload_observer(self.reload_buffer) tex.flip_vertical() if self.flip: tex.flip_horizontal() self.texture_size = img_w, img_h if kivy_ofmt == 'yuv420p': dy, du, dv, _ = img.to_memoryview() self._tex_y.blit_buffer(dy, colorfmt='luminance') self._tex_u.blit_buffer(du, colorfmt='luminance') self._tex_v.blit_buffer(dv, colorfmt='luminance') self._fbo.ask_update() self._fbo.draw() else: self.img_texture.blit_buffer(img.to_memoryview()[0], colorfmt=kivy_ofmt) self.canvas.ask_update()
class TextureStackBatchWidget(Widget): """Widget for efficiently drawing many TextureStacks Only add TextureStack or ImageStack widgets to this. Avoid adding any that are to be changed frequently. """ critical_props = ['texs', 'offxs', 'offys', 'pos'] """Properties that, when changed on my children, force a redraw.""" def __init__(self, **kwargs): self._trigger_redraw = Clock.create_trigger(self.redraw) self._trigger_rebind_children = Clock.create_trigger(self.rebind_children) super(TextureStackBatchWidget, self).__init__(**kwargs) def on_parent(self, *args): if not self.canvas: Clock.schedule_once(self.on_parent, 0) return if not hasattr(self, '_fbo'): with self.canvas: self._fbo = Fbo(size=self.size) self._fbo.add_reload_observer(self.redraw) self._translate = Translate(x=self.x, y=self.y) self._rectangle = Rectangle(texture=self._fbo.texture, size=self.size) self.rebind_children() def rebind_children(self, *args): child_by_uid = {} binds = {prop: self._trigger_redraw for prop in self.critical_props} for child in self.children: child_by_uid[child.uid] = child child.bind(**binds) if hasattr(self, '_old_children'): old_children = self._old_children for uid in set(old_children).difference(child_by_uid): old_children[uid].unbind(**binds) self.redraw() self._old_children = child_by_uid def redraw(self, *args): fbo = self._fbo fbo.bind() fbo.clear() fbo.clear_buffer() fbo.release() for child in self.children: assert child.canvas not in fbo.children fbo.add(child.canvas) def on_pos(self, *args): if not hasattr(self, '_translate'): return self._translate.x, self._translate.y = self.pos def on_size(self, *args): if not hasattr(self, '_rectangle'): return self._rectangle.size = self._fbo.size = self.size self.redraw() def add_widget(self, widget, index=0, canvas=None): if not isinstance(widget, TextureStack): raise TypeError("TextureStackBatch is only for TextureStack") if index == 0 or len(self.children) == 0: self.children.insert(0, widget) else: children = self.children if index >= len(children): index = len(children) children.insert(index, widget) widget.parent = self if hasattr(self, '_fbo'): self.rebind_children() def remove_widget(self, widget): if widget not in self.children: return self.children.remove(widget) widget.parent = None if hasattr(self, '_fbo'): self.rebind_children()
def __init__(self, **kwargs): self.canvas = Canvas() window_width = Window.width window_height = Window.height aspect = window_width / float(window_height) center_x = window_width / 2. center_y = window_height / 2. element_size = window_width with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True) self.fbo_color = Color(1, 1, 1, 1) self.fbo_rects = ( StencilPush(), Triangle(points=( 0, 0, center_x * 1.5, window_height, 0, window_height, )), StencilUse(), Rotate(angle=-90, axis=(0, 0, 1), origin=(center_x, window_height * 2 / 3.)), Rectangle(pos=(center_x - element_size / 2., -5), size=(element_size, element_size / aspect), texture=self.texture), Rotate(angle=90, axis=(0, 0, 1), origin=(center_x, window_height * 2 / 3.)), StencilUnUse(), Triangle(points=( 0, 0, center_x * 1.5, window_height, 0, window_height, )), StencilPop(), StencilPush(), Triangle(points=( window_width, 0, center_x * .5, window_height, window_width, window_height, )), StencilUse(), Rotate(angle=90, axis=(0, 0, 1), origin=(center_x, window_height * 2 / 3.)), Rectangle(pos=(center_x - element_size / 2., -5), size=(element_size, element_size / aspect), texture=self.texture), ) Rotate(angle=-90, axis=(0, 0, 1), origin=(center_x, window_height * 2 / 3.)) StencilUnUse() Triangle(points=( window_width, 0, center_x * .5, window_height, window_width, window_height, )) StencilPop() StencilPush() Triangle(points=( 0, 0, window_width, 0, center_x, window_height * 2 / 3., )) StencilUse() if self.texture: self.texture.flip_horizontal() self.mirrored_rect = Rectangle(pos=(center_x - element_size / 2., 0), size=(element_size, element_size / aspect), texture=self.texture) StencilUnUse() Triangle(points=( 0, 0, window_width, 0, center_x, window_height * 2 / 3., )) StencilPop() with self.fbo: ClearColor(0, 0, 0, 0) ClearBuffers() self.texture = self.fbo.texture super(HoloStandLayout, self).__init__(**kwargs)
def count_it(num): if num == 0: fbo = Fbo(size=self.stencil.size, with_stencilbuffer=True) with fbo: ClearColor(1, 1, 1, 0) ClearBuffers() img2 = self.paintscreen.bg.texture fbo.add(self.stencil.canvas) fbo.draw() img = fbo.texture fbo.remove(self.stencil.canvas) self.remove_widget(self.paintscreen) im = np.frombuffer(img.pixels, np.uint8) data = np.reshape(im, (im.shape[0], 1)).tostring() data2 = str(data) data2 = str.encode(data2) pix = np.frombuffer(data, np.uint8) a = np.empty_like(pix) a[:] = pix texture = Texture.create(size=self.stencil.size) texture.blit_buffer(a, colorfmt='rgba', bufferfmt='ubyte') self.imge = Image(pos=(0, 0), size=self.paintscreen.stencil.size, texture=texture) #self.paintscreen.stencil.add_widget(self.imge) #img2 = self.paintscreen.grid_layout.bg.texture im2 = np.frombuffer(img2.pixels, np.uint8) data = np.reshape(im2, (im2.shape[0], 1)).tostring() data2 = str(data) data2 = str.encode(data2) pix = np.frombuffer(data, np.uint8) a2 = np.empty_like(pix) a2[:] = pix img2 = a2 print(img2.shape) print(img2) img1 = a print(img1.shape) import cv2 #setting alpha=1, beta=1, gamma=0 gives direct overlay of two images # in theory this would give a direct overlay... #img3 = cv2.addWeighted(img1, 1, img2, 1, 0) #print(img3.shape) im = img1.reshape(1200, 1200, 4) # for i in range(0, 1200): # for j in range(0,1200): # points = im[i,j,:] # if (points[3] == 0):#points[0] == 255 & points[1] == 255 & points[2] == 255): # im[i,j,:] = [255,255,255,0] img_2 = img2.reshape((1200, 1200, 4)) for i in range(0, 1200): for j in range(0, 1200): points1 = im[i, j, :] if (points1[3] != 0): img_2[i, j, :] = im[i, j, :] socket_client.send(img_2) while MESSAGE is None: pass if MESSAGE is not None: new_img = MESSAGE else: new_img = img_2 texture = Texture.create(size=(1200, 1200)) texture.blit_buffer(np.reshape(new_img, (1200 * 1200 * 4, )), colorfmt='rgba', bufferfmt='ubyte') self.paintscreen = PaintScreen() self.add_widget(self.paintscreen) self.paintscreen.bg.texture = texture return num -= 1 self.count.text = str(num) Clock.schedule_once(lambda dt: count_it(num), 1)
class FboFloatLayout(FloatLayout): texture = ObjectProperty(None, allownone=True) alpha_blending = BooleanProperty(False) def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas.before: Callback(self._set_blend_func) #self.size self.fbo_texture = Texture.create(size=self.size, colorfmt='rgba') self.fbo_texture.mag_filter = 'linear' self.fbo_texture.min_filter = 'linear' with self.canvas: #self.cbs = Callback(self.prepare_canvas) self.fbo = Fbo(size=self.size, texture=self.fbo_texture) #Color(1, 1, 1, 0) #self.fbo_rect = Rectangle() with self.fbo: ClearColor(0.0, 0.0, 0.0, 0.0) ClearBuffers() self.fbo_rect = Rectangle(size=self.size) #self.fbo.shader.source = resource_find('./kivy3dgui/gles2.0/shaders/invert.glsl') #with self.fbo.after: # self.cbr = Callback(self.reset_gl_context) # PopMatrix() with self.canvas.before: Callback(self._set_blend_func) # wait that all the instructions are in the canvas to set texture self.texture = self.fbo.texture super(FboFloatLayout, self).__init__(**kwargs) def prepare_canvas(self, *args): glEnable(GL_BLEND) glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE) glEnable(GL_DEPTH_TEST) def _set_blend_func(self, instruction): # clobber the blend mode if self.alpha_blending: glBlendFunc(GL_ONE, GL_ZERO) else: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glDisable(GL_CULL_FACE) self.fbo.draw() glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) def setup_gl_context(self, *args): glEnable(GL_BLEND) glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) glEnable(GL_DEPTH_TEST) def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) glDisable(GL_CULL_FACE) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) def add_widget(self, *largs): # trick to attach kivy3dgui instructino to fbo instead of canvas canvas = self.canvas self.canvas = self.fbo ret = super(FboFloatLayout, self).add_widget(*largs) self.canvas = canvas return ret def remove_widget(self, *largs): canvas = self.canvas self.canvas = self.fbo super(FboFloatLayout, self).remove_widget(*largs) self.canvas = canvas def on_size(self, instance, value): self.fbo.size = value self.texture = self.fbo_texture self.fbo_rect.size = value def on_pos(self, instance, value): self.fbo_rect.pos = value def on_texture(self, instance, value): self.fbo_rect.texture = value def on_touch_down(self, touch): return super(FboFloatLayout, self).on_touch_down(touch) def on_touch_move(self, touch): return super(FboFloatLayout, self).on_touch_move(touch) """def on_touch_up(self, touch): return super(FboFloatLayout, self).on_touch_up(touch)""" def on_touch_up(self, touch): for e in self.children: if e.collide_point(touch.x, touch.y): return e.on_touch_up(touch)
def widgetshot(widget, filename='output.png'): # detach the widget from the parent parent = widget.parent if parent: parent.remove_widget(widget) # put the widget canvas on a Fbo texture = Texture.create(size=widget.size, colorfmt='rgb') fbo = Fbo(size=widget.size, texture=texture) fbo.add(widget.canvas) # clear the fbo background fbo.bind() fbo.clear_buffer() fbo.release() # draw! fbo.draw() # get the fbo data fbo.bind() data = glReadPixels(0, 0, widget.size[0], widget.size[1], GL_RGBA, GL_UNSIGNED_BYTE) fbo.release() # save to a file surf = pygame.image.fromstring(data, widget.size, 'RGBA', True) pygame.image.save(surf, filename) # reattach to the parent if parent: parent.add_widget(widget) return True
class ObjectRenderer(Widget): scene = StringProperty('') obj_id = StringProperty('') obj_translation = ListProperty([0, 0, 0]) obj_rotation = ListProperty([0, 0, 0]) obj_scale = NumericProperty(1) obj_texture = StringProperty('') texture = ObjectProperty(None, allownone=True) cam_translation = ListProperty([0, 0, 0]) cam_rotation = ListProperty([0, 0, 0]) display_all = BooleanProperty(False) light_sources = DictProperty() ambiant = NumericProperty(.5) diffuse = NumericProperty(.5) specular = NumericProperty(.5) mode = StringProperty('triangles') def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find( join(dirname(__file__), 'simple.glsl')) super(ObjectRenderer, self).__init__(**kwargs) def on_obj_rotation(self, *args): self.obj_rot_x.angle = self.obj_rotation[0] self.obj_rot_y.angle = self.obj_rotation[1] self.obj_rot_z.angle = self.obj_rotation[2] def on_cam_rotation(self, *args): self.cam_rot_x.angle = self.cam_rotation[0] self.cam_rot_y.angle = self.cam_rotation[1] self.cam_rot_z.angle = self.cam_rotation[2] def on_obj_translation(self, *args): self.obj_translate.xyz = self.cam_translation def on_cam_translation(self, *args): self.cam_translate.xyz = self.cam_translation def on_obj_scale(self, *args): self.scale.xyz = [self.obj_scale, ] * 3 def on_display_all(self, *args): self.setup_canvas() def on_light_sources(self, *args): self.fbo['light_sources'] = [ ls[:] for ls in list(self.light_sources.values())] self.fbo['nb_lights'] = len(self.light_sources) def on_ambiant(self, *args): self.fbo['ambiant'] = self.ambiant def on_diffuse(self, *args): self.fbo['diffuse'] = self.diffuse def on_specular(self, *args): self.fbo['specular'] = self.specular def on_mode(self, *args): self.setup_canvas() def setup_canvas(self, *args): if not (self.scene and self.obj_id or self.display_all): return print('setting up the scene') with self.fbo: self.fbo['ambiant'] = self.ambiant self.fbo['diffuse'] = self.diffuse self.fbo['specular'] = self.specular self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) def on_scene(self, instance, value): print("loading scene %s" % value) self._scene = ObjFileLoader(resource_find(value)) self.setup_canvas() def on_obj_id(self, *args): self.setup_canvas() def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def on_pos(self, instance, value): self.viewport.pos = value def on_texture(self, instance, value): self.viewport.texture = value def setup_gl_context(self, *args): glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *args): asp = self.width / float(self.height) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) self.fbo['projection_mat'] = proj def setup_scene(self): Color(1, 1, 1, 0) PushMatrix() self.cam_translate = Translate(self.cam_translation) # Rotate(0, 1, 0, 0) self.cam_rot_x = Rotate(self.cam_rotation[0], 1, 0, 0) self.cam_rot_y = Rotate(self.cam_rotation[1], 0, 1, 0) self.cam_rot_z = Rotate(self.cam_rotation[2], 0, 0, 1) self.scale = Scale(self.obj_scale) UpdateNormalMatrix() if self.display_all: for i in self._scene.objects: self.draw_object(i) else: self.draw_object(self.obj_id) PopMatrix() def draw_object(self, obj_id): m = self._scene.objects[obj_id] self.obj_rot_x = Rotate(self.obj_rotation[0], 1, 0, 0) self.obj_rot_y = Rotate(self.obj_rotation[1], 0, 1, 0) self.obj_rot_z = Rotate(self.obj_rotation[2], 0, 0, 1) self.obj_translate = Translate(xyz=self.obj_translation) if len(m.indices) > 2 ** 16: print('%s too big! %s indices' % (obj_id, len(m.indices))) if m.texture: print("loading texture %s " % m.texture) img = Image(source=resource_find( join(dirname(self.scene), m.texture))) texture = img.texture if texture: texture.wrap = 'repeat' else: texture = None vertex_lenght = sum(x[1] for x in m.vertex_format) if len(m.vertices) % vertex_lenght: print(( ( 'warning: vertices lenght (%s)' 'is not a multiple of vertex_format lenght(%s)' ) % (len(m.vertices), vertex_lenght))) Mesh( vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, texture=texture, mode=self.mode)
class Renderer(Widget): texture = ObjectProperty(None, allownone=True) def load(self, *l): self.button.disabled = True if os.path.isdir(meshdir): rep = meshdir self.fl = FileChooserListView(path=rep, rootpath=rep, filters=["*.mesh.ascii"], dirselect=False, size=(400, 400), center_x=250, center_y=250) else: rep = os.getcwd() self.fl = FileChooserListView(path=rep, filters=["*.mesh.ascii"], dirselect=False, size=(400, 400), center_x=250, center_y=250) '''if platform == 'android': rep = "." else: rep = "../../Mesh"''' self.fl.bind(selection=self.on_selected) super(Renderer, self).add_widget(self.fl) def on_selected(self, filechooser, selection): self.button.disabled = False print 'load', selection super(Renderer, self).remove_widget(self.fl) scale = 3 self.fbo.remove_group('truc') self.scene = MeshAsciiLoader(selection[0], scale) with self.fbo: #ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) def change_shader(self, *l): print 'change_shader' if self.shader == 0: self.fbo.shader.source = resource_find('simple.glsl') self.shader = 1 else: #self.fbo.shader.source = resource_find('flat.glsl') self.fbo.shader.source = resource_find('normalmap.glsl') self.shader = 0 def __init__(self, **kwargs): self.model = 0 self.shader = 0 self.canvas = Canvas() #self.scene = ObjFileLoader(resource_find("testnurbs.obj")) Logger.debug('******************************************************') scale = 3 #dir = "Duke Nukem Forever_Dr_Valencia" # error index out of range #dir = "Duke Nukem Forever_Kitty Pussoix" dir = "Duke_Nukem_by_Ventrue" #dir = "DOA5U_Rachel_Nurse/Model" #pb uv if not os.path.isdir(meshdir): self.scene = MeshAsciiLoader( resource_find(dir + "/Generic_Item.mesh.ascii"), scale) else: self.scene = MeshAsciiLoader( resource_find(meshdir + dir + "/Generic_Item.mesh.ascii"), scale) #scale = .03 #self.texturename = 'Batman_Rabbit_Head_Posed/Batman_V3_Body_D.PNG' #self.scene = PSKFileLoader(resource_find("Batman_Rabbit_Head_Posed/Batman_Rabbit_Head_Posed.psk"), scale) #self.texturename = 'Gray/Gray_C1.tga' #self.scene = PSKFileLoader(resource_find("Gray/Mike_TPP.psk"), scale) #too many indices, good for split test #self.texturename = 'CV_Talia/Talia_Body_D.tga' #self.texturename = 'CV_Talia/Talia_Legs_D.tga') #self.scene = PSKFileLoader(resource_find("CV_Talia/Talia_posed.psk"), scale) #too many indices, good for split test Logger.debug('******************************************************') with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0, 0, 0, 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) #self.fbo.shader.source = resource_find('simple.glsl') self.fbo.shader.source = resource_find('normalmap.glsl') super(Renderer, self).__init__(**kwargs) self.fbo['texture1'] = 1 self.fbo['toggletexture'] = 1 with self.fbo: #ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) Clock.schedule_interval(self.update_scene, 1 / 60.) self._touches = [] self.button = Button(text='load') self.button.bind(on_release=self.load) super(Renderer, self).add_widget(self.button) button1 = Button(text='shader', center_x=150) button1.bind(on_release=self.change_shader) super(Renderer, self).add_widget(button1) def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def on_pos(self, instance, value): self.viewport.pos = value def on_texture(self, instance, value): self.viewport.texture = value def setup_gl_context(self, *args): #clear_buffer glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() #glDepthMask(GL_FALSE); def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *largs): asp = self.width / float(self.height) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 500, 1) self.fbo['projection_mat'] = proj self.fbo['diffuse_light'] = (1.0, 0.0, 0.0) self.fbo['ambient_light'] = (0.1, 0.1, 0.1) self.fbo['glLightSource0_position'] = (1.0, 1.0, 1.0, 0.0) self.fbo['glLightSource0_spotCutoff'] = 360 self.fbo['glLightModel_ambient'] = (0.2, 0.2, 0.2, 1.0) self.fbo['glLightSource0_diffuse'] = (0.7, 0.7, 0.7, 1.0) self.fbo['glLightSource0_specular'] = (.1, .1, .1, 1.0) self.fbo['glFrontMaterial_specular'] = (.10, .10, .10, 1.0) self.fbo['glFrontMaterial_shininess'] = 0.1 def setup_scene(self): Color(.5, .5, .5, 0) PushMatrix() Translate(0, -3, -5) # This Kivy native Rotation is used just for # enabling rotation scene like trackball self.rotx = Rotate(0, 1, 0, 0) # here just rotate scene for best view self.roty = Rotate(180, 0, 1, 0) self.scale = Scale(1) UpdateNormalMatrix() self.draw_elements() PopMatrix() def draw_elements(self): #Draw separately all meshes on the scene def _draw_element(m, texture='', texture1=''): #bind the texture BEFORE the draw (Mesh) if texture1: # here, we are binding a custom texture at index 1 # this will be used as texture1 in shader. tex1 = Image(texture1).texture tex1.wrap = 'repeat' #enable of uv support >1 or <0 BindTexture(texture=tex1, index=1) #clear the texture if none else: BindTexture(source="", index=1) mesh = Mesh( vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode='triangles', group='truc', ) if texture: try: texture = Image(texture).texture texture.wrap = 'repeat' #enable of uv support >1 or <0 mesh.texture = texture except: #no texture if not found or not supported pass def _set_color(*color, **kw): id_color = kw.pop('id_color', (0, 0, 0)) return ChangeState( Kd=color, Ka=color, Ks=(.3, .3, .3), Tr=1., Ns=1., intensity=1., id_color=[i / 255. for i in id_color], ) for meshid in range(0, len(self.scene.objects)): # Draw each element mesh = self.scene.objects[meshid] #_set_color(0.7, 0.7, 0., id_color=(255, 255, 0)) if (mesh.diffuse != ""): _draw_element(mesh, mesh.diffuse, mesh.normal) #_draw_element(mesh, mesh.diffuse) #_draw_element(mesh, mesh.normal) else: _draw_element(mesh, self.texturename) def update_scene(self, *largs): pass # ============= All stuff after is for trackball implementation =========== def define_rotate_angle(self, touch): x_angle = (touch.dx / self.width) * 360 y_angle = -1 * (touch.dy / self.height) * 360 return x_angle, y_angle def on_touch_down(self, touch): self._touch = touch touch.grab(self) self._touches.append(touch) return super(Renderer, self).on_touch_down(touch) def on_touch_up(self, touch): touch.ungrab(self) self._touches.remove(touch) return super(Renderer, self).on_touch_up(touch) def on_touch_move(self, touch): self.update_glsl() if touch in self._touches and touch.grab_current == self: if len(self._touches) == 1: # here do just rotation ax, ay = self.define_rotate_angle(touch) self.roty.angle += ax self.rotx.angle += ay elif len(self._touches) == 2: # scaling here #use two touches to determine do we need scal touch1, touch2 = self._touches old_pos1 = (touch1.x - touch1.dx, touch1.y - touch1.dy) old_pos2 = (touch2.x - touch2.dx, touch2.y - touch2.dy) old_dx = old_pos1[0] - old_pos2[0] old_dy = old_pos1[1] - old_pos2[1] old_distance = (old_dx * old_dx + old_dy * old_dy) #Logger.debug('Old distance: %s' % old_distance) new_dx = touch1.x - touch2.x new_dy = touch1.y - touch2.y new_distance = (new_dx * new_dx + new_dy * new_dy) #Logger.debug('New distance: %s' % new_distance) SCALE_FACTOR = 0.01 if new_distance > old_distance: scale = SCALE_FACTOR #Logger.debug('Scale up') elif new_distance == old_distance: scale = 0 else: scale = -1 * SCALE_FACTOR #Logger.debug('Scale down') xyz = self.scale.xyz if scale: self.scale.xyz = tuple(p + scale for p in xyz)
class Paint(StencilView): scale = NumericProperty() def __init__(self, app, **kwargs): StencilView.__init__(self, **kwargs) self.app = app self.xx = 0 self.scale = 1.0 self.size_hint = (None, None) self.cursor_pos = (0, 0) self.fbo_size = DEFAULT_IMAGE_SIZE self.fbo = None self.fbo_rect = None self.tool_fbo = None self.tool_fbo_rect = None self.bg_rect = None self.rect = None self.fbo_clear_color = (1, 1, 1, 1) self.layer_undo_stack = [] self.undo_layer_index = 0 self.layer_rect = [] self.fbo_create_on_canvas() self.touches = [] self.move_image = False self.active_layer = None self.tool_buffer_enabled = True self.px = None self.py = None self.grid_texture = None self.active_layer_last_texture = None def grid_create(self, size): self.grid_texture = Texture.create(size=size, colorfmt='rgba', bufferfmt='ubyte') tex = improc.texture_draw_grid(self.grid_texture, 255, 4) return tex def fbo_create(self, size, tex=None): if tex is None: tex = Texture.create(size=size, colorfmt='rgba', bufferfmt='ubyte') tex.mag_filter = 'nearest' tex.min_filter = 'nearest' if self.fbo is None: self.fbo = Fbo(size=size, texture=tex) self.fbo.texture.mag_filter = 'nearest' self.fbo.texture.min_filter = 'nearest' else: self.fbo = Fbo(size=size, texture=tex) self.fbo.texture.mag_filter = 'nearest' self.fbo.texture.min_filter = 'nearest' tool_tex = Texture.create(size=size, colorfmt='rgba', bufferfmt='ubyte') tool_tex.mag_filter = 'nearest' tool_tex.min_filter = 'nearest' if self.tool_fbo is None: self.tool_fbo = Fbo(size=size, texture=tool_tex) self.tool_fbo.texture.mag_filter = 'nearest' self.tool_fbo.texture.min_filter = 'nearest' else: self.tool_fbo = Fbo(size=size, texture=tool_tex) self.tool_fbo.texture.mag_filter = 'nearest' self.tool_fbo.texture.min_filter = 'nearest' return self.fbo def refbo(self): tex = Texture.create(size=self.fbo.texture.size, colorfmt='rgba', bufferfmt='ubyte') self.fbo = Fbo(size=tex.size, texture=tex) self.fbo.texture.mag_filter = 'nearest' self.fbo.texture.min_filter = 'nearest' self.fbo.draw() self.canvas.ask_update() def canvas_put_drawarea(self, texture=None): self.canvas.clear() if texture: self.fbo_size = texture.size self.fbo_create(texture.size, tex=texture) self.bg_rect = layer.Layer.layer_bg_rect with self.canvas: self.canvas.add(self.bg_rect) Color(1, 1, 1, 1) for laybox in layer.LayerBox.boxlist: if laybox.layer: if laybox.layer.texture and laybox.layer.visible: self.canvas.add(laybox.layer.rect) laybox.layer.rect.pos = self.fbo_rect.pos if self.tool_buffer_enabled: self.tool_fbo_rect = Rectangle(pos=self.fbo_rect.pos, size=self.tool_fbo.texture.size, texture=self.tool_fbo.texture) self.fbo_update_pos() self.fbo.draw() self.canvas.ask_update() def fbo_create_on_canvas(self, size=None, pos=(0, 0)): self.canvas.clear() if size is None: size = self.fbo_size else: self.fbo_size = size self.fbo_create(size) with self.canvas: Color(1, 1, 1, 1) self.fbo_rect = Rectangle(texture=self.fbo.texture, pos=pos, size=self.fbo.texture.size) self.tool_fbo_rect = Rectangle(texture=self.tool_fbo.texture, pos=pos, size=self.tool_fbo.texture.size) self.fbo.draw() self.canvas.ask_update() def fbo_clear(self): self.fbo.bind() self.fbo.clear() self.fbo.clear_color = self.fbo_clear_color self.fbo.clear_buffer() self.fbo.release() self.fbo.draw() def fbo_update_pos(self): x = self.app.aPaintLayout.size[0] / self.scale / 2 - self.fbo.size[0] / 2 y = self.app.aPaintLayout.size[1] / self.scale / 2 - self.fbo.size[1] / 2 self.fbo_rect.pos = (x, y) self.tool_fbo_rect.pos = (x, y) if self.bg_rect: self.bg_rect.pos = (x, y) if self.app.layer_ribbon: for lb in layer.LayerBox.boxlist: if lb.layer.rect: lb.layer.rect.pos = self.fbo_rect.pos def fbo_move_by_offset(self, offset): if self.bg_rect: self.bg_rect.pos = self.bg_rect.pos[0] + offset[0], self.bg_rect.pos[1] + offset[1] self.fbo_rect.pos = self.bg_rect.pos self.tool_fbo_rect.pos = self.bg_rect.pos if self.app.layer_ribbon: for lb in layer.LayerBox.boxlist: if lb.layer.rect: lb.layer.rect.pos = self.fbo_rect.pos # self.ox, self.oy = self.bg_rect.pos # def fbo_render(self, touch, width): self.fbo.bind() if touch and touch.ud.has_key('line'): with self.fbo: self.fbo.add(self.app.aColor) d = width self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0], (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1]) touch.ud['line'].points += self.cursor_pos self.fbo.release() self.fbo.draw() self.canvas.ask_update() def fbo_get_texture(self): return self.fbo.texture def fbo_get_pixel_color(self, touch, format='1'): self.fbo.bind() x = touch.x / self.scale - self.fbo_rect.pos[0] y = touch.y / self.scale - self.fbo_rect.pos[1] data = glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE) self.fbo.release() if format == '1': c = [ord(a) / 255.0 for a in data] else: c = [ord(a) for a in data] return c def fbo_fill_region(self, touch): x = int(touch.x / self.scale - self.fbo_rect.pos[0]) y = int(touch.y / self.scale - self.fbo_rect.pos[1]) improc.fillimage(self.fbo, (x, y), [int(255 * c) for c in self.app.aColor.rgba]) self.canvas.ask_update() def fbo_replace_color(self, touch, width): cx = int(touch.x / self.scale - self.fbo_rect.pos[0]) cy = int(touch.y / self.scale - self.fbo_rect.pos[1]) if self.px is None: self.px = cx if self.py is None: self.py = cy if (cx - self.px) > 0: tg_alpha = float((cy - self.py)) / (cx - self.px) step = int(math.copysign(1, tg_alpha)) if abs(cx - self.px) > abs(cy - self.py): coords = [(x, self.py + (x - self.px) * tg_alpha) for x in xrange(int(self.px), int(cx))] else: coords = [(self.px + (y - self.py) / tg_alpha, y) for y in xrange(int(self.py), int(cy), step)] elif (cx - self.px) < 0: tg_alpha = float((cy - self.py)) / (cx - self.px) step = int(math.copysign(1, tg_alpha)) if abs(cx - self.px) > abs(cy - self.py): coords = [(x, self.py + (x - self.px) * tg_alpha) for x in xrange(int(cx), int(self.px))] else: coords = [(self.px + (y - self.py) / tg_alpha, y) for y in xrange(int(cy), int(self.py), step)] elif (cx - self.px) == 0: if (cy - self.py) > 0: coords = [(cx, y) for y in xrange(int(self.py), int(cy))] elif (cy - self.py) < 0: coords = [(cx, y) for y in xrange(int(cy), int(self.py))] else: coords = [(cx, cy), ] self.fbo.bind() for (x, y) in coords: improc.texture_replace_color(tex=self.fbo.texture, pos=(x, y), color=0, size=(width, width)) self.fbo.release() self.fbo.clear() self.fbo.draw() self.canvas.ask_update() self.px = cx self.py = cy def pos_to_widget(self, touch): return self.to_widget(touch.x, touch.y) def scale_canvas(self, zoom): with self.canvas.before: PushMatrix() self.scale *= zoom context_instructions.Scale(zoom) with self.canvas.after: PopMatrix() self.fbo_update_pos() def on_scale(self, instance, scale): ToolBehavior.scale() def scale_pos(self, pos): return [pos[0] / self.scale - self.fbo_rect.pos[0], pos[1] / self.scale - self.fbo_rect.pos[1]] def scaled_pos(self): return [self.fbo_rect.pos[0] * self.scale, self.fbo_rect.pos[1] * self.scale] def scaled_size(self): return [self.fbo_rect.texture.size[0] * self.scale, self.fbo_rect.texture.size[1] * self.scale] def add_touch(self, touch): if touch and len(self.touches) < 2: self.touches.append(touch) if len(self.touches) >= 2: self.touch_dist = self.touches[0].distance(self.touches[1]) self.touch_dist_const = self.touch_dist self.first_touch = self.touches[0] def double_touch(self): if len(self.touches) > 1: return True # def double_touch_distance(self): # return Vector(self.touches[0].pos).distance(self.touches[1].pos) def touch_responce(self): result = False if len(self.touches) >= 2: pos1 = self.pos_to_widget(self.touches[0]) pos2 = self.touches[1].pos dist = distance(pos1, pos2) if dist > self.touch_dist + 10: self.touch_dist = dist result = 2 elif dist <= self.touch_dist - 10: self.touch_dist = dist result = 1 if abs(self.touch_dist_const - dist) < 10: result = 3 return result return False def on_touch_down(self, touch): self.tool_buffer.on_touch_down(touch) if self.collide_point(*touch.pos): if self.app.config.getint('toolbars', 'toolbar_autohide'): self.app.toolbar.animate_hide() if self.app.config.getint('toolbars', 'palette_autohide'): self.app.palette.animate_hide() if self.app.config.getint('toolbars', 'layer_ribbon_autohide'): self.app.layer_ribbon.animate_hide() if not self.collide_point(*touch.pos): if self.app.active_tool == TOOL_LINE: self.tool_line._render_and_reset_state(self.fbo, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() return False touch.grab(self) self.add_touch(touch) if len(self.touches) == 1: self.active_layer_backup_texture() if self.double_touch(): self.active_layer_set_last_backup_texture() return if not self.app.layer_ribbon.get_active_layer().visible: dialog.PopupMessage("Notification", "The current layer is hidden, make it visible for edit") return if self.app.layer_ribbon.get_active_layer().texture_locked: dialog.PopupMessage("Notification", "The current layer is locked, make it unlock for edit") return if self.app.active_tool == TOOL_PENCIL1: self.fbo.bind() if touch: with self.fbo: self.fbo.add(self.app.aColor) d = 1. self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0], (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1]) Ellipse(pos=self.cursor_pos, size=(d, d)) touch.ud['line'] = Line(points=self.cursor_pos, width=d) self.fbo.release() self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_PENCIL2: self.fbo.bind() if touch: with self.fbo: self.fbo.add(self.app.aColor) d = 2.1 self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0], (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1]) Ellipse(pos=self.cursor_pos, size=(d, d)) touch.ud['line'] = Line(points=self.cursor_pos, width=d / 2.0) self.fbo.release() self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_PENCIL3: self.fbo.bind() if touch: with self.fbo: self.fbo.add(self.app.aColor) d = 3. self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0], (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1]) Ellipse(pos=self.cursor_pos, size=(d, d)) touch.ud['line'] = Line(points=self.cursor_pos, width=d / 2) self.fbo.release() self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_PICKER: if touch: if self.collide_point(touch.x, touch.y): c = self.fbo_get_pixel_color(touch) self.app.aColor = Color(c[0], c[1], c[2], c[3]) self.app.toolbar.tools_select(self.app.prev_tool) elif self.app.active_tool == TOOL_FILL: if touch: if self.collide_point(touch.x, touch.y): self.fbo_fill_region(touch) elif self.app.active_tool == TOOL_ERASE1: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=1) elif self.app.active_tool == TOOL_ERASE2: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=2) elif self.app.active_tool == TOOL_ERASE3: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=3) elif self.app.active_tool == TOOL_SELECT: if touch: if not self.tool_buffer.enabled: self.tool_select.on_touch_down(touch, self.fbo, self.tool_fbo) else: pass elif self.app.active_tool == TOOL_LINE: if touch: self.tool_line.on_touch_down(touch, self.fbo, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_RECT: if touch: self.tool_rect.on_touch_down(touch, self.fbo, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_ELLIPSE: if touch: self.tool_ellipse.on_touch_down(touch, self.fbo, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_MOVE: if touch: if self.collide_point(touch.x, touch.y): self.move_image = True self.ox, self.oy = touch.pos return True def on_touch_move(self, touch): result = self.touch_responce() if result == 2: self.scale_canvas(1.02) return elif result == 1: self.scale_canvas(0.98) return elif result == 3: dist = self.touches[0].distance(self.first_touch) self.fbo_move_by_offset((dist / self.scale, dist / self.scale)) if self.app.active_tool == TOOL_PENCIL1: self.fbo_render(touch, width=1.) elif self.app.active_tool == TOOL_PENCIL2: self.fbo_render(touch, width=2.) elif self.app.active_tool == TOOL_PENCIL3: self.fbo_render(touch, width=3.) elif self.app.active_tool == TOOL_PICKER: c = self.fbo_get_pixel_color(touch) self.app.aColor = Color(c[0], c[1], c[2]) elif self.app.active_tool == TOOL_ERASE1: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=1) elif self.app.active_tool == TOOL_ERASE2: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=2) elif self.app.active_tool == TOOL_ERASE3: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=3) elif self.app.active_tool == TOOL_SELECT: if touch: if not self.tool_buffer.enabled: self.tool_select.on_touch_move(touch, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() else: pass elif self.app.active_tool == TOOL_LINE: if touch: self.tool_line.on_touch_move(touch, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_RECT: if touch: self.tool_rect.on_touch_move(touch, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_ELLIPSE: if touch: self.tool_ellipse.on_touch_move(touch, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_MOVE: if self.move_image: self.fbo_move_by_offset((touch.dx / self.scale, touch.dy / self.scale)) self.tool_buffer.on_touch_move(touch, self.fbo) def on_touch_up(self, touch): self.tool_buffer.on_touch_up(touch) if touch.grab_current is not self: return False if not self.collide_point(*touch.pos): return False touch.ungrab(self) if self.double_touch(): _not_add_too_undo = True else: _not_add_too_undo = False if touch: try: self.touches.remove(touch) except: pass if self.app.active_tool == TOOL_SELECT: if touch: self.tool_select.on_touch_up(touch) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_LINE: if touch: self.tool_line.on_touch_up(touch) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_RECT: if touch: self.tool_rect.on_touch_up(touch) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_ELLIPSE: if touch: self.tool_ellipse.on_touch_up(touch) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_MOVE: if touch: self.move_image = False elif self.app.active_tool == TOOL_ERASE1 or self.app.active_tool == TOOL_ERASE2 or self.app.active_tool == TOOL_ERASE3: if touch: self.px = None self.py = None if self.app.active_tool == TOOL_PENCIL1 or self.app.active_tool == TOOL_ERASE1 \ or self.app.active_tool == TOOL_PENCIL2 or self.app.active_tool == TOOL_ERASE2 \ or self.app.active_tool == TOOL_PENCIL3 or self.app.active_tool == TOOL_ERASE3 \ or self.app.active_tool == TOOL_FILL: rect = self.app.layer_ribbon.get_active_layer().rect pos = rect.pos[0] * self.scale, rect.pos[1] * self.scale size = rect.size[0] * self.scale, rect.size[1] * self.scale if not _not_add_too_undo: if pos[0] <= touch.x <= pos[0] + size[0] and pos[1] <= touch.y <= pos[1] + size[1]: self.add_undo_stack() return True def add_redo_stack(self): pass def add_undo_stack(self): _active_layer = self.app.layer_ribbon.get_active_layer() _active_layer.backup_texture() self.layer_undo_stack = self.layer_undo_stack[:self.undo_layer_index + 1] self.layer_undo_stack.append(_active_layer) self.undo_layer_index = len(self.layer_undo_stack) - 1 def do_undo(self, *args): if self.layer_undo_stack: if self.undo_layer_index > 0: _layer = self.layer_undo_stack[self.undo_layer_index] _layer.texture_from_backup(direction=-1) _active_layer = self.app.layer_ribbon.get_active_layer() if _layer is _active_layer: self.fbo_create(_active_layer.texture.size, _active_layer.texture) self.undo_layer_index -= 1 self.canvas_put_drawarea() self.fbo_update_pos() def active_layer_backup_texture(self): active_layer = self.app.layer_ribbon.get_active_layer() self.active_layer_last_texture = improc.texture_copy(active_layer.texture) def active_layer_set_last_backup_texture(self): active_layer = self.app.layer_ribbon.get_active_layer() # texture = active_layer.textures_array[-1] active_layer.replace_texture(self.active_layer_last_texture) self.fbo_create(active_layer.texture.size, active_layer.texture) self.canvas_put_drawarea() self.fbo_update_pos() self.canvas.ask_update() def do_redo(self, *args): if self.layer_undo_stack: if self.undo_layer_index < len(self.layer_undo_stack) - 1: self.undo_layer_index += 1 _layer = self.layer_undo_stack[self.undo_layer_index] _layer.texture_from_backup(direction=1) _active_layer = self.app.layer_ribbon.get_active_layer() if _layer is _active_layer: self.fbo_create(_active_layer.texture.size, _active_layer.texture) self.canvas_put_drawarea() self.fbo_update_pos()
def __init__(self, **kwargs): self.model = 0 self.shader = 0 self.canvas = Canvas() #self.scene = ObjFileLoader(resource_find("testnurbs.obj")) Logger.debug('******************************************************') scale = 3 #dir = "Duke Nukem Forever_Dr_Valencia" # error index out of range #dir = "Duke Nukem Forever_Kitty Pussoix" dir = "Duke_Nukem_by_Ventrue" #dir = "DOA5U_Rachel_Nurse/Model" #pb uv if not os.path.isdir(meshdir): self.scene = MeshAsciiLoader( resource_find(dir + "/Generic_Item.mesh.ascii"), scale) else: self.scene = MeshAsciiLoader( resource_find(meshdir + dir + "/Generic_Item.mesh.ascii"), scale) #scale = .03 #self.texturename = 'Batman_Rabbit_Head_Posed/Batman_V3_Body_D.PNG' #self.scene = PSKFileLoader(resource_find("Batman_Rabbit_Head_Posed/Batman_Rabbit_Head_Posed.psk"), scale) #self.texturename = 'Gray/Gray_C1.tga' #self.scene = PSKFileLoader(resource_find("Gray/Mike_TPP.psk"), scale) #too many indices, good for split test #self.texturename = 'CV_Talia/Talia_Body_D.tga' #self.texturename = 'CV_Talia/Talia_Legs_D.tga') #self.scene = PSKFileLoader(resource_find("CV_Talia/Talia_posed.psk"), scale) #too many indices, good for split test Logger.debug('******************************************************') with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0, 0, 0, 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) #self.fbo.shader.source = resource_find('simple.glsl') self.fbo.shader.source = resource_find('normalmap.glsl') super(Renderer, self).__init__(**kwargs) self.fbo['texture1'] = 1 self.fbo['toggletexture'] = 1 with self.fbo: #ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) Clock.schedule_interval(self.update_scene, 1 / 60.) self._touches = [] self.button = Button(text='load') self.button.bind(on_release=self.load) super(Renderer, self).add_widget(self.button) button1 = Button(text='shader', center_x=150) button1.bind(on_release=self.change_shader) super(Renderer, self).add_widget(button1)
class ObjectRenderer(Widget): scene = StringProperty('') obj_id = StringProperty('') obj_translation = ListProperty([0, 0, 0]) obj_rotation = ListProperty([0, 0, 0]) obj_scale = NumericProperty(1) obj_texture = StringProperty('') texture = ObjectProperty(None, allownone=True) cam_translation = ListProperty([0, 0, 0]) cam_rotation = ListProperty([0, 0, 0]) display_all = BooleanProperty(False) light_sources = DictProperty() ambiant = NumericProperty(.5) diffuse = NumericProperty(.5) specular = NumericProperty(.5) mode = StringProperty('triangles') def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find( join(dirname(__file__), 'simple.glsl')) super(ObjectRenderer, self).__init__(**kwargs) def on_obj_rotation(self, *args): self.obj_rot_x.angle = self.obj_rotation[0] self.obj_rot_y.angle = self.obj_rotation[1] self.obj_rot_z.angle = self.obj_rotation[2] def on_cam_rotation(self, *args): self.cam_rot_x.angle = self.cam_rotation[0] self.cam_rot_y.angle = self.cam_rotation[1] self.cam_rot_z.angle = self.cam_rotation[2] def on_obj_translation(self, *args): self.obj_translate.xyz = self.cam_translation def on_cam_translation(self, *args): self.cam_translate.xyz = self.cam_translation def on_obj_scale(self, *args): self.scale.xyz = [ self.obj_scale, ] * 3 def on_display_all(self, *args): self.setup_canvas() def on_light_sources(self, *args): self.fbo['light_sources'] = [ ls[:] for ls in self.light_sources.values() ] self.fbo['nb_lights'] = len(self.light_sources) def on_ambiant(self, *args): self.fbo['ambiant'] = self.ambiant def on_diffuse(self, *args): self.fbo['diffuse'] = self.diffuse def on_specular(self, *args): self.fbo['specular'] = self.specular def on_mode(self, *args): self.setup_canvas() def setup_canvas(self, *args): if not (self.scene and self.obj_id or self.display_all): return print 'setting up the scene' with self.fbo: self.fbo['ambiant'] = self.ambiant self.fbo['diffuse'] = self.diffuse self.fbo['specular'] = self.specular self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) def on_scene(self, instance, value): print "loading scene %s" % value self._scene = ObjFileLoader(resource_find(value)) self.setup_canvas() def on_obj_id(self, *args): self.setup_canvas() def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def on_pos(self, instance, value): self.viewport.pos = value def on_texture(self, instance, value): self.viewport.texture = value def setup_gl_context(self, *args): glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *args): asp = self.width / max(float(self.height), 1) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) self.fbo['projection_mat'] = proj def setup_scene(self): Color(1, 1, 1, 0) PushMatrix() self.cam_translate = Translate(self.cam_translation) # Rotate(0, 1, 0, 0) self.cam_rot_x = Rotate(self.cam_rotation[0], 1, 0, 0) self.cam_rot_y = Rotate(self.cam_rotation[1], 0, 1, 0) self.cam_rot_z = Rotate(self.cam_rotation[2], 0, 0, 1) self.scale = Scale(self.obj_scale) UpdateNormalMatrix() if self.display_all: for i in self._scene.objects: self.draw_object(i) else: self.draw_object(self.obj_id) PopMatrix() def draw_object(self, obj_id): m = self._scene.objects[obj_id] self.obj_rot_z = Rotate(self.obj_rotation[2], 0, 0, 1) self.obj_rot_y = Rotate(self.obj_rotation[1], 0, 1, 0) self.obj_rot_x = Rotate(self.obj_rotation[0], 1, 0, 0) self.obj_translate = Translate(xyz=self.obj_translation) if len(m.indices) > 2**16: print '%s too big! %s indices' % (obj_id, len(m.indices)) if m.texture: print "loading texture %s " % m.texture img = Image( source=resource_find(join(dirname(self.scene), m.texture))) texture = img.texture if texture: texture.wrap = 'repeat' else: texture = None vertex_lenght = sum(x[1] for x in m.vertex_format) if len(m.vertices) % vertex_lenght: print(('warning: vertices lenght (%s)' 'is not a multiple of vertex_format lenght(%s)') % (len(m.vertices), vertex_lenght)) Mesh(vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, texture=texture, mode=self.mode)
class Renderer(Widget): texture = ObjectProperty(None, allownone=True) def __init__(self, **kwargs): # self.canvas = RenderContext(compute_normal_mat=True) # self.canvas.shader.source = resource_find('simple.glsl') self.canvas = Canvas() self.scene = ObjFileLoader(resource_find("testnurbs.obj")) self.meshes = [] with self.canvas: self.fbo = Fbo( size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0.0, 0.0, 0.0, 0.0) ) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find("simple.glsl") # self.texture = self.fbo.texture super(Renderer, self).__init__(**kwargs) with self.fbo: # ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) Clock.schedule_interval(self.update_scene, 1 / 60.0) self._touches = [] def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def on_pos(self, instance, value): self.viewport.pos = value def on_texture(self, instance, value): self.viewport.texture = value def setup_gl_context(self, *args): # clear_buffer glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() # glDepthMask(GL_FALSE); def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *largs): asp = self.width / float(self.height) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) self.fbo["projection_mat"] = proj def setup_scene(self): Color(1, 1, 1, 0) PushMatrix() Translate(0, 0, -4.75) # This Kivy native Rotation is used just for # enabling rotation scene like trackball self.rotx = Rotate(0, 1, 0, 0) self.roty = Rotate(-120, 0, 1, 0) # here just rotate scene for best view self.scale = Scale(1) UpdateNormalMatrix() self.draw_elements() PopMatrix() def draw_elements(self): """ Draw separately all objects on the scene to setup separate rotation for each object """ def _draw_element(m, texture=""): mesh = Mesh(vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode="triangles") if texture: texture = Image(texture).texture mesh.texture = texture def _set_color(*color, **kw): id_color = kw.pop("id_color", (0, 0, 0)) return ChangeState( Kd=color, Ka=color, Ks=(0.3, 0.3, 0.3), Tr=1.0, Ns=1.0, intensity=1.0, id_color=[i / 255.0 for i in id_color], ) # Draw sphere in the center sphere = self.scene.objects["Sphere"] _set_color(0.7, 0.7, 0.0, id_color=(255, 255, 0)) _draw_element(sphere, "rock.png") # Then draw other elements and totate it in different axis pyramid = self.scene.objects["Pyramid"] PushMatrix() self.pyramid_rot = Rotate(0, 0, 0, 1) _set_color(0.0, 0.0, 0.7, id_color=(0.0, 0.0, 255)) _draw_element(pyramid, "rain.png") PopMatrix() box = self.scene.objects["Box"] PushMatrix() self.box_rot = Rotate(0, 0, 1, 0) _set_color(0.7, 0.0, 0.0, id_color=(255, 0.0, 0)) _draw_element(box, "bricks.png") PopMatrix() cylinder = self.scene.objects["Cylinder"] PushMatrix() self.cylinder_rot = Rotate(0, 1, 0, 0) _set_color(0.0, 0.7, 0.0, id_color=(0.0, 255, 0)) _draw_element(cylinder, "wood.png") PopMatrix() def update_scene(self, *largs): self.pyramid_rot.angle += 0.5 self.box_rot.angle += 0.5 self.cylinder_rot.angle += 0.5 # =============== All stuff after is for trackball implementation ============= def define_rotate_angle(self, touch): x_angle = (touch.dx / self.width) * 360 y_angle = -1 * (touch.dy / self.height) * 360 return x_angle, y_angle def on_touch_down(self, touch): self._touch = touch touch.grab(self) self._touches.append(touch) def on_touch_up(self, touch): touch.ungrab(self) self._touches.remove(touch) def on_touch_move(self, touch): self.update_glsl() if touch in self._touches and touch.grab_current == self: if len(self._touches) == 1: # here do just rotation ax, ay = self.define_rotate_angle(touch) self.roty.angle += ax self.rotx.angle += ay elif len(self._touches) == 2: # scaling here # use two touches to determine do we need scal touch1, touch2 = self._touches old_pos1 = (touch1.x - touch1.dx, touch1.y - touch1.dy) old_pos2 = (touch2.x - touch2.dx, touch2.y - touch2.dy) old_dx = old_pos1[0] - old_pos2[0] old_dy = old_pos1[1] - old_pos2[1] old_distance = old_dx * old_dx + old_dy * old_dy Logger.debug("Old distance: %s" % old_distance) new_dx = touch1.x - touch2.x new_dy = touch1.y - touch2.y new_distance = new_dx * new_dx + new_dy * new_dy Logger.debug("New distance: %s" % new_distance) SCALE_FACTOR = 0.01 if new_distance > old_distance: scale = SCALE_FACTOR Logger.debug("Scale up") elif new_distance == old_distance: scale = 0 else: scale = -1 * SCALE_FACTOR Logger.debug("Scale down") xyz = self.scale.xyz if scale: self.scale.xyz = tuple(p + scale for p in xyz)
class Picture(Scatter): img_texture = ObjectProperty() alpha = NumericProperty() onLoadCallback = None filename = None vertices = ListProperty([]) fbo_texture = ObjectProperty(None) fbo = None border_image = None keep_aspect = True aspectRatio = 1.0 # -- def __init__(self, filename=None, onload=None, maxtexsize=(1024, 1024), **kwargs): if maxtexsize == None: maxtexsize = (1024, 1024) self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=maxtexsize) self.fbo.add_reload_observer(self.updateFbo) self.border_image = CoreImage('data/shadow32.png') self.img_texture = Texture.create(size=(16, 16), colorfmt="rgba") self.alpha = 0 self.fbo_texture = self.fbo.texture super(Picture, self).__init__(**kwargs) self.loadImage(filename, onload) # -- def updateFbo(self): with self.fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Color(1, 1, 1, 1) BorderImage(texture=self.border_image.texture, border=(36, 36, 36, 36), size=(self.fbo.size[0], self.fbo.size[1]), pos=(0, 0)) Rectangle(texture=self.img_texture, size=(self.fbo.size[0] - 72, self.fbo.size[1] - 72), pos=(36, 36)) self.fbo_texture = self.fbo.texture pass # -- def on_size(self, instance, value): # change the underlying size property newAspectRatio = float(value[1]) / float(value[0]) if self.keep_aspect: value[1] = value[0] * self.aspectRatio newAspectRatio = self.aspectRatio self.size = value # setup simple quad mesh to be rendered # the quad is used for actual resizing self.vertices = [] self.vertices.extend([0, 0, 0, 0]) self.vertices.extend([0, self.height, 0, 1]) self.vertices.extend([self.width, self.height, 1, 1]) self.vertices.extend([self.width, 0, 1, 0]) # if the aspect ratio of the underlying FBO is not the same as the aspect # ratio of the new size, then change the size of the FBO fboAspectRatio = float(self.fbo.size[1]) / float(self.fbo.size[0]) if abs(fboAspectRatio - newAspectRatio) > 0.1: fboSize = (self.fbo.size[0], self.fbo.size[1] * newAspectRatio) self.fbo.size = fboSize self.updateFbo() pass # -- def loadImage(self, filename, onload=None): self.filename = filename if filename != None: self.onLoadCallback = onload proxyImage = Loader.image(filename) # this is totally stupid behaviour of Kivy # the docs suggest to bind proxy image's on_load method to a callback # to indicate when image is loaded. However, when image is already # in the cache the callback won't be called. My first thought was # that it was a threading issue, because the bindind might have happened # after the callback was initiated, but it seems that indeed the method is just not called. if proxyImage.loaded == False: proxyImage.bind(on_load=self._image_loaded) else: self._image_loaded(proxyImage) # -- # All used memory except of the FBO texture is released. The image # can still be used, however, properties could not be changed def releaseMemory(self): self.img_texture = False self.border_image = False self.fbo_texture = Texture.create(size=(2, 2), colorfmt="rgba") # clear up cache Cache.remove('kv.image') Cache.remove('kv.texture') Cache.remove('kv.loader') pass # -- def _image_loaded(self, proxyImage): if proxyImage.image.texture: self.img_texture = proxyImage.image.texture self.aspectRatio = float(proxyImage.image.height) / float( proxyImage.image.width) self.updateFbo() anim = Animation(alpha=1, duration=0.2) anim.start(self) if self.onLoadCallback != None: self.onLoadCallback(self)
class Picture(Scatter): img_texture = ObjectProperty() alpha = NumericProperty() onLoadCallback = None filename = None vertices = ListProperty([]) fbo_texture = ObjectProperty(None) fbo = None border_image = None keep_aspect = True aspectRatio = 1.0 # -- def __init__(self, filename=None, onload=None, maxtexsize=(1024, 1024), **kwargs): if maxtexsize == None: maxtexsize = (1024, 1024) self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=maxtexsize) self.fbo.add_reload_observer(self.updateFbo) self.border_image = CoreImage("data/shadow32.png") self.img_texture = Texture.create(size=(16, 16), colorfmt="rgba") self.alpha = 0 self.fbo_texture = self.fbo.texture super(Picture, self).__init__(**kwargs) self.loadImage(filename, onload) # -- def updateFbo(self): with self.fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Color(1, 1, 1, 1) BorderImage( texture=self.border_image.texture, border=(36, 36, 36, 36), size=(self.fbo.size[0], self.fbo.size[1]), pos=(0, 0), ) Rectangle(texture=self.img_texture, size=(self.fbo.size[0] - 72, self.fbo.size[1] - 72), pos=(36, 36)) self.fbo_texture = self.fbo.texture pass # -- def on_size(self, instance, value): # change the underlying size property newAspectRatio = float(value[1]) / float(value[0]) if self.keep_aspect: value[1] = value[0] * self.aspectRatio newAspectRatio = self.aspectRatio self.size = value # setup simple quad mesh to be rendered # the quad is used for actual resizing self.vertices = [] self.vertices.extend([0, 0, 0, 0]) self.vertices.extend([0, self.height, 0, 1]) self.vertices.extend([self.width, self.height, 1, 1]) self.vertices.extend([self.width, 0, 1, 0]) # if the aspect ratio of the underlying FBO is not the same as the aspect # ratio of the new size, then change the size of the FBO fboAspectRatio = float(self.fbo.size[1]) / float(self.fbo.size[0]) if abs(fboAspectRatio - newAspectRatio) > 0.1: fboSize = (self.fbo.size[0], self.fbo.size[1] * newAspectRatio) self.fbo.size = fboSize self.updateFbo() pass # -- def loadImage(self, filename, onload=None): self.filename = filename if filename != None: self.onLoadCallback = onload proxyImage = Loader.image(filename) # this is totally stupid behaviour of Kivy # the docs suggest to bind proxy image's on_load method to a callback # to indicate when image is loaded. However, when image is already # in the cache the callback won't be called. My first thought was # that it was a threading issue, because the bindind might have happened # after the callback was initiated, but it seems that indeed the method is just not called. if proxyImage.loaded == False: proxyImage.bind(on_load=self._image_loaded) else: self._image_loaded(proxyImage) # -- # All used memory except of the FBO texture is released. The image # can still be used, however, properties could not be changed def releaseMemory(self): self.img_texture = False self.border_image = False self.fbo_texture = Texture.create(size=(2, 2), colorfmt="rgba") # clear up cache Cache.remove("kv.image") Cache.remove("kv.texture") Cache.remove("kv.loader") pass # -- def _image_loaded(self, proxyImage): if proxyImage.image.texture: self.img_texture = proxyImage.image.texture self.aspectRatio = float(proxyImage.image.height) / float(proxyImage.image.width) self.updateFbo() anim = Animation(alpha=1, duration=0.2) anim.start(self) if self.onLoadCallback != None: self.onLoadCallback(self)
def _show_image(config, img, scale=None, translation=None, rotation=None, transform_matrix=None): from kivy.graphics.texture import Texture from kivy.graphics.fbo import Fbo from kivy.graphics import (Mesh, StencilPush, StencilUse, StencilUnUse, StencilPop, Rectangle, Color) from kivy.graphics.context_instructions import (PushMatrix, PopMatrix, Rotate, Translate, Scale, MatrixInstruction, BindTexture) from kivy.graphics.transformation import Matrix img_fmt = img.get_pixel_format() img_w, img_h = img.get_size() size = config['orig_size'] pos = config['pos'] canvas = config['canvas'] if img_fmt not in ('yuv420p', 'rgba', 'rgb24', 'gray', 'bgr24', 'bgra'): ofmt = get_best_pix_fmt( img_fmt, ('yuv420p', 'rgba', 'rgb24', 'gray', 'bgr24', 'bgra')) swscale = SWScale(iw=img_w, ih=img_h, ifmt=img_fmt, ow=0, oh=0, ofmt=ofmt) img = swscale.scale(img) img_fmt = img.get_pixel_format() kivy_ofmt = { 'yuv420p': 'yuv420p', 'rgba': 'rgba', 'rgb24': 'rgb', 'gray': 'luminance', 'bgr24': 'bgr', 'bgra': 'bgra' }[img_fmt] if kivy_ofmt == 'yuv420p': w2 = int(img_w / 2) h2 = int(img_h / 2) tex_y = Texture.create(size=(img_w, img_h), colorfmt='luminance') tex_u = Texture.create(size=(w2, h2), colorfmt='luminance') tex_v = Texture.create(size=(w2, h2), colorfmt='luminance') with canvas: fbo = Fbo(size=(img_w, img_h)) with fbo: BindTexture(texture=tex_u, index=1) BindTexture(texture=tex_v, index=2) Rectangle(size=fbo.size, texture=tex_y) fbo.shader.fs = CeedDataReader._YUV_RGB_FS fbo['tex_y'] = 0 fbo['tex_u'] = 1 fbo['tex_v'] = 2 tex = fbo.texture dy, du, dv, _ = img.to_memoryview() tex_y.blit_buffer(dy, colorfmt='luminance') tex_u.blit_buffer(du, colorfmt='luminance') tex_v.blit_buffer(dv, colorfmt='luminance') else: tex = Texture.create(size=(img_w, img_h), colorfmt=kivy_ofmt) tex.blit_buffer(img.to_memoryview()[0], colorfmt=kivy_ofmt) tex.flip_vertical() with canvas: StencilPush() Rectangle(pos=pos, size=size) StencilUse() PushMatrix() center = pos[0] + size[0] / 2, pos[1] + size[1] / 2 if rotation: Rotate(angle=rotation, axis=(0, 0, 1), origin=center) if scale: Scale(scale, scale, 1, origin=center) if translation: Translate(*translation) if transform_matrix is not None: mat = Matrix() mat.set(array=transform_matrix) m = MatrixInstruction() m.matrix = mat Rectangle(size=(img_w, img_h), texture=tex, pos=pos) PopMatrix() StencilUnUse() Rectangle(pos=pos, size=size) StencilPop()
def generate_movie(self, filename, out_fmt='yuv420p', codec='libx264', lib_opts={'crf': '0'}, video_fmt='mp4', start=None, end=None, canvas_size=(0, 0), canvas_size_hint=(1, 1), projector_pos=(0, 0), projector_pos_hint=(None, None), paint_funcs=(), stimulation_transparency=1., lum=1., speed=1., hidden_shapes=None): from kivy.graphics import (Canvas, Translate, Fbo, ClearColor, ClearBuffers, Scale) from kivy.core.window import Window rate = float(self.view_controller.frame_rate) rate_int = int(rate) if rate != rate_int: raise ValueError('Frame rate should be integer') orig_w, orig_h = (self.view_controller.screen_width, self.view_controller.screen_height) canvas_w, canvas_h = canvas_size cv_hint_w, cv_hint_h = canvas_size_hint w = int(canvas_w if cv_hint_w is None else orig_w * cv_hint_w) h = int(canvas_h if cv_hint_h is None else orig_h * cv_hint_h) projector_x, projector_y = projector_pos projector_hint_x, projector_hint_y = projector_pos_hint x = int(projector_x if projector_hint_x is None else orig_w * projector_hint_x) y = int(projector_y if projector_hint_y is None else orig_h * projector_hint_y) Window.size = w, h intensities = self.shapes_intensity n = len(intensities[next(iter(intensities.keys()))]) if start is not None: start = int(start * rate) if start >= n: raise Exception('Start time is after the end of the data') else: start = 0 if end is not None: end = int(math.ceil(end * rate)) + 1 if end <= start: raise Exception('End time is before or at the start time') else: end = n stream = { 'pix_fmt_in': 'rgba', 'pix_fmt_out': out_fmt, 'width_in': w, 'height_in': h, 'width_out': w, 'height_out': h, 'codec': codec, 'frame_rate': (int(speed * rate_int), 1) } writer = MediaWriter(filename, [stream], fmt=video_fmt, lib_opts=lib_opts) fbo = Fbo(size=(w, h), with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Scale(1, -1, 1) Translate(0, -h, 0) config = { 'canvas': fbo, 'pos': (x, y), 'size': (w, h), 'orig_size': (orig_w, orig_h), 'rate': rate } paint_funcs = [func(config) for func in paint_funcs] paint_funcs = [func for func in paint_funcs if func is not None] fbo.draw() img = Image(plane_buffers=[fbo.pixels], pix_fmt='rgba', size=(w, h)) writer.write_frame(img, 0.) fbo.add(Translate(x, y)) shape_views = self.stage_factory.get_shapes_gl_color_instructions( fbo, 'stage_replay') fbo.add(Translate(-x, -y)) pbar = tqdm(total=(end - 1 - start) / rate, file=sys.stdout, unit='second', unit_scale=1) # all shapes listed in intensities must be in shape_views. However, # we don't want to show shapes not given values in intensities or if # they are to be hidden unused_shapes = set(shape_views) - set(intensities) unused_shapes.update(set(hidden_shapes or [])) for name in unused_shapes: if name in shape_views: shape_views[name].rgba = 0, 0, 0, 0 for i in range(start, end): pbar.update(1 / rate) for name, intensity in intensities.items(): r, g, b, a = intensity[i] if name in unused_shapes: a = 0 shape_views[name].rgba = \ r * lum, g * lum, b * lum, a * stimulation_transparency try: for func in paint_funcs: func(i) except EndOfDataException: break fbo.draw() img = Image(plane_buffers=[fbo.pixels], pix_fmt='rgba', size=(w, h)) writer.write_frame(img, (i - start + 1) / (rate * speed)) pbar.close()
class FboFloatLayout(Widget): texture = ObjectProperty(None, allownone=True) vertices = ListProperty([]) fbo = None tmp_fbo = None def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=self.size) super(FboFloatLayout, self).__init__(**kwargs) # -- # preload FBO with background texture def initFbo(self): with self.fbo: ClearColor(0, 0, 0, 0) ClearBuffers() #Rectangle(source = 'data/background.jpg', size=self.size, pos=self.pos) self.texture = self.fbo.texture # -- # add the content of the widget to the FBO # this will literally render the widget into the texture def render_widget(self, widget): # create an FBO to render the widget to self.tmp_fbo = Fbo(size=self.size) self.tmp_fbo.add(ClearColor(0, 0, 0, 0)) self.tmp_fbo.add(ClearBuffers()) self.tmp_fbo.add(widget.canvas) self.tmp_fbo.draw() # render a rectangle in the main fbo containing the content from the widget with self.fbo: Color(1, 1, 1, 1) Rectangle(texture=self.tmp_fbo.texture, size=self.tmp_fbo.size) #def add_widget(self, *largs): # trick to attach graphics instruction to fbo instead of canvas # canvas = self.canvas # self.canvas = self.fbo # ret = super(FboFloatLayout, self).add_widget(*largs) # self.canvas = canvas # remove widget after next frame, this makes sure that # we do not use the widget for more than one frame #Clock.schedule_once(lambda dt: self.remove_widget(*largs)) # return ret #def remove_widget(self, *largs): # canvas = self.canvas # self.canvas = self.fbo # super(FboFloatLayout, self).remove_widget(*largs) # self.canvas = canvas def on_size(self, instance, value): self.size = value self.fbo.size = value #self.fbo_rect.size = value #self.fbo_background.size = value #self.fbo_rect.texture = self.fbo.texture # setup simple quad mesh to be rendered # the quad is used for actual resizing self.vertices = [] self.vertices.extend([0, 0, 0, 0]) self.vertices.extend([0, self.height, 0, 1]) self.vertices.extend([self.width, self.height, 1, 1]) self.vertices.extend([self.width, 0, 1, 0]) #self.updateFbo() self.initFbo()
class FboFloatLayout(FloatLayout): texture = ObjectProperty(None, allownone=True) alpha_blending = BooleanProperty(False) def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas.before: Callback(self._set_blend_func) self.fbo_texture = Texture.create(size=self.size, colorfmt='rgba',) self.fbo_texture.mag_filter='nearest' with self.canvas: #self.cbs = Callback(self.prepare_canvas) self.fbo = Fbo(size=self.size, texture=self.fbo_texture) #Color(1, 1, 1, 0) #self.fbo_rect = Rectangle() with self.fbo: ClearColor(0.0, 0.0, 0.0, 0.0) ClearBuffers() self.fbo_rect = Rectangle(size=self.size) #self.fbo.shader.source = resource_find('./kivy3dgui/gles2.0/shaders/invert.glsl') #with self.fbo.after: # self.cbr = Callback(self.reset_gl_context) # PopMatrix() with self.canvas.before: Callback(self._set_blend_func) # wait that all the instructions are in the canvas to set texture self.texture = self.fbo.texture super(FboFloatLayout, self).__init__(**kwargs) def prepare_canvas(self, *args): glEnable(GL_BLEND) glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE) glEnable(GL_DEPTH_TEST) def _set_blend_func(self, instruction): # clobber the blend mode if self.alpha_blending: glBlendFunc(GL_ONE, GL_ZERO) else: #glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA,GL_ONE,GL_ONE_MINUS_SRC_ALPHA) #glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE) #glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) # draw the buffer, not the whole freakin canvas glDisable(GL_CULL_FACE) self.fbo.draw() # unclobber the buffer glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) def setup_gl_context(self, *args): glEnable(GL_BLEND) glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) glEnable(GL_DEPTH_TEST) def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) glDisable(GL_CULL_FACE) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) def add_widget(self, *largs): # trick to attach kivy3dgui instructino to fbo instead of canvas canvas = self.canvas self.canvas = self.fbo ret = super(FboFloatLayout, self).add_widget(*largs) self.canvas = canvas return ret def remove_widget(self, *largs): canvas = self.canvas self.canvas = self.fbo super(FboFloatLayout, self).remove_widget(*largs) self.canvas = canvas def on_size(self, instance, value): self.fbo.size = value self.texture = self.fbo_texture self.fbo_rect.size = value def on_pos(self, instance, value): self.fbo_rect.pos = value def on_texture(self, instance, value): self.fbo_rect.texture = value def on_touch_down(self, touch): return super(FboFloatLayout, self).on_touch_down(touch) def on_touch_move(self, touch): return super(FboFloatLayout, self).on_touch_move(touch) def on_touch_up(self, touch): return super(FboFloatLayout, self).on_touch_up(touch)
class FboFloatLayout(Widget): texture = ObjectProperty(None, allownone=True) vertices = ListProperty([]) fbo = None tmp_fbo = None def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=self.size) super(FboFloatLayout, self).__init__(**kwargs) # -- # preload FBO with background texture def initFbo(self): with self.fbo: ClearColor(0,0,0,0) ClearBuffers() #Rectangle(source = 'data/background.jpg', size=self.size, pos=self.pos) self.texture = self.fbo.texture # -- # add the content of the widget to the FBO # this will literally render the widget into the texture def render_widget(self, widget): # create an FBO to render the widget to self.tmp_fbo = Fbo(size = self.size) self.tmp_fbo.add(ClearColor(0,0,0,0)) self.tmp_fbo.add(ClearBuffers()) self.tmp_fbo.add(widget.canvas) self.tmp_fbo.draw() # render a rectangle in the main fbo containing the content from the widget with self.fbo: Color(1,1,1,1) Rectangle(texture=self.tmp_fbo.texture, size=self.tmp_fbo.size) #def add_widget(self, *largs): # trick to attach graphics instruction to fbo instead of canvas # canvas = self.canvas # self.canvas = self.fbo # ret = super(FboFloatLayout, self).add_widget(*largs) # self.canvas = canvas # remove widget after next frame, this makes sure that # we do not use the widget for more than one frame #Clock.schedule_once(lambda dt: self.remove_widget(*largs)) # return ret #def remove_widget(self, *largs): # canvas = self.canvas # self.canvas = self.fbo # super(FboFloatLayout, self).remove_widget(*largs) # self.canvas = canvas def on_size(self, instance, value): self.size = value self.fbo.size = value #self.fbo_rect.size = value #self.fbo_background.size = value #self.fbo_rect.texture = self.fbo.texture # setup simple quad mesh to be rendered # the quad is used for actual resizing self.vertices = [] self.vertices.extend([0,0,0,0]) self.vertices.extend([0,self.height,0,1]) self.vertices.extend([self.width,self.height,1,1]) self.vertices.extend([self.width,0,1,0]) #self.updateFbo() self.initFbo()
class Renderer(Widget): texture = ObjectProperty(None, allownone=True) def __init__(self, **kwargs): #self.canvas = RenderContext(compute_normal_mat=True) #self.canvas.shader.source = resource_find('simple.glsl') self.canvas = Canvas() self.scene = ObjFileLoader(resource_find("testnurbs.obj")) self.meshes = [] with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find('simple.glsl') #self.texture = self.fbo.texture super(Renderer, self).__init__(**kwargs) with self.fbo: #ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene() PopMatrix() self.cb = Callback(self.reset_gl_context) Clock.schedule_interval(self.update_scene, 1 / 60.) self._touches = [] def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def on_pos(self, instance, value): self.viewport.pos = value def on_texture(self, instance, value): self.viewport.texture = value def setup_gl_context(self, *args): #clear_buffer glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() #glDepthMask(GL_FALSE); def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *largs): asp = self.width / float(self.height) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) self.fbo['projection_mat'] = proj def setup_scene(self): Color(1, 1, 1, 0) PushMatrix() Translate(0, 0, -5) # This Kivy native Rotation is used just for # enabling rotation scene like trackball self.rotx = Rotate(0, 1, 0, 0) self.roty = Rotate(-120, 0, 1, 0) # here just rotate scene for best view self.scale = Scale(1) UpdateNormalMatrix() self.draw_elements() PopMatrix() def draw_elements(self): """ Draw separately all objects on the scene to setup separate rotation for each object """ def _draw_element(m): Mesh( vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode='triangles', ) def _set_color(*color, **kw): id_color = kw.pop('id_color', (0, 0, 0)) return ChangeState( Kd=color, Ka=color, Ks=(.3, .3, .3), Tr=1., Ns=1., intensity=1., id_color=[i / 255. for i in id_color], ) # Draw sphere in the center sphere = self.scene.objects['Sphere'] _set_color(0.7, 0.7, 0., id_color=(255, 255, 0)) _draw_element(sphere) # Then draw other elements and totate it in different axis pyramid = self.scene.objects['Pyramid'] PushMatrix() self.pyramid_rot = Rotate(0, 0, 0, 1) _set_color(0., 0., .7, id_color=(0., 0., 255)) _draw_element(pyramid) PopMatrix() box = self.scene.objects['Box'] PushMatrix() self.box_rot = Rotate(0, 0, 1, 0) _set_color(.7, 0., 0., id_color=(255, 0., 0)) _draw_element(box) PopMatrix() cylinder = self.scene.objects['Cylinder'] PushMatrix() self.cylinder_rot = Rotate(0, 1, 0, 0) _set_color(0.0, .7, 0., id_color=(0., 255, 0)) _draw_element(cylinder) PopMatrix() def update_scene(self, *largs): self.pyramid_rot.angle += 0.5 self.box_rot.angle += 0.5 self.cylinder_rot.angle += 0.5 # =============== All stuff after is for trackball implementation ============= def define_rotate_angle(self, touch): x_angle = (touch.dx/self.width)*360 y_angle = -1*(touch.dy/self.height)*360 return x_angle, y_angle def on_touch_down(self, touch): self._touch = touch touch.grab(self) self._touches.append(touch) def on_touch_up(self, touch): touch.ungrab(self) self._touches.remove(touch) self.fbo.shader.source = 'select_mode.glsl' self.fbo.ask_update() self.fbo.draw() print(self.fbo.get_pixel_color(touch.x, touch.y)) self.fbo.shader.source = 'simple.glsl' self.fbo.ask_update() self.fbo.draw() def on_touch_move(self, touch): self.update_glsl() if touch in self._touches and touch.grab_current == self: if len(self._touches) == 1: # here do just rotation ax, ay = self.define_rotate_angle(touch) self.roty.angle += ax self.rotx.angle += ay elif len(self._touches) == 2: # scaling here #use two touches to determine do we need scal touch1, touch2 = self._touches old_pos1 = (touch1.x - touch1.dx, touch1.y - touch1.dy) old_pos2 = (touch2.x - touch2.dx, touch2.y - touch2.dy) old_dx = old_pos1[0] - old_pos2[0] old_dy = old_pos1[1] - old_pos2[1] old_distance = (old_dx*old_dx + old_dy*old_dy) Logger.debug('Old distance: %s' % old_distance) new_dx = touch1.x - touch2.x new_dy = touch1.y - touch2.y new_distance = (new_dx*new_dx + new_dy*new_dy) Logger.debug('New distance: %s' % new_distance) SCALE_FACTOR = 0.01 if new_distance > old_distance: scale = SCALE_FACTOR Logger.debug('Scale up') elif new_distance == old_distance: scale = 0 else: scale = -1*SCALE_FACTOR Logger.debug('Scale down') xyz = self.scale.xyz if scale: self.scale.xyz = tuple(p + scale for p in xyz)
class NSpect(Widget): texture = ObjectProperty(None, allownone=True) def __init__(self, **kwargs): LOP, dm = initFiles() #self.canvas = RenderContext(compute_normal_mat=True) #self.canvas.shader.source = resource_find('simple.glsl') self.canvas = Canvas() self.scene = ObjFileLoader(resource_find("testnurbs.obj")) self.LOP = LOP self.dm = dm self.meshes = [] self.panCamera = False # KEITH EDIT self.pause = True # KEITH EDIT with self.canvas: self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self.viewport = Rectangle(size=self.size, pos=self.pos) self.fbo.shader.source = resource_find('simple.glsl') #self.texture = self.fbo.texture # *&Y*&Y*&YH*&Y*&Y*&Y*Y&* # Keith: This allows keyboard interaction # http://stackoverflow.com/questions/22137786/ self._keyboard = Window.request_keyboard(None, self) if not self._keyboard: return self._keyboard.bind(on_key_down=self.on_keyboard_down) # *&Y*&Y*&YH*&Y*&Y*&Y*Y&* super(NSpect, self).__init__(**kwargs) with self.fbo: #ClearBuffers(clear_depth=True) self.cb = Callback(self.setup_gl_context) PushMatrix() self.setup_scene(self.LOP, dm) PopMatrix() self.cb = Callback(self.reset_gl_context) Clock.schedule_interval(self.update_scene, 1 / 60.) self._touches = [] def on_size(self, instance, value): self.fbo.size = value self.viewport.texture = self.fbo.texture self.viewport.size = value self.update_glsl() def on_pos(self, instance, value): self.viewport.pos = value def on_texture(self, instance, value): self.viewport.texture = value def setup_gl_context(self, *args): #clear_buffer glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() #glDepthMask(GL_FALSE); def reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def update_glsl(self, *largs): asp = self.width / float(self.height) proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1) self.fbo['projection_mat'] = proj def setup_scene(self, LOP, dm): Color(1, 1, 1, 0) PushMatrix() Translate(0, 0, -5) # This Kivy native Rotation is used just for # enabling rotation scene like trackball self.rotx = Rotate(0, 1, 0, 0) self.roty = Rotate(-120, 0, 1, 0) # here just rotate scene for best view self.scale = Scale(1) UpdateNormalMatrix() self.draw_elements(LOP, dm) PopMatrix() def draw_elements(self, LOP, dm): """ Draw separately all objects on the scene to setup separate rotation for each object """ def _draw_element(m): Mesh( vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode='triangles', ) def _set_color(*color, **kw): id_color = kw.pop('id_color', (0, 0, 0)) return ChangeState( Kd=color, Ka=color, Ks=(.3, .3, .3), Tr=1., Ns=1., intensity=1., id_color=[i / 255. for i in id_color], ) def drawPoints(): print self.scene.objects for i in range(len(self.LOP)): PushMatrix() point = self.LOP[i] point.shape = self.scene.objects['Sphere'] point.color = _set_color(i/10., (i+1)/10., 0., id_color=(int(255/(1+i)), int(255/(1+i)), 255)) point.shape.scale = Scale((i+1)/10.0,(i+1)/10.0,(i+1)/10.0) self.LOP[i] = point print point.shape _draw_element(point.shape) point.shape.scale.origin = (point.loc[0],point.loc[1],point.loc[2]) PopMatrix() drawPoints() def update_scene(self, *largs): def randLoc(point): newLoc = (0.1*random.random(),0.1*random.random(),0.1*random.random()) oldLoc = point.shape.scale.origin newLoc = ( newLoc[0]-0.05+oldLoc[0], newLoc[1]-0.05+oldLoc[1], newLoc[2]-0.05+oldLoc[2] ) return newLoc def updateLocs(self): for i in range(len(self.LOP)): point = self.LOP[i] point.shape.scale.origin = randLoc(point) if not self.pause: updateLocs(self) pass # =============== All stuff after is for trackball implementation ============= def moveA(self): pass def moveB(self): pass def define_rotate_angle(self, touch): x_angle = (touch.dx/self.width)*360 y_angle = -1*(touch.dy/self.height)*360 return x_angle, y_angle def on_touch_down(self, touch): self._touch = touch touch.grab(self) self._touches.append(touch) def on_touch_up(self, touch): touch.ungrab(self) self._touches.remove(touch) self.fbo.shader.source = 'select_mode.glsl' self.fbo.ask_update() self.fbo.draw() print self.fbo.get_pixel_color(touch.x, touch.y) self.fbo.shader.source = 'simple.glsl' self.fbo.ask_update() self.fbo.draw() # *O(U(U())(*U(*(****************** # Keith: This allows keyboard interaction def on_keyboard_down(self, keyboard, keycode, text, modifiers): if keycode[1] == 'left': if self.panCamera == True: self.x -= 10 else: self.roty.angle += 10 elif keycode[1] == 'right': if self.panCamera == True: self.x += 10 else: self.roty.angle -= 10 if keycode[1] == 'up': if self.panCamera == True: self.y += 10 else: self.rotx.angle += 10 elif keycode[1] == 'down': if self.panCamera == True: self.y -= 10 else: self.rotx.angle -= 10 elif keycode[1] == 'i': self.update_glsl() SCALE_FACTOR = 0.01 scale = SCALE_FACTOR Logger.debug('Scale up') xyz = self.scale.xyz if scale: self.scale.xyz = tuple(p + scale for p in xyz) elif keycode[1] == 'o': self.update_glsl() SCALE_FACTOR = 0.01 scale = SCALE_FACTOR Logger.debug('Scale up') xyz = self.scale.xyz if scale: temp = tuple(p - scale for p in xyz) # Prevent the collection from having a negative size if temp[0] > 0: self.scale.xyz = temp elif keycode[1] == 't': self.panCamera = not self.panCamera elif keycode[1] == 'p': self.pause = not self.pause if not self.pause: print "Playing" else: print "Paused" def on_touch_move(self, touch): self.update_glsl() if touch in self._touches and touch.grab_current == self: if len(self._touches) == 1: # here do just rotation ax, ay = self.define_rotate_angle(touch) self.roty.angle += ax self.rotx.angle += ay elif len(self._touches) == 2: # scaling here #use two touches to determine do we need scal touch1, touch2 = self._touches old_pos1 = (touch1.x - touch1.dx, touch1.y - touch1.dy) old_pos2 = (touch2.x - touch2.dx, touch2.y - touch2.dy) old_dx = old_pos1[0] - old_pos2[0] old_dy = old_pos1[1] - old_pos2[1] old_distance = (old_dx*old_dx + old_dy*old_dy) Logger.debug('Old distance: %s' % old_distance) new_dx = touch1.x - touch2.x new_dy = touch1.y - touch2.y new_distance = (new_dx*new_dx + new_dy*new_dy) Logger.debug('New distance: %s' % new_distance) SCALE_FACTOR = 0.01 if new_distance > old_distance: scale = SCALE_FACTOR Logger.debug('Scale up') elif new_distance == old_distance: scale = 0 else: scale = -1*SCALE_FACTOR Logger.debug('Scale down') xyz = self.scale.xyz if scale: self.scale.xyz = tuple(p + scale for p in xyz)
class Renderer(Widget): def __init__(self, **kw): self.shader_file = kw.pop("shader_file", None) self.canvas = Canvas() super(Renderer, self).__init__(**kw) with self.canvas: self._viewport = Rectangle(size=self.size, pos=self.pos) self.fbo = Fbo(size=self.size, with_depthbuffer=True, compute_normal_mat=True, clear_color=(0., 0., 0., 0.)) self._config_fbo() self.texture = self.fbo.texture self.camera = None self.scene = None def _config_fbo(self): # set shader file here self.fbo.shader.source = self.shader_file or \ os.path.join(kivy3_path, "default.glsl") with self.fbo: Callback(self._setup_gl_context) PushMatrix() # instructions set for all instructions self._instructions = InstructionGroup() PopMatrix() Callback(self._reset_gl_context) def _setup_gl_context(self, *args): glEnable(GL_DEPTH_TEST) self.fbo.clear_buffer() def _reset_gl_context(self, *args): glDisable(GL_DEPTH_TEST) def render(self, scene, camera): self.scene = scene self.camera = camera self.camera.bind_to(self) self._instructions.add(scene.as_instructions()) Clock.schedule_once(self._update_matrices, -1) def add(self, obj): self._instructions.add(obj.as_instructions()) def on_size(self, instance, value): self.fbo.size = value self._viewport.texture = self.fbo.texture self._viewport.size = value self._viewport.pos = self.pos self._update_matrices() def on_pos(self, instance, value): self._viewport.pos = self.pos self._update_matrices() def on_texture(self, instance, value): self._viewport.texture = value def _update_matrices(self, dt=None): if self.camera: self.fbo['projection_mat'] = self.camera.projection_matrix self.fbo['modelview_mat'] = self.camera.modelview_matrix else: raise RendererError("Camera is not defined for renderer") def set_clear_color(self, color): self.fbo.clear_color = color
class DmdBase(object): """Base class for DMD devices.""" dmd_name_string = 'DMD' def __init__(self, mc: "MpfMc", name: str, config: dict) -> None: """Initialise DMD.""" self.mc = mc self.name = name self.mc.log.info('Initializing DMD') self.config = self._get_validated_config(config) self.source = self.mc.displays[self.config['source_display']] self.prev_data = None # put the widget canvas on a Fbo texture = Texture.create(size=self.source.size, colorfmt='rgb') self.fbo = Fbo(size=self.source.size, texture=texture) self.effect_widget = EffectWidget() effect_list = list() effect_list.append(FlipVerticalEffect()) if self.config['brightness'] != 1.0: if not 0.0 <= self.config['brightness'] <= 1.0: raise ValueError("DMD brightness value should be between 0.0 " "and 1.0. Yours is {}".format( self.config['brightness'])) effect_list.append(GainEffect(gain=self.config['brightness'])) if self.config['gamma'] != 1.0: effect_list.append(GammaEffect(gamma=self.config['gamma'])) self.effect_widget.effects = effect_list self.effect_widget.size = self.source.size self.fbo.add(self.effect_widget.canvas) self._set_dmd_fps() def _get_validated_config(self, config: dict) -> dict: raise NotImplementedError def _set_dmd_fps(self) -> None: # fps is the rate that the connected client requested. We'll use the # lower of the two mc_fps = self.config['fps'] if mc_fps == 0: # pylint: disable-msg=protected-access mc_fps = Clock._max_fps # pylint: disable-msg=protected-access if mc_fps > Clock._max_fps: self.mc.log.warning( "%s fps is higher than mpf-mc fps. " "Will use mpf-mc fps setting for the DMD.", DmdBase.dmd_name_string) # pylint: disable-msg=protected-access fps = Clock._max_fps update = 0 # pylint: disable-msg=protected-access elif Clock._max_fps > mc_fps > 0: fps = mc_fps update = 1 / fps else: # pylint: disable-msg=protected-access fps = Clock._max_fps update = 0 Clock.schedule_interval(self.tick, update) self.mc.log.info("Setting %s to %sfps", DmdBase.dmd_name_string, fps) def tick(self, dt) -> None: """Draw image for DMD and send it.""" del dt widget = self.source fbo = self.fbo # detach the widget from the parent parent = widget.parent if parent: parent.remove_widget(widget) self.effect_widget.add_widget(widget) # clear the fbo background fbo.bind() fbo.clear_buffer() fbo.release() fbo.draw() fbo.bind() data = glReadPixels(0, 0, widget.native_size[0], widget.native_size[1], GL_RGB, GL_UNSIGNED_BYTE) fbo.release() # reattach to the parent if parent: self.effect_widget.remove_widget(widget) parent.add_widget(widget) if not self.config['only_send_changes'] or self.prev_data != data: self.prev_data = data self.send(data) def send(self, data: bytes) -> None: """Send data to DMD via BCP.""" raise NotImplementedError
class EffectWidget(RelativeLayout): ''' Widget with the ability to apply a series of graphical effects to its children. See the module documentation for more information on setting effects and creating your own. ''' background_color = ListProperty((0, 0, 0, 0)) '''This defines the background color to be used for the fbo in the EffectWidget. :attr:`background_color` is a :class:`ListProperty` defaults to (0, 0, 0, 0) ''' texture = ObjectProperty(None) '''The output texture of the final :class:`~kivy.graphics.Fbo` after all effects have been applied. texture is an :class:`~kivy.properties.ObjectProperty` and defaults to None. ''' effects = ListProperty([]) '''List of all the effects to be applied. These should all be instances or subclasses of :class:`EffectBase`. effects is a :class:`ListProperty` and defaults to []. ''' fbo_list = ListProperty([]) '''(internal) List of all the fbos that are being used to apply the effects. fbo_list is a :class:`ListProperty` and defaults to []. ''' _bound_effects = ListProperty([]) '''(internal) List of effect classes that have been given an fbo to manage. This is necessary so that the fbo can be removed if the effect is no longer in use. _bound_effects is a :class:`ListProperty` and defaults to []. ''' def __init__(self, **kwargs): # Make sure opengl context exists EventLoop.ensure_window() self.canvas = RenderContext(use_parent_projection=True, use_parent_modelview=True) self._callbacks = {} with self.canvas: self.fbo = Fbo(size=self.size) with self.fbo.before: # noqa PushMatrix() with self.fbo: ClearColor(0, 0, 0, 0) ClearBuffers() self._background_color = Color(*self.background_color) self.fbo_rectangle = Rectangle(size=self.size) with self.fbo.after: # noqa PopMatrix() super(EffectWidget, self).__init__(**kwargs) fbind = self.fbind fbo_setup = self.refresh_fbo_setup fbind('size', fbo_setup) fbind('effects', fbo_setup) fbind('background_color', self._refresh_background_color) self.refresh_fbo_setup() self._refresh_background_color() # In case thi was changed in kwargs def _refresh_background_color(self, *args): # noqa self._background_color.rgba = self.background_color def _propagate_updates(self, *largs): """Propagate updates from widgets.""" del largs for fbo in self.fbo_list: fbo.ask_update() def refresh_fbo_setup(self, *args): # noqa '''(internal) Creates and assigns one :class:`~kivy.graphics.Fbo` per effect, and makes sure all sizes etc. are correct and consistent. ''' # Add/remove fbos until there is one per effect while len(self.fbo_list) < len(self.effects): with self.canvas: new_fbo = EffectFbo(size=self.size) with new_fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Color(1, 1, 1, 1) new_fbo.texture_rectangle = Rectangle(size=self.size) new_fbo.texture_rectangle.size = self.size self.fbo_list.append(new_fbo) while len(self.fbo_list) > len(self.effects): old_fbo = self.fbo_list.pop() self.canvas.remove(old_fbo) # Remove fbos from unused effects for effect in self._bound_effects: if effect not in self.effects: effect.fbo = None self._bound_effects = self.effects # Do resizing etc. self.fbo.size = self.size self.fbo_rectangle.size = self.size for i in range(len(self.fbo_list)): self.fbo_list[i].size = self.size self.fbo_list[i].texture_rectangle.size = self.size # If there are no effects, just draw our main fbo if len(self.fbo_list) == 0: # noqa self.texture = self.fbo.texture return for i in range(1, len(self.fbo_list)): fbo = self.fbo_list[i] fbo.texture_rectangle.texture = self.fbo_list[i - 1].texture # Build effect shaders for effect, fbo in zip(self.effects, self.fbo_list): effect.fbo = fbo self.fbo_list[0].texture_rectangle.texture = self.fbo.texture self.texture = self.fbo_list[-1].texture for fbo in self.fbo_list: fbo.draw() self.fbo.draw() def add_widget(self, widget): # noqa # Add the widget to our Fbo instead of the normal canvas c = self.canvas self.canvas = self.fbo with widget.canvas: self._callbacks[widget.canvas] = Callback(self._propagate_updates) super(EffectWidget, self).add_widget(widget) self.canvas = c def remove_widget(self, widget): # Remove the widget from our Fbo instead of the normal canvas c = self.canvas widget.canvas.remove(self._callbacks[widget.canvas]) del self._callbacks[widget.canvas] self.canvas = self.fbo super(EffectWidget, self).remove_widget(widget) self.canvas = c def clear_widgets(self, children=None): # Clear widgets from our Fbo instead of the normal canvas c = self.canvas self.canvas = self.fbo for canvas, callback in self._callbacks.items(): canvas.remove(callback) self._callbacks = {} super(EffectWidget, self).clear_widgets(children) self.canvas = c
def texture_merge(texture1, texture2): fbo = Fbo(size=texture2.size, texture=texture2) fbo.add(Rectangle(pos=(0, 0), texture=texture1, size=texture1.size)) fbo.draw() return fbo.texture
def init_smaa(self): curdir = dirname(__file__) # load shaders sources with open(join(curdir, "SMAA.h"), "r") as fd: smaa_h = fd.read() config = """ #version 410 compatibility #define SMAA_PIXEL_SIZE vec2(1.0 / {width}, 1.0 / {height}) #define SMAA_PRESET_{quality} 1 #define SMAA_GLSL_4 1 """.format( width=self.width, height=self.height, quality=self.quality.upper() ) header_vs = ( config + """ #define SMAA_ONLY_COMPILE_VS 1 in vec2 vPosition; in vec2 vTexCoords0; uniform mat4 modelview_mat; uniform mat4 projection_mat; """ + smaa_h ) header_fs = ( config + """ #define SMAA_ONLY_COMPILE_PS 1 """ + smaa_h ) edge_vs = ( header_vs + """ out vec2 texcoord; out vec4 offset[3]; out vec4 dummy2; void main() { texcoord = vTexCoords0; vec4 dummy1 = vec4(0); SMAAEdgeDetectionVS(dummy1, dummy2, texcoord, offset); gl_Position = projection_mat * modelview_mat * vec4(vPosition.xy, 0.0, 1.0); } """ ) edge_fs = ( header_fs + """ uniform sampler2D albedo_tex; in vec2 texcoord; in vec4 offset[3]; in vec4 dummy2; void main() { #if SMAA_PREDICATION == 1 gl_FragColor = SMAAColorEdgeDetectionPS(texcoord, offset, albedo_tex, depthTex); #else gl_FragColor = SMAAColorEdgeDetectionPS(texcoord, offset, albedo_tex); #endif } """ ) blend_vs = ( header_vs + """ out vec2 texcoord; out vec2 pixcoord; out vec4 offset[3]; out vec4 dummy2; void main() { texcoord = vTexCoords0; vec4 dummy1 = vec4(0); SMAABlendingWeightCalculationVS(dummy1, dummy2, texcoord, pixcoord, offset); gl_Position = projection_mat * modelview_mat * vec4(vPosition.xy, 0.0, 1.0); } """ ) blend_fs = ( header_fs + """ uniform sampler2D edge_tex; uniform sampler2D area_tex; uniform sampler2D search_tex; in vec2 texcoord; in vec2 pixcoord; in vec4 offset[3]; in vec4 dummy2; void main() { gl_FragColor = SMAABlendingWeightCalculationPS(texcoord, pixcoord, offset, edge_tex, area_tex, search_tex, ivec4(0)); } """ ) neighborhood_vs = ( header_vs + """ out vec2 texcoord; out vec4 offset[2]; out vec4 dummy2; void main() { texcoord = vTexCoords0; vec4 dummy1 = vec4(0); SMAANeighborhoodBlendingVS(dummy1, dummy2, texcoord, offset); gl_Position = projection_mat * modelview_mat * vec4(vPosition.xy, 0.0, 1.0); } """ ) neighborhood_fs = ( header_fs + """ uniform sampler2D albedo_tex; uniform sampler2D blend_tex; in vec2 texcoord; in vec4 offset[2]; in vec4 dummy2; void main() { gl_FragColor = SMAANeighborhoodBlendingPS(texcoord, offset, albedo_tex, blend_tex); } """ ) size = self.size self.albedo_tex = Texture.create(size=size, bufferfmt="float") self.albedo_fbo = Fbo(size=size, texture=self.albedo_tex) self.edge_tex = Texture.create(size=size, bufferfmt="float") self.edge_fbo = Fbo(size=size, vs=edge_vs, fs=edge_fs, texture=self.edge_tex) self.edge_fbo.bind() self.edge_fbo["albedo_tex"] = 0 self.edge_fbo.release() self.blend_tex = Texture.create(size=size, bufferfmt="float") self.blend_fbo = Fbo(size=size, vs=blend_vs, fs=blend_fs, texture=self.blend_tex) self.blend_fbo.bind() self.blend_fbo["edge_tex"] = 0 self.blend_fbo["area_tex"] = 1 self.blend_fbo["search_tex"] = 2 self.blend_fbo.release() self.neighborhood = RenderContext( use_parent_modelview=True, use_parent_projection=True, vs=neighborhood_vs, fs=neighborhood_fs ) with self.neighborhood: self.neighborhood["albedo_tex"] = 0 self.neighborhood["blend_tex"] = 1 self.area_tex = Texture.create(size=(AREATEX_WIDTH, AREATEX_HEIGHT), colorfmt="rg", icolorfmt="rg8") with open(join(curdir, "smaa_area.raw"), "rb") as fd: self.area_tex.blit_buffer(fd.read(), colorfmt="rg") self.search_tex = Texture.create(size=(SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT), colorfmt="red", icolorfmt="r8") self.search_tex.min_filter = "nearest" self.search_tex.mag_filter = "nearest" with open(join(curdir, "smaa_search.raw"), "rb") as fd: self.search_tex.blit_buffer(fd.read(), colorfmt="red") with self.albedo_fbo: ClearColor(0, 0, 0, 0) ClearBuffers() with self.edge_fbo: Rectangle(size=self.size, texture=self.albedo_tex) with self.blend_fbo: BindTexture(index=1, texture=self.area_tex) BindTexture(index=2, texture=self.search_tex) Rectangle(size=self.size, texture=self.edge_tex) self.neighborhood.add(self.albedo_fbo) self.neighborhood.add(Callback(lambda *x: glDisable(GL_BLEND))) self.neighborhood.add(self.edge_fbo) self.neighborhood.add(self.blend_fbo) self.neighborhood.add(Callback(lambda *x: glEnable(GL_BLEND))) with self.neighborhood: BindTexture(index=1, texture=self.blend_tex) Rectangle(size=self.size, texture=self.albedo_tex) self.smaa_canvas = Canvas() with self.smaa_canvas.before: def do_stuff(*args): self.albedo_fbo.bind() self.albedo_fbo.clear_buffer() self.albedo_fbo.release() self.edge_fbo.bind() self.edge_fbo.clear_buffer() self.edge_fbo.release() self.blend_fbo.bind() self.blend_fbo.clear_buffer() self.blend_fbo.release() self.albedo_fbo.ask_update() self.edge_fbo.ask_update() self.blend_fbo.ask_update() self.neighborhood.ask_update() Callback(do_stuff) self.smaa_canvas.add(self.neighborhood) self._g_debug_added = False self._g_debug = [ Callback(lambda *x: glDisable(GL_BLEND)), Color(0, 0, 0, 1), Rectangle(size=self.size), Color(1, 1, 1, 1), Rectangle(size=self.size), Callback(lambda *x: glEnable(GL_BLEND)), ]