// Paste pastes the img image to the background image at the specified position and returns the combined image. func Paste(background, img image.Image, pos image.Point) *image.NRGBA { src := toNRGBA(img) dst := Clone(background) // cloned image bounds start at (0, 0) startPt := pos.Sub(background.Bounds().Min) // so we should translate start point endPt := startPt.Add(src.Bounds().Size()) pasteBounds := image.Rectangle{startPt, endPt} if dst.Bounds().Overlaps(pasteBounds) { intersectBounds := dst.Bounds().Intersect(pasteBounds) rowSize := intersectBounds.Dx() * 4 numRows := intersectBounds.Dy() srcStartX := intersectBounds.Min.X - pasteBounds.Min.X srcStartY := intersectBounds.Min.Y - pasteBounds.Min.Y i0 := dst.PixOffset(intersectBounds.Min.X, intersectBounds.Min.Y) j0 := src.PixOffset(srcStartX, srcStartY) di := dst.Stride dj := src.Stride for row := 0; row < numRows; row++ { copy(dst.Pix[i0:i0+rowSize], src.Pix[j0:j0+rowSize]) i0 += di j0 += dj } } return dst }
func ClickInner(root *Widget, p image.Point) { for _, w := range root.Widgets { q := p.Sub(root.Rect.Min) if q.In(w.Rect) { w.Click(q) } } }
// (overwrite BBoxObject default implementation) func (n *Node) SetPosition(pos image.Point) { shift := pos.Sub(n.Position()) n.positioner.SetPosition(pos) n.BBoxDefaultSetPosition(pos) for _, p := range n.ports { p.SetPosition(p.Position().Add(shift)) } }
// Copy copies the part of the source image defined by src and sr and writes to // the part of the destination image defined by dst and the translation of sr // so that sr.Min translates to dp. func Copy(dst Image, dp image.Point, src image.Image, sr image.Rectangle, opts *Options) { mask, mp, op := image.Image(nil), image.Point{}, Over if opts != nil { // TODO: set mask, mp and op. } dr := sr.Add(dp.Sub(sr.Min)) DrawMask(dst, dr, src, sr.Min, mask, mp, op) }
// Copy copies the part of the source image defined by src and sr and writes to // the part of the destination image defined by dst and the translation of sr // so that sr.Min translates to dp. func Copy(dst Image, dp image.Point, src image.Image, sr image.Rectangle, opts *Options) { var o Options if opts != nil { o = *opts } dr := sr.Add(dp.Sub(sr.Min)) // TODO: honor o.DstMask and o.SrcMask. DrawMask(dst, dr, src, sr.Min, nil, image.Point{}, o.Op) }
func HoverInner(root *Widget, p0 image.Point, p1 image.Point) { for _, w := range root.Widgets { q0 := p0.Sub(root.Rect.Min) q1 := p1.Sub(root.Rect.Min) if q0.In(w.Rect) || q1.In(w.Rect) { w.Hover(q0, q1) } } }
func (obj *Image) SetCentre(p image.Point) { p = p.Sub(centreDist(obj.Bbox())) if p.Eq(obj.item.R.Min) { return } obj.backing.Atomically(func(flush FlushFunc) { r := obj.item.R obj.item.R = r.Add(p.Sub(r.Min)) flush(r, nil) flush(obj.item.R, nil) }) }
func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) { 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(sp.Sub(r.Min))) { if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X { x0, x1, dx = x1-1, x0-1, -1 y0, y1, dy = y1-1, y0-1, -1 } } sy := sp.Y + y0 - r.Min.Y my := mp.Y + y0 - r.Min.Y sx0 := sp.X + x0 - r.Min.X mx0 := mp.X + x0 - r.Min.X sx1 := sx0 + (x1 - x0) i0 := dst.PixOffset(x0, y0) di := dx * 4 for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy { for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx { ma := uint32(m) if mask != nil { _, _, _, ma = mask.At(mx, my).RGBA() } sr, sg, sb, sa := src.At(sx, sy).RGBA() if op == Over { dr := uint32(dst.Pix[i+0]) dg := uint32(dst.Pix[i+1]) db := uint32(dst.Pix[i+2]) da := uint32(dst.Pix[i+3]) // dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255]. // We work in 16-bit color, and so would normally do: // dr |= dr << 8 // and similarly for dg, db and da, but instead we multiply a // (which is a 16-bit color, ranging in [0,65535]) by 0x101. // This yields the same result, but is fewer arithmetic operations. a := (m - (sa * ma / m)) * 0x101 dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8) dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8) dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8) dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8) } else { dst.Pix[i+0] = uint8(sr * ma / m >> 8) dst.Pix[i+1] = uint8(sg * ma / m >> 8) dst.Pix[i+2] = uint8(sb * ma / m >> 8) dst.Pix[i+3] = uint8(sa * ma / m >> 8) } } i0 += dy * dst.Stride } }
// Copy copies the part of the source image defined by src and sr and writes // the result of a Porter-Duff composition to the part of the destination image // defined by dst and the translation of sr so that sr.Min translates to dp. func Copy(dst Image, dp image.Point, src image.Image, sr image.Rectangle, op Op, opts *Options) { var o Options if opts != nil { o = *opts } dr := sr.Add(dp.Sub(sr.Min)) if o.DstMask == nil { DrawMask(dst, dr, src, sr.Min, o.SrcMask, o.SrcMaskP.Add(sr.Min), op) } else { NearestNeighbor.Scale(dst, dr, src, sr, op, opts) } }
func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) { 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(sp.Sub(r.Min))) { if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X { x0, x1, dx = x1-1, x0-1, -1 y0, y1, dy = y1-1, y0-1, -1 } } sy := sp.Y + y0 - r.Min.Y my := mp.Y + y0 - r.Min.Y sx0 := sp.X + x0 - r.Min.X mx0 := mp.X + x0 - r.Min.X i0 := (y0 - dst.Rect.Min.Y) * dst.Stride for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy { dpix := dst.Pix[i0:] for x, sx, mx := x0, sx0, mx0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx { ma := uint32(m) if mask != nil { _, _, _, ma = mask.At(mx, my).RGBA() } sr, sg, sb, sa := src.At(sx, sy).RGBA() var dr, dg, db, da uint32 if op == Over { rgba := dpix[x-dst.Rect.Min.X] dr = uint32(rgba.R) dg = uint32(rgba.G) db = uint32(rgba.B) da = uint32(rgba.A) // dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255]. // We work in 16-bit color, and so would normally do: // dr |= dr << 8 // and similarly for dg, db and da, but instead we multiply a // (which is a 16-bit color, ranging in [0,65535]) by 0x101. // This yields the same result, but is fewer arithmetic operations. a := (m - (sa * ma / m)) * 0x101 dr = (dr*a + sr*ma) / m dg = (dg*a + sg*ma) / m db = (db*a + sb*ma) / m da = (da*a + sa*ma) / m } else { dr = sr * ma / m dg = sg * ma / m db = sb * ma / m da = sa * ma / m } dpix[x-dst.Rect.Min.X] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)} } i0 += dy * dst.Stride } }
func (v *signalGraphView) handleDrag(pos image.Point) { for _, n := range v.nodes { if n.IsSelected() { box := n.BBox() //if !overlaps(v.nodes, box.Min.Add(pos.Sub(v.dragOffs))) { v.repaintNode(n) box = box.Add(pos.Sub(v.dragOffs)) v.dragOffs = pos n.SetPosition(box.Min) v.repaintNode(n) //} } } }
func anchor(r image.Rectangle, flags Anchor, p image.Point) image.Rectangle { var dp image.Point switch flags & (E | W) { case E: dp.X = r.Dx() case E | W, 0: dp.X = r.Dx() / 2 } switch flags & (N | S) { case S: dp.Y = r.Dy() case S | N, 0: dp.Y = r.Dy() / 2 } return r.Add(p.Sub(r.Min).Sub(dp)) }
func DragInner(root *Widget, p image.Point, d image.Point) bool { for i := range root.Widgets { w := root.Widgets[len(root.Widgets)-i-1] q := p.Sub(root.Rect.Min) if !q.In(w.Rect) { continue } if w.Drag(q, d) { return true } } return false }
// Check if the selected object would overlap with any other // if we move it to p coordinates: func overlaps(list []graph.NodeIf, p image.Point) bool { var box image.Rectangle for _, n := range list { if n.IsSelected() { box = n.BBox() break } } newBox := box.Add(p.Sub(box.Min)) for _, n := range list { if !n.IsSelected() && newBox.Overlaps(n.BBox()) { return true } } return false }
func trViewNearestNode(pt image.Point, node []*trNode) *trNode { var trn *trNode best := 11 for _, n := range node { dif := pt.Sub(n.pos) if dif.X < 0 { dif.X = -dif.X } if dif.Y < 0 { dif.Y = -dif.Y } if d := dif.X + dif.Y; d < best { best = d trn = n } } return trn }
func (v *platformView) handleDrag(pos image.Point) { for _, a := range v.arch { if a.IsSelected() { box := a.BBox() repaint := box box = box.Add(pos.Sub(v.dragOffs)) v.dragOffs = pos a.SetPosition(box.Min) repaint = repaint.Union(box) for _, aa := range v.arch { if aa.IsLinked(a.Name()) { repaint = repaint.Union(aa.BBox()) } } v.drawScene(repaint) } } }
// Uses half-sample symmetry. func Symmetric(im image.Image, p image.Point) color.Color { b := im.Bounds() // Make twice as big. d := image.Rectangle{b.Min, b.Max.Add(b.Size())} p = p.Mod(d) // Move to origin. p = p.Sub(b.Min) w, h := b.Dx(), b.Dy() if p.X > w-1 { p.X = 2*w - 1 - p.X } if p.Y > h-1 { p.Y = 2*h - 1 - p.Y } p = p.Add(b.Min) return im.At(p.X, p.Y) }
// Overlay draws the source image over the background image at given position // and returns the combined image. Opacity parameter is the opacity of the source // image layer, used to compose the images, it must be from 0.0 to 1.0. // // Usage examples: // // // draw the sprite over the background at position (50, 50) // dstImage := imaging.Overlay(backgroundImage, spriteImage, image.Pt(50, 50), 1.0) // // // blend two opaque images of the same size // dstImage := imaging.Overlay(imageOne, imageTwo, image.Pt(0, 0), 0.5) // func Overlay(background, source image.Image, pos image.Point, opacity float64) *image.NRGBA { opacity = math.Min(math.Max(opacity, 0.0), 1.0) // check: 0.0 <= opacity <= 1.0 src := convertToNRGBA(source) srcBounds := src.Bounds() dst := Clone(background) // cloned image bounds start at (0, 0) startPt := pos.Sub(background.Bounds().Min) // so we should translate start point endPt := startPt.Add(srcBounds.Size()) pasteBounds := image.Rectangle{startPt, endPt} if dst.Bounds().Overlaps(pasteBounds) { intersectBounds := dst.Bounds().Intersect(pasteBounds) for y := intersectBounds.Min.Y; y < intersectBounds.Max.Y; y++ { for x := intersectBounds.Min.X; x < intersectBounds.Max.X; x++ { i := dst.PixOffset(x, y) srcX := x - pasteBounds.Min.X + srcBounds.Min.X srcY := y - pasteBounds.Min.Y + srcBounds.Min.Y j := src.PixOffset(srcX, srcY) a1 := float64(dst.Pix[i+3]) a2 := float64(src.Pix[j+3]) coef2 := opacity * a2 / 255.0 coef1 := (1 - coef2) * a1 / 255.0 coefSum := coef1 + coef2 coef1 /= coefSum coef2 /= coefSum dst.Pix[i+0] = uint8(float64(dst.Pix[i+0])*coef1 + float64(src.Pix[j+0])*coef2) dst.Pix[i+1] = uint8(float64(dst.Pix[i+1])*coef1 + float64(src.Pix[j+1])*coef2) dst.Pix[i+2] = uint8(float64(dst.Pix[i+2])*coef1 + float64(src.Pix[j+2])*coef2) dst.Pix[i+3] = uint8(math.Min(a1+a2*opacity*(255.0-a1)/255.0, 255.0)) } } } return dst }
func (t *textureImpl) Upload(dp image.Point, src screen.Buffer, sr image.Rectangle) { buf := src.(*bufferImpl) buf.preUpload() // src2dst is added to convert from the src coordinate space to the dst // coordinate space. It is subtracted to convert the other way. src2dst := dp.Sub(sr.Min) // Clip to the source. sr = sr.Intersect(buf.Bounds()) // Clip to the destination. dr := sr.Add(src2dst) dr = dr.Intersect(t.Bounds()) if dr.Empty() { return } // Bring dr.Min in dst-space back to src-space to get the pixel buffer offset. pix := buf.rgba.Pix[buf.rgba.PixOffset(dr.Min.X-src2dst.X, dr.Min.Y-src2dst.Y):] t.w.glctxMu.Lock() defer t.w.glctxMu.Unlock() t.w.glctx.BindTexture(gl.TEXTURE_2D, t.id) width := dr.Dx() if width*4 == buf.rgba.Stride { t.w.glctx.TexSubImage2D(gl.TEXTURE_2D, 0, dr.Min.X, dr.Min.Y, width, dr.Dy(), gl.RGBA, gl.UNSIGNED_BYTE, pix) return } // TODO: can we use GL_UNPACK_ROW_LENGTH with glPixelStorei for stride in // ES 3.0, instead of uploading the pixels row-by-row? for y, p := dr.Min.Y, 0; y < dr.Max.Y; y++ { t.w.glctx.TexSubImage2D(gl.TEXTURE_2D, 0, dr.Min.X, y, width, 1, gl.RGBA, gl.UNSIGNED_BYTE, pix[p:]) p += buf.rgba.Stride } }
func (v *mappingView) handleDrag(pos image.Point) { for _, a := range v.arch { if a.IsSelected() { box := a.BBox() v.repaintArch(a) box = box.Add(pos.Sub(v.dragOffs)) v.dragOffs = pos a.SetPosition(box.Min) v.repaintArch(a) } } if v.unmapped.IsSelected() { box := v.unmapped.BBox() v.repaintUnmapped(v.unmapped) box = box.Add(pos.Sub(v.dragOffs)) v.dragOffs = pos v.unmapped.SetPosition(box.Min) v.repaintUnmapped(v.unmapped) } for _, n := range v.nodes { n.Layout() } }
func (c *Container) ContainerDefaultSetPosition(pos image.Point) { if c.selectedChild != -1 { child := c.Children[c.selectedChild] childpos := child.Position() offset := childpos.Sub(c.Position()) child.SetPosition(pos.Add(offset)) c.box = c.Layout() } else if c.selectedPort != -1 { child := c.ports[c.selectedPort] childpos := child.Position() offset := childpos.Sub(c.Position()) newPos := pos.Add(offset) child.SetPosition(c.portClipPos(newPos)) } else { shift := pos.Sub(c.Position()) c.BBoxDefaultSetPosition(pos) for _, p := range c.Children { p.SetPosition(p.Position().Add(shift)) } for _, p := range c.ports { p.SetPosition(p.Position().Add(shift)) } } }
func processBackward(dst Image, r image.Rectangle, src image.Image, sp image.Point) bool { return image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) && (sp.Y < r.Min.Y || (sp.Y == r.Min.Y && sp.X < r.Min.X)) }
func (oc OffsetChunk) At(pt image.Point) (MapCell, bool) { if cell, ok := oc.chunk.cells[pt.Sub(oc.offset)]; ok { return cell, true } return spaceCell, false }
// DrawMask aligns r.Min in dst with sp in src and mp in mask and then replaces the rectangle r // in dst with the result of a Porter-Duff composition. A nil mask is treated as opaque. func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) { clip(dst, &r, src, &sp, mask, &mp) if r.Empty() { return } // Fast paths for special cases. If none of them apply, then we fall back to a general but slow implementation. if dst0, ok := dst.(*image.RGBA); ok { if op == Over { if mask == nil { switch src0 := src.(type) { case *image.ColorImage: drawFillOver(dst0, r, src0) return case *image.RGBA: drawCopyOver(dst0, r, src0, sp) return case *image.NRGBA: drawNRGBAOver(dst0, r, src0, sp) return case *ycbcr.YCbCr: drawYCbCr(dst0, r, src0, sp) return } } else if mask0, ok := mask.(*image.Alpha); ok { switch src0 := src.(type) { case *image.ColorImage: drawGlyphOver(dst0, r, src0, mask0, mp) return } } } else { if mask == nil { switch src0 := src.(type) { case *image.ColorImage: drawFillSrc(dst0, r, src0) return case *image.RGBA: drawCopySrc(dst0, r, src0, sp) return case *image.NRGBA: drawNRGBASrc(dst0, r, src0, sp) return case *ycbcr.YCbCr: drawYCbCr(dst0, r, src0, sp) return } } } drawRGBA(dst0, r, src, sp, mask, mp, op) return } 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(sp.Sub(r.Min))) { // Rectangles overlap: process backward? if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X { x0, x1, dx = x1-1, x0-1, -1 y0, y1, dy = y1-1, y0-1, -1 } } var out *image.RGBA64Color sy := sp.Y + y0 - r.Min.Y my := mp.Y + y0 - r.Min.Y for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy { sx := sp.X + x0 - r.Min.X mx := mp.X + x0 - r.Min.X for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx { ma := uint32(m) if mask != nil { _, _, _, ma = mask.At(mx, my).RGBA() } switch { case ma == 0: if op == Over { // No-op. } else { dst.Set(x, y, zeroColor) } case ma == m && op == Src: dst.Set(x, y, src.At(sx, sy)) default: sr, sg, sb, sa := src.At(sx, sy).RGBA() if out == nil { out = new(image.RGBA64Color) } if op == Over { dr, dg, db, da := dst.At(x, y).RGBA() a := m - (sa * ma / m) out.R = uint16((dr*a + sr*ma) / m) out.G = uint16((dg*a + sg*ma) / m) out.B = uint16((db*a + sb*ma) / m) out.A = uint16((da*a + sa*ma) / m) } else { out.R = uint16(sr * ma / m) out.G = uint16(sg * ma / m) out.B = uint16(sb * ma / m) out.A = uint16(sa * ma / m) } dst.Set(x, y, out) } } } }
// place the camera's center at pt func (c *Camera) SetCenter(pt image.Point) { newpos := pt.Sub(c.SizeRect.Size().Div(2)) c.Pos = pt c.Rect = image.Rect(newpos.X, newpos.Y, newpos.X+c.SizeRect.Dx(), newpos.Y+c.SizeRect.Dy()) }
func (c *Camera) Transform(pt image.Point) image.Point { return pt.Sub(c.Rect.Min) //.Add(c.Rect.Size().Div(2)) }
// HexDist returns the hexagonal distance between two points. func HexDist(p1, p2 image.Point) int { return HexLength(p2.Sub(p1)) }
func (t *Text) SetCentre(cp image.Point) { delta := cp.Sub(centre(t.Bbox())) t.SetPoint(t.p.Add(delta)) }
func exportMatrices(filename string, config *Config) { fmt.Printf("Processing %s... ", filename) // Open image file, err := os.Open(filename) if err != nil { log.Fatal(err) } defer file.Close() // Decode image image_file, err := png.Decode(file) if err != nil { log.Fatal(err) } // Set up some image variables image_size := image_file.Bounds().Size() tile_size := config.getTileGeometry("size") tile_origin := config.getTileGeometry("origin") tiles_x := image_size.X / tile_size.X tiles_y := image_size.Y / tile_size.Y fmt.Printf("Sprite sheet size: %dx%d\n", tiles_x, tiles_y) // Set up some path variables luaFilename := strings.Replace(filepath.Base(filename), filepath.Ext(filename), ".lua", 1) outputPath := filepath.Join(filepath.Dir(filename), luaFilename) // Open output lua file output, err := os.Create(outputPath) if err != nil { log.Fatal(err) } defer output.Close() // Populate table_data with blank data at the appropriate size table_data := config.getBlankTable(image.Point{tiles_x, tiles_y}) // Populate color data for speed colors := make(map[icolor.RGBA]string) for hex, name := range config.getColorMappings() { color := hexToColor(hex) colors[color] = name } // Loop through the image for y := 0; y < image_size.Y; y++ { for x := 0; x < image_size.X; x++ { r, g, b, a := image_file.At(x, y).RGBA() color := icolor.RGBA{uint8(r), uint8(g), uint8(b), uint8(a)} name, ok := colors[color] if ok { current_tile := image.Point{ x / tile_size.X, y / tile_size.Y, } current_offset := image.Point{ x % tile_size.X, y % tile_size.Y, } table_data[name][current_tile.Y][current_tile.X] = current_offset.Sub(tile_origin) } } } // Write this data to disk n, err := fmt.Fprintln(output, "return {") if n == 0 || err != nil { log.Fatal(err) } for name, _ := range table_data { fmt.Fprintf(output, " %s = {\n", name) // start table for y := 0; y < tiles_y; y++ { fmt.Fprintf(output, " {") // start row for x := 0; x < tiles_x; x++ { point := table_data[name][y][x] fmt.Fprintf(output, " {%d, %d},", point.X, point.Y) } fmt.Fprintln(output, " },") // end row } fmt.Fprintln(output, " },\n") // End table } fmt.Fprintln(output, "}") }
func main() { driver.Main(func(s screen.Screen) { w, err := s.NewWindow(nil) if err != nil { log.Fatal(err) } defer w.Release() var ( pool = &tilePool{ screen: s, drawRGBA: drawRGBA, m: map[image.Point]*tilePoolEntry{}, } dragging bool paintPending bool drag image.Point origin image.Point sz size.Event ) for e := range w.Events() { switch e := e.(type) { case key.Event: if e.Code == key.CodeEscape { return } case mouse.Event: p := image.Point{X: int(e.X), Y: int(e.Y)} if e.Button == mouse.ButtonLeft && e.Direction != mouse.DirNone { dragging = e.Direction == mouse.DirPress drag = p } if !dragging { break } origin = origin.Sub(p.Sub(drag)) drag = p if origin.X < 0 { origin.X = 0 } if origin.Y < 0 { origin.Y = 0 } if !paintPending { paintPending = true w.Send(paint.Event{}) } case paint.Event: generation++ var wg sync.WaitGroup for y := -(origin.Y & 0xff); y < sz.HeightPx; y += 256 { for x := -(origin.X & 0xff); x < sz.WidthPx; x += 256 { wg.Add(1) go drawTile(&wg, w, pool, origin, x, y) } } wg.Wait() w.Publish() paintPending = false pool.releaseUnused() case size.Event: sz = e case error: log.Print(e) } } }) }