mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
graphics: Add FilterDefault; Make DrawImageOptions specify Filter (#453)
This commit is contained in:
parent
929dfa1cfb
commit
6ef4bbde2d
@ -19,10 +19,13 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten/internal/opengl"
|
"github.com/hajimehoshi/ebiten/internal/opengl"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Filter represents the type of filter to be used when an image is maginified or minified.
|
// Filter represents the type of texture filter to be used when an image is maginified or minified.
|
||||||
type Filter int
|
type Filter int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// FilterDefault represents the defualt filter.
|
||||||
|
FilterDefault Filter = Filter(graphics.FilterDefault)
|
||||||
|
|
||||||
// FilterNearest represents nearest (crisp-edged) filter
|
// FilterNearest represents nearest (crisp-edged) filter
|
||||||
FilterNearest Filter = Filter(graphics.FilterNearest)
|
FilterNearest Filter = Filter(graphics.FilterNearest)
|
||||||
|
|
||||||
|
41
image.go
41
image.go
@ -33,6 +33,7 @@ import (
|
|||||||
// Functions of Image never returns error as of 1.5.0-alpha, and error values are always nil.
|
// Functions of Image never returns error as of 1.5.0-alpha, and error values are always nil.
|
||||||
type Image struct {
|
type Image struct {
|
||||||
restorable *restorable.Image
|
restorable *restorable.Image
|
||||||
|
filter Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns the size of the image.
|
// Size returns the size of the image.
|
||||||
@ -82,6 +83,7 @@ func (i *Image) Fill(clr color.Color) error {
|
|||||||
// * All render sources are same (B in A.DrawImage(B, op))
|
// * All render sources are same (B in A.DrawImage(B, op))
|
||||||
// * All ColorM values are same
|
// * All ColorM values are same
|
||||||
// * All CompositeMode values are same
|
// * All CompositeMode values are same
|
||||||
|
// * All Filter values are same
|
||||||
//
|
//
|
||||||
// For more performance tips, see https://github.com/hajimehoshi/ebiten/wiki/Performance-Tips.
|
// For more performance tips, see https://github.com/hajimehoshi/ebiten/wiki/Performance-Tips.
|
||||||
//
|
//
|
||||||
@ -144,7 +146,15 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
mode := opengl.CompositeMode(options.CompositeMode)
|
mode := opengl.CompositeMode(options.CompositeMode)
|
||||||
i.restorable.DrawImage(img.restorable, vs, &options.ColorM.impl, mode)
|
|
||||||
|
filter := graphics.FilterNearest
|
||||||
|
if options.Filter != FilterDefault {
|
||||||
|
filter = graphics.Filter(options.Filter)
|
||||||
|
} else if img.filter != FilterDefault {
|
||||||
|
filter = graphics.Filter(img.filter)
|
||||||
|
}
|
||||||
|
|
||||||
|
i.restorable.DrawImage(img.restorable, vs, &options.ColorM.impl, mode, filter)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,6 +253,15 @@ type DrawImageOptions struct {
|
|||||||
// The default (zero) value is regular alpha blending.
|
// The default (zero) value is regular alpha blending.
|
||||||
CompositeMode CompositeMode
|
CompositeMode CompositeMode
|
||||||
|
|
||||||
|
// Filter is a type of texture filter.
|
||||||
|
// The default (zero) value is FilterDefault.
|
||||||
|
//
|
||||||
|
// If both Filter specified at NewImage* and DrawImageOptions are FilterDefault,
|
||||||
|
// FilterNearest is used.
|
||||||
|
// If either is FilterDefault and the other is not, the latter is used.
|
||||||
|
// Otherwise, Filter specified at DrawImageOptions is used.
|
||||||
|
Filter Filter
|
||||||
|
|
||||||
// Deprecated (as of 1.5.0-alpha): Use SourceRect instead.
|
// Deprecated (as of 1.5.0-alpha): Use SourceRect instead.
|
||||||
ImageParts ImageParts
|
ImageParts ImageParts
|
||||||
|
|
||||||
@ -254,12 +273,15 @@ type DrawImageOptions struct {
|
|||||||
//
|
//
|
||||||
// If width or height is less than 1 or more than MaxImageSize, NewImage panics.
|
// If width or height is less than 1 or more than MaxImageSize, NewImage panics.
|
||||||
//
|
//
|
||||||
|
// filter argument is just for backward compatibility.
|
||||||
|
// If you are not sure, specify FilterDefault.
|
||||||
|
//
|
||||||
// Error returned by NewImage is always nil as of 1.5.0-alpha.
|
// Error returned by NewImage is always nil as of 1.5.0-alpha.
|
||||||
func NewImage(width, height int, filter Filter) (*Image, error) {
|
func NewImage(width, height int, filter Filter) (*Image, error) {
|
||||||
checkSize(width, height)
|
checkSize(width, height)
|
||||||
r := restorable.NewImage(width, height, graphics.Filter(filter), false)
|
r := restorable.NewImage(width, height, false)
|
||||||
r.Fill(0, 0, 0, 0)
|
r.Fill(0, 0, 0, 0)
|
||||||
i := &Image{r}
|
i := &Image{r, filter}
|
||||||
runtime.SetFinalizer(i, (*Image).Dispose)
|
runtime.SetFinalizer(i, (*Image).Dispose)
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
@ -281,9 +303,9 @@ func NewImage(width, height int, filter Filter) (*Image, error) {
|
|||||||
// Error returned by newVolatileImage is always nil as of 1.5.0-alpha.
|
// Error returned by newVolatileImage is always nil as of 1.5.0-alpha.
|
||||||
func newVolatileImage(width, height int, filter Filter) *Image {
|
func newVolatileImage(width, height int, filter Filter) *Image {
|
||||||
checkSize(width, height)
|
checkSize(width, height)
|
||||||
r := restorable.NewImage(width, height, graphics.Filter(filter), true)
|
r := restorable.NewImage(width, height, true)
|
||||||
r.Fill(0, 0, 0, 0)
|
r.Fill(0, 0, 0, 0)
|
||||||
i := &Image{r}
|
i := &Image{r, filter}
|
||||||
runtime.SetFinalizer(i, (*Image).Dispose)
|
runtime.SetFinalizer(i, (*Image).Dispose)
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
@ -292,12 +314,15 @@ func newVolatileImage(width, height int, filter Filter) *Image {
|
|||||||
//
|
//
|
||||||
// If source's width or height is less than 1 or more than MaxImageSize, NewImageFromImage panics.
|
// If source's width or height is less than 1 or more than MaxImageSize, NewImageFromImage panics.
|
||||||
//
|
//
|
||||||
|
// filter argument is just for backward compatibility.
|
||||||
|
// If you are not sure, specify FilterDefault.
|
||||||
|
//
|
||||||
// Error returned by NewImageFromImage is always nil as of 1.5.0-alpha.
|
// Error returned by NewImageFromImage is always nil as of 1.5.0-alpha.
|
||||||
func NewImageFromImage(source image.Image, filter Filter) (*Image, error) {
|
func NewImageFromImage(source image.Image, filter Filter) (*Image, error) {
|
||||||
size := source.Bounds().Size()
|
size := source.Bounds().Size()
|
||||||
checkSize(size.X, size.Y)
|
checkSize(size.X, size.Y)
|
||||||
r := restorable.NewImageFromImage(source, graphics.Filter(filter))
|
r := restorable.NewImageFromImage(source)
|
||||||
i := &Image{r}
|
i := &Image{r, filter}
|
||||||
runtime.SetFinalizer(i, (*Image).Dispose)
|
runtime.SetFinalizer(i, (*Image).Dispose)
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
@ -305,7 +330,7 @@ func NewImageFromImage(source image.Image, filter Filter) (*Image, error) {
|
|||||||
func newImageWithScreenFramebuffer(width, height int, offsetX, offsetY float64) *Image {
|
func newImageWithScreenFramebuffer(width, height int, offsetX, offsetY float64) *Image {
|
||||||
checkSize(width, height)
|
checkSize(width, height)
|
||||||
r := restorable.NewScreenFramebufferImage(width, height, offsetX, offsetY)
|
r := restorable.NewScreenFramebufferImage(width, height, offsetX, offsetY)
|
||||||
i := &Image{r}
|
i := &Image{r, FilterDefault}
|
||||||
runtime.SetFinalizer(i, (*Image).Dispose)
|
runtime.SetFinalizer(i, (*Image).Dispose)
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
@ -71,13 +71,13 @@ func (q *commandQueue) appendVertices(vertices []float32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EnqueueDrawImageCommand enqueues a drawing-image command.
|
// EnqueueDrawImageCommand enqueues a drawing-image command.
|
||||||
func (q *commandQueue) EnqueueDrawImageCommand(dst, src *Image, vertices []float32, clr *affine.ColorM, mode opengl.CompositeMode) {
|
func (q *commandQueue) EnqueueDrawImageCommand(dst, src *Image, vertices []float32, clr *affine.ColorM, mode opengl.CompositeMode, filter Filter) {
|
||||||
// Avoid defer for performance
|
// Avoid defer for performance
|
||||||
q.m.Lock()
|
q.m.Lock()
|
||||||
q.appendVertices(vertices)
|
q.appendVertices(vertices)
|
||||||
if 0 < len(q.commands) {
|
if 0 < len(q.commands) {
|
||||||
if c, ok := q.commands[len(q.commands)-1].(*drawImageCommand); ok {
|
if c, ok := q.commands[len(q.commands)-1].(*drawImageCommand); ok {
|
||||||
if c.canMerge(dst, src, clr, mode) {
|
if c.canMerge(dst, src, clr, mode, filter) {
|
||||||
c.verticesNum += len(vertices)
|
c.verticesNum += len(vertices)
|
||||||
q.m.Unlock()
|
q.m.Unlock()
|
||||||
return
|
return
|
||||||
@ -90,6 +90,7 @@ func (q *commandQueue) EnqueueDrawImageCommand(dst, src *Image, vertices []float
|
|||||||
verticesNum: len(vertices),
|
verticesNum: len(vertices),
|
||||||
color: *clr,
|
color: *clr,
|
||||||
mode: mode,
|
mode: mode,
|
||||||
|
filter: filter,
|
||||||
}
|
}
|
||||||
q.commands = append(q.commands, c)
|
q.commands = append(q.commands, c)
|
||||||
q.m.Unlock()
|
q.m.Unlock()
|
||||||
@ -225,6 +226,7 @@ type drawImageCommand struct {
|
|||||||
verticesNum int
|
verticesNum int
|
||||||
color affine.ColorM
|
color affine.ColorM
|
||||||
mode opengl.CompositeMode
|
mode opengl.CompositeMode
|
||||||
|
filter Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
// QuadVertexSizeInBytes returns the size in bytes of vertices for a quadrangle.
|
// QuadVertexSizeInBytes returns the size in bytes of vertices for a quadrangle.
|
||||||
@ -251,7 +253,7 @@ func (c *drawImageCommand) Exec(indexOffsetInBytes int) error {
|
|||||||
sh = emath.NextPowerOf2Int(sh)
|
sh = emath.NextPowerOf2Int(sh)
|
||||||
_, dh := c.dst.Size()
|
_, dh := c.dst.Size()
|
||||||
proj := f.projectionMatrix(dh)
|
proj := f.projectionMatrix(dh)
|
||||||
theOpenGLState.useProgram(proj, c.src.texture.native, sw, sh, c.color, c.src.texture.filter)
|
theOpenGLState.useProgram(proj, c.src.texture.native, sw, sh, c.color, c.filter)
|
||||||
// TODO: We should call glBindBuffer here?
|
// TODO: We should call glBindBuffer here?
|
||||||
// The buffer is already bound at begin() but it is counterintuitive.
|
// The buffer is already bound at begin() but it is counterintuitive.
|
||||||
opengl.GetContext().DrawElements(opengl.Triangles, 6*n, indexOffsetInBytes)
|
opengl.GetContext().DrawElements(opengl.Triangles, 6*n, indexOffsetInBytes)
|
||||||
@ -279,7 +281,7 @@ func (c *drawImageCommand) split(quadsNum int) [2]*drawImageCommand {
|
|||||||
|
|
||||||
// canMerge returns a boolean value indicating whether the other drawImageCommand can be merged
|
// canMerge returns a boolean value indicating whether the other drawImageCommand can be merged
|
||||||
// with the drawImageCommand c.
|
// with the drawImageCommand c.
|
||||||
func (c *drawImageCommand) canMerge(dst, src *Image, clr *affine.ColorM, mode opengl.CompositeMode) bool {
|
func (c *drawImageCommand) canMerge(dst, src *Image, clr *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool {
|
||||||
if c.dst != dst {
|
if c.dst != dst {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -292,6 +294,9 @@ func (c *drawImageCommand) canMerge(dst, src *Image, clr *affine.ColorM, mode op
|
|||||||
if c.mode != mode {
|
if c.mode != mode {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if c.filter != filter {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,7 +356,6 @@ func (c *disposeCommand) Exec(indexOffsetInBytes int) error {
|
|||||||
type newImageFromImageCommand struct {
|
type newImageFromImageCommand struct {
|
||||||
result *Image
|
result *Image
|
||||||
img *image.RGBA
|
img *image.RGBA
|
||||||
filter Filter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the newImageFromImageCommand.
|
// Exec executes the newImageFromImageCommand.
|
||||||
@ -373,7 +377,6 @@ func (c *newImageFromImageCommand) Exec(indexOffsetInBytes int) error {
|
|||||||
}
|
}
|
||||||
c.result.texture = &texture{
|
c.result.texture = &texture{
|
||||||
native: native,
|
native: native,
|
||||||
filter: c.filter,
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -383,7 +386,6 @@ type newImageCommand struct {
|
|||||||
result *Image
|
result *Image
|
||||||
width int
|
width int
|
||||||
height int
|
height int
|
||||||
filter Filter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes a newImageCommand.
|
// Exec executes a newImageCommand.
|
||||||
@ -402,7 +404,6 @@ func (c *newImageCommand) Exec(indexOffsetInBytes int) error {
|
|||||||
}
|
}
|
||||||
c.result.texture = &texture{
|
c.result.texture = &texture{
|
||||||
native: native,
|
native: native,
|
||||||
filter: c.filter,
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ type Image struct {
|
|||||||
// MaxImageSize is the maximum of width/height of an image.
|
// MaxImageSize is the maximum of width/height of an image.
|
||||||
const MaxImageSize = defaultViewportSize
|
const MaxImageSize = defaultViewportSize
|
||||||
|
|
||||||
func NewImage(width, height int, filter Filter) *Image {
|
func NewImage(width, height int) *Image {
|
||||||
i := &Image{
|
i := &Image{
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
@ -42,13 +42,12 @@ func NewImage(width, height int, filter Filter) *Image {
|
|||||||
result: i,
|
result: i,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
filter: filter,
|
|
||||||
}
|
}
|
||||||
theCommandQueue.Enqueue(c)
|
theCommandQueue.Enqueue(c)
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewImageFromImage(img *image.RGBA, width, height int, filter Filter) *Image {
|
func NewImageFromImage(img *image.RGBA, width, height int) *Image {
|
||||||
i := &Image{
|
i := &Image{
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
@ -56,7 +55,6 @@ func NewImageFromImage(img *image.RGBA, width, height int, filter Filter) *Image
|
|||||||
c := &newImageFromImageCommand{
|
c := &newImageFromImageCommand{
|
||||||
result: i,
|
result: i,
|
||||||
img: img,
|
img: img,
|
||||||
filter: filter,
|
|
||||||
}
|
}
|
||||||
theCommandQueue.Enqueue(c)
|
theCommandQueue.Enqueue(c)
|
||||||
return i
|
return i
|
||||||
@ -100,8 +98,8 @@ func (i *Image) Fill(r, g, b, a uint8) {
|
|||||||
theCommandQueue.Enqueue(c)
|
theCommandQueue.Enqueue(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) DrawImage(src *Image, vertices []float32, clr *affine.ColorM, mode opengl.CompositeMode) {
|
func (i *Image) DrawImage(src *Image, vertices []float32, clr *affine.ColorM, mode opengl.CompositeMode, filter Filter) {
|
||||||
theCommandQueue.EnqueueDrawImageCommand(i, src, vertices, clr, mode)
|
theCommandQueue.EnqueueDrawImageCommand(i, src, vertices, clr, mode, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) Pixels() ([]byte, error) {
|
func (i *Image) Pixels() ([]byte, error) {
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
type Filter int
|
type Filter int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
FilterNone Filter = iota
|
FilterDefault Filter = iota
|
||||||
FilterNearest
|
FilterNearest
|
||||||
FilterLinear
|
FilterLinear
|
||||||
)
|
)
|
||||||
@ -29,5 +29,4 @@ const (
|
|||||||
// texture represents OpenGL's texture.
|
// texture represents OpenGL's texture.
|
||||||
type texture struct {
|
type texture struct {
|
||||||
native opengl.Texture
|
native opengl.Texture
|
||||||
filter Filter
|
|
||||||
}
|
}
|
||||||
|
@ -40,11 +40,12 @@ type drawImageHistoryItem struct {
|
|||||||
vertices []float32
|
vertices []float32
|
||||||
colorm affine.ColorM
|
colorm affine.ColorM
|
||||||
mode opengl.CompositeMode
|
mode opengl.CompositeMode
|
||||||
|
filter graphics.Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
// canMerge returns a boolean value indicating whether the drawImageHistoryItem d
|
// canMerge returns a boolean value indicating whether the drawImageHistoryItem d
|
||||||
// can be merged with the given conditions.
|
// can be merged with the given conditions.
|
||||||
func (d *drawImageHistoryItem) canMerge(image *Image, colorm *affine.ColorM, mode opengl.CompositeMode) bool {
|
func (d *drawImageHistoryItem) canMerge(image *Image, colorm *affine.ColorM, mode opengl.CompositeMode, filter graphics.Filter) bool {
|
||||||
if d.image != image {
|
if d.image != image {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -54,13 +55,15 @@ func (d *drawImageHistoryItem) canMerge(image *Image, colorm *affine.ColorM, mod
|
|||||||
if d.mode != mode {
|
if d.mode != mode {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if d.filter != filter {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image represents an image that can be restored when GL context is lost.
|
// Image represents an image that can be restored when GL context is lost.
|
||||||
type Image struct {
|
type Image struct {
|
||||||
image *graphics.Image
|
image *graphics.Image
|
||||||
filter graphics.Filter
|
|
||||||
|
|
||||||
// baseImage and baseColor are exclusive.
|
// baseImage and baseColor are exclusive.
|
||||||
basePixels []byte
|
basePixels []byte
|
||||||
@ -83,11 +86,10 @@ type Image struct {
|
|||||||
offsetY float64
|
offsetY float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewImage creates an empty image with the given size and filter.
|
// NewImage creates an empty image with the given size.
|
||||||
func NewImage(width, height int, filter graphics.Filter, volatile bool) *Image {
|
func NewImage(width, height int, volatile bool) *Image {
|
||||||
i := &Image{
|
i := &Image{
|
||||||
image: graphics.NewImage(width, height, filter),
|
image: graphics.NewImage(width, height),
|
||||||
filter: filter,
|
|
||||||
volatile: volatile,
|
volatile: volatile,
|
||||||
}
|
}
|
||||||
theImages.add(i)
|
theImages.add(i)
|
||||||
@ -96,7 +98,7 @@ func NewImage(width, height int, filter graphics.Filter, volatile bool) *Image {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewImageFromImage creates an image with source image.
|
// NewImageFromImage creates an image with source image.
|
||||||
func NewImageFromImage(source image.Image, filter graphics.Filter) *Image {
|
func NewImageFromImage(source image.Image) *Image {
|
||||||
size := source.Bounds().Size()
|
size := source.Bounds().Size()
|
||||||
width, height := size.X, size.Y
|
width, height := size.X, size.Y
|
||||||
rgbaImg := CopyImage(source)
|
rgbaImg := CopyImage(source)
|
||||||
@ -106,9 +108,8 @@ func NewImageFromImage(source image.Image, filter graphics.Filter) *Image {
|
|||||||
copy(p[j*w2*4:(j+1)*w2*4], rgbaImg.Pix[j*rgbaImg.Stride:])
|
copy(p[j*w2*4:(j+1)*w2*4], rgbaImg.Pix[j*rgbaImg.Stride:])
|
||||||
}
|
}
|
||||||
i := &Image{
|
i := &Image{
|
||||||
image: graphics.NewImageFromImage(rgbaImg, width, height, filter),
|
image: graphics.NewImageFromImage(rgbaImg, width, height),
|
||||||
basePixels: p,
|
basePixels: p,
|
||||||
filter: filter,
|
|
||||||
}
|
}
|
||||||
theImages.add(i)
|
theImages.add(i)
|
||||||
runtime.SetFinalizer(i, (*Image).Dispose)
|
runtime.SetFinalizer(i, (*Image).Dispose)
|
||||||
@ -183,24 +184,24 @@ func (i *Image) ReplacePixels(pixels []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DrawImage draws a given image img to the image.
|
// DrawImage draws a given image img to the image.
|
||||||
func (i *Image) DrawImage(img *Image, vertices []float32, colorm *affine.ColorM, mode opengl.CompositeMode) {
|
func (i *Image) DrawImage(img *Image, vertices []float32, colorm *affine.ColorM, mode opengl.CompositeMode, filter graphics.Filter) {
|
||||||
theImages.makeStaleIfDependingOn(i)
|
theImages.makeStaleIfDependingOn(i)
|
||||||
if img.stale || img.volatile || !IsRestoringEnabled() {
|
if img.stale || img.volatile || !IsRestoringEnabled() {
|
||||||
i.makeStale()
|
i.makeStale()
|
||||||
} else {
|
} else {
|
||||||
i.appendDrawImageHistory(img, vertices, colorm, mode)
|
i.appendDrawImageHistory(img, vertices, colorm, mode, filter)
|
||||||
}
|
}
|
||||||
i.image.DrawImage(img.image, vertices, colorm, mode)
|
i.image.DrawImage(img.image, vertices, colorm, mode, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// appendDrawImageHistory appends a draw-image history item to the image.
|
// appendDrawImageHistory appends a draw-image history item to the image.
|
||||||
func (i *Image) appendDrawImageHistory(image *Image, vertices []float32, colorm *affine.ColorM, mode opengl.CompositeMode) {
|
func (i *Image) appendDrawImageHistory(image *Image, vertices []float32, colorm *affine.ColorM, mode opengl.CompositeMode, filter graphics.Filter) {
|
||||||
if i.stale || i.volatile {
|
if i.stale || i.volatile {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(i.drawImageHistory) > 0 {
|
if len(i.drawImageHistory) > 0 {
|
||||||
last := i.drawImageHistory[len(i.drawImageHistory)-1]
|
last := i.drawImageHistory[len(i.drawImageHistory)-1]
|
||||||
if last.canMerge(image, colorm, mode) {
|
if last.canMerge(image, colorm, mode, filter) {
|
||||||
last.vertices = append(last.vertices, vertices...)
|
last.vertices = append(last.vertices, vertices...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -217,6 +218,7 @@ func (i *Image) appendDrawImageHistory(image *Image, vertices []float32, colorm
|
|||||||
vertices: vertices,
|
vertices: vertices,
|
||||||
colorm: *colorm,
|
colorm: *colorm,
|
||||||
mode: mode,
|
mode: mode,
|
||||||
|
filter: filter,
|
||||||
}
|
}
|
||||||
i.drawImageHistory = append(i.drawImageHistory, item)
|
i.drawImageHistory = append(i.drawImageHistory, item)
|
||||||
}
|
}
|
||||||
@ -318,7 +320,7 @@ func (i *Image) restore() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if i.volatile {
|
if i.volatile {
|
||||||
i.image = graphics.NewImage(w, h, i.filter)
|
i.image = graphics.NewImage(w, h)
|
||||||
i.basePixels = nil
|
i.basePixels = nil
|
||||||
i.baseColor = color.RGBA{}
|
i.baseColor = color.RGBA{}
|
||||||
i.drawImageHistory = nil
|
i.drawImageHistory = nil
|
||||||
@ -336,7 +338,7 @@ func (i *Image) restore() error {
|
|||||||
copy(img.Pix[j*img.Stride:], i.basePixels[j*w2*4:(j+1)*w2*4])
|
copy(img.Pix[j*img.Stride:], i.basePixels[j*w2*4:(j+1)*w2*4])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gimg := graphics.NewImageFromImage(img, w, h, i.filter)
|
gimg := graphics.NewImageFromImage(img, w, h)
|
||||||
if i.baseColor != (color.RGBA{}) {
|
if i.baseColor != (color.RGBA{}) {
|
||||||
if i.basePixels != nil {
|
if i.basePixels != nil {
|
||||||
panic("not reached")
|
panic("not reached")
|
||||||
@ -348,7 +350,7 @@ func (i *Image) restore() error {
|
|||||||
if c.image.hasDependency() {
|
if c.image.hasDependency() {
|
||||||
panic("not reached")
|
panic("not reached")
|
||||||
}
|
}
|
||||||
gimg.DrawImage(c.image.image, c.vertices, &c.colorm, c.mode)
|
gimg.DrawImage(c.image.image, c.vertices, &c.colorm, c.mode, c.filter)
|
||||||
}
|
}
|
||||||
i.image = gimg
|
i.image = gimg
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ func sameColors(c1, c2 color.RGBA, delta int) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRestore(t *testing.T) {
|
func TestRestore(t *testing.T) {
|
||||||
img0 := NewImage(1, 1, graphics.FilterNearest, false)
|
img0 := NewImage(1, 1, false)
|
||||||
// Clear images explicitly.
|
// Clear images explicitly.
|
||||||
// In this 'restorable' layer, reused texture might not be cleared.
|
// In this 'restorable' layer, reused texture might not be cleared.
|
||||||
img0.Fill(0, 0, 0, 0)
|
img0.Fill(0, 0, 0, 0)
|
||||||
@ -109,7 +109,7 @@ func TestRestoreChain(t *testing.T) {
|
|||||||
const num = 10
|
const num = 10
|
||||||
imgs := []*Image{}
|
imgs := []*Image{}
|
||||||
for i := 0; i < num; i++ {
|
for i := 0; i < num; i++ {
|
||||||
img := NewImage(1, 1, graphics.FilterNearest, false)
|
img := NewImage(1, 1, false)
|
||||||
img.Fill(0, 0, 0, 0)
|
img.Fill(0, 0, 0, 0)
|
||||||
imgs = append(imgs, img)
|
imgs = append(imgs, img)
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ func TestRestoreChain(t *testing.T) {
|
|||||||
clr := color.RGBA{0x00, 0x00, 0x00, 0xff}
|
clr := color.RGBA{0x00, 0x00, 0x00, 0xff}
|
||||||
imgs[0].Fill(clr.R, clr.G, clr.B, clr.A)
|
imgs[0].Fill(clr.R, clr.G, clr.B, clr.A)
|
||||||
for i := 0; i < num-1; i++ {
|
for i := 0; i < num-1; i++ {
|
||||||
imgs[i+1].DrawImage(imgs[i], vertices(1, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver)
|
imgs[i+1].DrawImage(imgs[i], vertices(1, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver, graphics.FilterNearest)
|
||||||
}
|
}
|
||||||
if err := ResolveStaleImages(); err != nil {
|
if err := ResolveStaleImages(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -139,13 +139,13 @@ func TestRestoreChain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRestoreOverrideSource(t *testing.T) {
|
func TestRestoreOverrideSource(t *testing.T) {
|
||||||
img0 := NewImage(1, 1, graphics.FilterNearest, false)
|
img0 := NewImage(1, 1, false)
|
||||||
img0.Fill(0, 0, 0, 0)
|
img0.Fill(0, 0, 0, 0)
|
||||||
img1 := NewImage(1, 1, graphics.FilterNearest, false)
|
img1 := NewImage(1, 1, false)
|
||||||
img1.Fill(0, 0, 0, 0)
|
img1.Fill(0, 0, 0, 0)
|
||||||
img2 := NewImage(1, 1, graphics.FilterNearest, false)
|
img2 := NewImage(1, 1, false)
|
||||||
img2.Fill(0, 0, 0, 0)
|
img2.Fill(0, 0, 0, 0)
|
||||||
img3 := NewImage(1, 1, graphics.FilterNearest, false)
|
img3 := NewImage(1, 1, false)
|
||||||
img3.Fill(0, 0, 0, 0)
|
img3.Fill(0, 0, 0, 0)
|
||||||
defer func() {
|
defer func() {
|
||||||
img3.Dispose()
|
img3.Dispose()
|
||||||
@ -156,10 +156,10 @@ func TestRestoreOverrideSource(t *testing.T) {
|
|||||||
clr0 := color.RGBA{0x00, 0x00, 0x00, 0xff}
|
clr0 := color.RGBA{0x00, 0x00, 0x00, 0xff}
|
||||||
clr1 := color.RGBA{0x00, 0x00, 0x01, 0xff}
|
clr1 := color.RGBA{0x00, 0x00, 0x01, 0xff}
|
||||||
img1.Fill(clr0.R, clr0.G, clr0.B, clr0.A)
|
img1.Fill(clr0.R, clr0.G, clr0.B, clr0.A)
|
||||||
img2.DrawImage(img1, vertices(1, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver)
|
img2.DrawImage(img1, vertices(1, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver, graphics.FilterNearest)
|
||||||
img3.DrawImage(img2, vertices(1, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver)
|
img3.DrawImage(img2, vertices(1, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver, graphics.FilterNearest)
|
||||||
img0.Fill(clr1.R, clr1.G, clr1.B, clr1.A)
|
img0.Fill(clr1.R, clr1.G, clr1.B, clr1.A)
|
||||||
img1.DrawImage(img0, vertices(1, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver)
|
img1.DrawImage(img0, vertices(1, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver, graphics.FilterNearest)
|
||||||
if err := ResolveStaleImages(); err != nil {
|
if err := ResolveStaleImages(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -214,18 +214,18 @@ func TestRestoreComplexGraph(t *testing.T) {
|
|||||||
base.Pix[1] = 0xff
|
base.Pix[1] = 0xff
|
||||||
base.Pix[2] = 0xff
|
base.Pix[2] = 0xff
|
||||||
base.Pix[3] = 0xff
|
base.Pix[3] = 0xff
|
||||||
img0 := NewImageFromImage(base, graphics.FilterNearest)
|
img0 := NewImageFromImage(base)
|
||||||
img1 := NewImageFromImage(base, graphics.FilterNearest)
|
img1 := NewImageFromImage(base)
|
||||||
img2 := NewImageFromImage(base, graphics.FilterNearest)
|
img2 := NewImageFromImage(base)
|
||||||
img3 := NewImage(4, 1, graphics.FilterNearest, false)
|
img3 := NewImage(4, 1, false)
|
||||||
img3.Fill(0, 0, 0, 0)
|
img3.Fill(0, 0, 0, 0)
|
||||||
img4 := NewImage(4, 1, graphics.FilterNearest, false)
|
img4 := NewImage(4, 1, false)
|
||||||
img4.Fill(0, 0, 0, 0)
|
img4.Fill(0, 0, 0, 0)
|
||||||
img5 := NewImage(4, 1, graphics.FilterNearest, false)
|
img5 := NewImage(4, 1, false)
|
||||||
img5.Fill(0, 0, 0, 0)
|
img5.Fill(0, 0, 0, 0)
|
||||||
img6 := NewImage(4, 1, graphics.FilterNearest, false)
|
img6 := NewImage(4, 1, false)
|
||||||
img6.Fill(0, 0, 0, 0)
|
img6.Fill(0, 0, 0, 0)
|
||||||
img7 := NewImage(4, 1, graphics.FilterNearest, false)
|
img7 := NewImage(4, 1, false)
|
||||||
img7.Fill(0, 0, 0, 0)
|
img7.Fill(0, 0, 0, 0)
|
||||||
defer func() {
|
defer func() {
|
||||||
img7.Dispose()
|
img7.Dispose()
|
||||||
@ -237,15 +237,15 @@ func TestRestoreComplexGraph(t *testing.T) {
|
|||||||
img1.Dispose()
|
img1.Dispose()
|
||||||
img0.Dispose()
|
img0.Dispose()
|
||||||
}()
|
}()
|
||||||
img3.DrawImage(img0, vertices(4, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver)
|
img3.DrawImage(img0, vertices(4, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver, graphics.FilterNearest)
|
||||||
img3.DrawImage(img1, vertices(4, 1, 1, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver)
|
img3.DrawImage(img1, vertices(4, 1, 1, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver, graphics.FilterNearest)
|
||||||
img4.DrawImage(img1, vertices(4, 1, 1, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver)
|
img4.DrawImage(img1, vertices(4, 1, 1, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver, graphics.FilterNearest)
|
||||||
img4.DrawImage(img2, vertices(4, 1, 2, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver)
|
img4.DrawImage(img2, vertices(4, 1, 2, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver, graphics.FilterNearest)
|
||||||
img5.DrawImage(img3, vertices(4, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver)
|
img5.DrawImage(img3, vertices(4, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver, graphics.FilterNearest)
|
||||||
img6.DrawImage(img3, vertices(4, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver)
|
img6.DrawImage(img3, vertices(4, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver, graphics.FilterNearest)
|
||||||
img6.DrawImage(img4, vertices(4, 1, 1, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver)
|
img6.DrawImage(img4, vertices(4, 1, 1, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver, graphics.FilterNearest)
|
||||||
img7.DrawImage(img2, vertices(4, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver)
|
img7.DrawImage(img2, vertices(4, 1, 0, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver, graphics.FilterNearest)
|
||||||
img7.DrawImage(img3, vertices(4, 1, 2, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver)
|
img7.DrawImage(img3, vertices(4, 1, 2, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver, graphics.FilterNearest)
|
||||||
if err := ResolveStaleImages(); err != nil {
|
if err := ResolveStaleImages(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -318,15 +318,15 @@ func TestRestoreRecursive(t *testing.T) {
|
|||||||
base.Pix[1] = 0xff
|
base.Pix[1] = 0xff
|
||||||
base.Pix[2] = 0xff
|
base.Pix[2] = 0xff
|
||||||
base.Pix[3] = 0xff
|
base.Pix[3] = 0xff
|
||||||
img0 := NewImageFromImage(base, graphics.FilterNearest)
|
img0 := NewImageFromImage(base)
|
||||||
img1 := NewImage(4, 1, graphics.FilterNearest, false)
|
img1 := NewImage(4, 1, false)
|
||||||
img1.Fill(0, 0, 0, 0)
|
img1.Fill(0, 0, 0, 0)
|
||||||
defer func() {
|
defer func() {
|
||||||
img1.Dispose()
|
img1.Dispose()
|
||||||
img0.Dispose()
|
img0.Dispose()
|
||||||
}()
|
}()
|
||||||
img1.DrawImage(img0, vertices(4, 1, 1, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver)
|
img1.DrawImage(img0, vertices(4, 1, 1, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver, graphics.FilterNearest)
|
||||||
img0.DrawImage(img1, vertices(4, 1, 1, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver)
|
img0.DrawImage(img1, vertices(4, 1, 1, 0), &affine.ColorM{}, opengl.CompositeModeSourceOver, graphics.FilterNearest)
|
||||||
if err := ResolveStaleImages(); err != nil {
|
if err := ResolveStaleImages(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user