mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
graphics: Remove image commands and use functions instead
This commit is contained in:
parent
b8a062e813
commit
bbc2ad915a
155
image.go
155
image.go
@ -19,13 +19,31 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/internal/graphics"
|
"github.com/hajimehoshi/ebiten/internal/graphics"
|
||||||
|
"github.com/hajimehoshi/ebiten/internal/graphics/opengl"
|
||||||
)
|
)
|
||||||
|
|
||||||
var imageM sync.Mutex
|
var imageM sync.Mutex
|
||||||
|
|
||||||
|
var (
|
||||||
|
imageCommandQueue = []func() error{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func execBufferedImageCommands() error {
|
||||||
|
imageM.Lock()
|
||||||
|
defer imageM.Unlock()
|
||||||
|
for _, f := range imageCommandQueue {
|
||||||
|
if err := f(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imageCommandQueue = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Image represents an image.
|
// Image represents an image.
|
||||||
// The pixel format is alpha-premultiplied.
|
// The pixel format is alpha-premultiplied.
|
||||||
// Image implements image.Image.
|
// Image implements image.Image.
|
||||||
@ -68,15 +86,18 @@ func (i *Image) Fill(clr color.Color) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) fill(clr color.Color) (err error) {
|
func (i *Image) fill(clr color.Color) (err error) {
|
||||||
c := &fillCommand{
|
f := func() error {
|
||||||
dst: i,
|
if i.isDisposed() {
|
||||||
color: clr,
|
return errors.New("ebiten: image is already disposed")
|
||||||
|
}
|
||||||
|
i.pixels = nil
|
||||||
|
return i.framebuffer.Fill(glContext, clr)
|
||||||
}
|
}
|
||||||
if imageCommandQueue != nil {
|
if imageCommandQueue != nil {
|
||||||
imageCommandQueue = append(imageCommandQueue, c)
|
imageCommandQueue = append(imageCommandQueue, f)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return c.Exec()
|
return f()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,19 +147,19 @@ func (i *Image) DrawImage(image *Image, options *DrawImageOptions) (err error) {
|
|||||||
if i == image {
|
if i == image {
|
||||||
return errors.New("ebiten: Image.DrawImage: image should be different from the receiver")
|
return errors.New("ebiten: Image.DrawImage: image should be different from the receiver")
|
||||||
}
|
}
|
||||||
c := &drawImageCommand{
|
f := func() error {
|
||||||
dst: i,
|
if i.isDisposed() {
|
||||||
src: image,
|
return errors.New("ebiten: image is already disposed")
|
||||||
vertices: vertices[:16*n],
|
}
|
||||||
geoM: options.GeoM,
|
i.pixels = nil
|
||||||
colorM: options.ColorM,
|
m := opengl.CompositeMode(options.CompositeMode)
|
||||||
compositeMode: options.CompositeMode,
|
return i.framebuffer.DrawTexture(glContext, image.texture, vertices[:16*n], &options.GeoM, &options.ColorM, m)
|
||||||
}
|
}
|
||||||
if imageCommandQueue != nil {
|
if imageCommandQueue != nil {
|
||||||
imageCommandQueue = append(imageCommandQueue, c)
|
imageCommandQueue = append(imageCommandQueue, f)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return c.Exec()
|
return f()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bounds returns the bounds of the image.
|
// Bounds returns the bounds of the image.
|
||||||
@ -194,14 +215,32 @@ func (i *Image) At(x, y int) color.Color {
|
|||||||
func (i *Image) Dispose() error {
|
func (i *Image) Dispose() error {
|
||||||
imageM.Lock()
|
imageM.Lock()
|
||||||
defer imageM.Unlock()
|
defer imageM.Unlock()
|
||||||
c := &disposeCommand{
|
f := func() error {
|
||||||
image: i,
|
if i.isDisposed() {
|
||||||
|
return errors.New("ebiten: image is already disposed")
|
||||||
}
|
}
|
||||||
if imageCommandQueue != nil {
|
if i.framebuffer != nil {
|
||||||
imageCommandQueue = append(imageCommandQueue, c)
|
if err := i.framebuffer.Dispose(glContext); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.framebuffer = nil
|
||||||
|
}
|
||||||
|
if i.texture != nil {
|
||||||
|
if err := i.texture.Dispose(glContext); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.texture = nil
|
||||||
|
}
|
||||||
|
i.disposed = true
|
||||||
|
i.pixels = nil
|
||||||
|
runtime.SetFinalizer(i, nil)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return c.Exec()
|
if imageCommandQueue != nil {
|
||||||
|
imageCommandQueue = append(imageCommandQueue, f)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return f()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) isDisposed() bool {
|
func (i *Image) isDisposed() bool {
|
||||||
@ -218,20 +257,22 @@ func (i *Image) isDisposed() bool {
|
|||||||
func (i *Image) ReplacePixels(p []uint8) error {
|
func (i *Image) ReplacePixels(p []uint8) error {
|
||||||
imageM.Lock()
|
imageM.Lock()
|
||||||
defer imageM.Unlock()
|
defer imageM.Unlock()
|
||||||
// Don't set i.pixels here because i.pixels is used not every time.
|
|
||||||
i.pixels = nil
|
|
||||||
if l := 4 * i.width * i.height; len(p) != l {
|
if l := 4 * i.width * i.height; len(p) != l {
|
||||||
return fmt.Errorf("ebiten: p's length must be %d", l)
|
return fmt.Errorf("ebiten: p's length must be %d", l)
|
||||||
}
|
}
|
||||||
c := &replacePixelsCommand{
|
f := func() error {
|
||||||
dst: i,
|
// Don't set i.pixels here because i.pixels is used not every time.
|
||||||
pixels: p,
|
i.pixels = nil
|
||||||
|
if i.isDisposed() {
|
||||||
|
return errors.New("ebiten: image is already disposed")
|
||||||
|
}
|
||||||
|
return i.framebuffer.ReplacePixels(glContext, i.texture, p)
|
||||||
}
|
}
|
||||||
if imageCommandQueue != nil {
|
if imageCommandQueue != nil {
|
||||||
imageCommandQueue = append(imageCommandQueue, c)
|
imageCommandQueue = append(imageCommandQueue, f)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return c.Exec()
|
return f()
|
||||||
}
|
}
|
||||||
|
|
||||||
// A DrawImageOptions represents options to render an image on an image.
|
// A DrawImageOptions represents options to render an image on an image.
|
||||||
@ -256,23 +297,36 @@ type DrawImageOptions struct {
|
|||||||
func NewImage(width, height int, filter Filter) (*Image, error) {
|
func NewImage(width, height int, filter Filter) (*Image, error) {
|
||||||
imageM.Lock()
|
imageM.Lock()
|
||||||
defer imageM.Unlock()
|
defer imageM.Unlock()
|
||||||
c := &newImageCommand{
|
image := &Image{
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
filter: filter,
|
}
|
||||||
result: &Image{
|
f := func() error {
|
||||||
width: width,
|
texture, err := graphics.NewTexture(glContext, width, height, glFilter(glContext, filter))
|
||||||
height: height,
|
if err != nil {
|
||||||
},
|
return err
|
||||||
|
}
|
||||||
|
framebuffer, err := graphics.NewFramebufferFromTexture(glContext, texture)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: texture should be removed here?
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
image.framebuffer = framebuffer
|
||||||
|
image.texture = texture
|
||||||
|
runtime.SetFinalizer(image, (*Image).Dispose)
|
||||||
|
if err := image.framebuffer.Fill(glContext, color.Transparent); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if imageCommandQueue != nil {
|
if imageCommandQueue != nil {
|
||||||
imageCommandQueue = append(imageCommandQueue, c)
|
imageCommandQueue = append(imageCommandQueue, f)
|
||||||
return c.result, nil
|
return image, nil
|
||||||
}
|
}
|
||||||
if err := c.Exec(); err != nil {
|
if err := f(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return c.result, nil
|
return image, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewImageFromImage creates a new image with the given image (img).
|
// NewImageFromImage creates a new image with the given image (img).
|
||||||
@ -288,20 +342,31 @@ func NewImageFromImage(img image.Image, filter Filter) (*Image, error) {
|
|||||||
defer imageM.Unlock()
|
defer imageM.Unlock()
|
||||||
size := img.Bounds().Size()
|
size := img.Bounds().Size()
|
||||||
w, h := size.X, size.Y
|
w, h := size.X, size.Y
|
||||||
c := &newImageFromImageCommand{
|
image := &Image{
|
||||||
image: img,
|
|
||||||
filter: filter,
|
|
||||||
result: &Image{
|
|
||||||
width: w,
|
width: w,
|
||||||
height: h,
|
height: h,
|
||||||
},
|
}
|
||||||
|
f := func() error {
|
||||||
|
texture, err := graphics.NewTextureFromImage(glContext, img, glFilter(glContext, filter))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
framebuffer, err := graphics.NewFramebufferFromTexture(glContext, texture)
|
||||||
|
if err != nil {
|
||||||
|
// TODO: texture should be removed here?
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
image.framebuffer = framebuffer
|
||||||
|
image.texture = texture
|
||||||
|
runtime.SetFinalizer(image, (*Image).Dispose)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
if imageCommandQueue != nil {
|
if imageCommandQueue != nil {
|
||||||
imageCommandQueue = append(imageCommandQueue, c)
|
imageCommandQueue = append(imageCommandQueue, f)
|
||||||
return c.result, nil
|
return image, nil
|
||||||
}
|
}
|
||||||
if err := c.Exec(); err != nil {
|
if err := f(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return c.result, nil
|
return image, nil
|
||||||
}
|
}
|
||||||
|
164
imagecommand.go
164
imagecommand.go
@ -1,164 +0,0 @@
|
|||||||
// Copyright 2016 Hajime Hoshi
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package ebiten
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"image"
|
|
||||||
"image/color"
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/internal/graphics"
|
|
||||||
"github.com/hajimehoshi/ebiten/internal/graphics/opengl"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Commands are used only before the GL Context is created.
|
|
||||||
|
|
||||||
type imageCommand interface {
|
|
||||||
Exec() error
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
imageCommandQueue = []imageCommand{}
|
|
||||||
)
|
|
||||||
|
|
||||||
func execBufferedImageCommands() error {
|
|
||||||
imageM.Lock()
|
|
||||||
defer imageM.Unlock()
|
|
||||||
for _, c := range imageCommandQueue {
|
|
||||||
if err := c.Exec(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
imageCommandQueue = nil
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type fillCommand struct {
|
|
||||||
dst *Image
|
|
||||||
color color.Color
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *fillCommand) Exec() error {
|
|
||||||
if c.dst.isDisposed() {
|
|
||||||
return errors.New("ebiten: image is already disposed")
|
|
||||||
}
|
|
||||||
c.dst.pixels = nil
|
|
||||||
return c.dst.framebuffer.Fill(glContext, c.color)
|
|
||||||
}
|
|
||||||
|
|
||||||
type drawImageCommand struct {
|
|
||||||
dst *Image
|
|
||||||
src *Image
|
|
||||||
vertices []int16
|
|
||||||
geoM GeoM
|
|
||||||
colorM ColorM
|
|
||||||
compositeMode CompositeMode
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *drawImageCommand) Exec() error {
|
|
||||||
if c.dst.isDisposed() {
|
|
||||||
return errors.New("ebiten: image is already disposed")
|
|
||||||
}
|
|
||||||
c.dst.pixels = nil
|
|
||||||
m := opengl.CompositeMode(c.compositeMode)
|
|
||||||
return c.dst.framebuffer.DrawTexture(glContext, c.src.texture, c.vertices, &c.geoM, &c.colorM, m)
|
|
||||||
}
|
|
||||||
|
|
||||||
type replacePixelsCommand struct {
|
|
||||||
dst *Image
|
|
||||||
pixels []uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *replacePixelsCommand) Exec() error {
|
|
||||||
if c.dst.isDisposed() {
|
|
||||||
return errors.New("ebiten: image is already disposed")
|
|
||||||
}
|
|
||||||
return c.dst.framebuffer.ReplacePixels(glContext, c.dst.texture, c.pixels)
|
|
||||||
}
|
|
||||||
|
|
||||||
type disposeCommand struct {
|
|
||||||
image *Image
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *disposeCommand) Exec() error {
|
|
||||||
if c.image.isDisposed() {
|
|
||||||
return errors.New("ebiten: image is already disposed")
|
|
||||||
}
|
|
||||||
if c.image.framebuffer != nil {
|
|
||||||
if err := c.image.framebuffer.Dispose(glContext); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.image.framebuffer = nil
|
|
||||||
}
|
|
||||||
if c.image.texture != nil {
|
|
||||||
if err := c.image.texture.Dispose(glContext); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.image.texture = nil
|
|
||||||
}
|
|
||||||
c.image.disposed = true
|
|
||||||
c.image.pixels = nil
|
|
||||||
runtime.SetFinalizer(c.image, nil)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type newImageCommand struct {
|
|
||||||
result *Image
|
|
||||||
width int
|
|
||||||
height int
|
|
||||||
filter Filter
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *newImageCommand) Exec() error {
|
|
||||||
texture, err := graphics.NewTexture(glContext, c.width, c.height, glFilter(glContext, c.filter))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
framebuffer, err := graphics.NewFramebufferFromTexture(glContext, texture)
|
|
||||||
if err != nil {
|
|
||||||
// TODO: texture should be removed here?
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.result.framebuffer = framebuffer
|
|
||||||
c.result.texture = texture
|
|
||||||
runtime.SetFinalizer(c.result, (*Image).Dispose)
|
|
||||||
if err := c.result.framebuffer.Fill(glContext, color.Transparent); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type newImageFromImageCommand struct {
|
|
||||||
image image.Image
|
|
||||||
filter Filter
|
|
||||||
result *Image
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *newImageFromImageCommand) Exec() error {
|
|
||||||
texture, err := graphics.NewTextureFromImage(glContext, c.image, glFilter(glContext, c.filter))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
framebuffer, err := graphics.NewFramebufferFromTexture(glContext, texture)
|
|
||||||
if err != nil {
|
|
||||||
// TODO: texture should be removed here?
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.result.framebuffer = framebuffer
|
|
||||||
c.result.texture = texture
|
|
||||||
runtime.SetFinalizer(c.result, (*Image).Dispose)
|
|
||||||
return nil
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user