Skip to content

Commit

Permalink
Revert "internal/restorable: integrate Image functions into internal/…
Browse files Browse the repository at this point in the history
…atlas"

This reverts commit 59896e4.

Updates #3083
  • Loading branch information
hajimehoshi committed Sep 6, 2024
1 parent fd61f63 commit 4c11d2a
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 47 deletions.
61 changes: 16 additions & 45 deletions internal/atlas/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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
}
}
Expand Down Expand Up @@ -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,
}
Expand All @@ -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,
Expand Down Expand Up @@ -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),
Expand Down
41 changes: 41 additions & 0 deletions internal/restorable/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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)))
}
4 changes: 2 additions & 2 deletions internal/restorable/shader.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ var (
NearestFilterShaderIR *shaderir.Program
LinearFilterShader *Shader
LinearFilterShaderIR *shaderir.Program
ClearShader *Shader
clearShader *Shader
)

func init() {
Expand Down Expand Up @@ -78,5 +78,5 @@ func init() {
NearestFilterShader = NewShader(nearestIR)
LinearFilterShaderIR = linearIR
LinearFilterShader = NewShader(linearIR)
ClearShader = NewShader(clearIR)
clearShader = NewShader(clearIR)
}

0 comments on commit 4c11d2a

Please sign in to comment.