diff --git a/graphics.go b/graphics.go index 2e81cd877f4f9a19843bbe5fb3c59716d73aecde..9b788982506bc33bb65b82c4a478ba5cc6154fb2 100644 --- a/graphics.go +++ b/graphics.go @@ -116,13 +116,12 @@ func (td *TrianglesData) Picture(i int) Vec { // the Sprite, use Target's SetTransform method. type Sprite struct { data TrianglesData - td TrianglesDrawer - pic *GLPicture + d Drawer } // NewSprite creates a Sprite with the supplied Picture. The dimensions of the returned Sprite match // the dimensions of the Picture. -func NewSprite(pic *GLPicture) *Sprite { +func NewSprite(pic Picture) *Sprite { s := &Sprite{ data: TrianglesData{ {Position: V(0, 0), Color: NRGBA{1, 1, 1, 1}, Picture: V(0, 0)}, @@ -133,15 +132,15 @@ func NewSprite(pic *GLPicture) *Sprite { {Position: V(0, 0), Color: NRGBA{1, 1, 1, 1}, Picture: V(0, 1)}, }, } - s.td = TrianglesDrawer{Triangles: &s.data} + s.d = Drawer{Triangles: &s.data} s.SetPicture(pic) return s } // SetPicture changes the Picture of the Sprite and resizes it accordingly. -func (s *Sprite) SetPicture(pic *GLPicture) { - oldPic := s.pic - s.pic = pic +func (s *Sprite) SetPicture(pic Picture) { + oldPic := s.d.Picture + s.d.Picture = pic if oldPic != nil && oldPic.Bounds().Size == pic.Bounds().Size { return } @@ -152,23 +151,23 @@ func (s *Sprite) SetPicture(pic *GLPicture) { s.data[3].Position = V(0, 0) s.data[4].Position = V(w, h) s.data[5].Position = V(0, h) - s.td.Dirty() + s.d.Dirty() } // Picture returns the current Picture of the Sprite. -func (s *Sprite) Picture() *GLPicture { - return s.pic +func (s *Sprite) Picture() Picture { + return s.d.Picture } // Draw draws the Sprite onto the provided Target. func (s *Sprite) Draw(t Target) { - s.td.Draw(t) + s.d.Draw(t) } // Polygon is a convex polygon shape filled with a single color. type Polygon struct { data TrianglesData - td TrianglesDrawer + d Drawer col NRGBA } @@ -178,7 +177,7 @@ func NewPolygon(c color.Color, points ...Vec) *Polygon { p := &Polygon{ data: TrianglesData{}, } - p.td = TrianglesDrawer{Triangles: &p.data} + p.d = Drawer{Triangles: &p.data} p.SetColor(c) p.SetPoints(points...) return p @@ -193,7 +192,7 @@ func (p *Polygon) SetColor(c color.Color) { for i := range p.data { p.data[i].Color = p.col } - p.td.Dirty() + p.d.Dirty() } // Color returns the current color of the Polygon. @@ -217,7 +216,7 @@ func (p *Polygon) SetPoints(points ...Vec) { for i := range p.data { p.data[i].Color = p.col } - p.td.Dirty() + p.d.Dirty() } // Points returns a slice of points of the Polygon in the order they where supplied. @@ -231,5 +230,5 @@ func (p *Polygon) Points() []Vec { // Draw draws the Polygon onto the Target. func (p *Polygon) Draw(t Target) { - p.td.Draw(t) + p.d.Draw(t) } diff --git a/interface.go b/interface.go index 059bc3ca4dff53454490b3eade31dbd03412d465..18dfe910ba94e10771d32f6470738c779cfc90c4 100644 --- a/interface.go +++ b/interface.go @@ -31,9 +31,9 @@ type BasicTarget interface { // Triangles. SetTransform(...Transform) - // SetMaskColor sets a color that will be multiplied with the TrianglesColor property of all + // SetMColorMask sets a color that will be multiplied with the TrianglesColor property of all // Triangles. - SetMaskColor(color.Color) + SetColorMask(color.Color) } // Triangles represents a list of vertices, where each three vertices form a triangle. (First, @@ -69,14 +69,8 @@ type Triangles interface { Copy() Triangles } -//TODO: doc -type Picture interface { - Bounds() Rect - Slice(Rect) Picture -} - // TargetTriangles are Triangles generated by a Target with MakeTriangles method. They can be drawn -// onto that Target. +// onto that (no other) Target. type TargetTriangles interface { Triangles @@ -84,13 +78,6 @@ type TargetTriangles interface { Draw() } -//TODO: doc -type TargetPicture interface { - Picture - - Draw(TargetTriangles) -} - // TrianglesPosition specifies Triangles with Position property. type TrianglesPosition interface { Triangles @@ -110,3 +97,32 @@ type TrianglesPicture interface { Triangles Picture(i int) Vec } + +// Picture represents a rectangular area of raster data, such as a color. It has Bounds which +// specify the rectangle where data is located. +type Picture interface { + // Bounds returns the rectangle of the Picture. All data is located witih this rectangle. + // Querying properties outside the rectangle should return default value of that property. + Bounds() Rect + + // Slice returns a sub-Picture with specified Bounds. + Slice(Rect) Picture +} + +// TargetPicture is a Picture generated by a Target using MakePicture method. This Picture can be drawn onto +// that (no other) Target together with a TargetTriangles generated by the same Target. +// +// The TargetTriangles specify where, shape and how the Picture should be drawn. +type TargetPicture interface { + Picture + + Draw(TargetTriangles) +} + +// PictureColor specifies Picture with Color property, so that every position inside the Picture's +// Bounds has a color. +// +// Positions outside the Picture's Bounds must return opaque white (NRGBA{R: 1, G: 1, B:1, A: 1}). +type PictureColor interface { + Color(at Vec) NRGBA +} diff --git a/picture.go b/picture.go deleted file mode 100644 index cc89f550ec4f62ab2ccd44ccfa927bab30f28348..0000000000000000000000000000000000000000 --- a/picture.go +++ /dev/null @@ -1,113 +0,0 @@ -package pixel - -import ( - "image" - "image/draw" - - "github.com/faiface/glhf" - "github.com/faiface/mainthread" -) - -// GLPicture is a raster picture. It is usually used with sprites. -// -// A GLPicture is created from an image.Image, that can be either loaded from a file, or -// generated. After the creation, Pictures can be sliced (slicing creates a "sub-GLPicture" -// from a GLPicture) into smaller Pictures. -type GLPicture struct { - tex *glhf.Texture - bounds Rect -} - -// NewPicture creates a new Picture from an image.Image. -func NewPicture(img image.Image, smooth bool) *GLPicture { - // convert the image to NRGBA format - bounds := img.Bounds() - nrgba := image.NewNRGBA(image.Rect(0, 0, bounds.Dx(), bounds.Dy())) - draw.Draw(nrgba, nrgba.Bounds(), img, bounds.Min, draw.Src) - - // flip the image vertically - tmp := make([]byte, nrgba.Stride) - for i, j := 0, bounds.Dy()-1; i < j; i, j = i+1, j-1 { - iSlice := nrgba.Pix[i*nrgba.Stride : (i+1)*nrgba.Stride] - jSlice := nrgba.Pix[j*nrgba.Stride : (j+1)*nrgba.Stride] - copy(tmp, iSlice) - copy(iSlice, jSlice) - copy(jSlice, tmp) - } - - var tex *glhf.Texture - mainthread.Call(func() { - tex = glhf.NewTexture( - img.Bounds().Dx(), - img.Bounds().Dy(), - smooth, - nrgba.Pix, - ) - }) - - return PictureFromTexture(tex) -} - -// PictureFromTexture returns a new Picture that spans the whole supplied Texture. -func PictureFromTexture(tex *glhf.Texture) *GLPicture { - return &GLPicture{ - tex: tex, - bounds: R(0, 0, float64(tex.Width()), float64(tex.Height())), - } -} - -// Image returns the content of the Picture as an image.NRGBA. -// -// Note, that this operation can be rather expensive. -func (p *GLPicture) Image() *image.NRGBA { - bounds := p.Bounds() - nrgba := image.NewNRGBA(image.Rect(0, 0, int(bounds.W()), int(bounds.H()))) - - mainthread.Call(func() { - p.tex.Begin() - nrgba.Pix = p.tex.Pixels( - int(bounds.X()), - int(bounds.Y()), - int(bounds.W()), - int(bounds.H()), - ) - p.tex.End() - }) - - // flip the image vertically - tmp := make([]byte, nrgba.Stride) - for i, j := 0, nrgba.Bounds().Dy()-1; i < j; i, j = i+1, j-1 { - iSlice := nrgba.Pix[i*nrgba.Stride : (i+1)*nrgba.Stride] - jSlice := nrgba.Pix[j*nrgba.Stride : (j+1)*nrgba.Stride] - copy(tmp, iSlice) - copy(iSlice, jSlice) - copy(jSlice, tmp) - } - - return nrgba -} - -// Texture returns a pointer to the underlying OpenGL texture of the Picture. -func (p *GLPicture) Texture() *glhf.Texture { - return p.tex -} - -// Slice returns a Picture within the supplied rectangle of the original picture. The original -// and the sliced Picture share the same texture. -// -// For example, suppose we have a 100x200 pixels Picture. If we slice it with rectangle (50, -// 100, 50, 100), we get the upper-right quadrant of the original Picture. -func (p *GLPicture) Slice(slice Rect) *GLPicture { - return &GLPicture{ - tex: p.tex, - bounds: Rect{p.bounds.Pos + slice.Pos, slice.Size}, - } -} - -// Bounds returns the bounding rectangle of this Picture relative to the most original picture. -// -// If the original Picture was sliced with the return value of this method, this Picture would -// be obtained. -func (p *GLPicture) Bounds() Rect { - return p.bounds -} diff --git a/util.go b/util.go index 654ba4c3639a48904d7493f625977922324a90cc..45f5ba28cd8a408a6eec0df77a4be34468bf8381 100644 --- a/util.go +++ b/util.go @@ -31,8 +31,8 @@ func transformToMat(t ...Transform) mgl32.Mat3 { return mat } -func pictureBounds(p *GLPicture, v Vec) Vec { - w, h := float64(p.Texture().Width()), float64(p.Texture().Height()) +func pictureBounds(p Picture, v Vec) Vec { + w, h := p.Bounds().Size.XY() a := p.Bounds().Pos b := p.Bounds().Pos + p.Bounds().Size u := lerp2d(v, a, b)