Add internal/pixels

This commit is contained in:
Hajime Hoshi 2016-07-25 02:28:59 +09:00
parent 000958df56
commit f6be72fba2
2 changed files with 54 additions and 49 deletions

View File

@ -25,6 +25,7 @@ import (
"github.com/hajimehoshi/ebiten/internal/graphics" "github.com/hajimehoshi/ebiten/internal/graphics"
"github.com/hajimehoshi/ebiten/internal/graphics/opengl" "github.com/hajimehoshi/ebiten/internal/graphics/opengl"
"github.com/hajimehoshi/ebiten/internal/pixels"
) )
type imageImpl struct { type imageImpl struct {
@ -33,7 +34,7 @@ type imageImpl struct {
width int width int
height int height int
filter Filter filter Filter
pixels *pixels pixels *pixels.Pixels
volatile bool volatile bool
screen bool screen bool
m sync.Mutex m sync.Mutex
@ -50,11 +51,9 @@ func newImageImpl(width, height int, filter Filter, volatile bool) (*imageImpl,
height: height, height: height,
filter: filter, filter: filter,
volatile: volatile, volatile: volatile,
pixels: &pixels{ pixels: pixels.NewPixels(img),
image: img,
},
} }
i.pixels.resetWithPixels(make([]uint8, width*height*4)) i.pixels.ResetWithPixels(make([]uint8, width*height*4))
runtime.SetFinalizer(i, (*imageImpl).Dispose) runtime.SetFinalizer(i, (*imageImpl).Dispose)
return i, nil return i, nil
} }
@ -85,11 +84,9 @@ func newImageImplFromImage(source image.Image, filter Filter) (*imageImpl, error
width: w, width: w,
height: h, height: h,
filter: filter, filter: filter,
pixels: &pixels{ pixels: pixels.NewPixels(img),
image: img,
},
} }
i.pixels.resetWithPixels(p) i.pixels.ResetWithPixels(p)
runtime.SetFinalizer(i, (*imageImpl).Dispose) runtime.SetFinalizer(i, (*imageImpl).Dispose)
return i, nil return i, nil
} }
@ -105,11 +102,9 @@ func newScreenImageImpl(width, height int) (*imageImpl, error) {
height: height, height: height,
volatile: true, volatile: true,
screen: true, screen: true,
pixels: &pixels{ pixels: pixels.NewPixels(img),
image: img,
},
} }
i.pixels.resetWithPixels(make([]uint8, width*height*4)) i.pixels.ResetWithPixels(make([]uint8, width*height*4))
runtime.SetFinalizer(i, (*imageImpl).Dispose) runtime.SetFinalizer(i, (*imageImpl).Dispose)
return i, nil return i, nil
} }
@ -120,10 +115,10 @@ func (i *imageImpl) Fill(clr color.Color) error {
if i.disposed { if i.disposed {
return errors.New("ebiten: image is already disposed") return errors.New("ebiten: image is already disposed")
} }
if clr == color.Transparent && i.pixels.isCleared() { if clr == color.Transparent && i.pixels.IsCleared() {
return nil return nil
} }
i.pixels.fill(clr) i.pixels.Fill(clr)
return i.image.Fill(clr) return i.image.Fill(clr)
} }
@ -136,10 +131,10 @@ func (i *imageImpl) clearIfVolatile() error {
if !i.volatile { if !i.volatile {
return nil return nil
} }
if i.pixels.isCleared() { if i.pixels.IsCleared() {
return nil return nil
} }
i.pixels.clear() i.pixels.Clear()
return i.image.Fill(color.Transparent) return i.image.Fill(color.Transparent)
} }
@ -176,17 +171,10 @@ func (i *imageImpl) DrawImage(image *Image, options *DrawImageOptions) error {
} }
geom := options.GeoM geom := options.GeoM
colorm := options.ColorM colorm := options.ColorM
c := &drawImageHistoryItem{ if image.impl.pixels.IsInconsistent() {
image: image.impl.image, i.pixels.MakeInconsistent()
vertices: vertices,
geom: &geom,
colorm: &colorm,
mode: opengl.CompositeMode(options.CompositeMode),
} }
if image.impl.pixels.inconsistent { i.pixels.AppendDrawImageHistory(image.impl.image, vertices, &geom, &colorm, opengl.CompositeMode(options.CompositeMode))
i.pixels.makeInconsistent()
}
i.pixels.appendDrawImageHistory(c)
mode := opengl.CompositeMode(options.CompositeMode) mode := opengl.CompositeMode(options.CompositeMode)
if err := i.image.DrawImage(image.impl.image, vertices, &geom, &colorm, mode); err != nil { if err := i.image.DrawImage(image.impl.image, vertices, &geom, &colorm, mode); err != nil {
return err return err
@ -204,7 +192,7 @@ func (i *imageImpl) At(x, y int, context *opengl.Context) color.Color {
return color.Transparent return color.Transparent
} }
idx := 4*x + 4*y*i.width idx := 4*x + 4*y*i.width
clr, err := i.pixels.at(idx, context) clr, err := i.pixels.At(idx, context)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -217,7 +205,7 @@ func (i *imageImpl) flushPixelsIfInconsistent(context *opengl.Context) error {
if i.disposed { if i.disposed {
return nil return nil
} }
if err := i.pixels.flushIfInconsistent(context); err != nil { if err := i.pixels.FlushIfInconsistent(context); err != nil {
return err return err
} }
return nil return nil
@ -235,7 +223,7 @@ func (i *imageImpl) flushPixelsIfNeeded(target *imageImpl, context *opengl.Conte
if target.isDisposed() { if target.isDisposed() {
return errors.New("ebiten: target is already disposed") return errors.New("ebiten: target is already disposed")
} }
if err := i.pixels.flushIfNeeded(target.image, context); err != nil { if err := i.pixels.FlushIfNeeded(target.image, context); err != nil {
return err return err
} }
return nil return nil
@ -244,7 +232,7 @@ func (i *imageImpl) flushPixelsIfNeeded(target *imageImpl, context *opengl.Conte
func (i *imageImpl) hasHistory() bool { func (i *imageImpl) hasHistory() bool {
i.m.Lock() i.m.Lock()
defer i.m.Unlock() defer i.m.Unlock()
return i.pixels.hasHistory() return i.pixels.HasHistory()
} }
func (i *imageImpl) restore(context *opengl.Context) error { func (i *imageImpl) restore(context *opengl.Context) error {
@ -272,7 +260,7 @@ func (i *imageImpl) restore(context *opengl.Context) error {
return nil return nil
} }
var err error var err error
i.image, err = i.pixels.restore(context, i.width, i.height, i.filter) i.image, err = i.pixels.Restore(context, i.width, i.height, glFilter(i.filter))
if err != nil { if err != nil {
return err return err
} }
@ -303,7 +291,7 @@ func (i *imageImpl) ReplacePixels(p []uint8) error {
} }
i.m.Lock() i.m.Lock()
defer i.m.Unlock() defer i.m.Unlock()
i.pixels.resetWithPixels(p) i.pixels.ResetWithPixels(p)
if i.disposed { if i.disposed {
return errors.New("ebiten: image is already disposed") return errors.New("ebiten: image is already disposed")
} }

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package ebiten package pixels
import ( import (
"image" "image"
@ -32,7 +32,7 @@ type drawImageHistoryItem struct {
// basePixels and baseColor are exclusive. // basePixels and baseColor are exclusive.
type pixels struct { type Pixels struct {
image *graphics.Image image *graphics.Image
inconsistent bool inconsistent bool
basePixels []uint8 basePixels []uint8
@ -40,7 +40,13 @@ type pixels struct {
drawImageHistory []*drawImageHistoryItem drawImageHistory []*drawImageHistoryItem
} }
func (p *pixels) resetWithPixels(pixels []uint8) { func NewPixels(image *graphics.Image) *Pixels {
return &Pixels{
image: image,
}
}
func (p *Pixels) ResetWithPixels(pixels []uint8) {
if p.basePixels == nil { if p.basePixels == nil {
p.basePixels = make([]uint8, len(pixels)) p.basePixels = make([]uint8, len(pixels))
} }
@ -50,42 +56,53 @@ func (p *pixels) resetWithPixels(pixels []uint8) {
p.drawImageHistory = nil p.drawImageHistory = nil
} }
func (p *pixels) clear() { func (p *Pixels) Clear() {
p.inconsistent = false p.inconsistent = false
p.basePixels = nil p.basePixels = nil
p.baseColor = nil p.baseColor = nil
p.drawImageHistory = nil p.drawImageHistory = nil
} }
func (p *pixels) isCleared() bool { func (p *Pixels) IsCleared() bool {
if p.inconsistent { if p.inconsistent {
return false return false
} }
return p.basePixels == nil && p.baseColor == nil && p.drawImageHistory == nil return p.basePixels == nil && p.baseColor == nil && p.drawImageHistory == nil
} }
func (p *pixels) fill(clr color.Color) { func (p *Pixels) Fill(clr color.Color) {
p.inconsistent = false p.inconsistent = false
p.basePixels = nil p.basePixels = nil
p.baseColor = clr p.baseColor = clr
p.drawImageHistory = nil p.drawImageHistory = nil
} }
func (p *pixels) makeInconsistent() { func (p *Pixels) IsInconsistent() bool {
return p.inconsistent
}
func (p *Pixels) MakeInconsistent() {
p.inconsistent = true p.inconsistent = true
p.basePixels = nil p.basePixels = nil
p.baseColor = nil p.baseColor = nil
p.drawImageHistory = nil p.drawImageHistory = nil
} }
func (p *pixels) appendDrawImageHistory(item *drawImageHistoryItem) { func (p *Pixels) AppendDrawImageHistory(image *graphics.Image, vertices []int16, geom graphics.Matrix, colorm graphics.Matrix, mode opengl.CompositeMode) {
if p.inconsistent { if p.inconsistent {
return return
} }
item := &drawImageHistoryItem{
image: image,
vertices: vertices,
geom: geom,
colorm: colorm,
mode: mode,
}
p.drawImageHistory = append(p.drawImageHistory, item) p.drawImageHistory = append(p.drawImageHistory, item)
} }
func (p *pixels) at(idx int, context *opengl.Context) (color.Color, error) { func (p *Pixels) At(idx int, context *opengl.Context) (color.Color, error) {
if p.inconsistent || p.basePixels == nil || p.drawImageHistory != nil { if p.inconsistent || p.basePixels == nil || p.drawImageHistory != nil {
p.inconsistent = false p.inconsistent = false
var err error var err error
@ -100,7 +117,7 @@ func (p *pixels) at(idx int, context *opengl.Context) (color.Color, error) {
return color.RGBA{r, g, b, a}, nil return color.RGBA{r, g, b, a}, nil
} }
func (p *pixels) hasHistoryWith(target *graphics.Image) bool { func (p *Pixels) hasHistoryWith(target *graphics.Image) bool {
for _, c := range p.drawImageHistory { for _, c := range p.drawImageHistory {
if c.image == target { if c.image == target {
return true return true
@ -109,7 +126,7 @@ func (p *pixels) hasHistoryWith(target *graphics.Image) bool {
return false return false
} }
func (p *pixels) flushIfInconsistent(context *opengl.Context) error { func (p *Pixels) FlushIfInconsistent(context *opengl.Context) error {
if !p.inconsistent { if !p.inconsistent {
return nil return nil
} }
@ -124,7 +141,7 @@ func (p *pixels) flushIfInconsistent(context *opengl.Context) error {
return nil return nil
} }
func (p *pixels) flushIfNeeded(target *graphics.Image, context *opengl.Context) error { func (p *Pixels) FlushIfNeeded(target *graphics.Image, context *opengl.Context) error {
if p.drawImageHistory == nil { if p.drawImageHistory == nil {
return nil return nil
} }
@ -133,7 +150,7 @@ func (p *pixels) flushIfNeeded(target *graphics.Image, context *opengl.Context)
} }
if context == nil { if context == nil {
// context is null when this is not initialized yet. // context is null when this is not initialized yet.
p.makeInconsistent() p.MakeInconsistent()
return nil return nil
} }
p.inconsistent = false p.inconsistent = false
@ -147,21 +164,21 @@ func (p *pixels) flushIfNeeded(target *graphics.Image, context *opengl.Context)
return nil return nil
} }
func (p *pixels) hasHistory() bool { func (p *Pixels) HasHistory() bool {
return p.drawImageHistory != nil return p.drawImageHistory != nil
} }
// restore restores the pixels using its history. // restore restores the pixels using its history.
// //
// restore is the only function that the pixel data is not present on GPU when this is called. // restore is the only function that the pixel data is not present on GPU when this is called.
func (p *pixels) restore(context *opengl.Context, width, height int, filter Filter) (*graphics.Image, error) { func (p *Pixels) Restore(context *opengl.Context, width, height int, filter opengl.Filter) (*graphics.Image, error) {
img := image.NewRGBA(image.Rect(0, 0, width, height)) img := image.NewRGBA(image.Rect(0, 0, width, height))
if p.basePixels != nil { if p.basePixels != nil {
for j := 0; j < height; j++ { for j := 0; j < height; j++ {
copy(img.Pix[j*img.Stride:], p.basePixels[j*width*4:(j+1)*width*4]) copy(img.Pix[j*img.Stride:], p.basePixels[j*width*4:(j+1)*width*4])
} }
} }
gimg, err := graphics.NewImageFromImage(img, glFilter(filter)) gimg, err := graphics.NewImageFromImage(img, filter)
if err != nil { if err != nil {
return nil, err return nil, err
} }