add Picture interface

This commit is contained in:
faiface 2017-02-24 01:21:11 +01:00
parent c1843b8608
commit bffb3598c7
4 changed files with 49 additions and 147 deletions

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)