From 309148a7a2ac7c2f595665f21724b445c7c0f3a4 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Mon, 7 Mar 2011 16:01:17 +0100 Subject: [PATCH] graphics: introduce Callback() instruction, used to call a python callback when the instruction is used for drawing. The Callback() instruction include a basic reset_context behavior, that reset the opengl context to make Kivy rendering work without trouble (need more testing). --- kivy/graphics/instructions.pyx | 107 ++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/kivy/graphics/instructions.pyx b/kivy/graphics/instructions.pyx index 726b1fa76..3478fba3f 100644 --- a/kivy/graphics/instructions.pyx +++ b/kivy/graphics/instructions.pyx @@ -12,7 +12,8 @@ information about the usage of Canvas. __all__ = ('Instruction', 'InstructionGroup', 'ContextInstruction', 'VertexInstruction', - 'Canvas', 'CanvasBase', 'RenderContext') + 'Canvas', 'CanvasBase', 'RenderContext', + 'Callback') include "config.pxi" include "opcodes.pxi" @@ -185,6 +186,9 @@ cdef class ContextInstruction(Instruction): cdef class VertexInstruction(Instruction): + '''A vertex instruction is the base for creating displayed instruction + for Canvas (Rectangles, Triangles, Lines, Ellipse...) + ''' def __init__(self, **kwargs): #add a BindTexture instruction to bind teh texture used for #this instruction before the actual vertex instruction @@ -310,6 +314,106 @@ cdef class VertexInstruction(Instruction): self.batch.draw() +cdef class Callback(Instruction): + '''A Callback is a instruction that will be called when the drawing happen. + If you are building a canvas, you can do:: + + with self.canvas: + Color(1, 1, 1) + Rectangle(pos=self.pos, size=self.size) + Callback(self.my_callback) + + The definition of the callback must be:: + + def my_callback(self, instr): + print 'I am called !' + + The drawing of your canvas can not happen until something new changes. From + your callback, you can ask for an update:: + + with self.canvas: + self.cb = Canvas(self.my_callback) + # then later in the code + self.cb.ask_update() + + If you are using the Callback class to call rendering method of another + toolkit, you will have issues with opengl context. The opengl state can be + changed inside the another tookit, and so, as soon as you'll back to Kivy, + it will just broke. You can have glitch, crash, etc. + To prevent that, you can activate the :data:`reset_context` option. It will + reset the opengl context state to make Kivy rendering correct, after the + call of your callback. + + .. warning:: + + The :data:`reset_context` is not a full OpenGL reset. If you have issues + around that, please contact us. + + ''' + cdef object func + cdef int _reset_context + + def __init__(self, arg, **kwargs): + Instruction.__init__(self, **kwargs) + self.func = arg + self._reset_context = int(kwargs.get('reset_context', False)) + + def ask_update(self): + '''Ask the parent canvas to update itself the next frame. + Can be useful when a texture content is changing, but anything else in + the canvas. + ''' + self.flag_update() + + cdef void apply(self): + cdef RenderContext context + cdef Shader shader + + if self.func(self): + self.flag_update_done() + + if self._reset_context: + # FIXME do that in a proper way + glDisable(GL_DEPTH_TEST) + glDisable(GL_CULL_FACE) + glDisable(GL_SCISSOR_TEST) + glEnable(GL_BLEND) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + glUseProgram(0) + + # FIXME don't use 10. use max texture available from gl conf + for i in xrange(10): + glActiveTexture(GL_TEXTURE0 + i) + glBindTexture(GL_TEXTURE_2D, 0) + glDisableVertexAttribArray(i) + glBindBuffer(GL_ARRAY_BUFFER, 0) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) + + # force binding again all our textures. + context = getActiveContext() + shader = context.shader + context.enter() + shader.bind_attrib_locations() + for index, texture in context.bind_texture.iteritems(): + context.set_texture(index, texture) + + cdef void enter(self): + self._shader.use() + + property reset_context: + '''Set to True if you want to reset OpenGL context for kivy after the + callback have been called. + ''' + def __get__(self): + return self._reset_context + def __set__(self, value): + value = int(value) + if self._reset_context == value: + return + self._reset_context = value + self.flag_update() + + cdef class CanvasBase(InstructionGroup): def __enter__(self): pushActiveCanvas(self) @@ -317,6 +421,7 @@ cdef class CanvasBase(InstructionGroup): def __exit__(self, exc_type, exc_val, exc_tb): popActiveCanvas() + cdef class Canvas(CanvasBase): '''Our famous Canvas class. Use this class for add graphics or context instructions to use when drawing