”;
Kivy library provides an “Fbo” class which stands for Framebuffer offscreen. It is an off-screen window on which you can draw any graphics instructions and then use it as a texture for the canvas of a certain Kivy widget.
The Fbo class is defined in kivy.graphics,fbo module. The first step is to create the fbo and use the fbo texture on other rectangle.
from kivy.graphics import Fbo, Color, Rectangle with self.canvas: self.fbo = Fbo(size=self.size)
Next, add graphics instructions such as Rectangle to the Fbo object. For example −
with self.fbo: Color(1, 0, 0, .8) Rectangle(size=(256, 64)) Color(0, 1, 0, .8) Rectangle(size=(64, 256))
Finally, apply the Fbo texture to the canvas.
self.texture = self.fbo.texture
Note that the FBO is lost if the OpenGL context is lost. In such a case, you need to reupload data using the Fbo.add_reload_observer() method..
add_reload_observer(callback) − Add a callback to be called after the whole graphics context has been reloaded. The callback parameter will be the context itself.
The bind() method binds the FBO object to the current opengl context. This way all the drawing operations will act inside the Framebuffer, until release() is called. The release() method releases or unbinds the Framebuffer.
self.fbo = FBO() self.fbo.bind() # do any drawing command self.fbo.release() self.canvas = self.fbo.texture
There is also a remove_reload_observer(callback) method that removes a callback from the observer list, previously added by add_reload_observer().
The clear_buffer() and clear_color methods clear the framebuffer and clear color in (red, green, blue, alpha) format.
Example
The following code demonstrates the use of Framebuffer in a Kivy application. The important part of the code is a class named as FboFloatLayout which inherits Kivy”s FloatLayout class.
The constructor (__init__() method) creates a Fbo object on the canvase of float layout, draws a rectangle on it and sets its texture as the texture of the 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() self.texture = self.fbo.texture super(FboFloatLayout, self).__init__(**kwargs)
we are going to add a button to this FloatLayout class, but before that the add_widget() method is overridden so as to add the graphics instruction to the fbo and then add it to the canvas.
def add_widget(self, *args, **kwargs): canvas = self.canvas self.canvas = self.fbo ret = super(FboFloatLayout, self).add_widget(*args, **kwargs) self.canvas = canvas return ret
The FboFloatLayout class also has the callbacks that respond to the changes in the size, pos and texture.
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
Now to the App class. The build() method adds a button and applies a series of animation effects that change the button position up to down and from right to left, repeatedly.
def anim_btn(*args): animate = Animation(pos=(b.pos[0], Window.height - 50)) animate += Animation(pos=(b.pos[0], 0)) animate += Animation(pos_hint={''center_x'': 1}) animate += Animation(pos_hint={''center_x'': 0}) animate += Animation(pos_hint={''center_x'': .5}) animate.start(b) animate.repeat = True b.bind(on_press=anim_btn)
These code fragments are put together in the complete code listing for the sake of convenience −
from kivy.graphics import Color, Rectangle, Canvas, ClearBuffers, ClearColor from kivy.graphics.fbo import Fbo from kivy.uix.floatlayout import FloatLayout from kivy.uix.button import Button from kivy.properties import ObjectProperty, NumericProperty from kivy.app import App from kivy.animation import Animation from kivy.core.window import Window Window.size = (720, 400) class FboFloatLayout(FloatLayout): texture = ObjectProperty(None, allownone=True) 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() self.texture = self.fbo.texture super(FboFloatLayout, self).__init__(**kwargs) def add_widget(self, *args, **kwargs): canvas = self.canvas self.canvas = self.fbo ret = super(FboFloatLayout, self).add_widget(*args, **kwargs) self.canvas = canvas return ret 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 class FBOdemoApp(App): def build(self): f = FboFloatLayout() b = Button(text="FBO", size_hint=(None, None), pos_hint={''center_x'': .5}) f.add_widget(b) def anim_btn(*args): animate = Animation(pos=(b.pos[0], Window.height - 50)) animate += Animation(pos=(b.pos[0], 0)) animate += Animation(pos_hint={''center_x'': 1}) animate += Animation(pos_hint={''center_x'': 0}) animate += Animation(pos_hint={''center_x'': .5}) animate.start(b) animate.repeat = True b.bind(on_press=anim_btn) return f FBOdemoApp().run()
Output
The application starts with a button captioned FBO at the bottom. When clicked, it starts its animation effects as defined.
”;