// Copyright 2012 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.

// This file contains the code snippets included in "The Go image/draw package."

package main

import (
	"image"
	"image/color"
	"image/draw"
)

func main() {
	Color()
	Rect()
	RectAndScroll()
	ConvAndCircle()
	Glyph()
}

func Color() {
	c := color.RGBA{255, 0, 255, 255}
	r := image.Rect(0, 0, 640, 480)
	dst := image.NewRGBA(r)

	// ZERO OMIT
	// image.ZP is the zero point -- the origin.
	draw.Draw(dst, r, &image.Uniform{c}, image.ZP, draw.Src)
	// STOP OMIT

	// BLUE OMIT
	m := image.NewRGBA(image.Rect(0, 0, 640, 480))
	blue := color.RGBA{0, 0, 255, 255}
	draw.Draw(m, m.Bounds(), &image.Uniform{blue}, image.ZP, draw.Src)
	// STOP OMIT

	// RESET OMIT
	draw.Draw(m, m.Bounds(), image.Transparent, image.ZP, draw.Src)
	// STOP OMIT
}

func Rect() {
	dst := image.NewRGBA(image.Rect(0, 0, 640, 480))
	sr := image.Rect(0, 0, 200, 200)
	src := image.Black
	dp := image.Point{100, 100}

	// RECT OMIT
	r := image.Rectangle{dp, dp.Add(sr.Size())}
	draw.Draw(dst, r, src, sr.Min, draw.Src)
	// STOP OMIT
}

func RectAndScroll() {
	dst := image.NewRGBA(image.Rect(0, 0, 640, 480))
	sr := image.Rect(0, 0, 200, 200)
	src := image.Black
	dp := image.Point{100, 100}

	// RECT2 OMIT
	r := sr.Sub(sr.Min).Add(dp)
	draw.Draw(dst, r, src, sr.Min, draw.Src)
	// STOP OMIT

	m := dst

	// SCROLL OMIT
	b := m.Bounds()
	p := image.Pt(0, 20)
	// Note that even though the second argument is b,
	// the effective rectangle is smaller due to clipping.
	draw.Draw(m, b, m, b.Min.Add(p), draw.Src)
	dirtyRect := b.Intersect(image.Rect(b.Min.X, b.Max.Y-20, b.Max.X, b.Max.Y))
	// STOP OMIT

	_ = dirtyRect // noop
}

func ConvAndCircle() {
	src := image.NewRGBA(image.Rect(0, 0, 640, 480))
	dst := image.NewRGBA(image.Rect(0, 0, 640, 480))

	// CONV OMIT
	b := src.Bounds()
	m := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
	draw.Draw(m, m.Bounds(), src, b.Min, draw.Src)
	// STOP OMIT

	p := image.Point{100, 100}
	r := 50

	// CIRCLE2 OMIT
	draw.DrawMask(dst, dst.Bounds(), src, image.ZP, &circle{p, r}, image.ZP, draw.Over)
	// STOP OMIT
}

func theGlyphImageForAFont() image.Image {
	return image.NewRGBA(image.Rect(0, 0, 640, 480))
}

func theBoundsFor(index int) image.Rectangle {
	return image.Rect(0, 0, 32, 32)
}

func Glyph() {
	p := image.Point{100, 100}
	dst := image.NewRGBA(image.Rect(0, 0, 640, 480))
	glyphIndex := 42

	// GLYPH OMIT
	src := &image.Uniform{color.RGBA{0, 0, 255, 255}}
	mask := theGlyphImageForAFont()
	mr := theBoundsFor(glyphIndex)
	draw.DrawMask(dst, mr.Sub(mr.Min).Add(p), src, image.ZP, mask, mr.Min, draw.Over)
	// STOP OMIT
}

//CIRCLESTRUCT OMIT
type circle struct {
	p image.Point
	r int
}

func (c *circle) ColorModel() color.Model {
	return color.AlphaModel
}

func (c *circle) Bounds() image.Rectangle {
	return image.Rect(c.p.X-c.r, c.p.Y-c.r, c.p.X+c.r, c.p.Y+c.r)
}

func (c *circle) At(x, y int) color.Color {
	xx, yy, rr := float64(x-c.p.X)+0.5, float64(y-c.p.Y)+0.5, float64(c.r)
	if xx*xx+yy*yy < rr*rr {
		return color.Alpha{255}
	}
	return color.Alpha{0}
}

//STOP OMIT
