diff --git a/examples/canvas/mesh.py b/examples/canvas/mesh.py new file mode 100644 index 000000000..bff3a51c6 --- /dev/null +++ b/examples/canvas/mesh.py @@ -0,0 +1,52 @@ +''' +Mesh test +========= + +''' + +from kivy.uix.button import Button +from kivy.uix.widget import Widget +from kivy.uix.boxlayout import BoxLayout +from kivy.app import App +from kivy.graphics import Mesh +from functools import partial +from math import cos, sin, pi + + +class MeshTestApp(App): + + def change_mode(self, mode, *largs): + self.mesh.mode = mode + + def build_mesh(self): + vertices = [] + indices = [] + step = 10 + istep = (pi * 2) / float(step) + for i in xrange(step): + x = 300 + cos(istep * i) * 100 + y = 300 + sin(istep * i) * 100 + vertices.extend([x, y, 0, 0]) + indices.append(i) + return Mesh(vertices=vertices, indices=indices) + + def build(self): + wid = Widget() + with wid.canvas: + self.mesh = self.build_mesh() + + layout = BoxLayout(size_hint=(1, None), height=50) + for mode in ('points', 'line_strip', 'line_loop', 'lines', + 'triangle_strip', 'triangle_fan'): + button = Button(text=mode) + button.bind(on_release=partial(self.change_mode, mode)) + layout.add_widget(button) + + root = BoxLayout(orientation='vertical') + root.add_widget(wid) + root.add_widget(layout) + + return root + +if __name__ == '__main__': + MeshTestApp().run() diff --git a/kivy/graphics/vbo.pxd b/kivy/graphics/vbo.pxd index 90b7ccd73..f5487f5a3 100644 --- a/kivy/graphics/vbo.pxd +++ b/kivy/graphics/vbo.pxd @@ -29,6 +29,7 @@ cdef class VertexBatch: cdef Buffer elements cdef Buffer vbo_index cdef GLuint mode + cdef str mode_str cdef void clear_data(self) cdef void set_data(self, vertex_t *vertices, int vertices_count, @@ -37,4 +38,5 @@ cdef class VertexBatch: unsigned short *indices, int indices_count) cdef void draw(self) cdef void set_mode(self, str mode) + cdef str get_mode(self) cdef int count(self) diff --git a/kivy/graphics/vbo.pyx b/kivy/graphics/vbo.pyx index 67f485139..1e9b75309 100644 --- a/kivy/graphics/vbo.pyx +++ b/kivy/graphics/vbo.pyx @@ -160,6 +160,7 @@ cdef class VertexBatch: cdef void set_mode(self, str mode): # most common case in top; + self.mode_str = mode if mode is None: self.mode = GL_TRIANGLES elif mode == 'points': @@ -177,6 +178,9 @@ cdef class VertexBatch: else: self.mode = GL_TRIANGLES + cdef str get_mode(self): + return self.mode_str + cdef int count(self): return self.elements.count() diff --git a/kivy/graphics/vertex_instructions.pyx b/kivy/graphics/vertex_instructions.pyx index 879a5afc0..a4ad1e078 100644 --- a/kivy/graphics/vertex_instructions.pyx +++ b/kivy/graphics/vertex_instructions.pyx @@ -357,11 +357,35 @@ cdef class Bezier(VertexInstruction): cdef class Mesh(VertexInstruction): '''A 2d mesh. + The format of vertices are actually fixed, this might change in a future + release. Right now, each vertex is described with 2D coordinates (x, y) and + a 2D texture coordinate (u, v). + + In OpenGL ES 2.0 and in our graphics implementation, you cannot have more + than 65535 indices. + + A list of vertices is described as:: + + vertices = [x1, y1, u1, v1, x2, y2, u2, v2, ...] + | | | | + +---- i1 ----+ +---- i2 ----+ + + If you want to draw a triangles, put 3 vertices, then you can make an + indices list as: + + indices = [0, 1, 2] + + .. versionadded:: 1.0.10 + :Parameters: `vertices`: list - List of points in the format (x1, y1, x2, y2...) + List of vertices in the format (x1, y1, u1, v1, x2, y2, u2, v2...) `indices`: list List of indices in the format (i1, i2, i3...) + `mode`: str + Mode of the vbo. Check :data:`mode` for more information. Default to + 'points'. + ''' cdef list _vertices cdef list _indices @@ -370,21 +394,25 @@ cdef class Mesh(VertexInstruction): VertexInstruction.__init__(self, **kwargs) self.vertices = kwargs.get('vertices', []) self.indices = kwargs.get('indices', []) - self.batch.set_mode('points') + self.mode = kwargs.get('mode', 'points') cdef void build(self): - cdef int i, vcount = len(self._vertices) / 2 + cdef int i, vcount = len(self._vertices) / 4 cdef int icount = len(self._indices) cdef vertex_t *vertices = NULL - cdef int *indices = NULL + cdef unsigned short *indices = NULL cdef list lvertices = self._vertices cdef list lindices = self._indices + if vcount == 0 or icount == 0: + self.batch.clear_data() + return + vertices = malloc(vcount * sizeof(vertex_t)) if vertices == NULL: raise MemoryError('vertices') - indices = malloc(icount * sizeof(int)) + indices = malloc(icount * sizeof(unsigned short)) if indices == NULL: free(vertices) raise MemoryError('indices') @@ -404,6 +432,10 @@ cdef class Mesh(VertexInstruction): free(indices) property vertices: + '''List of x, y, u, v, ... used to construct the Mesh. Right now, the + Mesh instruction doesn't allow you to change the format of the vertices, + mean it's only x/y + one texture coordinate. + ''' def __get__(self): return self._vertices def __set__(self, value): @@ -411,12 +443,28 @@ cdef class Mesh(VertexInstruction): self.flag_update() property indices: + '''Vertex indices used to know which order you wanna do for drawing the + mesh. + ''' def __get__(self): return self._indices def __set__(self, value): + if len(value) > 65535: + raise GraphicException( + 'Cannot upload more than 65535 indices' + '(OpenGL ES 2 limitation)') self._indices = list(value) self.flag_update() + property mode: + '''VBO Mode used for drawing vertices/indices. Can be one of: 'points', + 'line_strip', 'line_loop', 'lines', 'triangle_strip', 'triangle_fan' + ''' + def __get__(self): + self.batch.get_mode() + def __set__(self, mode): + self.batch.set_mode(mode) + cdef class Point(VertexInstruction):