mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 11:18:54 +01:00
ebiten: add NewImageFromImageWithOptions
Closes #2013 Closes #2017 Closes #2124
This commit is contained in:
parent
aee2e67242
commit
acd70d6e34
57
image.go
57
image.go
@ -815,6 +815,8 @@ type NewImageOptions struct {
|
||||
// If DrawImage is called on a new image created by NewImageOptions,
|
||||
// for example, the center of scaling and rotating is (0, 0), that might not be a left-upper position.
|
||||
//
|
||||
// If options is nil, the default setting is used.
|
||||
//
|
||||
// NewImageWithOptions should be called only when necessary.
|
||||
// For example, you should avoid to call NewImageWithOptions every Update or Draw call.
|
||||
// Reusing the same image by Clear is much more efficient than creating a new image.
|
||||
@ -859,19 +861,62 @@ func newImage(bounds image.Rectangle, imageType atlas.ImageType) *Image {
|
||||
//
|
||||
// NewImageFromImage panics if RunGame already finishes.
|
||||
//
|
||||
// The returned image's origin is always (0, 0). The source's bounds are not respected.
|
||||
// The returned image's left-upper position is always (0, 0). The source's bounds are not respected.
|
||||
func NewImageFromImage(source image.Image) *Image {
|
||||
if isRunGameEnded() {
|
||||
panic(fmt.Sprintf("ebiten: NewImage cannot be called after RunGame finishes"))
|
||||
return NewImageFromImageWithOptions(source, nil)
|
||||
}
|
||||
|
||||
// NewImageFromImageOptions represents options for NewImageFromImage.
|
||||
type NewImageFromImageOptions struct {
|
||||
// Unmanaged represents whether the image is unmanaged or not.
|
||||
// The default (zero) value is false, that means the image is managed.
|
||||
//
|
||||
// An unmanged image is never on an internal automatic texture atlas.
|
||||
// A regular image is a part of an internal texture atlas, and locating them is done automatically in Ebitengine.
|
||||
// NewUnmanagedImage is useful when you want finer controls over the image for performance and memory reasons.
|
||||
Unmanaged bool
|
||||
|
||||
// PreserveBounds represents whether the new image's bounds are the same as the given image.
|
||||
// The default (zero) value is false, that means the new image's left-upper position is adjusted to (0, 0).
|
||||
PreserveBounds bool
|
||||
}
|
||||
|
||||
// NewImageFromImageWithOptions creates a new image with the given image (source) with the given options.
|
||||
//
|
||||
// If source's width or height is less than 1 or more than device-dependent maximum size, NewImageFromImageWithOptions panics.
|
||||
//
|
||||
// If options is nil, the default setting is used.
|
||||
//
|
||||
// NewImageFromImageWithOptions should be called only when necessary.
|
||||
// For example, you should avoid to call NewImageFromImageWithOptions every Update or Draw call.
|
||||
// Reusing the same image by Clear and ReplacePixels is much more efficient than creating a new image.
|
||||
//
|
||||
// NewImageFromImageWithOptions panics if RunGame already finishes.
|
||||
func NewImageFromImageWithOptions(source image.Image, options *NewImageFromImageOptions) *Image {
|
||||
if options == nil {
|
||||
options = &NewImageFromImageOptions{}
|
||||
}
|
||||
|
||||
size := source.Bounds().Size()
|
||||
i := NewImage(size.X, size.Y)
|
||||
var r image.Rectangle
|
||||
if options.PreserveBounds {
|
||||
r = source.Bounds()
|
||||
} else {
|
||||
size := source.Bounds().Size()
|
||||
r = image.Rect(0, 0, size.X, size.Y)
|
||||
}
|
||||
i := NewImageWithOptions(r, &NewImageOptions{
|
||||
Unmanaged: options.Unmanaged,
|
||||
})
|
||||
|
||||
// If the given image is an Ebitengine image, use DrawImage instead of reading pixels from the source.
|
||||
// This works even before the game loop runs.
|
||||
if source, ok := source.(*Image); ok {
|
||||
i.DrawImage(source, nil)
|
||||
op := &DrawImageOptions{}
|
||||
if options.PreserveBounds {
|
||||
b := source.Bounds()
|
||||
op.GeoM.Translate(float64(b.Min.X), float64(b.Min.Y))
|
||||
}
|
||||
i.DrawImage(source, op)
|
||||
return i
|
||||
}
|
||||
|
||||
|
@ -3045,7 +3045,7 @@ func TestImageOptionsNegativeBoundsDrawImage(t *testing.T) {
|
||||
want = color.RGBA{0xff, 0xff, 0xff, 0xff}
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("img.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||
t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3115,6 +3115,65 @@ func TestImageOptionsNegativeBoundsDrawTriangles(t *testing.T) {
|
||||
if -2 <= i && i < 2 && -3 <= j && j < 3 {
|
||||
want = color.RGBA{0xff, 0xff, 0xff, 0xff}
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageFromImageOptions(t *testing.T) {
|
||||
r := image.Rect(-2, -3, 4, 5)
|
||||
pix := make([]byte, 4*r.Dx()*r.Dy())
|
||||
for i := range pix {
|
||||
pix[i] = 0xff
|
||||
}
|
||||
src := &image.RGBA{
|
||||
Pix: pix,
|
||||
Stride: 4 * 2,
|
||||
Rect: r,
|
||||
}
|
||||
|
||||
op := &ebiten.NewImageFromImageOptions{
|
||||
PreserveBounds: true,
|
||||
}
|
||||
img := ebiten.NewImageFromImageWithOptions(src, op)
|
||||
if got, want := img.Bounds(), r; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
|
||||
for j := r.Min.Y; j < r.Max.Y; j++ {
|
||||
for i := r.Min.X; i < r.Max.X; i++ {
|
||||
got := img.At(i, j)
|
||||
want := color.RGBA{0xff, 0xff, 0xff, 0xff}
|
||||
if got != want {
|
||||
t.Errorf("img.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageFromEbitenImageOptions(t *testing.T) {
|
||||
r := image.Rect(-2, -3, 4, 5)
|
||||
src := ebiten.NewImageWithOptions(r, nil)
|
||||
pix := make([]byte, 4*r.Dx()*r.Dy())
|
||||
for i := range pix {
|
||||
pix[i] = 0xff
|
||||
}
|
||||
src.ReplacePixels(pix)
|
||||
|
||||
op := &ebiten.NewImageFromImageOptions{
|
||||
PreserveBounds: true,
|
||||
}
|
||||
img := ebiten.NewImageFromImageWithOptions(src, op)
|
||||
if got, want := img.Bounds(), r; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
|
||||
for j := r.Min.Y; j < r.Max.Y; j++ {
|
||||
for i := r.Min.X; i < r.Max.X; i++ {
|
||||
got := img.At(i, j)
|
||||
want := color.RGBA{0xff, 0xff, 0xff, 0xff}
|
||||
if got != want {
|
||||
t.Errorf("img.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user