mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
parent
358106bdc0
commit
3ca6184294
@ -72,7 +72,7 @@ type DrawTrianglesOptions struct {
|
|||||||
|
|
||||||
// FillRule indicates the rule how an overlapped region is rendered.
|
// FillRule indicates the rule how an overlapped region is rendered.
|
||||||
//
|
//
|
||||||
// The rule EvenOdd is useful when you want to render a complex polygon.
|
// The rules NonZero and EvenOdd are useful when you want to render a complex polygon.
|
||||||
// A complex polygon is a non-convex polygon like a concave polygon, a polygon with holes, or a self-intersecting polygon.
|
// A complex polygon is a non-convex polygon like a concave polygon, a polygon with holes, or a self-intersecting polygon.
|
||||||
// See examples/vector for actual usages.
|
// See examples/vector for actual usages.
|
||||||
//
|
//
|
||||||
|
@ -141,7 +141,10 @@ func drawEbitenText(screen *ebiten.Image, x, y int, aa bool, line bool) {
|
|||||||
op := &ebiten.DrawTrianglesOptions{}
|
op := &ebiten.DrawTrianglesOptions{}
|
||||||
op.AntiAlias = aa
|
op.AntiAlias = aa
|
||||||
if !line {
|
if !line {
|
||||||
op.FillRule = ebiten.EvenOdd
|
// ebiten.EvenOdd is also fine here.
|
||||||
|
// NonZero and EvenOdd differ when rendering a complex polygons with self-intersections and/or holes.
|
||||||
|
// See https://en.wikipedia.org/wiki/Nonzero-rule and https://en.wikipedia.org/wiki/Even%E2%80%93odd_rule .
|
||||||
|
op.FillRule = ebiten.NonZero
|
||||||
}
|
}
|
||||||
screen.DrawTriangles(vs, is, whiteSubImage, op)
|
screen.DrawTriangles(vs, is, whiteSubImage, op)
|
||||||
}
|
}
|
||||||
@ -197,7 +200,7 @@ func drawEbitenLogo(screen *ebiten.Image, x, y int, aa bool, line bool) {
|
|||||||
op := &ebiten.DrawTrianglesOptions{}
|
op := &ebiten.DrawTrianglesOptions{}
|
||||||
op.AntiAlias = aa
|
op.AntiAlias = aa
|
||||||
if !line {
|
if !line {
|
||||||
op.FillRule = ebiten.EvenOdd
|
op.FillRule = ebiten.NonZero
|
||||||
}
|
}
|
||||||
screen.DrawTriangles(vs, is, whiteSubImage, op)
|
screen.DrawTriangles(vs, is, whiteSubImage, op)
|
||||||
}
|
}
|
||||||
@ -241,7 +244,7 @@ func drawArc(screen *ebiten.Image, count int, aa bool, line bool) {
|
|||||||
op := &ebiten.DrawTrianglesOptions{}
|
op := &ebiten.DrawTrianglesOptions{}
|
||||||
op.AntiAlias = aa
|
op.AntiAlias = aa
|
||||||
if !line {
|
if !line {
|
||||||
op.FillRule = ebiten.EvenOdd
|
op.FillRule = ebiten.NonZero
|
||||||
}
|
}
|
||||||
screen.DrawTriangles(vs, is, whiteSubImage, op)
|
screen.DrawTriangles(vs, is, whiteSubImage, op)
|
||||||
}
|
}
|
||||||
@ -298,7 +301,7 @@ func drawWave(screen *ebiten.Image, counter int, aa bool, line bool) {
|
|||||||
op := &ebiten.DrawTrianglesOptions{}
|
op := &ebiten.DrawTrianglesOptions{}
|
||||||
op.AntiAlias = aa
|
op.AntiAlias = aa
|
||||||
if !line {
|
if !line {
|
||||||
op.FillRule = ebiten.EvenOdd
|
op.FillRule = ebiten.NonZero
|
||||||
}
|
}
|
||||||
screen.DrawTriangles(vs, is, whiteSubImage, op)
|
screen.DrawTriangles(vs, is, whiteSubImage, op)
|
||||||
}
|
}
|
||||||
|
8
image.go
8
image.go
@ -314,6 +314,10 @@ const (
|
|||||||
// FillAll indicates all the triangles are rendered regardless of overlaps.
|
// FillAll indicates all the triangles are rendered regardless of overlaps.
|
||||||
FillAll FillRule = FillRule(graphicsdriver.FillAll)
|
FillAll FillRule = FillRule(graphicsdriver.FillAll)
|
||||||
|
|
||||||
|
// NonZero means that triangles are rendered based on the non-zero rule.
|
||||||
|
// If and only if the number of overlaps is not 0, the region is rendered.
|
||||||
|
NonZero FillRule = FillRule(graphicsdriver.NonZero)
|
||||||
|
|
||||||
// EvenOdd means that triangles are rendered based on the even-odd rule.
|
// EvenOdd means that triangles are rendered based on the even-odd rule.
|
||||||
// If and only if the number of overlaps is odd, the region is rendered.
|
// If and only if the number of overlaps is odd, the region is rendered.
|
||||||
EvenOdd FillRule = FillRule(graphicsdriver.EvenOdd)
|
EvenOdd FillRule = FillRule(graphicsdriver.EvenOdd)
|
||||||
@ -367,7 +371,7 @@ type DrawTrianglesOptions struct {
|
|||||||
|
|
||||||
// FillRule indicates the rule how an overlapped region is rendered.
|
// FillRule indicates the rule how an overlapped region is rendered.
|
||||||
//
|
//
|
||||||
// The rule EvenOdd is useful when you want to render a complex polygon.
|
// The rules NonZero and EvenOdd are useful when you want to render a complex polygon.
|
||||||
// A complex polygon is a non-convex polygon like a concave polygon, a polygon with holes, or a self-intersecting polygon.
|
// A complex polygon is a non-convex polygon like a concave polygon, a polygon with holes, or a self-intersecting polygon.
|
||||||
// See examples/vector for actual usages.
|
// See examples/vector for actual usages.
|
||||||
//
|
//
|
||||||
@ -543,7 +547,7 @@ type DrawTrianglesShaderOptions struct {
|
|||||||
|
|
||||||
// FillRule indicates the rule how an overlapped region is rendered.
|
// FillRule indicates the rule how an overlapped region is rendered.
|
||||||
//
|
//
|
||||||
// The rule EvenOdd is useful when you want to render a complex polygon.
|
// The rules NonZero and EvenOdd are useful when you want to render a complex polygon.
|
||||||
// A complex polygon is a non-convex polygon like a concave polygon, a polygon with holes, or a self-intersecting polygon.
|
// A complex polygon is a non-convex polygon like a concave polygon, a polygon with holes, or a self-intersecting polygon.
|
||||||
// See examples/vector for actual usages.
|
// See examples/vector for actual usages.
|
||||||
//
|
//
|
||||||
|
183
image_test.go
183
image_test.go
@ -2793,6 +2793,189 @@ func TestImageEvenOdd(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestImageFillRule(t *testing.T) {
|
||||||
|
for _, fillRule := range []ebiten.FillRule{ebiten.FillAll, ebiten.NonZero, ebiten.EvenOdd} {
|
||||||
|
fillRule := fillRule
|
||||||
|
var name string
|
||||||
|
switch fillRule {
|
||||||
|
case ebiten.FillAll:
|
||||||
|
name = "FillAll"
|
||||||
|
case ebiten.NonZero:
|
||||||
|
name = "NonZero"
|
||||||
|
case ebiten.EvenOdd:
|
||||||
|
name = "EvenOdd"
|
||||||
|
}
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
whiteImage := ebiten.NewImage(3, 3)
|
||||||
|
whiteImage.Fill(color.White)
|
||||||
|
emptySubImage := whiteImage.SubImage(image.Rect(1, 1, 2, 2)).(*ebiten.Image)
|
||||||
|
|
||||||
|
// The outside rectangle (clockwise)
|
||||||
|
vs0 := []ebiten.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: 15, DstY: 15, 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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
is0 := []uint16{0, 1, 2, 2, 3, 0}
|
||||||
|
|
||||||
|
// An inside rectangle (clockwise)
|
||||||
|
vs1 := []ebiten.Vertex{
|
||||||
|
{
|
||||||
|
DstX: 2, DstY: 2, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 1, ColorB: 0, ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 7, DstY: 2, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 1, ColorB: 0, ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 7, DstY: 7, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 1, ColorB: 0, ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 2, DstY: 7, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 1, ColorB: 0, ColorA: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
is1 := []uint16{4, 5, 6, 6, 7, 4}
|
||||||
|
|
||||||
|
// An inside rectangle (counter-clockwise)
|
||||||
|
vs2 := []ebiten.Vertex{
|
||||||
|
{
|
||||||
|
DstX: 9, DstY: 9, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 0, ColorB: 1, ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 14, DstY: 9, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 0, ColorB: 1, ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 14, DstY: 14, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 0, ColorB: 1, ColorA: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 9, DstY: 14, SrcX: 1, SrcY: 1,
|
||||||
|
ColorR: 0, ColorG: 0, ColorB: 1, ColorA: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
is2 := []uint16{8, 11, 10, 10, 9, 8}
|
||||||
|
|
||||||
|
// Draw all the vertices once. The even-odd rule is applied for all the vertices once.
|
||||||
|
dst := ebiten.NewImage(16, 16)
|
||||||
|
op := &ebiten.DrawTrianglesOptions{
|
||||||
|
FillRule: fillRule,
|
||||||
|
}
|
||||||
|
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 2 <= i && i < 7 && 2 <= j && j < 7:
|
||||||
|
if fillRule != ebiten.EvenOdd {
|
||||||
|
want = color.RGBA{G: 0xff, A: 0xff}
|
||||||
|
}
|
||||||
|
case 9 <= i && i < 14 && 9 <= j && j < 14:
|
||||||
|
if fillRule == ebiten.FillAll {
|
||||||
|
want = color.RGBA{B: 0xff, A: 0xff}
|
||||||
|
}
|
||||||
|
case 1 <= i && i < 15 && 1 <= j && j < 15:
|
||||||
|
want = color.RGBA{R: 0xff, A: 0xff}
|
||||||
|
}
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the same thing but 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 3 <= i && i < 8 && 3 <= j && j < 8:
|
||||||
|
if fillRule != ebiten.EvenOdd {
|
||||||
|
want = color.RGBA{G: 0xff, A: 0xff}
|
||||||
|
}
|
||||||
|
case 10 <= i && i < 15 && 10 <= j && j < 15:
|
||||||
|
if fillRule == ebiten.FillAll {
|
||||||
|
want = color.RGBA{B: 0xff, A: 0xff}
|
||||||
|
}
|
||||||
|
case 2 <= i && i < 16 && 2 <= j && j < 16:
|
||||||
|
want = color.RGBA{R: 0xff, A: 0xff}
|
||||||
|
}
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the same thing but with split DrawTriangle calls. This confirms that fill rules are applied for one call.
|
||||||
|
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(vs0, []uint16{0, 1, 2, 2, 3, 0}, emptySubImage, op)
|
||||||
|
dst.DrawTriangles(vs1, []uint16{0, 1, 2, 2, 3, 0}, emptySubImage, op)
|
||||||
|
dst.DrawTriangles(vs2, []uint16{0, 3, 2, 2, 1, 0}, 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 2 <= i && i < 7 && 2 <= j && j < 7:
|
||||||
|
want = color.RGBA{G: 0xff, A: 0xff}
|
||||||
|
case 9 <= i && i < 14 && 9 <= j && j < 14:
|
||||||
|
want = color.RGBA{B: 0xff, A: 0xff}
|
||||||
|
case 1 <= i && i < 15 && 1 <= j && j < 15:
|
||||||
|
want = color.RGBA{R: 0xff, A: 0xff}
|
||||||
|
}
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// #1658
|
// #1658
|
||||||
func BenchmarkColorMScale(b *testing.B) {
|
func BenchmarkColorMScale(b *testing.B) {
|
||||||
r := rand.Float64
|
r := rand.Float64
|
||||||
|
@ -166,7 +166,7 @@ func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs
|
|||||||
if c.fillRule != fillRule {
|
if c.fillRule != fillRule {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if c.fillRule == graphicsdriver.EvenOdd && mightOverlapDstRegions(c.vertices, vertices) {
|
if c.fillRule != graphicsdriver.FillAll && mightOverlapDstRegions(c.vertices, vertices) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -584,25 +584,39 @@ func (g *graphics11) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphic
|
|||||||
switch fillRule {
|
switch fillRule {
|
||||||
case graphicsdriver.FillAll:
|
case graphicsdriver.FillAll:
|
||||||
g.deviceContext.DrawIndexed(uint32(dstRegion.IndexCount), uint32(indexOffset), 0)
|
g.deviceContext.DrawIndexed(uint32(dstRegion.IndexCount), uint32(indexOffset), 0)
|
||||||
case graphicsdriver.EvenOdd:
|
case graphicsdriver.NonZero:
|
||||||
bs, err := g.blendState(blend, prepareStencil)
|
bs, err := g.blendState(blend, incrementStencil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
g.deviceContext.OMSetBlendState(bs, nil, 0xffffffff)
|
g.deviceContext.OMSetBlendState(bs, nil, 0xffffffff)
|
||||||
dss, err := g.depthStencilState(prepareStencil)
|
dss, err := g.depthStencilState(incrementStencil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
g.deviceContext.OMSetDepthStencilState(dss, 0)
|
g.deviceContext.OMSetDepthStencilState(dss, 0)
|
||||||
g.deviceContext.DrawIndexed(uint32(dstRegion.IndexCount), uint32(indexOffset), 0)
|
g.deviceContext.DrawIndexed(uint32(dstRegion.IndexCount), uint32(indexOffset), 0)
|
||||||
|
case graphicsdriver.EvenOdd:
|
||||||
bs, err = g.blendState(blend, drawWithStencil)
|
bs, err := g.blendState(blend, invertStencil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
g.deviceContext.OMSetBlendState(bs, nil, 0xffffffff)
|
g.deviceContext.OMSetBlendState(bs, nil, 0xffffffff)
|
||||||
dss, err = g.depthStencilState(drawWithStencil)
|
dss, err := g.depthStencilState(invertStencil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g.deviceContext.OMSetDepthStencilState(dss, 0)
|
||||||
|
g.deviceContext.DrawIndexed(uint32(dstRegion.IndexCount), uint32(indexOffset), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fillRule != graphicsdriver.FillAll {
|
||||||
|
bs, err := g.blendState(blend, drawWithStencil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g.deviceContext.OMSetBlendState(bs, nil, 0xffffffff)
|
||||||
|
dss, err := g.depthStencilState(drawWithStencil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -627,9 +641,9 @@ func (g *graphics11) genNextShaderID() graphicsdriver.ShaderID {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *graphics11) blendState(blend graphicsdriver.Blend, stencilMode stencilMode) (*_ID3D11BlendState, error) {
|
func (g *graphics11) blendState(blend graphicsdriver.Blend, stencilMode stencilMode) (*_ID3D11BlendState, error) {
|
||||||
writeMask := uint8(_D3D11_COLOR_WRITE_ENABLE_ALL)
|
var writeMask uint8
|
||||||
if stencilMode == prepareStencil {
|
if stencilMode == noStencil || stencilMode == drawWithStencil {
|
||||||
writeMask = 0
|
writeMask = uint8(_D3D11_COLOR_WRITE_ENABLE_ALL)
|
||||||
}
|
}
|
||||||
|
|
||||||
key := blendStateKey{
|
key := blendStateKey{
|
||||||
@ -693,7 +707,11 @@ func (g *graphics11) depthStencilState(mode stencilMode) (*_ID3D11DepthStencilSt
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
switch mode {
|
switch mode {
|
||||||
case prepareStencil:
|
case incrementStencil:
|
||||||
|
desc.StencilEnable = 1
|
||||||
|
desc.FrontFace.StencilPassOp = _D3D11_STENCIL_OP_INCR
|
||||||
|
desc.BackFace.StencilPassOp = _D3D11_STENCIL_OP_DECR
|
||||||
|
case invertStencil:
|
||||||
desc.StencilEnable = 1
|
desc.StencilEnable = 1
|
||||||
desc.FrontFace.StencilPassOp = _D3D11_STENCIL_OP_INVERT
|
desc.FrontFace.StencilPassOp = _D3D11_STENCIL_OP_INVERT
|
||||||
desc.BackFace.StencilPassOp = _D3D11_STENCIL_OP_INVERT
|
desc.BackFace.StencilPassOp = _D3D11_STENCIL_OP_INVERT
|
||||||
|
@ -1097,7 +1097,7 @@ func (g *graphics12) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.
|
|||||||
|
|
||||||
// Release constant buffers when too many ones will be created.
|
// Release constant buffers when too many ones will be created.
|
||||||
numPipelines := 1
|
numPipelines := 1
|
||||||
if fillRule == graphicsdriver.EvenOdd {
|
if fillRule != graphicsdriver.FillAll {
|
||||||
numPipelines = 2
|
numPipelines = 2
|
||||||
}
|
}
|
||||||
if len(g.pipelineStates.constantBuffers[g.frameIndex])+numPipelines > numDescriptorsPerFrame {
|
if len(g.pipelineStates.constantBuffers[g.frameIndex])+numPipelines > numDescriptorsPerFrame {
|
||||||
|
@ -35,9 +35,10 @@ import (
|
|||||||
type stencilMode int
|
type stencilMode int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
prepareStencil stencilMode = iota
|
noStencil stencilMode = iota
|
||||||
|
incrementStencil
|
||||||
|
invertStencil
|
||||||
drawWithStencil
|
drawWithStencil
|
||||||
noStencil
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const frameCount = 2
|
const frameCount = 2
|
||||||
|
@ -309,21 +309,31 @@ func (p *pipelineStates) drawTriangles(device *_ID3D12Device, commandList *_ID3D
|
|||||||
switch fillRule {
|
switch fillRule {
|
||||||
case graphicsdriver.FillAll:
|
case graphicsdriver.FillAll:
|
||||||
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
||||||
case graphicsdriver.EvenOdd:
|
case graphicsdriver.NonZero:
|
||||||
s, err := shader.pipelineState(blend, prepareStencil, screen)
|
s, err := shader.pipelineState(blend, incrementStencil, screen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
commandList.SetPipelineState(s)
|
commandList.SetPipelineState(s)
|
||||||
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
||||||
|
case graphicsdriver.EvenOdd:
|
||||||
s, err = shader.pipelineState(blend, drawWithStencil, screen)
|
s, err := shader.pipelineState(blend, invertStencil, screen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
commandList.SetPipelineState(s)
|
commandList.SetPipelineState(s)
|
||||||
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fillRule != graphicsdriver.FillAll {
|
||||||
|
s, err := shader.pipelineState(blend, drawWithStencil, screen)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
commandList.SetPipelineState(s)
|
||||||
|
commandList.DrawIndexedInstanced(uint32(dstRegion.IndexCount), 1, uint32(indexOffset), 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
indexOffset += dstRegion.IndexCount
|
indexOffset += dstRegion.IndexCount
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,14 +453,21 @@ func (p *pipelineStates) newPipelineState(device *_ID3D12Device, vsh, psh *_ID3D
|
|||||||
StencilFunc: _D3D12_COMPARISON_FUNC_ALWAYS,
|
StencilFunc: _D3D12_COMPARISON_FUNC_ALWAYS,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
writeMask := uint8(_D3D12_COLOR_WRITE_ENABLE_ALL)
|
|
||||||
|
var writeMask uint8
|
||||||
|
if stencilMode == noStencil || stencilMode == drawWithStencil {
|
||||||
|
writeMask = uint8(_D3D12_COLOR_WRITE_ENABLE_ALL)
|
||||||
|
}
|
||||||
|
|
||||||
switch stencilMode {
|
switch stencilMode {
|
||||||
case prepareStencil:
|
case incrementStencil:
|
||||||
|
depthStencilDesc.StencilEnable = 1
|
||||||
|
depthStencilDesc.FrontFace.StencilPassOp = _D3D12_STENCIL_OP_INCR
|
||||||
|
depthStencilDesc.BackFace.StencilPassOp = _D3D12_STENCIL_OP_DECR
|
||||||
|
case invertStencil:
|
||||||
depthStencilDesc.StencilEnable = 1
|
depthStencilDesc.StencilEnable = 1
|
||||||
depthStencilDesc.FrontFace.StencilPassOp = _D3D12_STENCIL_OP_INVERT
|
depthStencilDesc.FrontFace.StencilPassOp = _D3D12_STENCIL_OP_INVERT
|
||||||
depthStencilDesc.BackFace.StencilPassOp = _D3D12_STENCIL_OP_INVERT
|
depthStencilDesc.BackFace.StencilPassOp = _D3D12_STENCIL_OP_INVERT
|
||||||
writeMask = 0
|
|
||||||
case drawWithStencil:
|
case drawWithStencil:
|
||||||
depthStencilDesc.StencilEnable = 1
|
depthStencilDesc.StencilEnable = 1
|
||||||
depthStencilDesc.FrontFace.StencilFunc = _D3D12_COMPARISON_FUNC_NOT_EQUAL
|
depthStencilDesc.FrontFace.StencilFunc = _D3D12_COMPARISON_FUNC_NOT_EQUAL
|
||||||
|
@ -31,6 +31,7 @@ type FillRule int
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
FillAll FillRule = iota
|
FillAll FillRule = iota
|
||||||
|
NonZero
|
||||||
EvenOdd
|
EvenOdd
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -38,6 +39,8 @@ func (f FillRule) String() string {
|
|||||||
switch f {
|
switch f {
|
||||||
case FillAll:
|
case FillAll:
|
||||||
return "FillAll"
|
return "FillAll"
|
||||||
|
case NonZero:
|
||||||
|
return "NonZero"
|
||||||
case EvenOdd:
|
case EvenOdd:
|
||||||
return "EvenOdd"
|
return "EvenOdd"
|
||||||
default:
|
default:
|
||||||
|
@ -70,9 +70,10 @@ type Graphics struct {
|
|||||||
type stencilMode int
|
type stencilMode int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
prepareStencil stencilMode = iota
|
noStencil stencilMode = iota
|
||||||
|
incrementStencil
|
||||||
|
invertStencil
|
||||||
drawWithStencil
|
drawWithStencil
|
||||||
noStencil
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -412,7 +413,35 @@ func (g *Graphics) Initialize() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The stencil reference value is always 0 (default).
|
// The stencil reference value is always 0 (default).
|
||||||
g.dsss[prepareStencil] = g.view.getMTLDevice().MakeDepthStencilState(mtl.DepthStencilDescriptor{
|
g.dsss[noStencil] = g.view.getMTLDevice().MakeDepthStencilState(mtl.DepthStencilDescriptor{
|
||||||
|
BackFaceStencil: mtl.StencilDescriptor{
|
||||||
|
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||||
|
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||||
|
DepthStencilPassOperation: mtl.StencilOperationKeep,
|
||||||
|
StencilCompareFunction: mtl.CompareFunctionAlways,
|
||||||
|
},
|
||||||
|
FrontFaceStencil: mtl.StencilDescriptor{
|
||||||
|
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||||
|
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||||
|
DepthStencilPassOperation: mtl.StencilOperationKeep,
|
||||||
|
StencilCompareFunction: mtl.CompareFunctionAlways,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
g.dsss[incrementStencil] = g.view.getMTLDevice().MakeDepthStencilState(mtl.DepthStencilDescriptor{
|
||||||
|
BackFaceStencil: mtl.StencilDescriptor{
|
||||||
|
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||||
|
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||||
|
DepthStencilPassOperation: mtl.StencilOperationDecrementWrap,
|
||||||
|
StencilCompareFunction: mtl.CompareFunctionAlways,
|
||||||
|
},
|
||||||
|
FrontFaceStencil: mtl.StencilDescriptor{
|
||||||
|
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||||
|
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||||
|
DepthStencilPassOperation: mtl.StencilOperationIncrementWrap,
|
||||||
|
StencilCompareFunction: mtl.CompareFunctionAlways,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
g.dsss[invertStencil] = g.view.getMTLDevice().MakeDepthStencilState(mtl.DepthStencilDescriptor{
|
||||||
BackFaceStencil: mtl.StencilDescriptor{
|
BackFaceStencil: mtl.StencilDescriptor{
|
||||||
StencilFailureOperation: mtl.StencilOperationKeep,
|
StencilFailureOperation: mtl.StencilOperationKeep,
|
||||||
DepthFailureOperation: mtl.StencilOperationKeep,
|
DepthFailureOperation: mtl.StencilOperationKeep,
|
||||||
@ -440,20 +469,6 @@ func (g *Graphics) Initialize() error {
|
|||||||
StencilCompareFunction: mtl.CompareFunctionNotEqual,
|
StencilCompareFunction: mtl.CompareFunctionNotEqual,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
g.dsss[noStencil] = g.view.getMTLDevice().MakeDepthStencilState(mtl.DepthStencilDescriptor{
|
|
||||||
BackFaceStencil: mtl.StencilDescriptor{
|
|
||||||
StencilFailureOperation: mtl.StencilOperationKeep,
|
|
||||||
DepthFailureOperation: mtl.StencilOperationKeep,
|
|
||||||
DepthStencilPassOperation: mtl.StencilOperationKeep,
|
|
||||||
StencilCompareFunction: mtl.CompareFunctionAlways,
|
|
||||||
},
|
|
||||||
FrontFaceStencil: mtl.StencilDescriptor{
|
|
||||||
StencilFailureOperation: mtl.StencilOperationKeep,
|
|
||||||
DepthFailureOperation: mtl.StencilOperationKeep,
|
|
||||||
DepthStencilPassOperation: mtl.StencilOperationKeep,
|
|
||||||
StencilCompareFunction: mtl.CompareFunctionAlways,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
g.cq = g.view.getMTLDevice().MakeCommandQueue()
|
g.cq = g.view.getMTLDevice().MakeCommandQueue()
|
||||||
return nil
|
return nil
|
||||||
@ -472,7 +487,7 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
|
|||||||
// When preparing a stencil buffer, flush the current render command encoder
|
// When preparing a stencil buffer, flush the current render command encoder
|
||||||
// to make sure the stencil buffer is cleared when loading.
|
// to make sure the stencil buffer is cleared when loading.
|
||||||
// TODO: What about clearing the stencil buffer by vertices?
|
// TODO: What about clearing the stencil buffer by vertices?
|
||||||
if g.lastDst != dst || g.lastFillRule != fillRule || fillRule == graphicsdriver.EvenOdd {
|
if g.lastDst != dst || g.lastFillRule != fillRule || fillRule != graphicsdriver.FillAll {
|
||||||
g.flushRenderCommandEncoderIfNeeded()
|
g.flushRenderCommandEncoderIfNeeded()
|
||||||
}
|
}
|
||||||
g.lastDst = dst
|
g.lastDst = dst
|
||||||
@ -498,7 +513,7 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
|
|||||||
rpd.ColorAttachments[0].Texture = t
|
rpd.ColorAttachments[0].Texture = t
|
||||||
rpd.ColorAttachments[0].ClearColor = mtl.ClearColor{}
|
rpd.ColorAttachments[0].ClearColor = mtl.ClearColor{}
|
||||||
|
|
||||||
if fillRule == graphicsdriver.EvenOdd {
|
if fillRule != graphicsdriver.FillAll {
|
||||||
dst.ensureStencil()
|
dst.ensureStencil()
|
||||||
rpd.StencilAttachment.LoadAction = mtl.LoadActionClear
|
rpd.StencilAttachment.LoadAction = mtl.LoadActionClear
|
||||||
rpd.StencilAttachment.StoreAction = mtl.StoreActionDontCare
|
rpd.StencilAttachment.StoreAction = mtl.StoreActionDontCare
|
||||||
@ -539,9 +554,10 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
prepareStencilRpss mtl.RenderPipelineState
|
noStencilRpss mtl.RenderPipelineState
|
||||||
drawWithStencilRpss mtl.RenderPipelineState
|
incrementStencilRpss mtl.RenderPipelineState
|
||||||
noStencilRpss mtl.RenderPipelineState
|
invertStencilRpss mtl.RenderPipelineState
|
||||||
|
drawWithStencilRpss mtl.RenderPipelineState
|
||||||
)
|
)
|
||||||
switch fillRule {
|
switch fillRule {
|
||||||
case graphicsdriver.FillAll:
|
case graphicsdriver.FillAll:
|
||||||
@ -550,14 +566,21 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
noStencilRpss = s
|
noStencilRpss = s
|
||||||
case graphicsdriver.EvenOdd:
|
case graphicsdriver.NonZero:
|
||||||
s, err := shader.RenderPipelineState(&g.view, blend, prepareStencil, dst.screen)
|
s, err := shader.RenderPipelineState(&g.view, blend, incrementStencil, dst.screen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
prepareStencilRpss = s
|
incrementStencilRpss = s
|
||||||
|
case graphicsdriver.EvenOdd:
|
||||||
s, err = shader.RenderPipelineState(&g.view, blend, drawWithStencil, dst.screen)
|
s, err := shader.RenderPipelineState(&g.view, blend, invertStencil, dst.screen)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
invertStencilRpss = s
|
||||||
|
}
|
||||||
|
if fillRule != graphicsdriver.FillAll {
|
||||||
|
s, err := shader.RenderPipelineState(&g.view, blend, drawWithStencil, dst.screen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -577,11 +600,16 @@ func (g *Graphics) draw(dst *Image, dstRegions []graphicsdriver.DstRegion, srcs
|
|||||||
g.rce.SetDepthStencilState(g.dsss[noStencil])
|
g.rce.SetDepthStencilState(g.dsss[noStencil])
|
||||||
g.rce.SetRenderPipelineState(noStencilRpss)
|
g.rce.SetRenderPipelineState(noStencilRpss)
|
||||||
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
||||||
case graphicsdriver.EvenOdd:
|
case graphicsdriver.NonZero:
|
||||||
g.rce.SetDepthStencilState(g.dsss[prepareStencil])
|
g.rce.SetDepthStencilState(g.dsss[incrementStencil])
|
||||||
g.rce.SetRenderPipelineState(prepareStencilRpss)
|
g.rce.SetRenderPipelineState(incrementStencilRpss)
|
||||||
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
||||||
|
case graphicsdriver.EvenOdd:
|
||||||
|
g.rce.SetDepthStencilState(g.dsss[invertStencil])
|
||||||
|
g.rce.SetRenderPipelineState(invertStencilRpss)
|
||||||
|
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
||||||
|
}
|
||||||
|
if fillRule != graphicsdriver.FillAll {
|
||||||
g.rce.SetDepthStencilState(g.dsss[drawWithStencil])
|
g.rce.SetDepthStencilState(g.dsss[drawWithStencil])
|
||||||
g.rce.SetRenderPipelineState(drawWithStencilRpss)
|
g.rce.SetRenderPipelineState(drawWithStencilRpss)
|
||||||
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
g.rce.DrawIndexedPrimitives(mtl.PrimitiveTypeTriangle, dstRegion.IndexCount, mtl.IndexTypeUInt32, g.ib, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
||||||
|
@ -119,10 +119,10 @@ func (s *Shader) RenderPipelineState(view *view, blend graphicsdriver.Blend, ste
|
|||||||
rpld.ColorAttachments[0].AlphaBlendOperation = blendOperationToMetalBlendOperation(blend.BlendOperationAlpha)
|
rpld.ColorAttachments[0].AlphaBlendOperation = blendOperationToMetalBlendOperation(blend.BlendOperationAlpha)
|
||||||
rpld.ColorAttachments[0].RGBBlendOperation = blendOperationToMetalBlendOperation(blend.BlendOperationRGB)
|
rpld.ColorAttachments[0].RGBBlendOperation = blendOperationToMetalBlendOperation(blend.BlendOperationRGB)
|
||||||
|
|
||||||
if stencilMode == prepareStencil {
|
if stencilMode == noStencil || stencilMode == drawWithStencil {
|
||||||
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskNone
|
|
||||||
} else {
|
|
||||||
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskAll
|
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskAll
|
||||||
|
} else {
|
||||||
|
rpld.ColorAttachments[0].WriteMask = mtl.ColorWriteMaskNone
|
||||||
}
|
}
|
||||||
|
|
||||||
rps, err := view.getMTLDevice().MakeRenderPipelineState(rpld)
|
rps, err := view.getMTLDevice().MakeRenderPipelineState(rpld)
|
||||||
|
@ -17,10 +17,12 @@ package gl
|
|||||||
const (
|
const (
|
||||||
ALWAYS = 0x0207
|
ALWAYS = 0x0207
|
||||||
ARRAY_BUFFER = 0x8892
|
ARRAY_BUFFER = 0x8892
|
||||||
|
BACK = 0x0405
|
||||||
BLEND = 0x0BE2
|
BLEND = 0x0BE2
|
||||||
CLAMP_TO_EDGE = 0x812F
|
CLAMP_TO_EDGE = 0x812F
|
||||||
COLOR_ATTACHMENT0 = 0x8CE0
|
COLOR_ATTACHMENT0 = 0x8CE0
|
||||||
COMPILE_STATUS = 0x8B81
|
COMPILE_STATUS = 0x8B81
|
||||||
|
DECR_WRAP = 0x8508
|
||||||
DEPTH24_STENCIL8 = 0x88F0
|
DEPTH24_STENCIL8 = 0x88F0
|
||||||
DST_ALPHA = 0x0304
|
DST_ALPHA = 0x0304
|
||||||
DST_COLOR = 0x0306
|
DST_COLOR = 0x0306
|
||||||
@ -32,10 +34,13 @@ const (
|
|||||||
FRAMEBUFFER = 0x8D40
|
FRAMEBUFFER = 0x8D40
|
||||||
FRAMEBUFFER_BINDING = 0x8CA6
|
FRAMEBUFFER_BINDING = 0x8CA6
|
||||||
FRAMEBUFFER_COMPLETE = 0x8CD5
|
FRAMEBUFFER_COMPLETE = 0x8CD5
|
||||||
|
FRONT = 0x0404
|
||||||
|
FRONT_AND_BACK = 0x0408
|
||||||
FUNC_ADD = 0x8006
|
FUNC_ADD = 0x8006
|
||||||
FUNC_REVERSE_SUBTRACT = 0x800b
|
FUNC_REVERSE_SUBTRACT = 0x800b
|
||||||
FUNC_SUBTRACT = 0x800a
|
FUNC_SUBTRACT = 0x800a
|
||||||
HIGH_FLOAT = 0x8DF2
|
HIGH_FLOAT = 0x8DF2
|
||||||
|
INCR_WRAP = 0x8507
|
||||||
INFO_LOG_LENGTH = 0x8B84
|
INFO_LOG_LENGTH = 0x8B84
|
||||||
INVERT = 0x150A
|
INVERT = 0x150A
|
||||||
KEEP = 0x1E00
|
KEEP = 0x1E00
|
||||||
|
@ -501,11 +501,11 @@ func (d *DebugContext) StencilFunc(arg0 uint32, arg1 int32, arg2 uint32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DebugContext) StencilOp(arg0 uint32, arg1 uint32, arg2 uint32) {
|
func (d *DebugContext) StencilOpSeparate(arg0 uint32, arg1 uint32, arg2 uint32, arg3 uint32) {
|
||||||
d.Context.StencilOp(arg0, arg1, arg2)
|
d.Context.StencilOpSeparate(arg0, arg1, arg2, arg3)
|
||||||
fmt.Fprintln(os.Stderr, "StencilOp")
|
fmt.Fprintln(os.Stderr, "StencilOpSeparate")
|
||||||
if e := d.Context.GetError(); e != NO_ERROR {
|
if e := d.Context.GetError(); e != NO_ERROR {
|
||||||
panic(fmt.Sprintf("gl: GetError() returned %d at StencilOp", e))
|
panic(fmt.Sprintf("gl: GetError() returned %d at StencilOpSeparate", e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,9 +244,9 @@ package gl
|
|||||||
// typedef void (*fn)(GLenum func, GLint ref, GLuint mask);
|
// typedef void (*fn)(GLenum func, GLint ref, GLuint mask);
|
||||||
// ((fn)(fnptr))(func, ref, mask);
|
// ((fn)(fnptr))(func, ref, mask);
|
||||||
// }
|
// }
|
||||||
// static void glowStencilOp(uintptr_t fnptr, GLenum fail, GLenum zfail, GLenum zpass) {
|
// static void glowStencilOpSeparate(uintptr_t fnptr, GLenum face, GLenum fail, GLenum zfail, GLenum zpass) {
|
||||||
// typedef void (*fn)(GLenum fail, GLenum zfail, GLenum zpass);
|
// typedef void (*fn)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
|
||||||
// ((fn)(fnptr))(fail, zfail, zpass);
|
// ((fn)(fnptr))(face, fail, zfail, zpass);
|
||||||
// }
|
// }
|
||||||
// static void glowTexImage2D(uintptr_t fnptr, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels) {
|
// static void glowTexImage2D(uintptr_t fnptr, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels) {
|
||||||
// typedef void (*fn)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels);
|
// typedef void (*fn)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels);
|
||||||
@ -384,7 +384,7 @@ type defaultContext struct {
|
|||||||
gpScissor C.uintptr_t
|
gpScissor C.uintptr_t
|
||||||
gpShaderSource C.uintptr_t
|
gpShaderSource C.uintptr_t
|
||||||
gpStencilFunc C.uintptr_t
|
gpStencilFunc C.uintptr_t
|
||||||
gpStencilOp C.uintptr_t
|
gpStencilOpSeparate C.uintptr_t
|
||||||
gpTexImage2D C.uintptr_t
|
gpTexImage2D C.uintptr_t
|
||||||
gpTexParameteri C.uintptr_t
|
gpTexParameteri C.uintptr_t
|
||||||
gpTexSubImage2D C.uintptr_t
|
gpTexSubImage2D C.uintptr_t
|
||||||
@ -688,8 +688,8 @@ func (c *defaultContext) StencilFunc(xfunc uint32, ref int32, mask uint32) {
|
|||||||
C.glowStencilFunc(c.gpStencilFunc, C.GLenum(xfunc), C.GLint(ref), C.GLuint(mask))
|
C.glowStencilFunc(c.gpStencilFunc, C.GLenum(xfunc), C.GLint(ref), C.GLuint(mask))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *defaultContext) StencilOp(fail uint32, zfail uint32, zpass uint32) {
|
func (c *defaultContext) StencilOpSeparate(face uint32, fail uint32, zfail uint32, zpass uint32) {
|
||||||
C.glowStencilOp(c.gpStencilOp, C.GLenum(fail), C.GLenum(zfail), C.GLenum(zpass))
|
C.glowStencilOpSeparate(c.gpStencilOpSeparate, C.GLenum(face), C.GLenum(fail), C.GLenum(zfail), C.GLenum(zpass))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *defaultContext) TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
func (c *defaultContext) TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
||||||
@ -840,7 +840,7 @@ func (c *defaultContext) LoadFunctions() error {
|
|||||||
c.gpScissor = C.uintptr_t(g.get("glScissor"))
|
c.gpScissor = C.uintptr_t(g.get("glScissor"))
|
||||||
c.gpShaderSource = C.uintptr_t(g.get("glShaderSource"))
|
c.gpShaderSource = C.uintptr_t(g.get("glShaderSource"))
|
||||||
c.gpStencilFunc = C.uintptr_t(g.get("glStencilFunc"))
|
c.gpStencilFunc = C.uintptr_t(g.get("glStencilFunc"))
|
||||||
c.gpStencilOp = C.uintptr_t(g.get("glStencilOp"))
|
c.gpStencilOpSeparate = C.uintptr_t(g.get("glStencilOpSeparate"))
|
||||||
c.gpTexImage2D = C.uintptr_t(g.get("glTexImage2D"))
|
c.gpTexImage2D = C.uintptr_t(g.get("glTexImage2D"))
|
||||||
c.gpTexParameteri = C.uintptr_t(g.get("glTexParameteri"))
|
c.gpTexParameteri = C.uintptr_t(g.get("glTexParameteri"))
|
||||||
c.gpTexSubImage2D = C.uintptr_t(g.get("glTexSubImage2D"))
|
c.gpTexSubImage2D = C.uintptr_t(g.get("glTexSubImage2D"))
|
||||||
|
@ -79,7 +79,7 @@ type defaultContext struct {
|
|||||||
fnShaderSource js.Value
|
fnShaderSource js.Value
|
||||||
fnStencilFunc js.Value
|
fnStencilFunc js.Value
|
||||||
fnStencilMask js.Value
|
fnStencilMask js.Value
|
||||||
fnStencilOp js.Value
|
fnStencilOpSeparate js.Value
|
||||||
fnTexImage2D js.Value
|
fnTexImage2D js.Value
|
||||||
fnTexSubImage2D js.Value
|
fnTexSubImage2D js.Value
|
||||||
fnTexParameteri js.Value
|
fnTexParameteri js.Value
|
||||||
@ -210,7 +210,7 @@ func NewDefaultContext(v js.Value) (Context, error) {
|
|||||||
fnShaderSource: v.Get("shaderSource").Call("bind", v),
|
fnShaderSource: v.Get("shaderSource").Call("bind", v),
|
||||||
fnStencilFunc: v.Get("stencilFunc").Call("bind", v),
|
fnStencilFunc: v.Get("stencilFunc").Call("bind", v),
|
||||||
fnStencilMask: v.Get("stencilMask").Call("bind", v),
|
fnStencilMask: v.Get("stencilMask").Call("bind", v),
|
||||||
fnStencilOp: v.Get("stencilOp").Call("bind", v),
|
fnStencilOpSeparate: v.Get("stencilOpSeparate").Call("bind", v),
|
||||||
fnTexImage2D: v.Get("texImage2D").Call("bind", v),
|
fnTexImage2D: v.Get("texImage2D").Call("bind", v),
|
||||||
fnTexSubImage2D: v.Get("texSubImage2D").Call("bind", v),
|
fnTexSubImage2D: v.Get("texSubImage2D").Call("bind", v),
|
||||||
fnTexParameteri: v.Get("texParameteri").Call("bind", v),
|
fnTexParameteri: v.Get("texParameteri").Call("bind", v),
|
||||||
@ -533,8 +533,8 @@ func (c *defaultContext) StencilFunc(func_ uint32, ref int32, mask uint32) {
|
|||||||
c.fnStencilFunc.Invoke(func_, ref, mask)
|
c.fnStencilFunc.Invoke(func_, ref, mask)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *defaultContext) StencilOp(sfail, dpfail, dppass uint32) {
|
func (c *defaultContext) StencilOpSeparate(face, sfail, dpfail, dppass uint32) {
|
||||||
c.fnStencilOp.Invoke(sfail, dpfail, dppass)
|
c.fnStencilOpSeparate.Invoke(face, sfail, dpfail, dppass)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *defaultContext) TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
func (c *defaultContext) TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
||||||
|
@ -80,7 +80,7 @@ type defaultContext struct {
|
|||||||
gpScissor uintptr
|
gpScissor uintptr
|
||||||
gpShaderSource uintptr
|
gpShaderSource uintptr
|
||||||
gpStencilFunc uintptr
|
gpStencilFunc uintptr
|
||||||
gpStencilOp uintptr
|
gpStencilOpSeparate uintptr
|
||||||
gpTexImage2D uintptr
|
gpTexImage2D uintptr
|
||||||
gpTexParameteri uintptr
|
gpTexParameteri uintptr
|
||||||
gpTexSubImage2D uintptr
|
gpTexSubImage2D uintptr
|
||||||
@ -384,8 +384,8 @@ func (c *defaultContext) StencilFunc(xfunc uint32, ref int32, mask uint32) {
|
|||||||
purego.SyscallN(c.gpStencilFunc, uintptr(xfunc), uintptr(ref), uintptr(mask))
|
purego.SyscallN(c.gpStencilFunc, uintptr(xfunc), uintptr(ref), uintptr(mask))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *defaultContext) StencilOp(fail uint32, zfail uint32, zpass uint32) {
|
func (c *defaultContext) StencilOpSeparate(face uint32, fail uint32, zfail uint32, zpass uint32) {
|
||||||
purego.SyscallN(c.gpStencilOp, uintptr(fail), uintptr(zfail), uintptr(zpass))
|
purego.SyscallN(c.gpStencilOpSeparate, uintptr(face), uintptr(fail), uintptr(zfail), uintptr(zpass))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *defaultContext) TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
func (c *defaultContext) TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
||||||
@ -536,7 +536,7 @@ func (c *defaultContext) LoadFunctions() error {
|
|||||||
c.gpScissor = g.get("glScissor")
|
c.gpScissor = g.get("glScissor")
|
||||||
c.gpShaderSource = g.get("glShaderSource")
|
c.gpShaderSource = g.get("glShaderSource")
|
||||||
c.gpStencilFunc = g.get("glStencilFunc")
|
c.gpStencilFunc = g.get("glStencilFunc")
|
||||||
c.gpStencilOp = g.get("glStencilOp")
|
c.gpStencilOpSeparate = g.get("glStencilOpSeparate")
|
||||||
c.gpTexImage2D = g.get("glTexImage2D")
|
c.gpTexImage2D = g.get("glTexImage2D")
|
||||||
c.gpTexParameteri = g.get("glTexParameteri")
|
c.gpTexParameteri = g.get("glTexParameteri")
|
||||||
c.gpTexSubImage2D = g.get("glTexSubImage2D")
|
c.gpTexSubImage2D = g.get("glTexSubImage2D")
|
||||||
|
@ -267,8 +267,8 @@ func (g *gomobileContext) StencilFunc(func_ uint32, ref int32, mask uint32) {
|
|||||||
g.ctx.StencilFunc(gl.Enum(func_), int(ref), mask)
|
g.ctx.StencilFunc(gl.Enum(func_), int(ref), mask)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *gomobileContext) StencilOp(sfail, dpfail, dppass uint32) {
|
func (g *gomobileContext) StencilOpSeparate(face, sfail, dpfail, dppass uint32) {
|
||||||
g.ctx.StencilOp(gl.Enum(sfail), gl.Enum(dpfail), gl.Enum(dppass))
|
g.ctx.StencilOpSeparate(gl.Enum(face), gl.Enum(sfail), gl.Enum(dpfail), gl.Enum(dppass))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *gomobileContext) TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
func (g *gomobileContext) TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte) {
|
||||||
|
@ -81,7 +81,7 @@ type Context interface {
|
|||||||
Scissor(x, y, width, height int32)
|
Scissor(x, y, width, height int32)
|
||||||
ShaderSource(shader uint32, xstring string)
|
ShaderSource(shader uint32, xstring string)
|
||||||
StencilFunc(func_ uint32, ref int32, mask uint32)
|
StencilFunc(func_ uint32, ref int32, mask uint32)
|
||||||
StencilOp(sfail, dpfail, dppass uint32)
|
StencilOpSeparate(face, sfail, dpfail, dppass uint32)
|
||||||
TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte)
|
TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, format uint32, xtype uint32, pixels []byte)
|
||||||
TexParameteri(target uint32, pname uint32, param int32)
|
TexParameteri(target uint32, pname uint32, param int32)
|
||||||
TexSubImage2D(target uint32, level int32, xoffset int32, yoffset int32, width int32, height int32, format uint32, xtype uint32, pixels []byte)
|
TexSubImage2D(target uint32, level int32, xoffset int32, yoffset int32, width int32, height int32, format uint32, xtype uint32, pixels []byte)
|
||||||
|
@ -243,7 +243,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
|||||||
}
|
}
|
||||||
g.uniformVars = g.uniformVars[:0]
|
g.uniformVars = g.uniformVars[:0]
|
||||||
|
|
||||||
if fillRule == graphicsdriver.EvenOdd {
|
if fillRule != graphicsdriver.FillAll {
|
||||||
if err := destination.ensureStencilBuffer(); err != nil {
|
if err := destination.ensureStencilBuffer(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -257,23 +257,32 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
|||||||
int32(dstRegion.Region.Dx()),
|
int32(dstRegion.Region.Dx()),
|
||||||
int32(dstRegion.Region.Dy()),
|
int32(dstRegion.Region.Dy()),
|
||||||
)
|
)
|
||||||
if fillRule == graphicsdriver.EvenOdd {
|
switch fillRule {
|
||||||
|
case graphicsdriver.NonZero:
|
||||||
g.context.ctx.Clear(gl.STENCIL_BUFFER_BIT)
|
g.context.ctx.Clear(gl.STENCIL_BUFFER_BIT)
|
||||||
g.context.ctx.StencilFunc(gl.ALWAYS, 0x00, 0xff)
|
g.context.ctx.StencilFunc(gl.ALWAYS, 0x00, 0xff)
|
||||||
g.context.ctx.StencilOp(gl.KEEP, gl.KEEP, gl.INVERT)
|
g.context.ctx.StencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.INCR_WRAP)
|
||||||
|
g.context.ctx.StencilOpSeparate(gl.BACK, gl.KEEP, gl.KEEP, gl.DECR_WRAP)
|
||||||
|
g.context.ctx.ColorMask(false, false, false, false)
|
||||||
|
g.context.ctx.DrawElements(gl.TRIANGLES, int32(dstRegion.IndexCount), gl.UNSIGNED_INT, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
||||||
|
case graphicsdriver.EvenOdd:
|
||||||
|
g.context.ctx.Clear(gl.STENCIL_BUFFER_BIT)
|
||||||
|
g.context.ctx.StencilFunc(gl.ALWAYS, 0x00, 0xff)
|
||||||
|
g.context.ctx.StencilOpSeparate(gl.FRONT_AND_BACK, gl.KEEP, gl.KEEP, gl.INVERT)
|
||||||
g.context.ctx.ColorMask(false, false, false, false)
|
g.context.ctx.ColorMask(false, false, false, false)
|
||||||
|
|
||||||
g.context.ctx.DrawElements(gl.TRIANGLES, int32(dstRegion.IndexCount), gl.UNSIGNED_INT, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
g.context.ctx.DrawElements(gl.TRIANGLES, int32(dstRegion.IndexCount), gl.UNSIGNED_INT, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
||||||
|
}
|
||||||
|
if fillRule != graphicsdriver.FillAll {
|
||||||
g.context.ctx.StencilFunc(gl.NOTEQUAL, 0x00, 0xff)
|
g.context.ctx.StencilFunc(gl.NOTEQUAL, 0x00, 0xff)
|
||||||
g.context.ctx.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)
|
g.context.ctx.StencilOpSeparate(gl.FRONT_AND_BACK, gl.KEEP, gl.KEEP, gl.KEEP)
|
||||||
g.context.ctx.ColorMask(true, true, true, true)
|
g.context.ctx.ColorMask(true, true, true, true)
|
||||||
}
|
}
|
||||||
g.context.ctx.DrawElements(gl.TRIANGLES, int32(dstRegion.IndexCount), gl.UNSIGNED_INT, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
g.context.ctx.DrawElements(gl.TRIANGLES, int32(dstRegion.IndexCount), gl.UNSIGNED_INT, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
||||||
indexOffset += dstRegion.IndexCount
|
indexOffset += dstRegion.IndexCount
|
||||||
}
|
}
|
||||||
|
|
||||||
if fillRule == graphicsdriver.EvenOdd {
|
if fillRule != graphicsdriver.FillAll {
|
||||||
g.context.ctx.Disable(gl.STENCIL_TEST)
|
g.context.ctx.Disable(gl.STENCIL_TEST)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,7 +396,7 @@ func (p *Path) Close() {
|
|||||||
//
|
//
|
||||||
// The returned vertice's SrcX and SrcY are 0, and ColorR, ColorG, ColorB, and ColorA are 1.
|
// The returned vertice's SrcX and SrcY are 0, and ColorR, ColorG, ColorB, and ColorA are 1.
|
||||||
//
|
//
|
||||||
// The returned values are intended to be passed to DrawTriangles or DrawTrianglesShader with the EvenOdd fill rule
|
// The returned values are intended to be passed to DrawTriangles or DrawTrianglesShader with the fill rule NonZero or EvenOdd
|
||||||
// in order to render a complex polygon like a concave polygon, a polygon with holes, or a self-intersecting polygon.
|
// in order to render a complex polygon like a concave polygon, a polygon with holes, or a self-intersecting polygon.
|
||||||
//
|
//
|
||||||
// The returned vertices and indices should be rendered with a solid (non-transparent) color with the default Blend (source-over).
|
// The returned vertices and indices should be rendered with a solid (non-transparent) color with the default Blend (source-over).
|
||||||
@ -480,7 +480,7 @@ type StrokeOptions struct {
|
|||||||
// The returned vertice's SrcX and SrcY are 0, and ColorR, ColorG, ColorB, and ColorA are 1.
|
// The returned vertice's SrcX and SrcY are 0, and ColorR, ColorG, ColorB, and ColorA are 1.
|
||||||
//
|
//
|
||||||
// The returned values are intended to be passed to DrawTriangles or DrawTrianglesShader with a solid (non-transparent) color
|
// The returned values are intended to be passed to DrawTriangles or DrawTrianglesShader with a solid (non-transparent) color
|
||||||
// with the FillAll fill rule (not the EvenOdd fill rule).
|
// with the FillAll fill rule (not NonZero or EvenOdd fill rule).
|
||||||
func (p *Path) AppendVerticesAndIndicesForStroke(vertices []ebiten.Vertex, indices []uint16, op *StrokeOptions) ([]ebiten.Vertex, []uint16) {
|
func (p *Path) AppendVerticesAndIndicesForStroke(vertices []ebiten.Vertex, indices []uint16, op *StrokeOptions) ([]ebiten.Vertex, []uint16) {
|
||||||
if op == nil {
|
if op == nil {
|
||||||
return vertices, indices
|
return vertices, indices
|
||||||
|
Loading…
Reference in New Issue
Block a user