     for i in [0...triangles.length] by 3
       @_filledTriangle extract(triangles[i]), extract(triangles[i+1]), extract(triangles[i+2]), color
 
-  _bresenham: (pointA, pointB) ->
-    bresenham pointA[0], pointA[1],
-              pointB[0], pointB[1]
+  # Inspired by Alois Zingl's "The Beauty of Bresenham's Algorithm"
+  # -> http://members.chello.at/~easyfilter/bresenham.html
+  _line: (pointA, pointB, width, color) ->
+
+    # Fall back to width-less bresenham algorithm if we dont have a width
+    unless width = Math.max 0, width-1
+      return bresenham pointA[0], pointA[1], pointB[0], pointB[1],
+        (x, y) => @buffer.setPixel x, y, color
+
+    [x0, y0] = pointA
+    [x1, y1] = pointB
+    dx = Math.abs x1-x0
+    sx = if x0 < x1 then 1 else -1
+    dy = Math.abs y1-y0
+    sy = if y0 < y1 then 1 else -1
+
+    err = dx-dy
+
+    ed = if dx+dy is 0 then 1 else Math.sqrt dx*dx+dy*dy
+
+    width = (width+1)/2
+    loop
+      @buffer.setPixel x0, y0, color
+      e2 = err
+      x2 = x0
+
+      if 2*e2 >= -dx
+         e2 += dy
+         y2 = y0
+         while e2 < ed*width && (y1 != y2 || dx > dy)
+            @buffer.setPixel x0, y2 += sy, color
+            e2 += dx
+         break if x0 is x1
+         e2 = err
+         err -= dy
+         x0 += sx
+
+      if 2*e2 <= dy
+         e2 = dx-e2
+         while e2 < ed*width && (x1 != x2 || dx < dy)
+            @buffer.setPixel x2 += sx, y0, color
+            e2 += dy
+         break if y0 is y1
+         err += dx
+         y0 += sy
 
   _project: (x, y) ->
     point = vec2.transformMat2d vec2.create(), vec2.fromValues(x, y), @matrix

    position = @_project x, y
    @buffer.writeText text, position[0], position[1], color, center

  polyline: (points, color) ->
    projected = (@_project point[0], point[1] for point in points)
    for i in [1...projected.length]
      bresenham projected[i-1]..., projected[i]...,
        (x, y) => @buffer.setPixel x, y, color

  setBackground: (color) ->
    @buffer.setGlobalBackground color

    # Filter out any points outside of the visible area
    # TODO: benchmark - is it more effective to filter double points, or does
    # it req more computing time than actually setting points multiple times?
    last = null
    points = a.concat(b).concat(c)
    .filter (point) => 0 <= point.y < @height
