Commits

aholkner  committed 77d7927

Fill polygon glitch fixes. Return clipped rectangle for all raster funcs.

  • Participants
  • Parent commits e53dd7a
  • Branches ctypes-soc

Comments (0)

Files changed (2)

File examples_pygame/draw.py

 class Shape(object):
     def __init__(self, npoints):
         self.points = []
+        self.area = None
         for i in range(npoints):
             self.points.append(Point())
         self.color = (random.randint(0, 255),
         r = Rect(self.get_points())
         r.width -= r.left
         r.height -= r.top
-        pygame.draw.rect(surface, self.color, r, self.width)
+        return pygame.draw.rect(surface, self.color, r, self.width)
 
 class Line(Shape):
     def __init__(self, width):
         self.width = width
 
     def draw(self, surface):
-        pygame.draw.line(surface, self.color, 
-                         self.get_points()[0],
-                         self.get_points()[1], self.width)
+        return pygame.draw.line(surface, self.color, 
+                                self.get_points()[0],
+                                self.get_points()[1], self.width)
 
 class AntialiasLine(Shape):
     def __init__(self):
         super(AntialiasLine, self).__init__(2)
 
     def draw(self, surface):
-        pygame.draw.aaline(surface, self.color, 
-                           self.get_points()[0],
-                           self.get_points()[1])
+        return pygame.draw.aaline(surface, self.color, 
+                                  self.get_points()[0],
+                                  self.get_points()[1])
 
 class Polygon(Shape):
     def __init__(self, width):
         self.width = width
 
     def draw(self, surface):
-        pygame.draw.polygon(surface, self.color, self.get_points(), self.width)
+        return pygame.draw.polygon(surface, self.color, 
+                                   self.get_points(), self.width)
 
 class Ellipse(Shape):
     def __init__(self, width):
         r.height -= r.top
         r.normalize()
         if self.width * 2 < r.width and self.width * 2 < r.height:
-            pygame.draw.ellipse(surface, self.color, r, self.width)
+            return pygame.draw.ellipse(surface, self.color, r, self.width)
+        return None
 
 if __name__ == '__main__':
     pygame.init()
     depth = 0
     screen = pygame.display.set_mode((width, height), flags, depth)
 
-    shapes = [Rectangle(2)]
+    shapes = [Polygon(0)]
 
     clock = pygame.time.Clock()
+    show_clips = False
     quit = False
     paused = False
     while not quit:
                     screen.set_clip(screen.get_clip().inflate(-50, -50))
                 elif event.unicode == 'C':
                     screen.set_clip(screen.get_clip().inflate(50, 50))
+                elif event.unicode == 'i':
+                    show_clips = not show_clips
 
         time = clock.tick()
         if not paused:
                 (clock.get_fps(), len(shapes)),
 
             screen.fill((0, 0, 0))
+
+            update_rect = Rect(width, height, -width, -height)
             for shape in shapes:
                 shape.update(time)
-                shape.draw(screen)
-            pygame.display.flip()
+                if shape.area:
+                    update_rect.union_ip(shape.area)
+                shape.area = shape.draw(screen)
+                if shape.area:
+                    update_rect.union_ip(shape.area)
+                if show_clips and shape.area:
+                    pygame.draw.rect(screen, (255, 0, 0), shape.area, 1)
+
+            if show_clips:
+                pygame.display.flip()
+            else:
+                update_rect.normalize()
+                pygame.display.update([update_rect])

File pygame/draw.py

     rect = _get_rect(rect)
     if width == 0:
         SDL_FillRect(surface._surf, rect, color)
+        return pygame.rect.Rect(rect)
     else:
-        # TODO clip edges wholly outside clip
         hw = width / 2
+        clip_rect = pygame.rect.Rect(rect.x - hw, rect.y - hw, 
+                         rect.w + width, rect.h + width)
+        clip_rect.clip_ip(surface._surf.clip_rect)
+
         r = SDL_Rect(rect.x, rect.y - hw, rect.w, width)
         SDL_FillRect(surface._surf, r, color)
-        r.y += rect.h
+        r = SDL_Rect(rect.x, rect.y - hw + rect.h, rect.w, width)
         SDL_FillRect(surface._surf, r, color)
-        r.x -= hw
-        r.w = width
-        r.y = rect.y
-        r.h = rect.h + 1
+        r = SDL_Rect(rect.x - hw, rect.y, width, rect.h)
         SDL_FillRect(surface._surf, r, color)
-        r.x += rect.w
+        r = SDL_Rect(rect.x - hw + rect.w, rect.y, width, rect.h)
         SDL_FillRect(surface._surf, r, color)
-        # XXX returned clip rectangle wrong
-    return pygame.rect.Rect(rect)
+        return clip_rect
 
 def polygon(surface, color, pointlist, width=0):
     '''Draw a shape with any number of sides.
     if len(pointlist) < 3:
         raise ValueError, 'pointlist argument must contain at least 3 points'
 
+    # TODO store bressenham info for edges instead of float gradient.
     edges = []
     x1, y1 = pointlist[0]
     miny = maxy = y1
             miny = min(miny, y2)
             maxy = max(maxy, y1)
         minx = min(minx, x1, x2)
-        maxx = max(maxx, x1, x2)
+        maxx = max(maxx, x1, x2) 
         x1, y1 = x2, y2
 
     surf = surface._surf
     clip = surf.clip_rect
-    miny = int(max(miny, clip.y))
+    clip_y = int(clip.y)
+    if int(miny) < clip_y:
+        for e in edges:
+            if clip_y > e[1]:
+                e[0] += e[3] * int(clip_y - e[1])
+        miny = clip_y
+    miny = int(miny)
     maxy = int(min(maxy + 1, clip.y + clip.h))
+    maxx = int(min(maxx + 1, clip.x + clip.w))
     
     r = SDL_Rect()
-    r.h = 1
     for y in range(miny, maxy):
         scan_edges = [e for e in edges if y >= e[1] and y < e[2]]
         scan_edges.sort(lambda a,b: cmp(a[0], b[0]))
         assert len(scan_edges) % 2 == 0
         r.y = y
+        r.h = 1
         for i in range(0, len(scan_edges), 2):
             r.x = int(scan_edges[i][0])
-            r.w = int(scan_edges[i+1][0]) - r.x
+            r.w = int(scan_edges[i+1][0]) - r.x + 1
             SDL_FillRect(surf, r, color)
             scan_edges[i][0] += scan_edges[i][3]
             scan_edges[i+1][0] += scan_edges[i+1][3]
     :return: Affected bounding box.
     '''
     if width < 1:
-        return
+        return pygame.rect.Rect(surface._surf.w,
+                                surface._surf.h,
+                                -surface._surf.w,
+                                -surface._surf.h)
 
     color = _get_color(color, surface)
 
     width = int(width)
     if start_pos[0] == end_pos[0]:
         # Vertical
+        x = int(start_pos[0])
         y1 = int(min(start_pos[1], end_pos[1]))
         y2 = int(max(start_pos[1], end_pos[1]))
-        r = SDL_Rect(int(start_pos[0]) - width / 2, y1, width, y2 - y1)
+        r = SDL_Rect(x - width / 2, y1, width, y2 - y1)
         SDL_FillRect(surface._surf, r, color)
+        return pygame.rect.Rect(r)
     elif start_pos[1] == end_pos[1]:
         # Horizontal
         x1 = int(min(start_pos[0], end_pos[0]))
         x2 = int(max(start_pos[0], end_pos[0]))
         r = SDL_Rect(x1, int(start_pos[1]) - width / 2, x2 - x1, width)
         SDL_FillRect(surface._surf, r, color)
+        return pygame.rect.Rect(r)
     elif width > 1:
         # Optimise me (scanlines instead of multiple lines)
         if abs(end_pos[0] - start_pos[0]) > abs(end_pos[1] - start_pos[1]):
         y1 = start_pos[1] - width * yinc / 2
         x2 = end_pos[0] - width * xinc / 2
         y2 = end_pos[1] - width * yinc / 2
+        # This clip rect slightly larger than necessary, but easier than
+        # unioning for each line
+        clip_rect = pygame.rect.Rect(min(x1, x2), 
+                                     min(y1, y2),
+                                     abs(x2 - x1) + width,
+                                     abs(y2 - y1) + width)
+        clip_rect.clip_ip(surface._surf.clip_rect)
         for i in range(width):
             line(surface, color, (x1, y1), (x2, y2), 1)
             x1 += xinc
             y1 += yinc
             x2 += xinc
             y2 += yinc
+        return clip_rect
     else:
         if surface._surf.format.BytesPerPixel == 3:
             raise NotImplementedError, 'TODO'
                                     clip.x, clip.x + clip.w - 1,
                                     clip.y, clip.y + clip.h - 1)
         if x1 is None:
-            return
+            return pygame.rect.Rect(surface._surf.w,
+                                    surface._surf.h,
+                                    -surface._surf.w,
+                                    -surface._surf.h)
 
         pixels = surface._surf.pixels.as_ctypes()
         pitch = surface._surf.pitch / surface._surf.format.BytesPerPixel
         while x < dx:
             pixels[pixel] = color
             y += dy
-            if y > dx:
+            if y >= dx:
                 y -= dx
                 pixel += incy
             x += 1
             pixel += incx
+        return pygame.rect.Rect(min(x1, x2), 
+                                min(y1, y2),
+                                abs(x2 - x1) + 1, 
+                                abs(y2 - y1) + 1)
 
-    return None # XXX return clipped rect
     
 def lines(surface, color, closed, pointlist, width=1):
     '''Draw multiple contiguous line segments.
     if len(pointlist) < 2:
         raise ValueError, 'points argument must contain more than one point'
 
+    clip_rect = pygame.rect.Rect(surface._surf.w,
+                                 surface._surf.h,
+                                 -surface._surf.w,
+                                 -surface._surf.h)
     last = pointlist[0]
     for point in pointlist[1:]:
-        line(surface, color, last, point, width)
+        r = line(surface, color, last, point, width)
+        clip_rect.union_ip(r)
         last = point
     if closed:
-        line(surface, color, last, pointlist[0], width)
+        r = line(surface, color, last, pointlist[0], width)
+        clip_rect.union_ip(r)
 
-    # XXX return clipped rect
+    return clip_rect
 
 def aaline(surface, color, startpos, endpos, blend=1):
     '''Draw a line with antialiasing.
     :rtype: `Rect`
     :return: Affected bounding box.
     '''
+    # TODO 
+    return line(surface, color, startpos, endpos)
 
 def aalines(surface, color, closed, pointlist, blend=1):
     '''Draw multiple contiguous line segments with antialiasing.
     :rtype: `Rect`
     :return: Affected bounding box.
     '''
+    # TODO
+    return lines(surface, color, closed, pointlist)