ebiten: add FillRuleFillAll, FillRuleEvenOdd, and FillRuleNonZero

This change also deprecates the existing constants.

Closes #3006
This commit is contained in:
Hajime Hoshi 2024-06-08 12:06:00 +09:00
parent d37301eeeb
commit b121468991
6 changed files with 51 additions and 32 deletions

View File

@ -72,11 +72,11 @@ type DrawTrianglesOptions struct {
// FillRule indicates the rule how an overlapped region is rendered.
//
// The rules NonZero and EvenOdd are useful when you want to render a complex polygon.
// The rules FileRuleNonZero and FillRuleEvenOdd 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.
// See examples/vector for actual usages.
//
// The default (zero) value is ebiten.FillAll.
// The default (zero) value is ebiten.FillRuleFillAll.
FillRule ebiten.FillRule
// AntiAlias indicates whether the rendering uses anti-alias or not.

View File

@ -141,14 +141,14 @@ func drawEbitenText(screen *ebiten.Image, x, y int, aa bool, line bool) {
op := &ebiten.DrawTrianglesOptions{}
op.AntiAlias = aa
// For strokes (AppendVerticesAndIndicesForStroke), FillAll and NonZero work.
// For strokes (AppendVerticesAndIndicesForStroke), FillRuleFillAll and FillRuleNonZero work.
//
// For filling (AppendVerticesAndIndicesForFilling), NonZero and EvenOdd work.
// NonZero and EvenOdd differ when rendering a complex polygons with self-intersections and/or holes.
// For filling (AppendVerticesAndIndicesForFilling), FillRuleNonZero and FillRuleEvenOdd work.
// FillRuleNonZero and FillRuleEvenOdd 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 .
//
// For simplicity, this example always uses NonZero, whichever strokes or filling is done.
op.FillRule = ebiten.NonZero
// For simplicity, this example always uses FillRuleNonZero, whichever strokes or filling is done.
op.FillRule = ebiten.FillRuleNonZero
screen.DrawTriangles(vs, is, whiteSubImage, op)
}
@ -203,7 +203,7 @@ func drawEbitenLogo(screen *ebiten.Image, x, y int, aa bool, line bool) {
op := &ebiten.DrawTrianglesOptions{}
op.AntiAlias = aa
op.FillRule = ebiten.NonZero
op.FillRule = ebiten.FillRuleNonZero
screen.DrawTriangles(vs, is, whiteSubImage, op)
}
@ -245,7 +245,7 @@ func drawArc(screen *ebiten.Image, count int, aa bool, line bool) {
op := &ebiten.DrawTrianglesOptions{}
op.AntiAlias = aa
op.FillRule = ebiten.NonZero
op.FillRule = ebiten.FillRuleNonZero
screen.DrawTriangles(vs, is, whiteSubImage, op)
}
@ -300,7 +300,7 @@ func drawWave(screen *ebiten.Image, counter int, aa bool, line bool) {
op := &ebiten.DrawTrianglesOptions{}
op.AntiAlias = aa
op.FillRule = ebiten.NonZero
op.FillRule = ebiten.FillRuleNonZero
screen.DrawTriangles(vs, is, whiteSubImage, op)
}

View File

@ -310,17 +310,36 @@ const (
// FillRule is the rule whether an overlapped region is rendered with DrawTriangles(Shader).
type FillRule int
const (
// FillRuleFillAll indicates all the triangles are rendered regardless of overlaps.
FillRuleFillAll FillRule = FillRule(graphicsdriver.FillRuleFillAll)
// FillRuleNonZero 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.
FillRuleNonZero FillRule = FillRule(graphicsdriver.FillRuleNonZero)
// FillRuleEvenOdd 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.
FillRuleEvenOdd FillRule = FillRule(graphicsdriver.FillRuleEvenOdd)
)
const (
// FillAll indicates all the triangles are rendered regardless of overlaps.
FillAll FillRule = FillRule(graphicsdriver.FillRuleFillAll)
//
// Deprecated: as of v2.8. Use FillRuleFillAll instead.
FillAll = FillRuleFillAll
// 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.FillRuleNonZero)
//
// Deprecated: as of v2.8. Use FillRuleNonZero instead.
NonZero = FillRuleNonZero
// 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.
EvenOdd FillRule = FillRule(graphicsdriver.FillRuleEvenOdd)
//
// Deprecated: as of v2.8. Use FillRuleEvenOdd instead.
EvenOdd = FillRuleEvenOdd
)
// ColorScaleMode is the mode of color scales in vertices.
@ -371,11 +390,11 @@ type DrawTrianglesOptions struct {
// FillRule indicates the rule how an overlapped region is rendered.
//
// The rules NonZero and EvenOdd are useful when you want to render a complex polygon.
// The rules FillRuleNonZero and FillRuleEvenOdd 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.
// See examples/vector for actual usages.
//
// The default (zero) value is FillAll.
// The default (zero) value is FillRuleFillAll.
FillRule FillRule
// AntiAlias indicates whether the rendering uses anti-alias or not.
@ -547,11 +566,11 @@ type DrawTrianglesShaderOptions struct {
// FillRule indicates the rule how an overlapped region is rendered.
//
// The rules NonZero and EvenOdd are useful when you want to render a complex polygon.
// The rules FillRuleNonZero and FillRuleEvenOdd 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.
// See examples/vector for actual usages.
//
// The default (zero) value is FillAll.
// The default (zero) value is FillRuleFillAll.
FillRule FillRule
// AntiAlias indicates whether the rendering uses anti-alias or not.

View File

@ -2696,7 +2696,7 @@ func TestImageEvenOdd(t *testing.T) {
// 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: ebiten.EvenOdd,
FillRule: ebiten.FillRuleEvenOdd,
}
dst.DrawTriangles(append(append(vs0, vs1...), vs2...), append(append(is0, is1...), is2...), emptySubImage, op)
for j := 0; j < 16; j++ {
@ -2794,15 +2794,15 @@ func TestImageEvenOdd(t *testing.T) {
}
func TestImageFillRule(t *testing.T) {
for _, fillRule := range []ebiten.FillRule{ebiten.FillAll, ebiten.NonZero, ebiten.EvenOdd} {
for _, fillRule := range []ebiten.FillRule{ebiten.FillRuleFillAll, ebiten.FillRuleNonZero, ebiten.FillRuleEvenOdd} {
fillRule := fillRule
var name string
switch fillRule {
case ebiten.FillAll:
case ebiten.FillRuleFillAll:
name = "FillAll"
case ebiten.NonZero:
case ebiten.FillRuleNonZero:
name = "NonZero"
case ebiten.EvenOdd:
case ebiten.FillRuleEvenOdd:
name = "EvenOdd"
}
t.Run(name, func(t *testing.T) {
@ -2885,11 +2885,11 @@ func TestImageFillRule(t *testing.T) {
var want color.RGBA
switch {
case 2 <= i && i < 7 && 2 <= j && j < 7:
if fillRule != ebiten.EvenOdd {
if fillRule != ebiten.FillRuleEvenOdd {
want = color.RGBA{G: 0xff, A: 0xff}
}
case 9 <= i && i < 14 && 9 <= j && j < 14:
if fillRule == ebiten.FillAll {
if fillRule == ebiten.FillRuleFillAll {
want = color.RGBA{B: 0xff, A: 0xff}
}
case 1 <= i && i < 15 && 1 <= j && j < 15:
@ -2922,11 +2922,11 @@ func TestImageFillRule(t *testing.T) {
var want color.RGBA
switch {
case 3 <= i && i < 8 && 3 <= j && j < 8:
if fillRule != ebiten.EvenOdd {
if fillRule != ebiten.FillRuleEvenOdd {
want = color.RGBA{G: 0xff, A: 0xff}
}
case 10 <= i && i < 15 && 10 <= j && j < 15:
if fillRule == ebiten.FillAll {
if fillRule == ebiten.FillRuleFillAll {
want = color.RGBA{B: 0xff, A: 0xff}
}
case 2 <= i && i < 16 && 2 <= j && j < 16:
@ -3726,7 +3726,7 @@ func TestImageTooManyConstantBuffersInDirectX(t *testing.T) {
dst0 := ebiten.NewImage(16, 16)
dst1 := ebiten.NewImage(16, 16)
op := &ebiten.DrawTrianglesOptions{
FillRule: ebiten.EvenOdd,
FillRule: ebiten.FillRuleEvenOdd,
}
for i := 0; i < 100; i++ {
dst0.DrawTriangles(vs, is, src, op)

View File

@ -59,7 +59,7 @@ func (g *Game) Update() error {
}
func (g *Game) Draw(screen *ebiten.Image) {
// Before the fix, some complex renderings with EvenOdd might cause a DirectX error like this (#2138):
// Before the fix, some complex renderings with FillRuleEvenOdd might cause a DirectX error like this (#2138):
// panic: directx: IDXGISwapChain4::Present failed: HRESULT(2289696773)
screen.DrawImage(debugCircleImage, nil)
@ -74,7 +74,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
p.Arc(100, 100, 6, 0, 2*math.Pi, vector.Clockwise)
filling, indicies := p.AppendVerticesAndIndicesForFilling(nil, nil)
screen.DrawTriangles(filling, indicies, whiteTextureImage, &ebiten.DrawTrianglesOptions{
FillRule: ebiten.EvenOdd,
FillRule: ebiten.FillRuleEvenOdd,
})
}

View File

@ -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 values are intended to be passed to DrawTriangles or DrawTrianglesShader with the fill rule NonZero or EvenOdd
// The returned values are intended to be passed to DrawTriangles or DrawTrianglesShader with FileRuleNonZero or FillRuleEvenOdd
// 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).
@ -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 values are intended to be passed to DrawTriangles or DrawTrianglesShader with a solid (non-transparent) color
// with FillAll or NonZero fill rule, not EvenOdd fill rule.
// with FillRuleFillAll or FillRuleNonZero, not FileRuleEvenOdd.
func (p *Path) AppendVerticesAndIndicesForStroke(vertices []ebiten.Vertex, indices []uint16, op *StrokeOptions) ([]ebiten.Vertex, []uint16) {
if op == nil {
return vertices, indices
@ -536,7 +536,7 @@ func (p *Path) AppendVerticesAndIndicesForStroke(vertices []ebiten.Vertex, indic
ColorA: 1,
})
}
// All the triangles are rendered in clockwise order to enable NonZero filling rule (#2833).
// All the triangles are rendered in clockwise order to enable FillRuleNonZero (#2833).
indices = append(indices, idx, idx+1, idx+2, idx+1, idx+3, idx+2)
// Add line joints.