mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 02:38:53 +01:00
internal/atlas: refactoring: remove SetVolatile and SetIsolate
Pass an image type to NewImage instead.
This commit is contained in:
parent
b8e8d72377
commit
81f91658ff
13
gameforui.go
13
gameforui.go
@ -15,6 +15,7 @@
|
||||
package ebiten
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/ui"
|
||||
)
|
||||
|
||||
@ -34,7 +35,17 @@ func (c *gameForUI) NewOffscreenImage(width, height int) *ui.Image {
|
||||
c.offscreen.Dispose()
|
||||
c.offscreen = nil
|
||||
}
|
||||
c.offscreen = NewImage(width, height)
|
||||
|
||||
// Keep the offscreen an isolated image from an atlas (#1938).
|
||||
// The shader program for the screen is special and doesn't work well with an image on an atlas.
|
||||
// An image on an atlas is surrounded by a transparent edge,
|
||||
// and the shader program unexpectedly picks the pixel on the edges.
|
||||
imageType := atlas.ImageTypeIsolated
|
||||
if ui.IsScreenClearedEveryFrame() {
|
||||
// A violatile image is also always isolated.
|
||||
imageType = atlas.ImageTypeVolatile
|
||||
}
|
||||
c.offscreen = newImage(width, height, imageType)
|
||||
return c.offscreen.image
|
||||
}
|
||||
|
||||
|
9
image.go
9
image.go
@ -20,6 +20,7 @@ import (
|
||||
"image/color"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/affine"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/ui"
|
||||
@ -787,6 +788,10 @@ func (i *Image) ReplacePixels(pixels []byte) {
|
||||
//
|
||||
// NewImage panics if RunGame already finishes.
|
||||
func NewImage(width, height int) *Image {
|
||||
return newImage(width, height, atlas.ImageTypeRegular)
|
||||
}
|
||||
|
||||
func newImage(width, height int, imageType atlas.ImageType) *Image {
|
||||
if isRunGameEnded() {
|
||||
panic(fmt.Sprintf("ebiten: NewImage cannot be called after RunGame finishes"))
|
||||
}
|
||||
@ -797,7 +802,7 @@ func NewImage(width, height int) *Image {
|
||||
panic(fmt.Sprintf("ebiten: height at NewImage must be positive but %d", height))
|
||||
}
|
||||
i := &Image{
|
||||
image: ui.NewImage(width, height),
|
||||
image: ui.NewImage(width, height, imageType),
|
||||
bounds: image.Rect(0, 0, width, height),
|
||||
}
|
||||
i.addr = i
|
||||
@ -839,7 +844,7 @@ func NewImageFromImage(source image.Image) *Image {
|
||||
}
|
||||
|
||||
i := &Image{
|
||||
image: ui.NewImage(width, height),
|
||||
image: ui.NewImage(width, height, atlas.ImageTypeRegular),
|
||||
bounds: image.Rect(0, 0, width, height),
|
||||
}
|
||||
i.addr = i
|
||||
|
@ -206,14 +206,21 @@ func init() {
|
||||
backendsM.Lock()
|
||||
}
|
||||
|
||||
type ImageType int
|
||||
|
||||
const (
|
||||
ImageTypeRegular ImageType = iota
|
||||
ImageTypeScreen
|
||||
ImageTypeVolatile
|
||||
ImageTypeIsolated
|
||||
)
|
||||
|
||||
// Image is a rectangle pixel set that might be on an atlas.
|
||||
type Image struct {
|
||||
width int
|
||||
height int
|
||||
disposed bool
|
||||
isolated bool
|
||||
volatile bool
|
||||
screen bool
|
||||
width int
|
||||
height int
|
||||
imageType ImageType
|
||||
disposed bool
|
||||
|
||||
backend *backend
|
||||
|
||||
@ -284,7 +291,7 @@ func (i *Image) ensureIsolated() {
|
||||
sx1 /= float32(sw)
|
||||
sy1 /= float32(sh)
|
||||
typ := restorable.ImageTypeRegular
|
||||
if i.volatile {
|
||||
if i.imageType == ImageTypeVolatile {
|
||||
typ = restorable.ImageTypeVolatile
|
||||
}
|
||||
newImg := restorable.NewImage(w, h, typ)
|
||||
@ -326,11 +333,8 @@ func (i *Image) putOnAtlas(graphicsDriver graphicsdriver.Graphics) error {
|
||||
if !i.canBePutOnAtlas() {
|
||||
panic("atlas: putOnAtlas cannot be called on a image that cannot be on an atlas")
|
||||
}
|
||||
if i.volatile {
|
||||
panic("atlas: a volatile image cannot be put on an atlas")
|
||||
}
|
||||
|
||||
newI := NewImage(i.width, i.height)
|
||||
newI := NewImage(i.width, i.height, i.imageType)
|
||||
|
||||
if restorable.NeedsRestoring() {
|
||||
// If the underlying graphics driver requires restoring from the context lost, the pixel data is
|
||||
@ -433,7 +437,7 @@ func (i *Image) drawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []f
|
||||
|
||||
var dx, dy float32
|
||||
// A screen image doesn't have its padding.
|
||||
if !i.screen {
|
||||
if i.imageType != ImageTypeScreen {
|
||||
x, y, _, _ := i.regionWithPadding()
|
||||
dx = float32(x) + paddingSize
|
||||
dy = float32(y) + paddingSize
|
||||
@ -708,43 +712,20 @@ func (i *Image) dispose(markDisposed bool) {
|
||||
theBackends = append(theBackends[:index], theBackends[index+1:]...)
|
||||
}
|
||||
|
||||
func NewImage(width, height int) *Image {
|
||||
func NewImage(width, height int, imageType ImageType) *Image {
|
||||
// Actual allocation is done lazily, and the lock is not needed.
|
||||
return &Image{
|
||||
width: width,
|
||||
height: height,
|
||||
width: width,
|
||||
height: height,
|
||||
imageType: imageType,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Image) SetIsolated(isolated bool) {
|
||||
if i.backend != nil {
|
||||
panic("atlas: SetIsolated must be called before its backend is allocated")
|
||||
}
|
||||
i.isolated = isolated
|
||||
}
|
||||
|
||||
func (i *Image) SetVolatile(volatile bool) {
|
||||
i.volatile = volatile
|
||||
if i.backend == nil {
|
||||
return
|
||||
}
|
||||
if i.volatile {
|
||||
i.ensureIsolated()
|
||||
}
|
||||
i.backend.restorable.SetVolatile(i.volatile)
|
||||
}
|
||||
|
||||
func (i *Image) canBePutOnAtlas() bool {
|
||||
if minSize == 0 || maxSize == 0 {
|
||||
panic("atlas: minSize or maxSize must be initialized")
|
||||
}
|
||||
if i.isolated {
|
||||
return false
|
||||
}
|
||||
if i.volatile {
|
||||
return false
|
||||
}
|
||||
if i.screen {
|
||||
if i.imageType != ImageTypeRegular {
|
||||
return false
|
||||
}
|
||||
return i.width+2*paddingSize <= maxSize && i.height+2*paddingSize <= maxSize
|
||||
@ -757,7 +738,7 @@ func (i *Image) allocate(putOnAtlas bool) {
|
||||
|
||||
runtime.SetFinalizer(i, (*Image).MarkDisposed)
|
||||
|
||||
if i.screen {
|
||||
if i.imageType == ImageTypeScreen {
|
||||
// A screen image doesn't have a padding.
|
||||
i.backend = &backend{
|
||||
restorable: restorable.NewImage(i.width, i.height, restorable.ImageTypeScreen),
|
||||
@ -767,7 +748,7 @@ func (i *Image) allocate(putOnAtlas bool) {
|
||||
|
||||
if !putOnAtlas || !i.canBePutOnAtlas() {
|
||||
typ := restorable.ImageTypeRegular
|
||||
if i.volatile {
|
||||
if i.imageType == ImageTypeVolatile {
|
||||
typ = restorable.ImageTypeVolatile
|
||||
}
|
||||
i.backend = &backend{
|
||||
@ -792,7 +773,7 @@ func (i *Image) allocate(putOnAtlas bool) {
|
||||
}
|
||||
|
||||
typ := restorable.ImageTypeRegular
|
||||
if i.volatile {
|
||||
if i.imageType == ImageTypeVolatile {
|
||||
typ = restorable.ImageTypeVolatile
|
||||
}
|
||||
b := &backend{
|
||||
@ -816,16 +797,6 @@ func (i *Image) DumpScreenshot(graphicsDriver graphicsdriver.Graphics, path stri
|
||||
return i.backend.restorable.Dump(graphicsDriver, path, blackbg, image.Rect(paddingSize, paddingSize, paddingSize+i.width, paddingSize+i.height))
|
||||
}
|
||||
|
||||
func NewScreenFramebufferImage(width, height int) *Image {
|
||||
// Actual allocation is done lazily.
|
||||
i := &Image{
|
||||
width: width,
|
||||
height: height,
|
||||
screen: true,
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func EndFrame(graphicsDriver graphicsdriver.Graphics) error {
|
||||
backendsM.Lock()
|
||||
|
||||
|
@ -60,25 +60,25 @@ const bigSize = 2049
|
||||
func TestEnsureIsolated(t *testing.T) {
|
||||
// Create img1 and img2 with this size so that the next images are allocated
|
||||
// with non-upper-left location.
|
||||
img1 := atlas.NewImage(bigSize, 100)
|
||||
img1 := atlas.NewImage(bigSize, 100, atlas.ImageTypeRegular)
|
||||
defer img1.MarkDisposed()
|
||||
// Ensure img1's region is allocated.
|
||||
img1.ReplacePixels(make([]byte, 4*bigSize*100), nil)
|
||||
|
||||
img2 := atlas.NewImage(100, bigSize)
|
||||
img2 := atlas.NewImage(100, bigSize, atlas.ImageTypeRegular)
|
||||
defer img2.MarkDisposed()
|
||||
img2.ReplacePixels(make([]byte, 4*100*bigSize), nil)
|
||||
|
||||
const size = 32
|
||||
|
||||
img3 := atlas.NewImage(size/2, size/2)
|
||||
img3 := atlas.NewImage(size/2, size/2, atlas.ImageTypeRegular)
|
||||
defer img3.MarkDisposed()
|
||||
img3.ReplacePixels(make([]byte, (size/2)*(size/2)*4), nil)
|
||||
|
||||
img4 := atlas.NewImage(size, size)
|
||||
img4 := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer img4.MarkDisposed()
|
||||
|
||||
img5 := atlas.NewImage(size/2, size/2)
|
||||
img5 := atlas.NewImage(size/2, size/2, atlas.ImageTypeRegular)
|
||||
defer img3.MarkDisposed()
|
||||
|
||||
pix := make([]byte, size*size*4)
|
||||
@ -155,18 +155,18 @@ func TestEnsureIsolated(t *testing.T) {
|
||||
func TestReputOnAtlas(t *testing.T) {
|
||||
const size = 16
|
||||
|
||||
img0 := atlas.NewImage(size, size)
|
||||
img0 := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer img0.MarkDisposed()
|
||||
img0.ReplacePixels(make([]byte, 4*size*size), nil)
|
||||
|
||||
img1 := atlas.NewImage(size, size)
|
||||
img1 := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer img1.MarkDisposed()
|
||||
img1.ReplacePixels(make([]byte, 4*size*size), nil)
|
||||
if got, want := img1.IsOnAtlasForTesting(), true; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
|
||||
img2 := atlas.NewImage(size, size)
|
||||
img2 := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer img2.MarkDisposed()
|
||||
pix := make([]byte, 4*size*size)
|
||||
for j := 0; j < size; j++ {
|
||||
@ -179,8 +179,8 @@ func TestReputOnAtlas(t *testing.T) {
|
||||
}
|
||||
img2.ReplacePixels(pix, nil)
|
||||
|
||||
img3 := atlas.NewImage(size, size)
|
||||
img3.SetVolatile(true)
|
||||
// Create a volatile image. This should always be isolated.
|
||||
img3 := atlas.NewImage(size, size, atlas.ImageTypeVolatile)
|
||||
defer img3.MarkDisposed()
|
||||
img1.ReplacePixels(make([]byte, 4*size*size), nil)
|
||||
if got, want := img3.IsOnAtlasForTesting(), false; got != want {
|
||||
@ -303,7 +303,7 @@ func TestReputOnAtlas(t *testing.T) {
|
||||
|
||||
func TestExtend(t *testing.T) {
|
||||
const w0, h0 = 100, 100
|
||||
img0 := atlas.NewImage(w0, h0)
|
||||
img0 := atlas.NewImage(w0, h0, atlas.ImageTypeRegular)
|
||||
defer img0.MarkDisposed()
|
||||
|
||||
p0 := make([]byte, 4*w0*h0)
|
||||
@ -316,7 +316,7 @@ func TestExtend(t *testing.T) {
|
||||
img0.ReplacePixels(p0, nil)
|
||||
|
||||
const w1, h1 = minImageSizeForTesting + 1, 100
|
||||
img1 := atlas.NewImage(w1, h1)
|
||||
img1 := atlas.NewImage(w1, h1, atlas.ImageTypeRegular)
|
||||
defer img1.MarkDisposed()
|
||||
|
||||
p1 := make([]byte, 4*w1*h1)
|
||||
@ -370,9 +370,9 @@ func TestExtend(t *testing.T) {
|
||||
|
||||
func TestReplacePixelsAfterDrawTriangles(t *testing.T) {
|
||||
const w, h = 256, 256
|
||||
src := atlas.NewImage(w, h)
|
||||
src := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer src.MarkDisposed()
|
||||
dst := atlas.NewImage(w, h)
|
||||
dst := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer dst.MarkDisposed()
|
||||
|
||||
pix := make([]byte, 4*w*h)
|
||||
@ -418,9 +418,9 @@ func TestReplacePixelsAfterDrawTriangles(t *testing.T) {
|
||||
// Issue #887
|
||||
func TestSmallImages(t *testing.T) {
|
||||
const w, h = 4, 8
|
||||
src := atlas.NewImage(w, h)
|
||||
src := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer src.MarkDisposed()
|
||||
dst := atlas.NewImage(w, h)
|
||||
dst := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer dst.MarkDisposed()
|
||||
|
||||
pix := make([]byte, 4*w*h)
|
||||
@ -463,11 +463,11 @@ func TestSmallImages(t *testing.T) {
|
||||
// Issue #887
|
||||
func TestLongImages(t *testing.T) {
|
||||
const w, h = 1, 6
|
||||
src := atlas.NewImage(w, h)
|
||||
src := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
defer src.MarkDisposed()
|
||||
|
||||
const dstW, dstH = 256, 256
|
||||
dst := atlas.NewImage(dstW, dstH)
|
||||
dst := atlas.NewImage(dstW, dstH, atlas.ImageTypeRegular)
|
||||
defer dst.MarkDisposed()
|
||||
|
||||
pix := make([]byte, 4*w*h)
|
||||
@ -511,11 +511,11 @@ func TestLongImages(t *testing.T) {
|
||||
func TestDisposeImmediately(t *testing.T) {
|
||||
// This tests restorable.Image.ClearPixels is called but ReplacePixels is not called.
|
||||
|
||||
img0 := atlas.NewImage(16, 16)
|
||||
img0 := atlas.NewImage(16, 16, atlas.ImageTypeRegular)
|
||||
img0.EnsureIsolatedForTesting()
|
||||
defer img0.MarkDisposed()
|
||||
|
||||
img1 := atlas.NewImage(16, 16)
|
||||
img1 := atlas.NewImage(16, 16, atlas.ImageTypeRegular)
|
||||
img1.EnsureIsolatedForTesting()
|
||||
defer img1.MarkDisposed()
|
||||
|
||||
@ -524,12 +524,12 @@ func TestDisposeImmediately(t *testing.T) {
|
||||
|
||||
// Issue #1028
|
||||
func TestExtendWithBigImage(t *testing.T) {
|
||||
img0 := atlas.NewImage(1, 1)
|
||||
img0 := atlas.NewImage(1, 1, atlas.ImageTypeRegular)
|
||||
defer img0.MarkDisposed()
|
||||
|
||||
img0.ReplacePixels(make([]byte, 4*1*1), nil)
|
||||
|
||||
img1 := atlas.NewImage(minImageSizeForTesting+1, minImageSizeForTesting+1)
|
||||
img1 := atlas.NewImage(minImageSizeForTesting+1, minImageSizeForTesting+1, atlas.ImageTypeRegular)
|
||||
defer img1.MarkDisposed()
|
||||
|
||||
img1.ReplacePixels(make([]byte, 4*(minImageSizeForTesting+1)*(minImageSizeForTesting+1)), nil)
|
||||
@ -539,7 +539,7 @@ func TestExtendWithBigImage(t *testing.T) {
|
||||
func TestMaxImageSize(t *testing.T) {
|
||||
// This tests that a too-big image is allocated correctly.
|
||||
s := maxImageSizeForTesting - 2*atlas.PaddingSize
|
||||
img := atlas.NewImage(s, s)
|
||||
img := atlas.NewImage(s, s, atlas.ImageTypeRegular)
|
||||
defer img.MarkDisposed()
|
||||
img.ReplacePixels(make([]byte, 4*s*s), nil)
|
||||
}
|
||||
@ -552,7 +552,7 @@ func Disable_TestMinImageSize(t *testing.T) {
|
||||
// This tests that extending a backend works correctly.
|
||||
// Though the image size is minimum size of the backend, extending the backend happens due to the paddings.
|
||||
s := minImageSizeForTesting
|
||||
img := atlas.NewImage(s, s)
|
||||
img := atlas.NewImage(s, s, atlas.ImageTypeRegular)
|
||||
defer img.MarkDisposed()
|
||||
img.ReplacePixels(make([]byte, 4*s*s), nil)
|
||||
}
|
||||
@ -561,11 +561,11 @@ func Disable_TestMinImageSize(t *testing.T) {
|
||||
func TestDisposedAndReputOnAtlas(t *testing.T) {
|
||||
const size = 16
|
||||
|
||||
src := atlas.NewImage(size, size)
|
||||
src := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer src.MarkDisposed()
|
||||
src2 := atlas.NewImage(size, size)
|
||||
src2 := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer src2.MarkDisposed()
|
||||
dst := atlas.NewImage(size, size)
|
||||
dst := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer dst.MarkDisposed()
|
||||
|
||||
// Use src as a render target so that src is not on an atlas.
|
||||
@ -609,11 +609,11 @@ func TestDisposedAndReputOnAtlas(t *testing.T) {
|
||||
func TestImageIsNotReputOnAtlasWithoutUsingAsSource(t *testing.T) {
|
||||
const size = 16
|
||||
|
||||
src := atlas.NewImage(size, size)
|
||||
src := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer src.MarkDisposed()
|
||||
src2 := atlas.NewImage(size, size)
|
||||
src2 := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer src2.MarkDisposed()
|
||||
dst := atlas.NewImage(size, size)
|
||||
dst := atlas.NewImage(size, size, atlas.ImageTypeRegular)
|
||||
defer dst.MarkDisposed()
|
||||
|
||||
// Use src as a render target so that src is not on an atlas.
|
||||
|
@ -29,7 +29,7 @@ import (
|
||||
func TestShaderFillTwice(t *testing.T) {
|
||||
const w, h = 1, 1
|
||||
|
||||
dst := atlas.NewImage(w, h)
|
||||
dst := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
|
||||
vs := quadVertices(w, h, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
@ -60,10 +60,10 @@ func TestShaderFillTwice(t *testing.T) {
|
||||
func TestImageDrawTwice(t *testing.T) {
|
||||
const w, h = 1, 1
|
||||
|
||||
dst := atlas.NewImage(w, h)
|
||||
src0 := atlas.NewImage(w, h)
|
||||
dst := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
src0 := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
src0.ReplacePixels([]byte{0xff, 0xff, 0xff, 0xff}, nil)
|
||||
src1 := atlas.NewImage(w, h)
|
||||
src1 := atlas.NewImage(w, h, atlas.ImageTypeRegular)
|
||||
src1.ReplacePixels([]byte{0x80, 0x80, 0x80, 0xff}, nil)
|
||||
|
||||
vs := quadVertices(w, h, 0, 0, 1)
|
||||
|
@ -45,70 +45,25 @@ func EndFrame(graphicsDriver graphicsdriver.Graphics) error {
|
||||
return atlas.EndFrame(graphicsDriver)
|
||||
}
|
||||
|
||||
func NewImage(width, height int) *Image {
|
||||
func NewImage(width, height int, imageType atlas.ImageType) *Image {
|
||||
i := &Image{
|
||||
width: width,
|
||||
height: height,
|
||||
}
|
||||
i.initialize()
|
||||
i.initialize(imageType)
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *Image) initialize() {
|
||||
func (i *Image) initialize(imageType atlas.ImageType) {
|
||||
if maybeCanAddDelayedCommand() {
|
||||
if tryAddDelayedCommand(func() error {
|
||||
i.initialize()
|
||||
i.initialize(imageType)
|
||||
return nil
|
||||
}) {
|
||||
return
|
||||
}
|
||||
}
|
||||
i.img = atlas.NewImage(i.width, i.height)
|
||||
}
|
||||
|
||||
func (i *Image) SetIsolated(isolated bool) {
|
||||
if maybeCanAddDelayedCommand() {
|
||||
if tryAddDelayedCommand(func() error {
|
||||
i.SetIsolated(isolated)
|
||||
return nil
|
||||
}) {
|
||||
return
|
||||
}
|
||||
}
|
||||
i.img.SetIsolated(isolated)
|
||||
}
|
||||
|
||||
func (i *Image) SetVolatile(volatile bool) {
|
||||
if maybeCanAddDelayedCommand() {
|
||||
if tryAddDelayedCommand(func() error {
|
||||
i.SetVolatile(volatile)
|
||||
return nil
|
||||
}) {
|
||||
return
|
||||
}
|
||||
}
|
||||
i.img.SetVolatile(volatile)
|
||||
}
|
||||
|
||||
func NewScreenFramebufferImage(width, height int) *Image {
|
||||
i := &Image{}
|
||||
i.initializeAsScreenFramebuffer(width, height)
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *Image) initializeAsScreenFramebuffer(width, height int) {
|
||||
if maybeCanAddDelayedCommand() {
|
||||
if tryAddDelayedCommand(func() error {
|
||||
i.initializeAsScreenFramebuffer(width, height)
|
||||
return nil
|
||||
}) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
i.img = atlas.NewScreenFramebufferImage(width, height)
|
||||
i.width = width
|
||||
i.height = height
|
||||
i.img = atlas.NewImage(i.width, i.height, imageType)
|
||||
}
|
||||
|
||||
func (i *Image) invalidatePixels() {
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"math"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/affine"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/buffered"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
@ -35,38 +36,15 @@ type Mipmap struct {
|
||||
imgs map[int]*buffered.Image
|
||||
}
|
||||
|
||||
func New(width, height int) *Mipmap {
|
||||
func New(width, height int, imageType atlas.ImageType) *Mipmap {
|
||||
return &Mipmap{
|
||||
width: width,
|
||||
height: height,
|
||||
orig: buffered.NewImage(width, height),
|
||||
width: width,
|
||||
height: height,
|
||||
orig: buffered.NewImage(width, height, imageType),
|
||||
volatile: imageType == atlas.ImageTypeVolatile,
|
||||
}
|
||||
}
|
||||
|
||||
func NewScreenFramebufferMipmap(width, height int) *Mipmap {
|
||||
return &Mipmap{
|
||||
width: width,
|
||||
height: height,
|
||||
orig: buffered.NewScreenFramebufferImage(width, height),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Mipmap) SetIsolated(isolated bool) {
|
||||
m.orig.SetIsolated(isolated)
|
||||
}
|
||||
|
||||
func (m *Mipmap) SetVolatile(volatile bool) {
|
||||
if m.volatile == volatile {
|
||||
return
|
||||
}
|
||||
|
||||
m.volatile = volatile
|
||||
if m.volatile {
|
||||
m.disposeMipmaps()
|
||||
}
|
||||
m.orig.SetVolatile(volatile)
|
||||
}
|
||||
|
||||
func (m *Mipmap) DumpScreenshot(graphicsDriver graphicsdriver.Graphics, name string, blackbg bool) error {
|
||||
return m.orig.DumpScreenshot(graphicsDriver, name, blackbg)
|
||||
}
|
||||
@ -203,8 +181,7 @@ func (m *Mipmap) level(level int) *buffered.Image {
|
||||
m.setImg(level, nil)
|
||||
return nil
|
||||
}
|
||||
s := buffered.NewImage(w2, h2)
|
||||
s.SetVolatile(m.volatile)
|
||||
s := buffered.NewImage(w2, h2, atlas.ImageTypeVolatile)
|
||||
|
||||
dstRegion := graphicsdriver.Region{
|
||||
X: 0,
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/affine"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/buffered"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/clock"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/debug"
|
||||
@ -149,13 +150,6 @@ func (c *context) drawGame(graphicsDriver graphicsdriver.Graphics) {
|
||||
w, h := c.offscreen.width, c.offscreen.height
|
||||
c.offscreen.MarkDisposed()
|
||||
c.offscreen = c.game.NewOffscreenImage(w, h)
|
||||
|
||||
// TODO: Give volatile/isolated property to the constructor.
|
||||
if theGlobalState.isScreenClearedEveryFrame() {
|
||||
c.offscreen.setVolatile(true)
|
||||
} else {
|
||||
c.offscreen.mipmap.SetIsolated(true)
|
||||
}
|
||||
}
|
||||
|
||||
// Even though updateCount == 0, the offscreen is cleared and Draw is called.
|
||||
@ -244,7 +238,7 @@ func (c *context) layoutGame(outsideWidth, outsideHeight float64, deviceScaleFac
|
||||
}
|
||||
}
|
||||
if c.screen == nil {
|
||||
c.screen = newScreenFramebufferImage(sw, sh)
|
||||
c.screen = NewImage(sw, sh, atlas.ImageTypeScreen)
|
||||
}
|
||||
|
||||
if c.offscreen != nil {
|
||||
@ -255,17 +249,6 @@ func (c *context) layoutGame(outsideWidth, outsideHeight float64, deviceScaleFac
|
||||
}
|
||||
if c.offscreen == nil {
|
||||
c.offscreen = c.game.NewOffscreenImage(ow, oh)
|
||||
|
||||
// TODO: Give volatile/isolated property to the constructor.
|
||||
if theGlobalState.isScreenClearedEveryFrame() {
|
||||
c.offscreen.setVolatile(true)
|
||||
} else {
|
||||
// Keep the offscreen an isolated image from an atlas (#1938).
|
||||
// The shader program for the screen is special and doesn't work well with an image on an atlas.
|
||||
// An image on an atlas is surrounded by a transparent edge,
|
||||
// and the shader program unexpectedly picks the pixel on the edges.
|
||||
c.offscreen.mipmap.SetIsolated(true)
|
||||
}
|
||||
}
|
||||
|
||||
return ow, oh
|
||||
|
@ -16,6 +16,7 @@ package ui
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/affine"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/mipmap"
|
||||
@ -36,27 +37,14 @@ type Image struct {
|
||||
volatile bool
|
||||
}
|
||||
|
||||
func NewImage(width, height int) *Image {
|
||||
func NewImage(width, height int, imageType atlas.ImageType) *Image {
|
||||
return &Image{
|
||||
mipmap: mipmap.New(width, height),
|
||||
mipmap: mipmap.New(width, height, imageType),
|
||||
width: width,
|
||||
height: height,
|
||||
}
|
||||
}
|
||||
|
||||
func newScreenFramebufferImage(width, height int) *Image {
|
||||
return &Image{
|
||||
mipmap: mipmap.NewScreenFramebufferMipmap(width, height),
|
||||
width: width,
|
||||
height: height,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Image) setVolatile(volatile bool) {
|
||||
i.volatile = volatile
|
||||
i.mipmap.SetVolatile(volatile)
|
||||
}
|
||||
|
||||
func (i *Image) MarkDisposed() {
|
||||
if i.mipmap == nil {
|
||||
return
|
||||
@ -112,7 +100,7 @@ func DumpImages(dir string) error {
|
||||
}
|
||||
|
||||
var (
|
||||
emptyImage = NewImage(3, 3)
|
||||
emptyImage = NewImage(3, 3, atlas.ImageTypeRegular)
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
Loading…
Reference in New Issue
Block a user