TextureGrid, untested.
TextureGrid, untested.


Index: pyglet/image/__init__.py
===================================================================
--- pyglet/image/__init__.py	(revision 663)
+++ pyglet/image/__init__.py	(working copy)
@@ -1342,16 +1342,120 @@
     # TODO mask methods

 class TextureSequence(object):
-    def __init__(self, texture):
-        self.texture = texture
-
     def __getitem__(self, slice):
-        raise ImageException('Cannot getitem from %r' % self)
+        raise NotImplementedError('abstract')

     def __setitem__(self, slice, image):
-        raise ImageException('Cannot setitem on %r' % self)
+        raise NotImplementedError('abstract')

+    def __len__(self):
+        raise NotImplementedError('abstract')

+class UniformTextureSequence(TextureSequence):
+    def _get_item_width(self):
+        raise NotImplementedError('abstract')
+    item_width = property(_get_item_width)
+
+    def _get_item_height(self):
+        raise NotImplementedError('abstract')
+    item_height = property(_get_item_height)
+
+class TextureGrid(TextureRegion, UniformTextureSequence):
+    items = ()
+    rows = 1
+    columns = 1
+    item_width = 0
+    item_height = 0
+
+    @classmethod
+    def create_for_image(cls, image, rows, columns,
+                         item_width=None, item_height=None,
+                         row_padding=0, column_padding=0):
+        image = image.texture
+        texture = cls(image.width, image.height, image, image.tex_coords)
+        if item_width is None:
+            item_width = \
+                int((texture.width - column_padding * (columns - 1)) / columns)
+        if item_height is None:
+            item_height = \
+                int((texture.height - row_padding * (rows - 1)) / rows)
+        items = []
+        y = 0
+        for row in rows:
+            x = 0
+            for col in columns:
+                items.append(self.get_region(x, y, item_width, item_height))
+                x + item_width + column_padding
+            y += item_height + row_padding
+
+        texture.items = items
+        texture.rows = rows
+        texture.columns = columns
+        texture.item_width = item_width
+        texture.item_height = item_height
+        return texture
+
+    def get(self, row, column):
+        return self[(row, column)]
+
+    def __getitem__(self, index):
+        if type(index) is slice:
+            if type(index.start) is not tuple and \
+               type(index.stop) is not tuple:
+                return self.items[index]
+            else:
+                row1 = 0
+                col1 = 0
+                row2 = self.rows
+                col2 = self.cols
+                if type(index.start) is tuple:
+                    row1, col1 = index.start
+                elif type(index.start) is int:
+                    row1 = index.start / self.columns
+                    col1 = index.start % self.columns
+                assert row1 >= 0 and column1 >= 0 and \
+                       row1 < self.rows and column1 < self.columns
+
+                if type(index.stop) is tuple:
+                    row2, col2 = index.stop
+                elif type(index.stop) is int:
+                    row2 = index.stop / self.columns
+                    col2 = index.stop % self.columns
+                assert row2 >= 0 and column2 >= 0 and \
+                       row2 < self.rows and column2 < self.columns
+
+                result = []
+                i = row1 * self.columns
+                for row in range(row1, row2):
+                    result += self.items[i+col1:i+col2]
+                    i += self.columns
+                return result
+        else:
+            if type(index) is tuple:
+                row, column = index
+                assert row >= 0 and column >= 0 and \
+                       row < self.rows and column < self.columns
+                return self.items[row * self.columns + column]
+            elif type(index) is int:
+                return self.items[index]
+
+    def __setitem__(self, index, value):
+        if type(index) is slice:
+            for region, image in zip(self[index], value):
+                if image.width != self.item_width or \
+                   image.height != self.item_height:
+                    raise ImageException('Image has incorrect dimensions')
+                image.blit_into(region)
+        else:
+            image = value
+            if image.width != self.item_width or \
+               image.height != self.item_height:
+                raise ImageException('Image has incorrect dimensions')
+            image.blit_into(self[index])
+
+    def __len__(self):
+        return len(self.items)
+
 # Initialise default codecs
 from pyglet.image.codecs import *
 add_default_image_codecs()

cledio66/pyglet,gdkar/pyglet,arifgursel/pyglet,mpasternak/michaldtz-fix-552,odyaka341/pyglet,google-code-export/pyglet,mpasternak/michaldtz-fixes-518-522,cledio66/pyglet,mpasternak/michaldtz-fixes-518-522,google-code-export/pyglet,cledio66/pyglet,cledio66/pyglet,odyaka341/pyglet,arifgursel/pyglet,mpasternak/pyglet-fix-issue-552,kmonsoor/pyglet,Austin503/pyglet,xshotD/pyglet,Austin503/pyglet,mpasternak/pyglet-fix-issue-518-522,shaileshgoogler/pyglet,xshotD/pyglet,qbektrix/pyglet,kmonsoor/pyglet,shaileshgoogler/pyglet,odyaka341/pyglet,Alwnikrotikz/pyglet,Alwnikrotikz/pyglet,shaileshgoogler/pyglet,xshotD/pyglet,arifgursel/pyglet,mpasternak/pyglet-fix-issue-518-522,gdkar/pyglet,gdkar/pyglet,Austin503/pyglet,google-code-export/pyglet,mpasternak/michaldtz-fixes-518-522,kmonsoor/pyglet,qbektrix/pyglet,mpasternak/michaldtz-fix-552,qbektrix/pyglet,Alwnikrotikz/pyglet,google-code-export/pyglet,arifgursel/pyglet,arifgursel/pyglet,Alwnikrotikz/pyglet,kmonsoor/pyglet,mpasternak/michaldtz-fixes-518-522,xshotD/pyglet,mpasternak/michaldtz-fix-552,odyaka341/pyglet,qbektrix/pyglet,google-code-export/pyglet,qbektrix/pyglet,xshotD/pyglet,gdkar/pyglet,kmonsoor/pyglet,mpasternak/pyglet-fix-issue-552,Alwnikrotikz/pyglet,Austin503/pyglet,shaileshgoogler/pyglet,mpasternak/michaldtz-fix-552,shaileshgoogler/pyglet,Austin503/pyglet,mpasternak/pyglet-fix-issue-518-522,mpasternak/pyglet-fix-issue-552,mpasternak/pyglet-fix-issue-552,gdkar/pyglet,odyaka341/pyglet,mpasternak/pyglet-fix-issue-518-522,cledio66/pyglet