From 54c117b0defffed9cfd8b06e2c80a95b1223bb59 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Fri, 6 Sep 2024 13:47:29 +0900 Subject: [PATCH] Revert "internal/restorable: integrate Image functions into internal/atlas" This reverts commit 59896e44478e167f182208632121e281bef05a15. Updates #3083 --- internal/atlas/image.go | 61 +++++++++-------------------------- internal/restorable/image.go | 41 +++++++++++++++++++++++ internal/restorable/shader.go | 4 +-- 3 files changed, 59 insertions(+), 47 deletions(-) diff --git a/internal/atlas/image.go b/internal/atlas/image.go index 2b57eb1a3..abcd1fda2 100644 --- a/internal/atlas/image.go +++ b/internal/atlas/image.go @@ -136,7 +136,7 @@ func (b *backend) extendIfNeeded(width, height int) { } // Assume that the screen image is never extended. - newImg := newClearedImage(width, height, false) + newImg := restorable.NewImage(width, height, false) // Use DrawTriangles instead of WritePixels because the image i might be stale and not have its pixels // information. @@ -155,45 +155,6 @@ func (b *backend) extendIfNeeded(width, height int) { b.height = height } -// newClearedImage creates an emtpy image with the given size. -// -// Note that Dispose is not called automatically. -func newClearedImage(width, height int, screen bool) *restorable.Image { - i := &restorable.Image{ - Image: graphicscommand.NewImage(width, height, screen), - } - - // This needs to use 'InternalSize' to render the whole region, or edges are unexpectedly cleared on some - // devices. - iw, ih := i.Image.InternalSize() - clearImage(i.Image, image.Rect(0, 0, iw, ih)) - return i -} - -func clearImage(i *graphicscommand.Image, region image.Rectangle) { - vs := make([]float32, 4*graphics.VertexFloatCount) - graphics.QuadVerticesFromDstAndSrc(vs, float32(region.Min.X), float32(region.Min.Y), float32(region.Max.X), float32(region.Max.Y), 0, 0, 0, 0, 0, 0, 0, 0) - is := graphics.QuadIndices() - i.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendClear, region, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.ClearShader.Shader, nil, graphicsdriver.FillRuleFillAll) -} - -func (b *backend) clearPixels(region image.Rectangle) { - if region.Dx() <= 0 || region.Dy() <= 0 { - panic("atlas: width/height must be positive") - } - clearImage(b.restorable.Image, region.Intersect(image.Rect(0, 0, b.width, b.height))) -} - -func (b *backend) writePixels(pixels *graphics.ManagedBytes, region image.Rectangle) { - if region.Dx() <= 0 || region.Dy() <= 0 { - panic("atlas: width/height must be positive") - } - if !region.In(image.Rect(0, 0, b.width, b.height)) { - panic(fmt.Sprintf("atlas: out of range %v", region)) - } - b.restorable.Image.WritePixels(pixels, region) -} - var ( // backendsM is a mutex for critical sections of the backend and packing.Node objects. backendsM sync.Mutex @@ -578,7 +539,7 @@ func (i *Image) writePixels(pix []byte, region image.Rectangle) { region = region.Add(r.Min) if pix == nil { - i.backend.clearPixels(region) + i.backend.restorable.ClearPixels(region) return } @@ -618,6 +579,16 @@ func (i *Image) writePixels(pix []byte, region image.Rectangle) { i.backend.writePixels(pixb, r) } +func (b *backend) writePixels(pixels *graphics.ManagedBytes, region image.Rectangle) { + if region.Dx() <= 0 || region.Dy() <= 0 { + panic("atlas: width/height must be positive") + } + if !region.In(image.Rect(0, 0, b.width, b.height)) { + panic(fmt.Sprintf("atlas: out of range %v", region)) + } + b.restorable.Image.WritePixels(pixels, region) +} + func (i *Image) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byte, region image.Rectangle) (ok bool, err error) { backendsM.Lock() defer backendsM.Unlock() @@ -687,7 +658,7 @@ func (i *Image) deallocate() { if !i.backend.page.IsEmpty() { // As this part can be reused, this should be cleared explicitly. r := i.regionWithPadding() - i.backend.clearPixels(r) + i.backend.restorable.ClearPixels(r) return } } @@ -752,7 +723,7 @@ func (i *Image) allocate(forbiddenBackends []*backend, asSource bool) { } // A screen image doesn't have a padding. i.backend = &backend{ - restorable: newClearedImage(i.width, i.height, true), + restorable: restorable.NewImage(i.width, i.height, true), width: i.width, height: i.height, } @@ -769,7 +740,7 @@ func (i *Image) allocate(forbiddenBackends []*backend, asSource bool) { } i.backend = &backend{ - restorable: newClearedImage(wp, hp, false), + restorable: restorable.NewImage(wp, hp, false), width: wp, height: hp, source: asSource && i.imageType == ImageTypeRegular, @@ -817,7 +788,7 @@ loop: } b := &backend{ - restorable: newClearedImage(width, height, false), + restorable: restorable.NewImage(width, height, false), width: width, height: height, page: packing.NewPage(width, height, maxSize), diff --git a/internal/restorable/image.go b/internal/restorable/image.go index 3793a918f..14960bfde 100644 --- a/internal/restorable/image.go +++ b/internal/restorable/image.go @@ -15,7 +15,11 @@ package restorable import ( + "image" + + "github.com/hajimehoshi/ebiten/v2/internal/graphics" "github.com/hajimehoshi/ebiten/v2/internal/graphicscommand" + "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver" ) // Image represents an image. @@ -24,4 +28,41 @@ type Image struct { // This member is exported on purpose. // TODO: Move the implementation to internal/atlas package (#805). Image *graphicscommand.Image + + width int + height int +} + +// NewImage creates an emtpy image with the given size. +// +// The returned image is cleared. +// +// Note that Dispose is not called automatically. +func NewImage(width, height int, screen bool) *Image { + i := &Image{ + Image: graphicscommand.NewImage(width, height, screen), + width: width, + height: height, + } + + // This needs to use 'InternalSize' to render the whole region, or edges are unexpectedly cleared on some + // devices. + iw, ih := i.Image.InternalSize() + clearImage(i.Image, image.Rect(0, 0, iw, ih)) + return i +} + +func clearImage(i *graphicscommand.Image, region image.Rectangle) { + vs := make([]float32, 4*graphics.VertexFloatCount) + graphics.QuadVerticesFromDstAndSrc(vs, float32(region.Min.X), float32(region.Min.Y), float32(region.Max.X), float32(region.Max.Y), 0, 0, 0, 0, 0, 0, 0, 0) + is := graphics.QuadIndices() + i.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendClear, region, [graphics.ShaderSrcImageCount]image.Rectangle{}, clearShader.Shader, nil, graphicsdriver.FillRuleFillAll) +} + +// ClearPixels clears the specified region by WritePixels. +func (i *Image) ClearPixels(region image.Rectangle) { + if region.Dx() <= 0 || region.Dy() <= 0 { + panic("restorable: width/height must be positive") + } + clearImage(i.Image, region.Intersect(image.Rect(0, 0, i.width, i.height))) } diff --git a/internal/restorable/shader.go b/internal/restorable/shader.go index c09a8c4fe..bc2247f50 100644 --- a/internal/restorable/shader.go +++ b/internal/restorable/shader.go @@ -41,7 +41,7 @@ var ( NearestFilterShaderIR *shaderir.Program LinearFilterShader *Shader LinearFilterShaderIR *shaderir.Program - ClearShader *Shader + clearShader *Shader ) func init() { @@ -78,5 +78,5 @@ func init() { NearestFilterShader = NewShader(nearestIR) LinearFilterShaderIR = linearIR LinearFilterShader = NewShader(linearIR) - ClearShader = NewShader(clearIR) + clearShader = NewShader(clearIR) }