mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 18:58:54 +01:00
ebiten: Bug fix: Stencil buffers should not be cleared until all the vertices are rendered
Updates #1684
This commit is contained in:
parent
b466a0cbd7
commit
daa883d799
127
image_test.go
127
image_test.go
@ -2240,3 +2240,130 @@ func TestImageSubImageFill(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestImageEvenOdd(t *testing.T) {
|
||||||
|
emptyImage := NewImage(3, 3)
|
||||||
|
emptyImage.Fill(color.White)
|
||||||
|
emptySubImage := emptyImage.SubImage(image.Rect(1, 1, 2, 2)).(*Image)
|
||||||
|
|
||||||
|
vs0 := []Vertex{
|
||||||
|
{
|
||||||
|
DstX: 1, DstY: 1, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 1, ColorG: 0, ColorB: 0, ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 15, DstY: 1, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 1, ColorG: 0, ColorB: 0, ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 1, DstY: 15, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 1, ColorG: 0, ColorB: 0, ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 15, DstY: 15, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 1, ColorG: 0, ColorB: 0, ColorA: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
is0 := []uint16{0, 1, 2, 1, 2, 3}
|
||||||
|
|
||||||
|
vs1 := []Vertex{
|
||||||
|
{
|
||||||
|
DstX: 2, DstY: 2, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 1, ColorB: 0, ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 14, DstY: 2, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 1, ColorB: 0, ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 2, DstY: 14, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 1, ColorB: 0, ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 14, DstY: 14, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 1, ColorB: 0, ColorA: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
is1 := []uint16{4, 5, 6, 5, 6, 7}
|
||||||
|
|
||||||
|
vs2 := []Vertex{
|
||||||
|
{
|
||||||
|
DstX: 3, DstY: 3, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 0, ColorB: 1, ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 13, DstY: 3, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 0, ColorB: 1, ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 3, DstY: 13, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 0, ColorB: 1, ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 13, DstY: 13, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 0, ColorB: 1, ColorA: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
is2 := []uint16{8, 9, 10, 9, 10, 11}
|
||||||
|
|
||||||
|
// Draw all the vertices once. The even-odd rule is applied for all the vertices once.
|
||||||
|
dst := NewImage(16, 16)
|
||||||
|
op := &DrawTrianglesOptions{
|
||||||
|
EvenOdd: true,
|
||||||
|
}
|
||||||
|
dst.DrawTriangles(append(append(vs0, vs1...), vs2...), append(append(is0, is1...), is2...), emptySubImage, op)
|
||||||
|
for j := 0; j < 16; j++ {
|
||||||
|
for i := 0; i < 16; i++ {
|
||||||
|
got := dst.At(i, j)
|
||||||
|
var want color.RGBA
|
||||||
|
switch {
|
||||||
|
case 3 <= i && i < 13 && 3 <= j && j < 13:
|
||||||
|
want = color.RGBA{0, 0, 0xff, 0xff}
|
||||||
|
case 2 <= i && i < 14 && 2 <= j && j < 14:
|
||||||
|
want = color.RGBA{0, 0, 0, 0}
|
||||||
|
case 1 <= i && i < 15 && 1 <= j && j < 15:
|
||||||
|
want = color.RGBA{0xff, 0, 0, 0xff}
|
||||||
|
default:
|
||||||
|
want = color.RGBA{0, 0, 0, 0}
|
||||||
|
}
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the same thing with a little shift. This confirms that the underlying stencil buffer is cleared correctly.
|
||||||
|
for i := range vs0 {
|
||||||
|
vs0[i].DstX++
|
||||||
|
vs0[i].DstY++
|
||||||
|
}
|
||||||
|
for i := range vs1 {
|
||||||
|
vs1[i].DstX++
|
||||||
|
vs1[i].DstY++
|
||||||
|
}
|
||||||
|
for i := range vs2 {
|
||||||
|
vs2[i].DstX++
|
||||||
|
vs2[i].DstY++
|
||||||
|
}
|
||||||
|
dst.Clear()
|
||||||
|
dst.DrawTriangles(append(append(vs0, vs1...), vs2...), append(append(is0, is1...), is2...), emptySubImage, op)
|
||||||
|
for j := 0; j < 16; j++ {
|
||||||
|
for i := 0; i < 16; i++ {
|
||||||
|
got := dst.At(i, j)
|
||||||
|
var want color.RGBA
|
||||||
|
switch {
|
||||||
|
case 4 <= i && i < 14 && 4 <= j && j < 14:
|
||||||
|
want = color.RGBA{0, 0, 0xff, 0xff}
|
||||||
|
case 3 <= i && i < 15 && 3 <= j && j < 15:
|
||||||
|
want = color.RGBA{0, 0, 0, 0}
|
||||||
|
case 2 <= i && i < 16 && 2 <= j && j < 16:
|
||||||
|
want = color.RGBA{0xff, 0, 0, 0xff}
|
||||||
|
default:
|
||||||
|
want = color.RGBA{0, 0, 0, 0}
|
||||||
|
}
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -745,15 +745,15 @@ func (g *Graphics) draw(rps mtl.RenderPipelineState, dst *Image, dstRegion drive
|
|||||||
case drawWithStencil:
|
case drawWithStencil:
|
||||||
desc := mtl.DepthStencilDescriptor{
|
desc := mtl.DepthStencilDescriptor{
|
||||||
BackFaceStencil: mtl.StencilDescriptor{
|
BackFaceStencil: mtl.StencilDescriptor{
|
||||||
StencilFailureOperation: mtl.StencilOperationZero,
|
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||||
DepthFailureOperation: mtl.StencilOperationZero,
|
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||||
DepthStencilPassOperation: mtl.StencilOperationZero,
|
DepthStencilPassOperation: mtl.StencilOperationKeep,
|
||||||
StencilCompareFunction: mtl.CompareFunctionNotEqual,
|
StencilCompareFunction: mtl.CompareFunctionNotEqual,
|
||||||
},
|
},
|
||||||
FrontFaceStencil: mtl.StencilDescriptor{
|
FrontFaceStencil: mtl.StencilDescriptor{
|
||||||
StencilFailureOperation: mtl.StencilOperationZero,
|
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||||
DepthFailureOperation: mtl.StencilOperationZero,
|
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||||
DepthStencilPassOperation: mtl.StencilOperationZero,
|
DepthStencilPassOperation: mtl.StencilOperationKeep,
|
||||||
StencilCompareFunction: mtl.CompareFunctionNotEqual,
|
StencilCompareFunction: mtl.CompareFunctionNotEqual,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,6 @@ func (c *context) bindStencilBuffer(f framebufferNative, r renderbufferNative) e
|
|||||||
if s := gl.CheckFramebufferStatusEXT(gl.FRAMEBUFFER); s != gl.FRAMEBUFFER_COMPLETE {
|
if s := gl.CheckFramebufferStatusEXT(gl.FRAMEBUFFER); s != gl.FRAMEBUFFER_COMPLETE {
|
||||||
return errors.New(fmt.Sprintf("opengl: glFramebufferRenderbuffer failed: %d", s))
|
return errors.New(fmt.Sprintf("opengl: glFramebufferRenderbuffer failed: %d", s))
|
||||||
}
|
}
|
||||||
gl.Clear(gl.STENCIL_BUFFER_BIT)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -550,6 +549,7 @@ func (c *context) disableStencilTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) beginStencilWithEvenOddRule() {
|
func (c *context) beginStencilWithEvenOddRule() {
|
||||||
|
gl.Clear(gl.STENCIL_BUFFER_BIT)
|
||||||
gl.StencilFunc(gl.ALWAYS, 0x00, 0xff)
|
gl.StencilFunc(gl.ALWAYS, 0x00, 0xff)
|
||||||
gl.StencilOp(gl.KEEP, gl.KEEP, gl.INVERT)
|
gl.StencilOp(gl.KEEP, gl.KEEP, gl.INVERT)
|
||||||
gl.ColorMask(false, false, false, false)
|
gl.ColorMask(false, false, false, false)
|
||||||
@ -557,6 +557,6 @@ func (c *context) beginStencilWithEvenOddRule() {
|
|||||||
|
|
||||||
func (c *context) endStencilWithEvenOddRule() {
|
func (c *context) endStencilWithEvenOddRule() {
|
||||||
gl.StencilFunc(gl.NOTEQUAL, 0x00, 0xff)
|
gl.StencilFunc(gl.NOTEQUAL, 0x00, 0xff)
|
||||||
gl.StencilOp(gl.ZERO, gl.ZERO, gl.ZERO)
|
gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)
|
||||||
gl.ColorMask(true, true, true, true)
|
gl.ColorMask(true, true, true, true)
|
||||||
}
|
}
|
||||||
|
@ -298,7 +298,6 @@ func (c *context) bindStencilBuffer(f framebufferNative, r renderbufferNative) e
|
|||||||
if s := gl.checkFramebufferStatus.Invoke(gles.FRAMEBUFFER); s.Int() != gles.FRAMEBUFFER_COMPLETE {
|
if s := gl.checkFramebufferStatus.Invoke(gles.FRAMEBUFFER); s.Int() != gles.FRAMEBUFFER_COMPLETE {
|
||||||
return errors.New(fmt.Sprintf("opengl: framebufferRenderbuffer failed: %d", s.Int()))
|
return errors.New(fmt.Sprintf("opengl: framebufferRenderbuffer failed: %d", s.Int()))
|
||||||
}
|
}
|
||||||
gl.clear.Invoke(gles.STENCIL_BUFFER_BIT)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -660,6 +659,7 @@ func (c *context) disableStencilTest() {
|
|||||||
|
|
||||||
func (c *context) beginStencilWithEvenOddRule() {
|
func (c *context) beginStencilWithEvenOddRule() {
|
||||||
gl := c.gl
|
gl := c.gl
|
||||||
|
gl.clear.Invoke(gles.STENCIL_BUFFER_BIT)
|
||||||
gl.stencilFunc.Invoke(gles.ALWAYS, 0x00, 0xff)
|
gl.stencilFunc.Invoke(gles.ALWAYS, 0x00, 0xff)
|
||||||
gl.stencilOp.Invoke(gles.KEEP, gles.KEEP, gles.INVERT)
|
gl.stencilOp.Invoke(gles.KEEP, gles.KEEP, gles.INVERT)
|
||||||
gl.colorMask.Invoke(false, false, false, false)
|
gl.colorMask.Invoke(false, false, false, false)
|
||||||
@ -668,6 +668,6 @@ func (c *context) beginStencilWithEvenOddRule() {
|
|||||||
func (c *context) endStencilWithEvenOddRule() {
|
func (c *context) endStencilWithEvenOddRule() {
|
||||||
gl := c.gl
|
gl := c.gl
|
||||||
gl.stencilFunc.Invoke(gles.NOTEQUAL, 0x00, 0xff)
|
gl.stencilFunc.Invoke(gles.NOTEQUAL, 0x00, 0xff)
|
||||||
gl.stencilOp.Invoke(gles.ZERO, gles.ZERO, gles.ZERO)
|
gl.stencilOp.Invoke(gles.KEEP, gles.KEEP, gles.KEEP)
|
||||||
gl.colorMask.Invoke(true, true, true, true)
|
gl.colorMask.Invoke(true, true, true, true)
|
||||||
}
|
}
|
||||||
|
@ -246,7 +246,6 @@ func (c *context) bindStencilBuffer(f framebufferNative, r renderbufferNative) e
|
|||||||
if s := c.ctx.CheckFramebufferStatus(gles.FRAMEBUFFER); s != gles.FRAMEBUFFER_COMPLETE {
|
if s := c.ctx.CheckFramebufferStatus(gles.FRAMEBUFFER); s != gles.FRAMEBUFFER_COMPLETE {
|
||||||
return errors.New(fmt.Sprintf("opengl: glFramebufferRenderbuffer failed: %d", s))
|
return errors.New(fmt.Sprintf("opengl: glFramebufferRenderbuffer failed: %d", s))
|
||||||
}
|
}
|
||||||
c.ctx.Clear(gles.STENCIL_BUFFER_BIT)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,6 +510,7 @@ func (c *context) disableStencilTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) beginStencilWithEvenOddRule() {
|
func (c *context) beginStencilWithEvenOddRule() {
|
||||||
|
c.ctx.Clear(gles.STENCIL_BUFFER_BIT)
|
||||||
c.ctx.StencilFunc(gles.ALWAYS, 0x00, 0xff)
|
c.ctx.StencilFunc(gles.ALWAYS, 0x00, 0xff)
|
||||||
c.ctx.StencilOp(gles.KEEP, gles.KEEP, gles.INVERT)
|
c.ctx.StencilOp(gles.KEEP, gles.KEEP, gles.INVERT)
|
||||||
c.ctx.ColorMask(false, false, false, false)
|
c.ctx.ColorMask(false, false, false, false)
|
||||||
@ -518,6 +518,6 @@ func (c *context) beginStencilWithEvenOddRule() {
|
|||||||
|
|
||||||
func (c *context) endStencilWithEvenOddRule() {
|
func (c *context) endStencilWithEvenOddRule() {
|
||||||
c.ctx.StencilFunc(gles.NOTEQUAL, 0x00, 0xff)
|
c.ctx.StencilFunc(gles.NOTEQUAL, 0x00, 0xff)
|
||||||
c.ctx.StencilOp(gles.ZERO, gles.ZERO, gles.ZERO)
|
c.ctx.StencilOp(gles.KEEP, gles.KEEP, gles.KEEP)
|
||||||
c.ctx.ColorMask(true, true, true, true)
|
c.ctx.ColorMask(true, true, true, true)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user