2003/09/27 06:42:26
[org.ibex.core.git] / src / org / xwt / PixelBuffer.java
index 3d6e09a..065b027 100644 (file)
@@ -3,8 +3,7 @@ package org.xwt;
 
 /**
  *  <p>
- *  A block of pixels which can be drawn on and rapidly copied to the
- *  screen.
+ *  A block of pixels which can be drawn on.
  *  </p>
  *
  *  <p>
@@ -13,19 +12,80 @@ package org.xwt;
  *  method. These implementations may choose to use off-screen video
  *  ram for this purpose (for example, a Pixmap on X11).
  *  </p>
+ *
+ *  <p>
+ *  Many of these functions come in pairs, one that uses ints and one
+ *  that uses floats.  The int functions are intended for situations
+ *  in which the CTM is the identity transform.
+ *  </p>
  */
 public abstract class PixelBuffer {
 
-    /** Draw the region of source within s onto the region d on this PixelBuffer, scaling as needed */
-    public abstract void drawPicture(Picture source, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2);
-
-    /** Fill the region (x1, y1, x2, y2) with <tt>color</tt> (AARRGGBB format); the alpha channel component is ignored */
-    public abstract void fillRect(int x1, int y1, int x2, int y2, int color);
-
+    // FIXME: try to remove
     /** returns the height of the PixelBuffer */
     public abstract int getHeight();
 
+    // FIXME: try to remove
     /** returns the width of the PixelBuffer */
     public abstract int getWidth();
 
+
+
+    /** Draw the region of source within s onto the region d on this PixelBuffer, scaling as needed */
+    public abstract void drawPicture(Picture source, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2);
+
+    /** fill a trapezoid whose top and bottom edges are horizontal */
+    public abstract void fillTrapezoid(int x1, int x2, int y1, int x3, int x4, int y2, int color);
+
+    // FIXME: we want floats (inter-pixel spacing) for antialiasing, but this hoses the fastpath line drawing... argh!
+    /** draws a line of width <tt>w</tt>; note that the coordinates here are <i>post-transform</i> */
+    public void drawLine(int x1, int y1, int x2, int y2, int w, int color, boolean capped) {
+
+       if (y1 > y2) { int t = x1; x1 = x2; x2 = t; t = y1; y1 = y2; y2 = t; }
+
+       if (x1 == x2) {
+            fillTrapezoid(x1 - w / 2, x2 + w / 2, y1 - (capped ? w / 2 : 0), x1 - w / 2, x2 + w / 2, y2 + (capped ? w / 2 : 0), color);
+            return;
+        }
+
+        // fastpath for single-pixel width lines
+        if (w == 1) {
+            float slope = (float)(y2 - y1) / (float)(x2 - x1);
+            int last_x = x1;
+            for(int y=y1; y<=y2; y++) {
+                int new_x = (int)((float)(y - y1) / slope) + x1;
+                if (slope >= 0) fillTrapezoid(last_x + 1, y != y2 ? new_x + 1 : new_x, y,
+                                              last_x + 1, y != y2 ? new_x + 1 : new_x, y + 1, color);
+                else fillTrapezoid(y != y2 ? new_x : new_x + 1, last_x, y,
+                                   y != y2 ? new_x : new_x + 1, last_x, y + 1, color);
+                last_x = new_x;
+            }
+            return;
+        }
+
+        // actually half-width
+       float width = (float)w / 2;
+       float phi = (float)Math.atan((y2 - y1) / (x2 - x1));
+       if (phi < 0.0) phi += (float)Math.PI * 2;
+       float theta = (float)Math.PI / 2 - phi;
+
+       // dx and dy are the x and y distance between each endpoint and the corner of the stroke
+       int dx = (int)(width * Math.cos(theta));
+       int dy = (int)(width * Math.sin(theta));
+
+       // slice is the longest possible length of a horizontal line across the stroke
+       int slice = (int)(2 * width / Math.cos(theta));
+
+       if (capped) {
+           x1 -= width * Math.cos(phi);
+           x2 += width * Math.cos(phi);
+           y1 -= width * Math.sin(phi);
+           y2 += width * Math.sin(phi);
+       }
+
+       fillTrapezoid(x1 + dx, x1 + dx, y1 - dy, x1 - dx, x1 - dx + slice, y1 + dy, color);           // top corner
+       fillTrapezoid(x2 + dx - slice, x2 + dx, y2 - dy, x2 - dx, x2 - dx, y2 + dy, color);           // bottom corner
+       fillTrapezoid(x1 - dx, x1 - dx + slice, y1 + dy, x2 + dx - slice, x2 + dx, y2 - dy, color);   // middle
+    }
+
 }