graphics: Add DrawImageOptions.SourceRect

This commit is contained in:
Hajime Hoshi 2017-01-18 01:35:21 +09:00
parent 8614599c5c
commit de7215f3fc
4 changed files with 109 additions and 124 deletions

View File

@ -76,25 +76,6 @@ func (s *Sprites) Update() {
}
}
func (s *Sprites) Len() int {
return s.num
}
func (s *Sprites) Dst(i int) (x0, y0, x1, y1 int) {
if s.num <= i {
return 0, 0, 0, 0
}
ss := s.sprites[i]
return ss.x, ss.y, ss.x + ebitenImageWidth, ss.y + ebitenImageHeight
}
func (s *Sprites) Src(i int) (x0, y0, x1, y1 int) {
if s.num <= i {
return 0, 0, 0, 0
}
return 0, 0, ebitenImageWidth, ebitenImageHeight
}
const (
MinSprites = 0
MaxSprites = 50000
@ -102,6 +83,13 @@ const (
var sprites = &Sprites{make([]*Sprite, MaxSprites), 500}
var op *ebiten.DrawImageOptions
func init() {
op = &ebiten.DrawImageOptions{}
op.ColorM.Scale(1.0, 1.0, 1.0, 0.5)
}
func update(screen *ebiten.Image) error {
if ebiten.IsKeyPressed(ebiten.KeyLeft) {
sprites.num -= 20
@ -120,15 +108,18 @@ func update(screen *ebiten.Image) error {
if ebiten.IsRunningSlowly() {
return nil
}
op := &ebiten.DrawImageOptions{
ImageParts: sprites,
for i := 0; i < sprites.num; i++ {
s := sprites.sprites[i]
op.GeoM = ebiten.GeoM{}
op.GeoM.Translate(float64(s.x), float64(s.y))
screen.DrawImage(ebitenImage, op)
}
op.ColorM.Scale(1.0, 1.0, 1.0, 0.5)
screen.DrawImage(ebitenImage, op)
msg := fmt.Sprintf(`FPS: %0.2f
Num of sprites: %d
Press <- or -> to change the number of sprites`, ebiten.CurrentFPS(), sprites.Len())
ebitenutil.DebugPrint(screen, msg)
Press <- or -> to change the number of sprites`, ebiten.CurrentFPS(), sprites.num)
if err := ebitenutil.DebugPrint(screen, msg); err != nil {
return err
}
return nil
}

View File

@ -79,8 +79,7 @@ func (i *Image) Fill(clr color.Color) error {
// After determining parts to draw, this applies the geometry matrix and the color matrix.
//
// Here are the default values:
// ImageParts: (0, 0) - (source width, source height) to (0, 0) - (source width, source height)
// (i.e. the whole source image)
// SourceRect: nil. When SourceRect is nil, the whole source image is used.
// GeoM: Identity matrix
// ColorM: Identity matrix (that changes no colors)
// CompositeMode: CompositeModeSourceOver (regular alpha blending)
@ -94,7 +93,7 @@ func (i *Image) Fill(clr color.Color) error {
// When image is as same as i, DrawImage panics.
//
// DrawImage always returns nil as of 1.5.0-alpha.
func (i *Image) DrawImage(image *Image, options *DrawImageOptions) error {
func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error {
if i.restorable == nil {
return nil
}
@ -104,26 +103,45 @@ func (i *Image) DrawImage(image *Image, options *DrawImageOptions) error {
options = &DrawImageOptions{}
}
parts := options.ImageParts
if parts == nil {
// Check options.Parts for backward-compatibility.
dparts := options.Parts
if dparts != nil {
parts = imageParts(dparts)
} else {
w, h := image.restorable.Size()
parts = &wholeImage{w, h}
}
// Parts is deprecated. This implementations is for backward compatibility.
if parts == nil && options.Parts != nil {
parts = imageParts(options.Parts)
}
w, h := image.restorable.Size()
vs := vertices(parts, w, h, &options.GeoM.impl)
if len(vs) == 0 {
// ImageParts is deprecated. This implementations is for backward compatibility.
if parts != nil {
l := parts.Len()
for idx := 0; idx < l; idx++ {
sx0, sy0, sx1, sy1 := parts.Src(idx)
dx0, dy0, dx1, dy1 := parts.Dst(idx)
op := &DrawImageOptions{
ColorM: options.ColorM,
CompositeMode: options.CompositeMode,
}
r := image.Rect(sx0, sy0, sx1, sy1)
op.SourceRect = &r
op.GeoM.Scale(
float64(dx1-dx0)/float64(sx1-sx0),
float64(dy1-dy0)/float64(sy1-sy0))
op.GeoM.Translate(float64(dx0), float64(dy0))
op.GeoM.Concat(options.GeoM)
i.DrawImage(img, op)
}
return nil
}
if i == image {
panic("ebiten: Image.DrawImage: image must be different from the receiver")
w, h := img.restorable.Size()
sx0, sy0, sx1, sy1 := 0, 0, w, h
if r := options.SourceRect; r != nil {
sx0 = r.Min.X
sy0 = r.Min.Y
sx1 = r.Max.X
sy1 = r.Max.Y
}
vs := vertices(sx0, sy0, sx1, sy1, w, h, &options.GeoM.impl)
if i == img {
panic("ebiten: Image.DrawImage: img must be different from the receiver")
}
mode := opengl.CompositeMode(options.CompositeMode)
i.restorable.DrawImage(image.restorable, vs, &options.ColorM.impl, mode)
i.restorable.DrawImage(img.restorable, vs, &options.ColorM.impl, mode)
return nil
}
@ -203,12 +221,15 @@ func (i *Image) ReplacePixels(p []uint8) error {
// A DrawImageOptions represents options to render an image on an image.
type DrawImageOptions struct {
ImageParts ImageParts
SourceRect *image.Rectangle
GeoM GeoM
ColorM ColorM
CompositeMode CompositeMode
// Deprecated (as of 1.1.0-alpha): Use ImageParts instead.
// Deprecated (as of 1.5.0-alpha): Use Part instead.
ImageParts ImageParts
// Deprecated (as of 1.1.0-alpha): Use Part instead.
Parts []ImagePart
}

View File

@ -18,13 +18,13 @@ import (
"image"
)
// An ImagePart is deprecated (as of 1.1.0-alpha): Use ImageParts instead.
// An ImagePart is deprecated (as of 1.1.0-alpha): Use SourceRect instead.
type ImagePart struct {
Dst image.Rectangle
Src image.Rectangle
}
// An ImageParts represents the parts of the destination image and the parts of the source image.
// An ImageParts is deprecated (as of 1.5.0-alpha): Use SourceRect instead.
type ImageParts interface {
Len() int
Dst(i int) (x0, y0, x1, y1 int)
@ -47,20 +47,3 @@ func (p imageParts) Src(i int) (x0, y0, x1, y1 int) {
src := &p[i].Src
return src.Min.X, src.Min.Y, src.Max.X, src.Max.Y
}
type wholeImage struct {
width int
height int
}
func (w *wholeImage) Len() int {
return 1
}
func (w *wholeImage) Dst(i int) (x0, y0, x1, y1 int) {
return 0, 0, w.width, w.height
}
func (w *wholeImage) Src(i int) (x0, y0, x1, y1 int) {
return 0, 0, w.width, w.height
}

View File

@ -27,10 +27,12 @@ const texelAdjustment = 256
var quadFloat32Num = graphics.QuadVertexSizeInBytes() / 4
func vertices(parts ImageParts, width, height int, geo *affine.GeoM) []float32 {
func vertices(sx0, sy0, sx1, sy1 int, width, height int, geo *affine.GeoM) []float32 {
if sx0 == sx1 || sy0 == sy1 {
return nil
}
// TODO: This function should be in graphics package?
l := parts.Len()
vs := make([]float32, l*quadFloat32Num)
vs := make([]float32, quadFloat32Num)
a, b, c, d, tx, ty := geo.Elements()
g0 := float32(a)
g1 := float32(b)
@ -48,66 +50,54 @@ func vertices(parts ImageParts, width, height int, geo *affine.GeoM) []float32 {
}
wf := float32(w)
hf := float32(h)
n := 0
for i := 0; i < l; i++ {
dx0, dy0, dx1, dy1 := parts.Dst(i)
if dx0 == dx1 || dy0 == dy1 {
continue
}
x0, y0, x1, y1 := float32(dx0), float32(dy0), float32(dx1), float32(dy1)
sx0, sy0, sx1, sy1 := parts.Src(i)
if sx0 == sx1 || sy0 == sy1 {
continue
}
u0, v0, u1, v1 := float32(sx0)/wf, float32(sy0)/hf, float32(sx1)/wf, float32(sy1)/hf
// Adjust texels to fix a problem that outside texels are used (#317).
u1 -= 1.0 / wf / texelAdjustment
v1 -= 1.0 / hf / texelAdjustment
vs[n] = x0
vs[n+1] = y0
vs[n+2] = u0
vs[n+3] = v0
vs[n+4] = g0
vs[n+5] = g1
vs[n+6] = g2
vs[n+7] = g3
vs[n+8] = g4
vs[n+9] = g5
x0, y0, x1, y1 := float32(0), float32(0), float32(sx1-sx0), float32(sy1-sy0)
u0, v0, u1, v1 := float32(sx0)/wf, float32(sy0)/hf, float32(sx1)/wf, float32(sy1)/hf
// Adjust texels to fix a problem that outside texels are used (#317).
u1 -= 1.0 / wf / texelAdjustment
v1 -= 1.0 / hf / texelAdjustment
vs[0] = x0
vs[1] = y0
vs[2] = u0
vs[3] = v0
vs[4] = g0
vs[5] = g1
vs[6] = g2
vs[7] = g3
vs[8] = g4
vs[9] = g5
vs[n+10] = x1
vs[n+11] = y0
vs[n+12] = u1
vs[n+13] = v0
vs[n+14] = g0
vs[n+15] = g1
vs[n+16] = g2
vs[n+17] = g3
vs[n+18] = g4
vs[n+19] = g5
vs[10] = x1
vs[11] = y0
vs[12] = u1
vs[13] = v0
vs[14] = g0
vs[15] = g1
vs[16] = g2
vs[17] = g3
vs[18] = g4
vs[19] = g5
vs[n+20] = x0
vs[n+21] = y1
vs[n+22] = u0
vs[n+23] = v1
vs[n+24] = g0
vs[n+25] = g1
vs[n+26] = g2
vs[n+27] = g3
vs[n+28] = g4
vs[n+29] = g5
vs[20] = x0
vs[21] = y1
vs[22] = u0
vs[23] = v1
vs[24] = g0
vs[25] = g1
vs[26] = g2
vs[27] = g3
vs[28] = g4
vs[29] = g5
vs[n+30] = x1
vs[n+31] = y1
vs[n+32] = u1
vs[n+33] = v1
vs[n+34] = g0
vs[n+35] = g1
vs[n+36] = g2
vs[n+37] = g3
vs[n+38] = g4
vs[n+39] = g5
vs[30] = x1
vs[31] = y1
vs[32] = u1
vs[33] = v1
vs[34] = g0
vs[35] = g1
vs[36] = g2
vs[37] = g3
vs[38] = g4
vs[39] = g5
n += quadFloat32Num
}
return vs
}