Commits

Daniel Pope committed f6e152b

New: use numpy for surface operations

Comments (0)

Files changed (4)

heightfield/main.py

         c = Surface.make_cone(size, height)
         sys.stdout.write('.')
         sys.stdout.flush()
-        for j in xrange(10):
+        for j in xrange(5):
             with viewer.lock:
-                for i in range(number // 10):
+                for i in range(number // 5):
                     xpos = random.randint(-size, SIZE)
                     ypos = random.randint(-size, SIZE)
                     landscape.blit(c, xpos, ypos)

heightfield/surface.py

 import math
+from numpy import zeros
 from PIL import Image
 from pkg_resources import resource_stream
 
 
 class Surface(object):
     def __init__(self, size, fill=0):
-        self.surface = [fill] * size * size
+        self.surface = zeros((size, size))
         self.size = size
-
-    def _index(self, pos):
-        """Compute the index in self.surface of a given position pos"""
-        x, y = pos
-        if 0 <= x < self.size:
-            if 0 <= y < self.size:
-                return x + y * self.size
-        raise IndexError("out of range")
+        self.dirty = True
 
     def __getitem__(self, pos):
-        return self.surface[self._index(pos)]
+        return self.surface[pos]
 
     def __setitem__(self, pos, value):
-        self.surface[self._index(pos)] = value
+        self.surface[pos] = value
+        self.dirty = False
 
     def __repr__(self):
         s = []
 
     def blit(self, img, x, y):
         """Add the heights in img to this surface at (x, y)"""
-        for sy in range(img.size):
-            for sx in range(img.size):
-                dx = sx + x
-                dy = sy + y
-                try:
-                    self[dx, dy] += img[sx, sy]
-                except IndexError:
-                    pass
+        if x < 0:
+            sx = -x
+            dx = 0
+        else:
+            sx = 0
+            dx = x
+        if y < 0:
+            sy = -y
+            dy = 0
+        else:
+            sy = 0
+            dy = y
+        w = img.size - sx
+        h = img.size - sy
+        dx2 = min(dx + w, self.size)
+        dy2 = min(dy + h, self.size)
+        sw, sh = self.surface[dx:dx2,dy:dy2].shape
+        self.surface[dx:dx2,dy:dy2] += img.surface[sx:sx+sw,sy:sy+sh]
+        self.dirty = True
 
     def to_pil(self):
         im = Image.new(colours.mode, (self.size, self.size))

heightfield/viewer/pygameviewer.py

     
     def repaint_rgb(self):
         """Draw the surface to the screen"""
-        with self.lock:
-            self.screen.lock()
-            try:
-                for y in xrange(self.surface.size):
-                    for x in xrange(self.surface.size):
-                        h = self.surface[x, y]
-                        val = max(0, min(1.0, h * 0.1) * 255)
-                        col = self.colormap[int(val)]
-                        self.screen.set_at((x, y), col)
-            finally:
-                self.screen.unlock()
+        if self.surface.dirty:
+            with self.lock:
+                self.screen.lock()
+                try:
+                    for y in xrange(self.surface.size):
+                        for x in xrange(self.surface.size):
+                            h = self.surface[x, y]
+                            val = max(0, min(1.0, h * 0.1) * 255)
+                            col = self.colormap[int(val)]
+                            self.screen.set_at((x, y), col)
+                    self.surface.dirty = False
+                finally:
+                    self.screen.unlock()
 
     def run(self):
         clock = pygame.time.Clock()
     url='https://bitbucket.org/lordmauve/heightfield',
     install_requires=[
         'PIL>=1.1.6',
+        'numpy>=1.5.1'
     ],
+    extras_require = {
+        'pygameviewer': ['pygame>=1.9']
+    },
     license='LGPL',
     classifiers=[
         'Development Status :: 2 - Pre-Alpha',
     entry_points={
         'console_scripts': [
             'heightfield = heightfield.main:main',
-            'mapbuilder = heightfield.main:visible_deposition',
+            'mapbuilder = heightfield.main:visible_deposition [pygameviewer]',
         ]
     }
 )