1
0
mirror of https://github.com/golang/go synced 2024-11-22 07:54:40 -07:00

toy draw implementation

R=r
DELTA=471  (471 added, 0 deleted, 0 changed)
OCL=35090
CL=35099
This commit is contained in:
Russ Cox 2009-09-29 14:04:08 -07:00
parent c59a965133
commit 5c2c57e5db
5 changed files with 471 additions and 0 deletions

14
usr/rsc/draw/Makefile Normal file
View File

@ -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

168
usr/rsc/draw/arith.go Normal file
View File

@ -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
}

117
usr/rsc/draw/color.go Normal file
View File

@ -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);
}

125
usr/rsc/draw/draw.go Normal file
View File

@ -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
}

47
usr/rsc/draw/event.go Normal file
View File

@ -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
}