mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 18:58:54 +01:00
Add internal/pixels
This commit is contained in:
parent
000958df56
commit
f6be72fba2
54
imageimpl.go
54
imageimpl.go
@ -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")
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user