Your gpu is an awesome thing, it can do all kind of calculations, very fast. For example, instead of telling it exactly how you want each pixels to be, you can throw textures and vertices at it, and have it correctly deduce how this things will have to look.
To do this, though, you must tell it what part of the texture will be stuck to
each vertice. This is usually denoted using
Texture coordinates, like usual coordinates, indicate the place of something.
Instead of noting them
y, they are often called
allows to clearly note what parts of an equation relate to each.
While kivy offers you high level canvas instructions, it gives you a pretty good access to lower level features, and you can actually manipulate the texture coordinates of your Rectangle instructions. This allow for cheap zooming, repeat-scrolling, and other image manipulations, since your gpu is doing all the actual work.
tex_coords = u, v, u + w, v, u + w, v + h, u, v + h
which is better understood as:
tex_coords = [ u, v, u + w, v, u + w, v + h, u, v + h ]
considering a default tex_coords value, where u and v = 0, and w and h = 1 (all values are relatives, so usually between 0 and 1).
u, v + h-------u + w, v + h | | u, v-----------u + w, v
which means the 4 angles of your texture, will be on the 4 angles of your rectangle, how dull!
One way to play with different values, is to create a little app showing you the effect of deformations.
from kivy.app import App from kivy.lang import Builder from kivy.uix.widget import Widget from kivy.properties import ObjectProperty, ListProperty from kivy.core.image import Image as CoreImage kv = ''' #:import chain itertools.chain RootWidget: canvas: Color: rgba: 1, 1, 1, 1 Rectangle: pos: root.pos size: root.size texture: app.texture # here is our usage of the calculated texture coordinates # we devide by 100 because we took the input with a 100x100 # rectangle as default value tex_coords: [x / 100. for x in chain(*root.points)] PushMatrix # translate the rectangle to make it easier to play with Translate: xy: root.width / 2, root.height / 2 Color: rgba: 1, 0, 0, .5 Line: points: chain(*root.points + root.points[:1]) width: 2 PopMatrix ''' def dist(point, pos): return ((point - pos) ** 2 + (point - pos) ** 2) # ** .5 # who cares about square root here? it doesn't change the order class RootWidget(Widget): # the default values, a 100x100 square, displayed around the middle of the screen points = ListProperty([[0, 0], [100, 0], [100, 100], [0, 100]]) def on_touch_down(self, touch, *args): # compensate the translation done in canvas pos = touch.pos - self.width / 2, touch.pos - self.height / 2 touch.ud['point'] = min( range(4), key=lambda x: dist(self.points[x], pos)) def on_touch_move(self, touch, *args): # compensate the translation done in canvas pos = touch.pos - self.width / 2, touch.pos - self.height / 2 # update the point self.points[touch.ud['point']] = pos class TexCoordsApp(App): texture = ObjectProperty(None) def build(self): self.root = Builder.load_string(kv) self.texture = CoreImage.load( 'GrassGreenTexture0002.jpg').texture self.texture.wrap = 'repeat' return self.root if __name__ == '__main__': TexCoordsApp().run()
The texture have been scrapped on the web and is not very interesting, but you can find it here.
Of course, this is much more a learning device (helful because these transformation are not quite straighforward for our brains) than a practical application, but a lot more can be done.
Here is, for example, a little infinite scroll app uting this concept.