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:
parent
c59a965133
commit
5c2c57e5db
14
usr/rsc/draw/Makefile
Normal file
14
usr/rsc/draw/Makefile
Normal 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
168
usr/rsc/draw/arith.go
Normal 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
117
usr/rsc/draw/color.go
Normal 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
125
usr/rsc/draw/draw.go
Normal 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
47
usr/rsc/draw/event.go
Normal 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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user