// imgHandle serves images of the player's view. func imgHandle(w http.ResponseWriter, r *http.Request) { quality, err := strconv.Atoi(r.FormValue("quality")) if err != nil || quality < 0 || quality > 100 { quality = 70 } // Center Gopher in view if possible gpos := model.Gopher.Pos rect := image.Rect(0, 0, ViewWidth, ViewHeight).Add(image.Pt(int(gpos.X)-ViewWidth/2, int(gpos.Y)-ViewHeight/2)) // But needs correction at the edges of the view (it can't be centered) corr := image.Point{} if rect.Min.X < 0 { corr.X = -rect.Min.X } if rect.Min.Y < 0 { corr.Y = -rect.Min.Y } if rect.Max.X > model.LabWidth { corr.X = model.LabWidth - rect.Max.X } if rect.Max.Y > model.LabHeight { corr.Y = model.LabHeight - rect.Max.Y } rect = rect.Add(corr) model.Mutex.Lock() jpeg.Encode(w, model.LabImg.SubImage(rect), &jpeg.Options{quality}) model.Mutex.Unlock() // Store the new view's position: Pos = rect.Min }
func canfit(p *Piece) bool { var dx = [...]int{0, -1, 1, -2, 2, -3, 3, 4, -4} j := N + 1 if j >= 4 { j = p.sz.X if j < p.sz.Y { j = p.sz.Y } j = 2*j - 1 } for i := 0; i < j; i++ { var z image.Point z.X = pos.X + dx[i]*pcsz z.Y = pos.Y if !collide(z, p) { z.Y = pos.Y + pcsz - 1 if !collide(z, p) { undrawpiece() pos.X = z.X return true } } } return false }
func (self *Image) sourceRectTouchOriginalFromInside(width, height int, horAlign HorAlignment, verAlign VerAlignment) (r image.Rectangle) { var offset image.Point aspectRatio := float64(width) / float64(height) if aspectRatio > self.AspectRatio() { // Wider than original // so touchOriginalFromInside means // that the source rect is as wide as the original r.Max.X = self.Width() r.Max.Y = int(float64(self.Width()) / aspectRatio) switch verAlign { case VerCenter: offset.Y = (self.Height() - r.Max.Y) / 2 case Bottom: offset.Y = self.Height() - r.Max.Y } } else { // Heigher than original, // so touchOriginalFromInside means // that the source rect is as high as the original r.Max.X = int(float64(self.Height()) * aspectRatio) r.Max.Y = self.Height() switch horAlign { case HorCenter: offset.X = (self.Width() - r.Max.X) / 2 case Right: offset.X = self.Width() - r.Max.X } } return r.Add(offset) }
// originTrans translates the origin with respect to the current image and the // current canvas size. This makes sure we never incorrect position the image. // (i.e., panning never goes too far, and whenever the canvas is bigger than // the image, the origin is *always* (0, 0). func originTrans(pt image.Point, win *window, img *vimage) image.Point { // If there's no valid image, then always return (0, 0). if img == nil { return image.Point{0, 0} } // Quick aliases. ww, wh := win.Geom.Width(), win.Geom.Height() dw := img.Bounds().Dx() - ww dh := img.Bounds().Dy() - wh // Set the allowable range of the origin point of the image. // i.e., never less than (0, 0) and never greater than the width/height // of the image that isn't viewable at any given point (which is determined // by the canvas size). pt.X = min(img.Bounds().Min.X+dw, max(pt.X, 0)) pt.Y = min(img.Bounds().Min.Y+dh, max(pt.Y, 0)) // Validate origin point. If the width/height of an image is smaller than // the canvas width/height, then the image origin cannot change in x/y // direction. if img.Bounds().Dx() < ww { pt.X = 0 } if img.Bounds().Dy() < wh { pt.Y = 0 } return pt }
func (f *Frame) grid(p image.Point) image.Point { p.Y -= f.Rect.Min.Y p.Y -= p.Y % f.Font.Height p.Y += f.Rect.Min.Y if p.X > f.Rect.Max.X { p.X = f.Rect.Max.X } return p }
func main() { g = image.NewGray(image.Rectangle{image.Point{0, 0}, image.Point{w, h}}) // off center seed position makes pleasingly asymetrical tree g.SetGray(w/3, h/3, color.Gray{frost}) generate: for a := 0; a < n; { // generate random position for new particle rp := image.Point{rand.Intn(w), rand.Intn(h)} if g.At(rp.X, rp.Y).(color.Gray).Y == frost { // position is already set. find a nearby free position. for { rp.X += rand.Intn(3) - 1 rp.Y += rand.Intn(3) - 1 // execpt if we run out of bounds, consider the particle lost. if !rp.In(g.Rect) { continue generate } if g.At(rp.X, rp.Y).(color.Gray).Y != frost { break } } } else { // else particle is in free space. let it wander // until it touches tree for !hasNeighbor(rp) { rp.X += rand.Intn(3) - 1 rp.Y += rand.Intn(3) - 1 // but again, if it wanders out of bounds consider it lost. if !rp.In(g.Rect) { continue generate } } } // x, y now specify a free position toucing the tree. g.SetGray(rp.X, rp.Y, color.Gray{frost}) a++ // progress indicator if a%100 == 0 { fmt.Println(a, "of", n) } } f, err := os.Create("tree.png") if err != nil { fmt.Println(err) return } err = png.Encode(f, g) if err != nil { fmt.Println(err) } f.Close() }
func (f *Frame) cklinewrap(p *image.Point, b *frbox) { if b.Nrune < 0 { if b.Minwid > byte(f.Rect.Max.X-p.X) { p.X = f.Rect.Min.X p.Y += f.Font.Height } } else { if b.Wid > f.Rect.Max.X-p.X { p.X = f.Rect.Min.X p.Y += f.Font.Height } } }
func warp(p image.Point, x int) int { if !suspended && piece != nil { x = pos.X + piece.sz.X*pcsz/2 if p.Y < rboard.Min.Y { p.Y = rboard.Min.Y } if p.Y >= rboard.Max.Y { p.Y = rboard.Max.Y - 1 } //mousectl.MoveTo(image.Pt(x, p.Y)) } return x }
func collide(pt image.Point, p *Piece) bool { pt.X = (pt.X - rboard.Min.X) / pcsz pt.Y = (pt.Y - rboard.Min.Y) / pcsz for _, q := range p.d { pt.X += q.X pt.Y += q.Y if pt.X < 0 || pt.X >= NX || pt.Y < 0 || pt.Y >= NY { return true } if board[pt.Y][pt.X] != 0 { return true } } return false }
func (f *Frame) _draw(pt image.Point) image.Point { for nb := 0; nb < f.nbox; nb++ { b := f.box[nb] f.cklinewrap0(&pt, b) if pt.Y == f.Rect.Max.Y { f.nchars -= f.strlen(nb) f.delbox(nb, f.nbox-1) break } if b.Nrune > 0 { n, fits := f.canfit(pt, b) if !fits { break } if n != b.Nrune { f.splitbox(uint64(nb), uint64(n)) b = f.box[nb] } pt.X += b.Wid } else { if b.Bc == '\n' { pt.X = f.Rect.Min.X pt.Y += f.Font.Height } else { pt.X += f.newwid(pt, b) } } } return pt }
func main() { bounds := image.Rect(0, 0, 100, 100) im := image.NewGray(bounds) gBlack := color.Gray{0} gWhite := color.Gray{255} draw.Draw(im, bounds, image.NewUniform(gWhite), image.ZP, draw.Src) pos := image.Point{50, 50} dir := up for pos.In(bounds) { switch im.At(pos.X, pos.Y).(color.Gray).Y { case gBlack.Y: im.SetGray(pos.X, pos.Y, gWhite) dir-- case gWhite.Y: im.SetGray(pos.X, pos.Y, gBlack) dir++ } if dir&1 == 1 { pos.X += 1 - dir&2 } else { pos.Y -= 1 - dir&2 } } f, err := os.Create("ant.png") if err != nil { fmt.Println(err) return } if err = png.Encode(f, im); err != nil { fmt.Println(err) } if err = f.Close(); err != nil { fmt.Println(err) } }
// Clamp a bound to inside the given bounds func clamp(point image.Point, bounds image.Rectangle) image.Point { if point.X < bounds.Min.X { point.X = bounds.Min.X } if point.X >= bounds.Max.X { point.X -= bounds.Max.X - 1 } if point.Y < bounds.Min.Y { point.Y = bounds.Min.Y } if point.Y >= bounds.Max.Y { point.Y = bounds.Max.Y - 1 } return point }
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)) }
// Thumbnail scales and crops src so it fits in dst. func Thumbnail(dst draw.Image, src image.Image) error { // Scale down src in the dimension that is closer to dst. sb := src.Bounds() db := dst.Bounds() rx := float64(sb.Dx()) / float64(db.Dx()) ry := float64(sb.Dy()) / float64(db.Dy()) var b image.Rectangle if rx < ry { b = image.Rect(0, 0, db.Dx(), int(float64(sb.Dy())/rx)) } else { b = image.Rect(0, 0, int(float64(sb.Dx())/ry), db.Dy()) } buf := image.NewRGBA(b) if err := Scale(buf, src); err != nil { return err } // Crop. // TODO(crawshaw): improve on center-alignment. var pt image.Point if rx < ry { pt.Y = (b.Dy() - db.Dy()) / 2 } else { pt.X = (b.Dx() - db.Dx()) / 2 } draw.Draw(dst, db, buf, pt, draw.Src) return nil }
func (f *Frame) advance(p *image.Point, b *frbox) { if b.Nrune < 0 && b.Bc == '\n' { p.X = f.Rect.Min.X p.Y += f.Font.Height } else { p.X += b.Wid } }
// clip clips r against each image's bounds (after translating into the // destination image's coordinate space) and shifts the points sp and mp by // the same amount as the change in r.Min. func clip(dst draw.Image, r *image.Rectangle, src image.Image, sp *image.Point, mask image.Image, mp *image.Point) { orig := r.Min *r = r.Intersect(dst.Bounds()) *r = r.Intersect(src.Bounds().Add(orig.Sub(*sp))) if mask != nil { *r = r.Intersect(mask.Bounds().Add(orig.Sub(*mp))) } dx := r.Min.X - orig.X dy := r.Min.Y - orig.Y if dx == 0 && dy == 0 { return } sp.X += dx sp.Y += dy if mp != nil { mp.X += dx mp.Y += dy } }
func GenerateImage(generatorSpecifications GeneratorSpecifications) *image.RGBA { minPoint := image.Point{0, 0} maxPoint := minPoint for i := 0; i < len(generatorSpecifications.lines); i++ { currentLen := len(generatorSpecifications.lines[i].points) for j := 1; j <= currentLen; j++ { currentPoint := Point(generatorSpecifications.lines[i].points[j%currentLen]) max := Max(int(generatorSpecifications.lines[i].jagged[j%currentLen]), int(generatorSpecifications.lines[i].jagged[j-1])) + int(generatorSpecifications.lines[i].width) min := max / 2 max -= min maxPoint.X = Max(maxPoint.X, currentPoint.X+max) maxPoint.Y = Max(maxPoint.Y, currentPoint.Y+max) minPoint.X = Min(maxPoint.X, currentPoint.X-min) minPoint.Y = Min(maxPoint.Y, currentPoint.Y-min) } } for i := 0; i < len(generatorSpecifications.circles); i++ { currentPoint := Point(generatorSpecifications.circles[i].point) max := int(generatorSpecifications.circles[i].width + generatorSpecifications.circles[i].jagged) min := max / 2 max += int(generatorSpecifications.circles[i].radius) - min min += int(generatorSpecifications.circles[i].radius) maxPoint.X = Max(maxPoint.X, currentPoint.X+max) maxPoint.Y = Max(maxPoint.Y, currentPoint.Y+max) minPoint.X = Min(maxPoint.X, currentPoint.X-min) minPoint.Y = Min(maxPoint.Y, currentPoint.Y-min) } ret := image.NewRGBA(image.Rectangle{minPoint, maxPoint}) for i := 0; i < len(generatorSpecifications.lines); i++ { DrawLine(ret, generatorSpecifications.lines[i]) } for i := 0; i < len(generatorSpecifications.circles); i++ { DrawCircle(ret, generatorSpecifications.circles[i]) } return ret }
func (poly *jsonWedPolygon) BoundingBox() image.Rectangle { min := image.Point{math.MaxUint16, math.MaxUint16} max := image.Point{0, 0} for _, vert := range poly.Verts { if vert.X < min.X { min.X = int(vert.X) } if vert.Y < min.Y { min.Y = int(vert.Y) } if vert.X > max.X { max.X = int(vert.X) } if vert.Y > max.Y { max.Y = int(vert.Y) } } return image.Rectangle{min, max}.Canon() }
func fitted(into image.Rectangle, size image.Point) image.Rectangle { ratio := float64(size.X) / float64(size.Y) if size.X > into.Dx() { size.X = into.Dx() size.Y = int(float64(into.Dx()) / ratio) } if size.Y > into.Dy() { size.X = int(float64(into.Dy()) * ratio) size.Y = into.Dy() } r := image.Rectangle{ Min: into.Min, Max: into.Min.Add(size), } r = r.Add(image.Point{into.Dx() / 2, into.Dy() / 2}). Sub(image.Point{size.X / 2, size.Y / 2}) return r }
func (atlas *ManagedAtlas) LoadGroupSheetOffset(path string, pt image.Point, width, height, frames int) (err error, groupID ID) { fName := filepath.Base(path) extIndex := strings.LastIndex(fName, ".") if extIndex != -1 { fName = fName[:extIndex] } fName = atlas.nextGroupID(fName) file, e := os.Open(path) if e != nil { return e, nil } defer file.Close() ds, e := file.Stat() if e != nil { return e, nil } if ds.IsDir() { return errors.New("The path is not a file. " + path), nil } file.Close() img, e := LoadImage(path) if e != nil { return e, nil } group := make([]ID, 0) point := image.Point{pt.X, pt.Y} for i := 0; i < frames; i++ { is := strconv.FormatInt(int64(i), 10) if i == 0 { is = "" } sprite := image.NewRGBA(image.Rect(0, 0, width, height)) draw.Draw(sprite, sprite.Rect, img, point, draw.Src) atlas.AddImage(sprite, fName+is) group = append(group, fName+is) point.X += width if !sprite.Rect.Add(point).In(img.Bounds()) { point.X = 0 point.Y += height } } atlas.groups[fName] = group return nil, fName }
func getSpriteSize(imgs []*cssImage) image.Point { p := image.Point{} for _, img := range imgs { st := img.img if st.sp.X == -1 { st.sp = image.Pt(-p.X, 0) p.X += st.dx() if p.Y < st.dy() { p.Y = st.dy() } } } return p }
// Image Handler // Reads the stored GIF & overlay for the authenticated user and returns a new GIF with the overlay copied onto each frame of the input GIF func imageHandler(w http.ResponseWriter, r *http.Request) { token, _ := jwt.ParseFromRequest(r, hmacKeyFunc) issuer := token.Claims["iss"].(string) gfFile, err1 := os.Open(getFileName("gif:" + issuer)) overlayFile, err2 := os.Open(getFileName("overlay:" + issuer)) if err1 != nil || err2 != nil { sendResponse(w, 400, map[string]string{ "error": "Error while reading images", }) return } // Decode images dst, err1 := gif.DecodeAll(gfFile) src, _, err2 := image.Decode(overlayFile) if err1 != nil || err2 != nil { sendResponse(w, 400, map[string]string{ "error": "Error while decoding images", }) return } // Create location for the draw pt := new(image.Point) x, err := strconv.Atoi(r.URL.Query().Get("x")) if err != nil { x = 0 } y, err := strconv.Atoi(r.URL.Query().Get("y")) if err != nil { y = 0 } pt.X = x pt.Y = y // Draw the overlay over each frame of the GIF for _, frame := range dst.Image { draw.Draw(frame, frame.Bounds(), src, *pt, draw.Over) } // Encode image to base64 buffer := new(bytes.Buffer) gif.EncodeAll(buffer, dst) fmt.Fprint(w, base64.StdEncoding.EncodeToString(buffer.Bytes())) }
func (pyr *Pyramid) Visualize() image.Image { var width, height int for _, level := range pyr.Levels { if level.Bounds().Dx() > width { width = level.Bounds().Dx() } height += level.Bounds().Dy() } im := image.NewRGBA64(image.Rect(0, 0, width, height)) var p image.Point for _, level := range pyr.Levels { draw.Draw(im, level.Bounds().Add(p), level, image.ZP, draw.Src) p.Y += level.Bounds().Dy() } return im }
func (poly *jsonWedPolygon) EffectedTiles(pt image.Point) []int { out := make([]int, 0) bb := poly.BoundingBox() bb.Min.X /= 64 bb.Min.Y /= 64 bb.Max.X /= 64 bb.Max.Y /= 64 pt.X /= 64 pt.Y /= 64 // All tiles in our bounding box should be considered effected for y := bb.Min.Y; y <= bb.Max.Y; y++ { for x := bb.Min.X; x <= bb.Max.X; x++ { out = append(out, y*pt.X+x) } } return out }
// 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) }
// Warning: does modify contents of polys func DrawPolygons(mul float64, polys []polyclip.Polygon) *image.NRGBA { img := image.NewNRGBA(image.Rect(0, 0, 0, 0)) min := polyclip.Point{0, 0} for i, polygon := range polys { r0 := safebbox(polygon) translate := image.Point{} if r0.Min.X < min.X { translate.X = int(mul*min.X) - int(mul*r0.Min.X) min.X = r0.Min.X } if r0.Min.Y < min.Y { translate.Y = int(mul*min.Y) - int(mul*r0.Min.Y) min.Y = r0.Min.Y } for _, c := range polygon { for j, p := range c { c[j].X = (p.X - min.X) * mul c[j].Y = (p.Y - min.Y) * mul } } r := safebbox(polygon) img2 := image.NewNRGBA(img.Bounds().Add(translate).Union(image.Rect(int(r.Min.X), int(r.Min.Y), int(r.Max.X), int(r.Max.Y)))) draw.Draw(img2, img2.Bounds(), image.Black, image.Pt(0, 0), draw.Src) draw.Draw(img2, img.Bounds().Add(translate), img, image.Pt(0, 0), draw.Src) img = img2 for _, c := range polygon { polyutil.DrawPolyline(c, brush(img, i)) } } return img }
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) } } }) }
func drawLinesOverGrid(w http.ResponseWriter, r *http.Request, m map[string]interface{}) { c := appengine.NewContext(r) // prepare a line color lineCol := color.RGBA{} lineCol.R, lineCol.G, lineCol.B, lineCol.A = 255, 244, 22, 0 c.Infof("brush color %#v \n", lineCol) p := r.FormValue("p") if p == "" { p = "static/chartbg_400x960__480x1040__12x10.png" } if p == "" { p = "static/pberg1.png" } f, err := os.Open(p) util_err.Err_http(w, r, err, false) defer f.Close() img, whichFormat, err := image.Decode(f) util_err.Err_http(w, r, err, false, "only jpeg and png are 'activated' ") c.Infof("serving img format %v %T\n", whichFormat, img) switch imgXFull := img.(type) { default: util_err.Err_http(w, r, false, true, "convertibility into internal color format image.RGBA required") case *image.RGBA: drawLine := FuncDrawLiner(lineCol, imgXFull) xb, yb := 40, 440 P0 := image.Point{xb + 0, yb - 0} drawLine(P0, lineCol, imgXFull) for i := 0; i < 1; i++ { P1 := image.Point{xb + 80, yb - 80} drawLine(P1, lineCol, imgXFull) P1.X = xb + 160 P1.Y = yb - 160 drawLine(P1, lineCol, imgXFull) P1.X = xb + 240 P1.Y = yb - 240 drawLine(P1, lineCol, imgXFull) P1.X = xb + 320 P1.Y = yb - 320 drawLine(P1, lineCol, imgXFull) P1.X = xb + 400 P1.Y = yb - 400 drawLine(P1, lineCol, imgXFull) drawLine = FuncDrawLiner(lineCol, imgXFull) yb = 440 P0 = image.Point{xb + 0, yb - 0} drawLine(P0, lineCol, imgXFull) P1 = image.Point{xb + 80, yb - 40} drawLine(P1, lineCol, imgXFull) P1.X = xb + 160 P1.Y = yb - 90 drawLine(P1, lineCol, imgXFull) P1.X = xb + 240 P1.Y = yb - 120 drawLine(P1, lineCol, imgXFull) P1.X = xb + 320 P1.Y = yb - 300 drawLine(P1, lineCol, imgXFull) P1.X = xb + 400 P1.Y = yb - 310 drawLine(P1, lineCol, imgXFull) } SaveImageToDatastore(w, r, imgXFull, "chart1") img := GetImageFromDatastore(w, r, "chart1") w.Header().Set("Content-Type", "image/png") png.Encode(w, img) // end case } }
func (bam *BAM) MakeSpriteSheet(imgWriter io.Writer, jsonWriter io.Writer) { size := image.Point{0, 0} maxY := 0 jsonData := fmt.Sprintf("{\"frames\": [\n") numFramesX := int(math.Sqrt(float64(len(bam.Frames)))) seqSize := image.Point{0, 0} for idx, f := range bam.Frames { seqSize.X += int(f.Width) if int(f.Height) > seqSize.Y { seqSize.Y = int(f.Height) } if int(f.Height) > maxY { maxY = int(f.Height) } if (idx+1)%numFramesX == 0 { size.Y += seqSize.Y if seqSize.X > size.X { size.X = seqSize.X } seqSize = image.Point{0, 0} } } size.Y += maxY size.X = int(next_pow_two(uint(size.X))) size.Y = int(next_pow_two(uint(size.Y))) i := image.NewPaletted(image.Rect(0, 0, size.X, size.Y), bam.Image[0].Palette) maxY = 0 y := 1 x := 1 lastFrame := len(bam.Frames) - 1 for idx, frame := range bam.Frames { img := &bam.Image[idx] drawRect := image.Rect( x, y, x+int(frame.Width), y+int(frame.Height), ) draw.Draw(i, drawRect, img, image.Point{0, 0}, draw.Src) jsonData += fmt.Sprintf("\t{\"filename\": \"frame_%d\", \"frame\": {\"x\":%d,\"y\":%d,\"w\":%d,\"h\":%d},\"rotated\": false,\"trimmed\":true,\"spriteSourceSize\": {\"x\":%d,\"y\":%d,\"w\":%d,\"h\":%d}, \"sourceSize\": {\"w\":%d,\"h\":%d}}", idx, drawRect.Min.X, drawRect.Min.Y, drawRect.Dx(), drawRect.Dy(), frame.CenterX*-1, frame.CenterY*-1, int16(frame.Width)+frame.CenterX, int16(frame.Height)+frame.CenterY, frame.Width, frame.Height) x += int(frame.Width) + 2 if int(frame.Height) > maxY { maxY = int(frame.Height) } if (idx+1)%numFramesX == 0 { y += maxY //maxY = 0 x = 1 } if idx != lastFrame { jsonData += fmt.Sprintf(",\n") } else { jsonData += fmt.Sprintf("\n") } } i.Palette[0] = color.RGBA{0, 0, 0, 0} jsonData += fmt.Sprintf("]}\n") jsonWriter.Write([]byte(jsonData)) png.Encode(imgWriter, i) }
func Paint(w wde.Window, rect image.Rectangle) { xOffset, yOffset := GetTopLeft() center := layout.Coord{ViewportWidth/2 - xOffset, ViewportHeight/2 - yOffset} if center != oldCenter || layout.Version() != oldVersion { oldCenter = center oldVersion = layout.Version() for x := 0; x <= ViewportWidth; x++ { for y := 0; y <= ViewportHeight; y++ { if layout.Visible(center, layout.Coord{x - xOffset, y - yOffset}) { res.Tile(terrain, res.Terrain, uint16(layout.GetSpace(x-xOffset, y-yOffset)), x, y) draw.Draw(terrain, image.Rect(x<<res.TileSize, y<<res.TileSize, (x+1)<<res.TileSize, (y+1)<<res.TileSize), image.Transparent, image.ZP, draw.Src) for _, t := range layout.Get(x-xOffset, y-yOffset) { if !t.NoClient() { res.Tile(terrain, res.Terrain, uint16(t), x, y) } } } else { res.Tile(terrain, image.Black, 0, x, y) } } } switch GetPlayerFlags() & packet.FlagSpriteMask { case packet.FlagEngineer: for x := 0; x <= ViewportWidth; x++ { for y := 0; y <= ViewportHeight; y++ { dx, dy := x-ViewportWidth/2, y-ViewportHeight/2 dist := dx*dx + dy*dy if dist <= 3*3 && layout.Visible(center, layout.Coord{x - xOffset, y - yOffset}) { for _, t := range layout.Get(x-xOffset, y-yOffset) { if t >= layout.WireW && t <= layout.WireS { res.Tile(terrain, res.Terrain, uint16(t), x, y) } } } } } } } minX, maxX := rect.Min.X>>res.TileSize, (rect.Max.X-1)>>res.TileSize+1 minY, maxY := rect.Min.Y>>res.TileSize, (rect.Max.Y-1)>>res.TileSize+1 draw.Draw(sprites, sprites.Bounds(), image.Transparent, image.ZP, draw.Src) var pixOffset image.Point var hasAnimation image.Rectangle paintLock.Lock() for _, p := range paintContexts { if layout.Visible(center, p.To) { x1, y1 := p.From.X+xOffset, p.From.Y+yOffset x2, y2 := p.To.X+xOffset, p.To.Y+yOffset if minX <= x2 && x2 <= maxX && minY <= y2 && y2 <= maxY { interp := float32(time.Since(p.Changed)*5) / float32(time.Second) if interp >= 1 { res.Tile(sprites, res.Actors, p.Sprite, x2, y2) } else { toInvalidate := image.Rect(x1, y1, x1+1, y1+1).Union(image.Rect(x2, y2, x2+1, y2+1)) if hasAnimation.Empty() { hasAnimation = toInvalidate } else { hasAnimation = hasAnimation.Union(toInvalidate) } if p == thePlayer.paint { pixOffset.X = int(float32((x1-x2)<<res.TileSize) * (1 - interp)) pixOffset.Y = int(float32((y1-y2)<<res.TileSize) * (1 - interp)) hasAnimation = viewport.Bounds() } res.TileFloat(sprites, res.Actors, p.Sprite, x1, y1, x2, y2, interp) } } } } paintLock.Unlock() draw.Draw(viewport, rect, terrain, rect.Min.Add(pixOffset), draw.Src) draw.Draw(viewport, rect, sprites, rect.Min.Add(pixOffset), draw.Over) draw.DrawMask(viewport, rect, image.Black, image.ZP, light.Image(-xOffset, -yOffset), rect.Min.Add(light.Origin(-xOffset, -yOffset)).Add(pixOffset), draw.Over) if image.Rect(0, 0, 1, 1).Overlaps(rect) { mouseTileLock.Lock() res.DrawString(viewport, mouseTileString, color.White, res.FontSmall, 1, 1) mouseTileLock.Unlock() } if !hasAnimation.Empty() { Invalidate(image.Rectangle{hasAnimation.Min.Mul(1 << res.TileSize), hasAnimation.Max.Mul(1 << res.TileSize)}) } paints++ /* // For debugging paints res.DrawString(viewport, strconv.FormatUint(paints, 10), color.White, res.FontSmall, 300, 1) draw.Draw(viewport, image.Rectangle{rect.Min, image.Pt(rect.Max.X+1, rect.Min.Y+1)}, image.White, image.ZP, draw.Src) draw.Draw(viewport, image.Rectangle{image.Pt(rect.Min.X-1, rect.Max.Y-1), rect.Max}, image.White, image.ZP, draw.Src) draw.Draw(viewport, image.Rectangle{rect.Min, image.Pt(rect.Min.X+1, rect.Max.Y+1)}, image.White, image.ZP, draw.Src) draw.Draw(viewport, image.Rectangle{image.Pt(rect.Max.X-1, rect.Min.Y-1), rect.Max}, image.White, image.ZP, draw.Src) //*/ w.Screen().CopyRGBA(viewport, viewport.Bounds()) w.FlushImage(rect) }