mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-01-26 02:42:02 +01:00
ebiten: Allow SubImage at DrawRectShader
This commit is contained in:
parent
f287fada13
commit
41564533f9
54
image.go
54
image.go
@ -274,26 +274,23 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error {
|
||||
vs := graphics.QuadVertices(sx0, sy0, sx1, sy1, a, b, c, d, tx, ty, 1, 1, 1, 1, filter == driver.FilterScreen)
|
||||
is := graphics.QuadIndices()
|
||||
|
||||
var sr driver.Region
|
||||
// Pass the source region only when the shader is used, since this affects the condition of merging graphics
|
||||
// commands (#1293).
|
||||
if options.Shader != nil {
|
||||
sr = driver.Region{
|
||||
X: float32(bounds.Min.X),
|
||||
Y: float32(bounds.Min.Y),
|
||||
Width: float32(bounds.Dx()),
|
||||
Height: float32(bounds.Dy()),
|
||||
}
|
||||
}
|
||||
|
||||
srcs := [graphics.ShaderImageNum]*mipmap.Mipmap{img.mipmap}
|
||||
if options.Shader == nil {
|
||||
i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.impl, mode, filter, driver.AddressUnsafe, sr, nil, nil, canSkipMipmap(options.GeoM, filter))
|
||||
i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.impl, mode, filter, driver.AddressUnsafe, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, canSkipMipmap(options.GeoM, filter))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Pass the source region only when the shader is used, since this affects the condition of merging graphics
|
||||
// commands (#1293).
|
||||
sr := driver.Region{
|
||||
X: float32(bounds.Min.X),
|
||||
Y: float32(bounds.Min.Y),
|
||||
Width: float32(bounds.Dx()),
|
||||
Height: float32(bounds.Dy()),
|
||||
}
|
||||
|
||||
us := options.Shader.convertUniforms(options.Uniforms)
|
||||
i.mipmap.DrawTriangles(srcs, vs, is, nil, mode, filter, driver.AddressUnsafe, sr, options.Shader.shader, us, canSkipMipmap(options.GeoM, filter))
|
||||
i.mipmap.DrawTriangles(srcs, vs, is, nil, mode, filter, driver.AddressUnsafe, sr, [graphics.ShaderImageNum - 1][2]float32{}, options.Shader.shader, us, canSkipMipmap(options.GeoM, filter))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -489,12 +486,12 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
|
||||
}
|
||||
|
||||
if options.Shader == nil {
|
||||
i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.impl, mode, filter, driver.Address(options.Address), sr, nil, nil, false)
|
||||
i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.impl, mode, filter, driver.Address(options.Address), sr, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false)
|
||||
return
|
||||
}
|
||||
|
||||
us := options.Shader.convertUniforms(options.Uniforms)
|
||||
i.mipmap.DrawTriangles(srcs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, sr, options.Shader.shader, us, false)
|
||||
i.mipmap.DrawTriangles(srcs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, sr, [graphics.ShaderImageNum - 1][2]float32{}, options.Shader.shader, us, false)
|
||||
}
|
||||
|
||||
// DrawRectShaderOptions represents options for DrawRectShader
|
||||
@ -557,18 +554,21 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR
|
||||
if img.isDisposed() {
|
||||
panic("ebiten: the given image to DrawRectShader must not be disposed")
|
||||
}
|
||||
if img.isSubImage() {
|
||||
// TODO: Implement this.
|
||||
panic("ebiten: rendering a sub-image is not implemented (DrawRectShader)")
|
||||
}
|
||||
if w, h := img.Size(); width != w || height != h {
|
||||
panic("ebiten: all the source images must be the same size with the rectangle")
|
||||
}
|
||||
imgs[i] = img.mipmap
|
||||
}
|
||||
|
||||
sx, sy := float32(0), float32(0)
|
||||
if options.Images[0] != nil {
|
||||
b := options.Images[0].Bounds()
|
||||
sx = float32(b.Min.X)
|
||||
sy = float32(b.Min.Y)
|
||||
}
|
||||
|
||||
a, b, c, d, tx, ty := options.GeoM.elements32()
|
||||
vs := graphics.QuadVertices(0, 0, float32(width), float32(height), a, b, c, d, tx, ty, 1, 1, 1, 1, false)
|
||||
vs := graphics.QuadVertices(sx, sy, sx+float32(width), sy+float32(height), a, b, c, d, tx, ty, 1, 1, 1, 1, false)
|
||||
is := graphics.QuadIndices()
|
||||
|
||||
var sr driver.Region
|
||||
@ -582,8 +582,18 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR
|
||||
}
|
||||
}
|
||||
|
||||
var offsets [graphics.ShaderImageNum - 1][2]float32
|
||||
for i, img := range options.Images[1:] {
|
||||
if img == nil {
|
||||
continue
|
||||
}
|
||||
b := img.Bounds()
|
||||
offsets[i][0] = -sx + float32(b.Min.X)
|
||||
offsets[i][1] = -sy + float32(b.Min.Y)
|
||||
}
|
||||
|
||||
us := shader.convertUniforms(options.Uniforms)
|
||||
i.mipmap.DrawTriangles(imgs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, sr, shader.shader, us, canSkipMipmap(options.GeoM, driver.FilterNearest))
|
||||
i.mipmap.DrawTriangles(imgs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, sr, offsets, shader.shader, us, canSkipMipmap(options.GeoM, driver.FilterNearest))
|
||||
}
|
||||
|
||||
// SubImage returns an image representing the portion of the image p visible through r.
|
||||
|
@ -248,7 +248,7 @@ func (i *Image) replacePendingPixels(pix []byte, x, y, width, height int) {
|
||||
// DrawTriangles draws the src image with the given vertices.
|
||||
//
|
||||
// Copying vertices and indices is the caller's responsibility.
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader, uniforms []interface{}) {
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}) {
|
||||
for _, src := range srcs {
|
||||
if i == src {
|
||||
panic("buffered: Image.DrawTriangles: source images must be different from the receiver")
|
||||
@ -258,7 +258,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []f
|
||||
if maybeCanAddDelayedCommand() {
|
||||
if tryAddDelayedCommand(func() error {
|
||||
// Arguments are not copied. Copying is the caller's responsibility.
|
||||
i.DrawTriangles(srcs, vertices, indices, colorm, mode, filter, address, sourceRegion, shader, uniforms)
|
||||
i.DrawTriangles(srcs, vertices, indices, colorm, mode, filter, address, sourceRegion, subimageOffsets, shader, uniforms)
|
||||
return nil
|
||||
}) {
|
||||
return
|
||||
@ -286,7 +286,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []f
|
||||
imgs[i] = img.img
|
||||
}
|
||||
|
||||
i.img.DrawTriangles(imgs, vertices, indices, colorm, mode, filter, address, sourceRegion, s, uniforms)
|
||||
i.img.DrawTriangles(imgs, vertices, indices, colorm, mode, filter, address, sourceRegion, subimageOffsets, s, uniforms)
|
||||
i.invalidatePendingPixels()
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ func (m *Mipmap) Pixels(x, y, width, height int) ([]byte, error) {
|
||||
return m.orig.Pixels(x, y, width, height)
|
||||
}
|
||||
|
||||
func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageNum]*Mipmap, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader, uniforms []interface{}, canSkipMipmap bool) {
|
||||
func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageNum]*Mipmap, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}, canSkipMipmap bool) {
|
||||
if len(indices) == 0 {
|
||||
return
|
||||
}
|
||||
@ -176,7 +176,7 @@ func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageNum]*Mipmap, vertices [
|
||||
imgs[i] = src.orig
|
||||
}
|
||||
|
||||
m.orig.DrawTriangles(imgs, vertices, indices, colorm, mode, filter, address, sourceRegion, s, uniforms)
|
||||
m.orig.DrawTriangles(imgs, vertices, indices, colorm, mode, filter, address, sourceRegion, subimageOffsets, s, uniforms)
|
||||
m.disposeMipmaps()
|
||||
}
|
||||
|
||||
@ -238,7 +238,7 @@ func (m *Mipmap) level(level int) *buffered.Image {
|
||||
}
|
||||
s := buffered.NewImage(w2, h2)
|
||||
s.SetVolatile(m.volatile)
|
||||
s.DrawTriangles([graphics.ShaderImageNum]*buffered.Image{src}, vs, is, nil, driver.CompositeModeCopy, filter, driver.AddressUnsafe, driver.Region{}, nil, nil)
|
||||
s.DrawTriangles([graphics.ShaderImageNum]*buffered.Image{src}, vs, is, nil, driver.CompositeModeCopy, filter, driver.AddressUnsafe, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
m.imgs[level] = s
|
||||
|
||||
return m.imgs[level]
|
||||
|
@ -306,7 +306,7 @@ func (i *Image) processSrc(src *Image) {
|
||||
// 5: Color G
|
||||
// 6: Color B
|
||||
// 7: Color Y
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, shader *Shader, uniforms []interface{}) {
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, sourceRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}) {
|
||||
backendsM.Lock()
|
||||
// Do not use defer for performance.
|
||||
|
||||
@ -362,8 +362,8 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []f
|
||||
ox, oy, _, _ := src.regionWithPadding()
|
||||
ox += paddingSize
|
||||
oy += paddingSize
|
||||
offsets[i][0] = float32(ox) - oxf
|
||||
offsets[i][1] = float32(oy) - oyf
|
||||
offsets[i][0] = float32(ox) - oxf + subimageOffsets[i][0]
|
||||
offsets[i][1] = float32(oy) - oyf + subimageOffsets[i][0]
|
||||
}
|
||||
|
||||
var s *restorable.Shader
|
||||
|
@ -96,7 +96,7 @@ func TestEnsureNotShared(t *testing.T) {
|
||||
// img4.ensureNotShared() should be called.
|
||||
vs := quadVertices(size/2, size/2, size/4, size/4, 1)
|
||||
is := graphics.QuadIndices()
|
||||
img4.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
|
||||
img4.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
want := false
|
||||
if got := img4.IsSharedForTesting(); got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
@ -126,7 +126,7 @@ func TestEnsureNotShared(t *testing.T) {
|
||||
|
||||
// Check further drawing doesn't cause panic.
|
||||
// This bug was fixed by 03dcd948.
|
||||
img4.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
|
||||
img4.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
}
|
||||
|
||||
func TestReshared(t *testing.T) {
|
||||
@ -167,7 +167,7 @@ func TestReshared(t *testing.T) {
|
||||
// Use img1 as a render target.
|
||||
vs := quadVertices(size, size, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
|
||||
img1.DrawTriangles([graphics.ShaderImageNum]*Image{img2}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
if got, want := img1.IsSharedForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -177,7 +177,7 @@ func TestReshared(t *testing.T) {
|
||||
if err := MakeImagesSharedForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
if got, want := img1.IsSharedForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -204,7 +204,7 @@ func TestReshared(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img1}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
if got, want := img1.IsSharedForTesting(), true; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -232,7 +232,7 @@ func TestReshared(t *testing.T) {
|
||||
if err := MakeImagesSharedForTesting(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
|
||||
img0.DrawTriangles([graphics.ShaderImageNum]*Image{img3}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
if got, want := img3.IsSharedForTesting(), false; got != want {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
@ -327,7 +327,7 @@ func TestReplacePixelsAfterDrawTriangles(t *testing.T) {
|
||||
|
||||
vs := quadVertices(w, h, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
dst.ReplacePixels(pix)
|
||||
|
||||
pix, err := dst.Pixels(0, 0, w, h)
|
||||
@ -369,7 +369,7 @@ func TestSmallImages(t *testing.T) {
|
||||
|
||||
vs := quadVertices(w, h, 0, 0, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
|
||||
pix, err := dst.Pixels(0, 0, w, h)
|
||||
if err != nil {
|
||||
@ -411,7 +411,7 @@ func TestLongImages(t *testing.T) {
|
||||
const scale = 120
|
||||
vs := quadVertices(w, h, 0, 0, scale)
|
||||
is := graphics.QuadIndices()
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, nil, nil)
|
||||
dst.DrawTriangles([graphics.ShaderImageNum]*Image{src}, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressUnsafe, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil)
|
||||
|
||||
pix, err := dst.Pixels(0, 0, dstW, dstH)
|
||||
if err != nil {
|
||||
|
@ -15,6 +15,7 @@
|
||||
package ebiten_test
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"testing"
|
||||
|
||||
@ -798,3 +799,66 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestShaderSubImage(t *testing.T) {
|
||||
const w, h = 16, 16
|
||||
|
||||
dst, _ := NewImage(w, h, FilterDefault)
|
||||
s, err := NewShader([]byte(`package main
|
||||
|
||||
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
|
||||
r := imageSrc0At(texCoord).r
|
||||
g := imageSrc1At(texCoord).g
|
||||
return vec4(r, g, 0, 1)
|
||||
}
|
||||
`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
src0, _ := NewImage(w, h, FilterDefault)
|
||||
pix0 := make([]byte, 4*w*h)
|
||||
for j := 0; j < h; j++ {
|
||||
for i := 0; i < w; i++ {
|
||||
if 2 <= i && i < 10 && 2 <= j && j < 10 {
|
||||
pix0[4*(j*w+i)] = 0xff
|
||||
pix0[4*(j*w+i)+1] = 0
|
||||
pix0[4*(j*w+i)+2] = 0
|
||||
pix0[4*(j*w+i)+3] = 0xff
|
||||
}
|
||||
}
|
||||
}
|
||||
src0.ReplacePixels(pix0)
|
||||
|
||||
src1, _ := NewImage(w, h, FilterDefault)
|
||||
pix1 := make([]byte, 4*w*h)
|
||||
for j := 0; j < h; j++ {
|
||||
for i := 0; i < w; i++ {
|
||||
if 6 <= i && i < 14 && 6 <= j && j < 14 {
|
||||
pix1[4*(j*w+i)] = 0
|
||||
pix1[4*(j*w+i)+1] = 0xff
|
||||
pix1[4*(j*w+i)+2] = 0
|
||||
pix1[4*(j*w+i)+3] = 0xff
|
||||
}
|
||||
}
|
||||
}
|
||||
src1.ReplacePixels(pix1)
|
||||
|
||||
op := &DrawRectShaderOptions{}
|
||||
op.Images[0] = src0.SubImage(image.Rect(2, 2, 10, 10)).(*Image)
|
||||
op.Images[1] = src1.SubImage(image.Rect(6, 6, 14, 14)).(*Image)
|
||||
dst.DrawRectShader(w/2, h/2, s, op)
|
||||
|
||||
for j := 0; j < h; j++ {
|
||||
for i := 0; i < w; i++ {
|
||||
got := dst.At(i, j).(color.RGBA)
|
||||
var want color.RGBA
|
||||
if i < w/2 && j < h/2 {
|
||||
want = color.RGBA{0xff, 0xff, 0, 0xff}
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user