]> Cypherpunks repositories - gostls13.git/commitdiff
toy draw implementation
authorRuss Cox <rsc@golang.org>
Tue, 29 Sep 2009 21:04:08 +0000 (14:04 -0700)
committerRuss Cox <rsc@golang.org>
Tue, 29 Sep 2009 21:04:08 +0000 (14:04 -0700)
R=r
DELTA=471  (471 added, 0 deleted, 0 changed)
OCL=35090
CL=35099

usr/rsc/draw/Makefile [new file with mode: 0644]
usr/rsc/draw/arith.go [new file with mode: 0644]
usr/rsc/draw/color.go [new file with mode: 0644]
usr/rsc/draw/draw.go [new file with mode: 0644]
usr/rsc/draw/event.go [new file with mode: 0644]

diff --git a/usr/rsc/draw/Makefile b/usr/rsc/draw/Makefile
new file mode 100644 (file)
index 0000000..865fae1
--- /dev/null
@@ -0,0 +1,14 @@
+# Copyright 2009 The Go Authors.  All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include $(GOROOT)/src/Make.$(GOARCH)
+
+TARG=draw
+GOFILES=\
+       arith.go\
+       color.go\
+       draw.go\
+       event.go\
+
+include $(GOROOT)/src/Make.pkg
diff --git a/usr/rsc/draw/arith.go b/usr/rsc/draw/arith.go
new file mode 100644 (file)
index 0000000..4c09965
--- /dev/null
@@ -0,0 +1,168 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package draw
+
+// A Point is an X, Y coordinate pair.
+type Point struct {
+       X, Y int;
+}
+
+// ZP is the zero Point.
+var ZP Point
+
+// A Rectangle contains the Points with Min.X <= X < Max.X, Min.Y <= Y < Max.Y.
+type Rectangle struct {
+       Min, Max Point;
+}
+
+// ZR is the zero Rectangle.
+var ZR Rectangle
+
+// Pt is shorthand for Point{X, Y}.
+func Pt(X, Y int) Point {
+       return Point{X, Y}
+}
+
+// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}.
+func Rect(x0, y0, x1, y1 int) Rectangle {
+       return Rectangle{Point{x0,y0}, Point{x1,y1}}
+}
+
+// Rpt is shorthand for Rectangle{min, max}.
+func Rpt(min, max Point) Rectangle {
+       return Rectangle{min, max}
+}
+
+// Add returns the sum of p and q: Pt(p.X+q.X, p.Y+q.Y).
+func (p Point) Add(q Point) Point {
+       return Point{p.X+q.X, p.Y+q.Y}
+}
+
+// Sub returns the difference of p and q: Pt(p.X-q.X, p.Y-q.Y).
+func (p Point) Sub(q Point) Point {
+       return Point{p.X-q.X, p.Y-q.Y}
+}
+
+// Mul returns p scaled by k: Pt(p.X*k p.Y*k).
+func (p Point) Mul(k int) Point {
+       return Point{p.X*k, p.Y*k}
+}
+
+// Div returns p divided by k: Pt(p.X/k, p.Y/k).
+func (p Point) Div(k int) Point {
+       return Point{p.X/k, p.Y/k}
+}
+
+// Eq returns true if p and q are equal.
+func (p Point) Eq(q Point) bool {
+       return p.X == q.X && p.Y == q.Y
+}
+
+// Inset returns the rectangle r inset by n: Rect(r.Min.X+n, r.Min.Y+n, r.Max.X-n, r.Max.Y-n).
+func (r Rectangle) Inset(n int) Rectangle {
+       return Rectangle{Point{r.Min.X+n, r.Min.Y+n}, Point{r.Max.X-n, r.Max.Y-n}}
+}
+
+// Add returns the rectangle r translated by p: Rpt(r.Min.Add(p), r.Max.Add(p)).
+func (r Rectangle) Add(p Point) Rectangle {
+       return Rectangle{r.Min.Add(p), r.Max.Add(p)}
+}
+
+// Sub returns the rectangle r translated by -p: Rpt(r.Min.Sub(p), r.Max.Sub(p)).
+func (r Rectangle) Sub(p Point) Rectangle {
+       return Rectangle{r.Min.Sub(p), r.Max.Sub(p)}
+}
+
+// Canon returns a canonical version of r: the returned rectangle
+// has Min.X <= Max.X and Min.Y <= Max.Y.
+func (r Rectangle) Canon() Rectangle {
+       if r.Max.X < r.Min.X {
+               r.Max.X = r.Min.X
+       }
+       if r.Max.Y < r.Min.Y {
+               r.Max.Y = r.Min.Y
+       }
+       return r;
+}
+
+// Overlaps returns true if r and r1 cross; that is, it returns true if they share any point.
+func (r Rectangle) Overlaps(r1 Rectangle) bool {
+       return r.Min.X < r1.Max.X && r1.Min.X < r.Max.X
+               && r.Min.Y < r1.Max.Y && r1.Min.Y < r.Max.Y
+}
+
+// Empty retruns true if r contains no points.
+func (r Rectangle) Empty() bool {
+       return r.Max.X <= r.Min.X || r.Max.Y <= r.Min.Y
+}
+
+// InRect returns true if all the points in r are also in r1.
+func (r Rectangle) In(r1 Rectangle) bool {
+       if r.Empty() {
+               return true
+       }
+       if r1.Empty() {
+               return false
+       }
+       return r1.Min.X <= r.Min.X && r.Max.X <= r1.Max.X
+               && r1.Min.Y <= r.Min.Y && r.Max.Y <= r1.Max.Y
+}
+
+// Combine returns the smallest rectangle containing all points from r and from r1.
+func (r Rectangle) Combine(r1 Rectangle) Rectangle {
+       if r.Empty() {
+               return r1
+       }
+       if r1.Empty() {
+               return r
+       }
+       if r.Min.X > r1.Min.X {
+               r.Min.X = r1.Min.X
+       }
+       if r.Min.Y > r1.Min.Y {
+               r.Min.Y = r1.Min.Y
+       }
+       if r.Max.X < r1.Max.X {
+               r.Max.X = r1.Max.X
+       }
+       if r.Max.Y < r1.Max.Y {
+               r.Max.Y = r1.Max.Y
+       }
+       return r
+}
+
+// Clip returns the largest rectangle containing only points shared by r and r1.
+func (r Rectangle) Clip(r1 Rectangle) Rectangle {
+       if r.Empty() {
+               return r
+       }
+       if r1.Empty() {
+               return r1
+       }
+       if r.Min.X < r1.Min.X {
+               r.Min.X = r1.Min.X
+       }
+       if r.Min.Y < r1.Min.Y {
+               r.Min.Y = r1.Min.Y
+       }
+       if r.Max.X > r1.Max.X {
+               r.Max.X = r1.Max.X
+       }
+       if r.Max.Y > r1.Max.Y {
+               r.Max.Y = r1.Max.Y
+       }
+       return r;
+}
+
+// Dx returns the width of the rectangle r: r.Max.X - r.Min.X.
+func (r Rectangle) Dx() int {
+       return r.Max.X - r.Min.X
+}
+
+// Dy returns the width of the rectangle r: r.Max.Y - r.Min.Y.
+func (r Rectangle) Dy() int {
+       return r.Max.Y - r.Min.Y
+}
+
diff --git a/usr/rsc/draw/color.go b/usr/rsc/draw/color.go
new file mode 100644 (file)
index 0000000..bae35eb
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package draw
+
+import "image"
+
+// A Color represents a color with 8-bit R, G, B, and A values,
+// packed into a uint32—0xRRGGBBAA—so that comparison
+// is defined on colors.
+// Color implements image.Color.
+// Color also implements image.Image: it is a
+// 10⁹x10⁹-pixel image of uniform color.
+type Color uint32
+
+// Check that Color implements image.Color and image.Image
+var _ image.Color = Black
+var _ image.Image = Black
+
+var (
+       Opaque Color = 0xFFFFFFFF;
+       Transparent Color = 0x00000000;
+       Black Color = 0x000000FF;
+       White Color = 0xFFFFFFFF;
+       Red Color = 0xFF0000FF;
+       Green Color = 0x00FF00FF;
+       Blue Color = 0x0000FFFF;
+       Cyan Color = 0x00FFFFFF;
+       Magenta Color = 0xFF00FFFF;
+       Yellow Color = 0xFFFF00FF;
+       PaleYellow Color = 0xFFFFAAFF;
+       DarkYellow Color = 0xEEEE9EFF;
+       DarkGreen Color = 0x448844FF;
+       PaleGreen Color = 0xAAFFAAFF;
+       MedGreen Color = 0x88CC88FF;
+       DarkBlue Color = 0x000055FF;
+       PaleBlueGreen Color = 0xAAFFFFFF;
+       PaleBlue Color = 0x0000BBFF;
+       BlueGreen Color = 0x008888FF;
+       GreyGreen Color = 0x55AAAAFF;
+       PaleGreyGreen Color = 0x9EEEEEFF;
+       YellowGreen Color = 0x99994CFF;
+       MedBlue Color = 0x000099FF;
+       GreyBlue Color = 0x005DBBFF;
+       PaleGreyBlue Color = 0x4993DDFF;
+       PurpleBlue Color = 0x8888CCFF;
+)
+
+func (c Color) RGBA() (r, g, b, a uint32) {
+       x := uint32(c);
+       r, g, b, a = x>>24, (x>>16)&0xFF, (x>>8)&0xFF, x&0xFF;
+       r |= r<<8;
+       r |= r<<16;
+       g |= g<<8;
+       g |= g<<16;
+       b |= b<<8;
+       b |= b<<16;
+       a |= a<<8;
+       a |= a<<16;
+       return;
+}
+
+// SetAlpha returns the color obtained by changing
+// c's alpha value to a and scaling r, g, and b appropriately.
+func (c Color) SetAlpha(a uint8) Color {
+       r, g, b, oa := c>>24, (c>>16)&0xFF, (c>>8)&0xFF, c&0xFF;
+       if oa == 0 {
+               return 0
+       }
+       r = r*Color(a)/oa;
+       if r < 0 {
+               r = 0;
+       }
+       if r > 0xFF {
+               r = 0xFF;
+       }
+       g = g*Color(a)/oa;
+       if g < 0 {
+               g = 0;
+       }
+       if g > 0xFF {
+               g = 0xFF;
+       }
+       b = b*Color(a)/oa;
+       if b < 0 {
+               b = 0;
+       }
+       if b > 0xFF {
+               b = 0xFF;
+       }
+       return r<<24 | g<<16 | b<<8 | Color(a);
+}
+
+func (c Color) Width() int {
+       return 1e9;
+}
+
+func (c Color) Height() int {
+       return 1e9;
+}
+
+func (c Color) At(x, y int) image.Color {
+       return c;
+}
+
+func toColor(color image.Color) image.Color {
+       if c, ok := color.(Color); ok {
+               return c;
+       }
+       r, g, b, a := color.RGBA();
+       return Color(r>>24<<24 | g>>24<<16 | b>>24<<8 | a>>24);
+}
+
+func (c Color) ColorModel() image.ColorModel {
+       return image.ColorModelFunc(toColor);
+}
diff --git a/usr/rsc/draw/draw.go b/usr/rsc/draw/draw.go
new file mode 100644 (file)
index 0000000..4fc6a94
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package draw provides basic graphics and drawing primitives,
+// in the style of the Plan 9 graphics library
+// (see http://plan9.bell-labs.com/magic/man2html/2/draw)
+// and the X Render extension.
+package draw
+
+// BUG(rsc): This is a toy library and not ready for production use.
+
+import "image"
+
+// A draw.Image is an image.Image with a Set method to change a single pixel.
+type Image interface {
+       image.Image;
+       Set(x, y int, c image.Color);
+}
+
+// Draw aligns r.Min in dst with pt in src and mask
+// and then replaces the rectangle r in dst with the
+// result of the Porter-Duff compositing operation
+// ``(src in mask) over dst.''  If mask is nil, the operation
+// simplifies to ``src over dst.''
+// The implementation is simple and slow.
+func Draw(dst Image, r Rectangle, src, mask image.Image, pt Point) {
+       // Plenty of room for optimizations here.
+
+       dx, dy := src.Width(), src.Height();
+       if mask != nil {
+               if dx > mask.Width() {
+                       dx = mask.Width();
+               }
+               if dy > mask.Width() {
+                       dy = mask.Width();
+               }
+       }
+       dx -= pt.X;
+       dy -= pt.Y;
+       if r.Dx() > dx {
+               r.Max.X = r.Min.X + dx;
+       }
+       if r.Dy() > dy {
+               r.Max.Y = r.Min.Y + dy;
+       }
+
+       x0, x1, dx := r.Min.X, r.Max.X, 1;
+       y0, y1, dy := r.Min.Y, r.Max.Y, 1;
+       if image.Image(dst) == src && r.Overlaps(r.Add(pt.Sub(r.Min))) {
+               // Rectangles overlap: process backward?
+               if pt.Y < r.Min.Y || pt.Y == r.Min.Y && pt.X < r.Min.X {
+                       x0, x1, dx = x1-1, x0-1, -1;
+                       y0, y1, dy = y1-1, y0-1, -1;
+               }
+       }
+
+       var out *image.RGBA64Color;
+       for y := y0; y != y1; y+=dy {
+               for x := x0; x != x1; x+=dx {
+                       sx := pt.X + x - r.Min.X;
+                       sy := pt.Y + y - r.Min.Y;
+                       if mask == nil {
+                               dst.Set(x, y, src.At(sx, sy));
+                               continue;
+                       }
+                       _, _, _, ma := mask.At(sx, sy).RGBA();
+                       switch ma {
+                       case 0:
+                               continue;
+                       case 0xFFFFFFFF:
+                               dst.Set(x, y, src.At(sx, sy));
+                       default:
+                               dr, dg, db, da := dst.At(x, y).RGBA();
+                               dr >>= 16;
+                               dg >>= 16;
+                               db >>= 16;
+                               da >>= 16;
+                               sr, sg, sb, sa := src.At(sx, sy).RGBA();
+                               sr >>= 16;
+                               sg >>= 16;
+                               sb >>= 16;
+                               sa >>= 16;
+                               ma >>= 16;
+                               const M = 1<<16 - 1;
+                               a := sa*ma/M;
+                               dr = (dr*(M-a) + sr*ma) / M;
+                               dg = (dg*(M-a) + sg*ma) / M;
+                               db = (db*(M-a) + sb*ma) / M;
+                               da = (da*(M-a) + sa*ma) / M;
+                               if out == nil {
+                                       out = new(image.RGBA64Color);
+                               }
+                               out.R = uint16(dr);
+                               out.G = uint16(dg);
+                               out.B = uint16(db);
+                               out.A = uint16(da);
+                               dst.Set(x, y, out);
+                       }
+               }
+       }
+}
+
+// Border aligns r.Min in dst with sp in src and then replaces pixels
+// in a w-pixel border around r in dst with the result of the Porter-Duff compositing
+// operation ``src over dst.''  If w is positive, the border extends w pixels inside r.
+// If w is negative, the border extends w pixels outside r.
+func Border(dst Image, r Rectangle, w int, src image.Image, sp Point) {
+       i := w;
+       if i > 0 {
+               // inside r
+               Draw(dst, Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+i), src, nil, sp);    // top
+               Draw(dst, Rect(r.Min.X, r.Min.Y+i, r.Min.X+i, r.Max.Y-i), src, nil, sp.Add(Pt(0, i)));  // left
+               Draw(dst, Rect(r.Max.X-i, r.Min.Y+i, r.Max.X, r.Max.Y-i), src, nil, sp.Add(Pt(r.Dx()-i, i)));   // right
+               Draw(dst, Rect(r.Min.X, r.Max.Y-i, r.Max.X, r.Max.Y), src, nil, sp.Add(Pt(0, r.Dy()-i)));       // bottom
+               return;
+       }
+
+       // outside r;
+       i = -i;
+       Draw(dst, Rect(r.Min.X-i, r.Min.Y-i, r.Max.X+i, r.Min.Y), src, nil, sp.Add(Pt(-i, -i)));        // top
+       Draw(dst, Rect(r.Min.X-i, r.Min.Y, r.Min.X, r.Max.Y), src, nil, sp.Add(Pt(-i, 0)));     // left
+       Draw(dst, Rect(r.Max.X, r.Min.Y, r.Max.X+i, r.Max.Y), src, nil, sp.Add(Pt(r.Dx(), 0))); // right
+       Draw(dst, Rect(r.Min.X-i, r.Max.Y, r.Max.X+i, r.Max.Y+i), src, nil, sp.Add(Pt(-i, 0))); // bottom
+}
diff --git a/usr/rsc/draw/event.go b/usr/rsc/draw/event.go
new file mode 100644 (file)
index 0000000..b5bce50
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package draw
+
+// A Context represents a single graphics window.
+type Context interface {
+       // Screen returns an editable Image of window.
+       Screen() Image;
+
+       // FlushImage flushes changes made to Screen() back to screen.
+       FlushImage();
+
+       // KeyboardChan returns a channel carrying keystrokes.
+       // An event is sent each time a key is pressed or released.
+       // The value k represents key k being pressed.
+       // The value -k represents key k being released.
+       // The specific set of key values is not specified,
+       // but ordinary character represent themselves.
+       KeyboardChan() <-chan int;
+
+       // MouseChan returns a channel carrying mouse events.
+       // A new event is sent each time the mouse moves or a
+       // button is pressed or released.
+       MouseChan() <-chan Mouse;
+
+       // ResizeChan returns a channel carrying resize events.
+       // An event is sent each time the window is resized;
+       // the client should respond by calling Screen() to obtain
+       // the new screen image.
+       // The value sent on the channel is always ``true'' and can be ignored.
+       ResizeChan() <-chan bool;
+
+       // QuitChan returns a channel carrying quit requests.
+       // After reading a value from the quit channel, the application
+       // should exit.
+       QuitChan() <-chan bool;
+}
+
+// A Mouse represents the state of the mouse.
+type Mouse struct {
+       Buttons int;    // bit mask of buttons: 1<<0 is left, 1<<1 middle, 1<<2 right
+       Point;  // location of cursor
+       Nsec int64;     // time stamp
+}
+