mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 02:38:53 +01:00
ebiten: add DrawTrianglesOptions.AntiAlias
and DrawTrianglesShaderOptions.AntiAlias
Closes #2385
This commit is contained in:
parent
8b16badb83
commit
9ec23ddeb4
@ -57,8 +57,6 @@ type Game struct {
|
||||
vertices []ebiten.Vertex
|
||||
indices []uint16
|
||||
|
||||
offscreen *ebiten.Image
|
||||
|
||||
aa bool
|
||||
showCenter bool
|
||||
}
|
||||
@ -76,24 +74,6 @@ func (g *Game) Update() error {
|
||||
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
target := screen
|
||||
if g.aa {
|
||||
// Prepare the double-sized offscreen.
|
||||
// This is for anti-aliasing by a pseudo MSAA (multisample anti-aliasing).
|
||||
if g.offscreen != nil {
|
||||
sw, sh := screen.Size()
|
||||
ow, oh := g.offscreen.Size()
|
||||
if ow != sw*2 || oh != sh*2 {
|
||||
g.offscreen.Dispose()
|
||||
g.offscreen = nil
|
||||
}
|
||||
}
|
||||
if g.offscreen == nil {
|
||||
sw, sh := screen.Size()
|
||||
g.offscreen = ebiten.NewImage(sw*2, sh*2)
|
||||
}
|
||||
g.offscreen.Clear()
|
||||
target = g.offscreen
|
||||
}
|
||||
|
||||
joins := []vector.LineJoin{
|
||||
vector.LineJoinMiter,
|
||||
@ -123,14 +103,6 @@ func (g *Game) Draw(screen *ebiten.Image) {
|
||||
}
|
||||
}
|
||||
|
||||
if g.aa {
|
||||
// Render the offscreen to the screen.
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Scale(0.5, 0.5)
|
||||
op.Filter = ebiten.FilterLinear
|
||||
screen.DrawImage(g.offscreen, op)
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf(`FPS: %0.2f, TPS: %0.2f
|
||||
Press A to switch anti-aliasing.
|
||||
Press C to switch to draw the center lines.`, ebiten.ActualFPS(), ebiten.ActualTPS())
|
||||
@ -165,7 +137,9 @@ func (g *Game) drawLine(screen *ebiten.Image, region image.Rectangle, cap vector
|
||||
vs[i].SrcX = 1
|
||||
vs[i].SrcY = 1
|
||||
}
|
||||
screen.DrawTriangles(vs, is, emptySubImage, nil)
|
||||
screen.DrawTriangles(vs, is, emptySubImage, &ebiten.DrawTrianglesOptions{
|
||||
AntiAlias: g.aa,
|
||||
})
|
||||
|
||||
// Draw the center line in red.
|
||||
if g.showCenter {
|
||||
@ -180,7 +154,9 @@ func (g *Game) drawLine(screen *ebiten.Image, region image.Rectangle, cap vector
|
||||
vs[i].ColorG = 0
|
||||
vs[i].ColorB = 0
|
||||
}
|
||||
screen.DrawTriangles(vs, is, emptySubImage, nil)
|
||||
screen.DrawTriangles(vs, is, emptySubImage, &ebiten.DrawTrianglesOptions{
|
||||
AntiAlias: g.aa,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ const (
|
||||
screenHeight = 480
|
||||
)
|
||||
|
||||
func drawEbitenText(screen *ebiten.Image, x, y int, scale float32, line bool) {
|
||||
func drawEbitenText(screen *ebiten.Image, x, y int, aa bool, line bool) {
|
||||
var path vector.Path
|
||||
|
||||
// E
|
||||
@ -125,8 +125,8 @@ func drawEbitenText(screen *ebiten.Image, x, y int, scale float32, line bool) {
|
||||
}
|
||||
|
||||
for i := range vs {
|
||||
vs[i].DstX = (vs[i].DstX + float32(x)) * scale
|
||||
vs[i].DstY = (vs[i].DstY + float32(y)) * scale
|
||||
vs[i].DstX = (vs[i].DstX + float32(x))
|
||||
vs[i].DstY = (vs[i].DstY + float32(y))
|
||||
vs[i].SrcX = 1
|
||||
vs[i].SrcY = 1
|
||||
vs[i].ColorR = 0xdb / float32(0xff)
|
||||
@ -135,13 +135,14 @@ func drawEbitenText(screen *ebiten.Image, x, y int, scale float32, line bool) {
|
||||
}
|
||||
|
||||
op := &ebiten.DrawTrianglesOptions{}
|
||||
op.AntiAlias = aa
|
||||
if !line {
|
||||
op.FillRule = ebiten.EvenOdd
|
||||
}
|
||||
screen.DrawTriangles(vs, is, emptySubImage, op)
|
||||
}
|
||||
|
||||
func drawEbitenLogo(screen *ebiten.Image, x, y int, scale float32, line bool) {
|
||||
func drawEbitenLogo(screen *ebiten.Image, x, y int, aa bool, line bool) {
|
||||
const unit = 16
|
||||
|
||||
var path vector.Path
|
||||
@ -178,8 +179,8 @@ func drawEbitenLogo(screen *ebiten.Image, x, y int, scale float32, line bool) {
|
||||
}
|
||||
|
||||
for i := range vs {
|
||||
vs[i].DstX = (vs[i].DstX + float32(x)) * scale
|
||||
vs[i].DstY = (vs[i].DstY + float32(y)) * scale
|
||||
vs[i].DstX = (vs[i].DstX + float32(x))
|
||||
vs[i].DstY = (vs[i].DstY + float32(y))
|
||||
vs[i].SrcX = 1
|
||||
vs[i].SrcY = 1
|
||||
vs[i].ColorR = 0xdb / float32(0xff)
|
||||
@ -188,13 +189,14 @@ func drawEbitenLogo(screen *ebiten.Image, x, y int, scale float32, line bool) {
|
||||
}
|
||||
|
||||
op := &ebiten.DrawTrianglesOptions{}
|
||||
op.AntiAlias = aa
|
||||
if !line {
|
||||
op.FillRule = ebiten.EvenOdd
|
||||
}
|
||||
screen.DrawTriangles(vs, is, emptySubImage, op)
|
||||
}
|
||||
|
||||
func drawArc(screen *ebiten.Image, count int, scale float32, line bool) {
|
||||
func drawArc(screen *ebiten.Image, count int, aa bool, line bool) {
|
||||
var path vector.Path
|
||||
|
||||
path.MoveTo(350, 100)
|
||||
@ -220,8 +222,6 @@ func drawArc(screen *ebiten.Image, count int, scale float32, line bool) {
|
||||
}
|
||||
|
||||
for i := range vs {
|
||||
vs[i].DstX *= scale
|
||||
vs[i].DstY *= scale
|
||||
vs[i].SrcX = 1
|
||||
vs[i].SrcY = 1
|
||||
vs[i].ColorR = 0x33 / float32(0xff)
|
||||
@ -230,6 +230,7 @@ func drawArc(screen *ebiten.Image, count int, scale float32, line bool) {
|
||||
}
|
||||
|
||||
op := &ebiten.DrawTrianglesOptions{}
|
||||
op.AntiAlias = aa
|
||||
if !line {
|
||||
op.FillRule = ebiten.EvenOdd
|
||||
}
|
||||
@ -240,7 +241,7 @@ func maxCounter(index int) int {
|
||||
return 128 + (17*index+32)%64
|
||||
}
|
||||
|
||||
func drawWave(screen *ebiten.Image, counter int, scale float32, line bool) {
|
||||
func drawWave(screen *ebiten.Image, counter int, aa bool, line bool) {
|
||||
var path vector.Path
|
||||
|
||||
const npoints = 8
|
||||
@ -277,8 +278,6 @@ func drawWave(screen *ebiten.Image, counter int, scale float32, line bool) {
|
||||
}
|
||||
|
||||
for i := range vs {
|
||||
vs[i].DstX *= scale
|
||||
vs[i].DstY *= scale
|
||||
vs[i].SrcX = 1
|
||||
vs[i].SrcY = 1
|
||||
vs[i].ColorR = 0x33 / float32(0xff)
|
||||
@ -287,6 +286,7 @@ func drawWave(screen *ebiten.Image, counter int, scale float32, line bool) {
|
||||
}
|
||||
|
||||
op := &ebiten.DrawTrianglesOptions{}
|
||||
op.AntiAlias = aa
|
||||
if !line {
|
||||
op.FillRule = ebiten.EvenOdd
|
||||
}
|
||||
@ -296,9 +296,8 @@ func drawWave(screen *ebiten.Image, counter int, scale float32, line bool) {
|
||||
type Game struct {
|
||||
counter int
|
||||
|
||||
aa bool
|
||||
line bool
|
||||
offscreen *ebiten.Image
|
||||
aa bool
|
||||
line bool
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
@ -318,37 +317,13 @@ func (g *Game) Update() error {
|
||||
}
|
||||
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
if g.offscreen != nil {
|
||||
w, h := screen.Size()
|
||||
if ow, oh := g.offscreen.Size(); ow != w*2 || oh != h*2 {
|
||||
g.offscreen.Dispose()
|
||||
g.offscreen = nil
|
||||
}
|
||||
}
|
||||
if g.aa && g.offscreen == nil {
|
||||
w, h := screen.Size()
|
||||
g.offscreen = ebiten.NewImage(w*2, h*2)
|
||||
}
|
||||
|
||||
scale := float32(1)
|
||||
dst := screen
|
||||
if g.aa {
|
||||
scale = 2
|
||||
dst = g.offscreen
|
||||
}
|
||||
|
||||
dst.Fill(color.RGBA{0xe0, 0xe0, 0xe0, 0xff})
|
||||
drawEbitenText(dst, 0, 50, scale, g.line)
|
||||
drawEbitenLogo(dst, 20, 150, scale, g.line)
|
||||
drawArc(dst, g.counter, scale, g.line)
|
||||
drawWave(dst, g.counter, scale, g.line)
|
||||
|
||||
if g.aa {
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Scale(0.5, 0.5)
|
||||
op.Filter = ebiten.FilterLinear
|
||||
screen.DrawImage(g.offscreen, op)
|
||||
}
|
||||
drawEbitenText(dst, 0, 50, g.aa, g.line)
|
||||
drawEbitenLogo(dst, 20, 150, g.aa, g.line)
|
||||
drawArc(dst, g.counter, g.aa, g.line)
|
||||
drawWave(dst, g.counter, g.aa, g.line)
|
||||
|
||||
msg := fmt.Sprintf("TPS: %0.2f\nFPS: %0.2f", ebiten.ActualTPS(), ebiten.ActualFPS())
|
||||
msg += "\nPress A to switch anti-alias."
|
||||
|
26
image.go
26
image.go
@ -257,7 +257,7 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) {
|
||||
})
|
||||
}
|
||||
|
||||
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, uniforms, false, canSkipMipmap(options.GeoM, filter))
|
||||
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, uniforms, false, canSkipMipmap(options.GeoM, filter), false)
|
||||
}
|
||||
|
||||
// Vertex represents a vertex passed to DrawTriangles.
|
||||
@ -365,6 +365,15 @@ type DrawTrianglesOptions struct {
|
||||
//
|
||||
// The default (zero) value is FillAll.
|
||||
FillRule FillRule
|
||||
|
||||
// AntiAlias indicates whether the rendering uses anti-alias or not.
|
||||
// AntiAlias is useful especially when you pass vertices you get from the vector package.
|
||||
//
|
||||
// AntiAlias increases internal draw calls and might affect performance.
|
||||
// Use `ebitenginedebug` to check the number of draw calls if you care.
|
||||
//
|
||||
// The default (zero) value is false.
|
||||
AntiAlias bool
|
||||
}
|
||||
|
||||
// MaxIndicesCount is the maximum number of indices for DrawTriangles and DrawTrianglesShader.
|
||||
@ -479,7 +488,7 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
|
||||
})
|
||||
}
|
||||
|
||||
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), sr, [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, uniforms, options.FillRule == EvenOdd, filter != builtinshader.FilterLinear)
|
||||
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), sr, [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, uniforms, options.FillRule == EvenOdd, filter != builtinshader.FilterLinear, options.AntiAlias)
|
||||
}
|
||||
|
||||
// DrawTrianglesShaderOptions represents options for DrawTrianglesShader.
|
||||
@ -515,6 +524,15 @@ type DrawTrianglesShaderOptions struct {
|
||||
//
|
||||
// The default (zero) value is FillAll.
|
||||
FillRule FillRule
|
||||
|
||||
// AntiAlias indicates whether the rendering uses anti-alias or not.
|
||||
// AntiAlias is useful especially when you pass vertices you get from the vector package.
|
||||
//
|
||||
// AntiAlias increases internal draw calls and might affect performance.
|
||||
// Use `ebitenginedebug` to check the number of draw calls if you care.
|
||||
//
|
||||
// The default (zero) value is false.
|
||||
AntiAlias bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
@ -625,7 +643,7 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader
|
||||
offsets[i][1] = float32(y - sy)
|
||||
}
|
||||
|
||||
i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedRegion(), sr, offsets, shader.shader, shader.convertUniforms(options.Uniforms), options.FillRule == EvenOdd, true)
|
||||
i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedRegion(), sr, offsets, shader.shader, shader.convertUniforms(options.Uniforms), options.FillRule == EvenOdd, true, options.AntiAlias)
|
||||
}
|
||||
|
||||
// DrawRectShaderOptions represents options for DrawRectShader.
|
||||
@ -738,7 +756,7 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR
|
||||
offsets[i][1] = float32(y - sy)
|
||||
}
|
||||
|
||||
i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedRegion(), sr, offsets, shader.shader, shader.convertUniforms(options.Uniforms), false, true)
|
||||
i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedRegion(), sr, offsets, shader.shader, shader.convertUniforms(options.Uniforms), false, true, false)
|
||||
}
|
||||
|
||||
// SubImage returns an image representing the portion of the image p visible through r.
|
||||
|
@ -3864,3 +3864,80 @@ func TestImageBlendFactor(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageAntiAliasAndBlend(t *testing.T) {
|
||||
const w, h = 16, 16
|
||||
|
||||
dst0 := ebiten.NewImage(w, h)
|
||||
dst1 := ebiten.NewImage(w, h)
|
||||
src := ebiten.NewImage(w, h)
|
||||
|
||||
for _, blend := range []ebiten.Blend{
|
||||
{}, // Default
|
||||
ebiten.BlendClear,
|
||||
ebiten.BlendCopy,
|
||||
ebiten.BlendSourceOver,
|
||||
} {
|
||||
dst0.Fill(color.RGBA{0x24, 0x3f, 0x6a, 0x88})
|
||||
dst1.Fill(color.RGBA{0x24, 0x3f, 0x6a, 0x88})
|
||||
src.Fill(color.RGBA{0x85, 0xa3, 0x08, 0xd3})
|
||||
|
||||
op0 := &ebiten.DrawTrianglesOptions{}
|
||||
op0.Blend = blend
|
||||
op0.AntiAlias = true
|
||||
vs := []ebiten.Vertex{
|
||||
{
|
||||
DstX: 0,
|
||||
DstY: 0,
|
||||
SrcX: 0,
|
||||
SrcY: 0,
|
||||
ColorR: 1,
|
||||
ColorG: 1,
|
||||
ColorB: 1,
|
||||
ColorA: 1,
|
||||
},
|
||||
{
|
||||
DstX: w,
|
||||
DstY: 0,
|
||||
SrcX: w,
|
||||
SrcY: 0,
|
||||
ColorR: 1,
|
||||
ColorG: 1,
|
||||
ColorB: 1,
|
||||
ColorA: 1,
|
||||
},
|
||||
{
|
||||
DstX: 0,
|
||||
DstY: h,
|
||||
SrcX: 0,
|
||||
SrcY: h,
|
||||
ColorR: 1,
|
||||
ColorG: 1,
|
||||
ColorB: 1,
|
||||
ColorA: 1,
|
||||
},
|
||||
{
|
||||
DstX: w,
|
||||
DstY: h,
|
||||
SrcX: w,
|
||||
SrcY: h,
|
||||
ColorR: 1,
|
||||
ColorG: 1,
|
||||
ColorB: 1,
|
||||
ColorA: 1,
|
||||
},
|
||||
}
|
||||
is := []uint16{0, 1, 2, 1, 2, 3}
|
||||
dst0.DrawTriangles(vs, is, src, op0)
|
||||
got := dst0.At(0, 0).(color.RGBA)
|
||||
|
||||
op1 := &ebiten.DrawImageOptions{}
|
||||
op1.Blend = blend
|
||||
dst1.DrawImage(src, op1)
|
||||
want := dst1.At(0, 0).(color.RGBA)
|
||||
|
||||
if got != want {
|
||||
t.Errorf("blend: %v, got: %v, want: %v", blend, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/buffered"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/clock"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/debug"
|
||||
@ -153,7 +154,7 @@ func (c *context) updateFrameImpl(graphicsDriver graphicsdriver.Graphics, update
|
||||
}
|
||||
|
||||
func (c *context) drawGame(graphicsDriver graphicsdriver.Graphics) error {
|
||||
if c.offscreen.volatile != theGlobalState.isScreenClearedEveryFrame() {
|
||||
if (c.offscreen.imageType == atlas.ImageTypeVolatile) != theGlobalState.isScreenClearedEveryFrame() {
|
||||
w, h := c.offscreen.width, c.offscreen.height
|
||||
c.offscreen.MarkDisposed()
|
||||
c.offscreen = c.game.NewOffscreenImage(w, h)
|
||||
|
@ -15,6 +15,8 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
@ -30,20 +32,25 @@ func SetPanicOnErrorOnReadingPixelsForTesting(value bool) {
|
||||
}
|
||||
|
||||
type Image struct {
|
||||
mipmap *mipmap.Mipmap
|
||||
width int
|
||||
height int
|
||||
volatile bool
|
||||
mipmap *mipmap.Mipmap
|
||||
width int
|
||||
height int
|
||||
imageType atlas.ImageType
|
||||
|
||||
dotsBuffer map[[2]int][4]byte
|
||||
|
||||
// bigOffscreenBuffer is a double-sized offscreen for anti-alias rendering.
|
||||
bigOffscreenBuffer *Image
|
||||
bigOffscreenBufferBlend graphicsdriver.Blend
|
||||
bigOffscreenBufferDirty bool
|
||||
}
|
||||
|
||||
func NewImage(width, height int, imageType atlas.ImageType) *Image {
|
||||
return &Image{
|
||||
mipmap: mipmap.New(width, height, imageType),
|
||||
width: width,
|
||||
height: height,
|
||||
volatile: imageType == atlas.ImageTypeVolatile,
|
||||
mipmap: mipmap.New(width, height, imageType),
|
||||
width: width,
|
||||
height: height,
|
||||
imageType: imageType,
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,12 +58,72 @@ func (i *Image) MarkDisposed() {
|
||||
if i.mipmap == nil {
|
||||
return
|
||||
}
|
||||
if i.bigOffscreenBuffer != nil {
|
||||
i.bigOffscreenBuffer.MarkDisposed()
|
||||
i.bigOffscreenBuffer = nil
|
||||
i.bigOffscreenBufferDirty = false
|
||||
}
|
||||
i.mipmap.MarkDisposed()
|
||||
i.mipmap = nil
|
||||
i.dotsBuffer = nil
|
||||
}
|
||||
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms [][]float32, evenOdd bool, canSkipMipmap bool) {
|
||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms [][]float32, evenOdd bool, canSkipMipmap bool, antialias bool) {
|
||||
if antialias {
|
||||
// Flush the other buffer to make the buffers exclusive.
|
||||
i.flushDotsBufferIfNeeded()
|
||||
|
||||
if i.bigOffscreenBufferBlend != blend {
|
||||
i.flushBigOffscreenBufferIfNeeded()
|
||||
}
|
||||
|
||||
if i.bigOffscreenBuffer == nil {
|
||||
var imageType atlas.ImageType
|
||||
switch i.imageType {
|
||||
case atlas.ImageTypeRegular, atlas.ImageTypeUnmanaged:
|
||||
imageType = atlas.ImageTypeUnmanaged
|
||||
case atlas.ImageTypeScreen, atlas.ImageTypeVolatile:
|
||||
imageType = atlas.ImageTypeVolatile
|
||||
default:
|
||||
panic(fmt.Sprintf("ui: unexpected image type: %d", imageType))
|
||||
}
|
||||
i.bigOffscreenBuffer = NewImage(i.width*2, i.height*2, imageType)
|
||||
}
|
||||
|
||||
i.bigOffscreenBufferBlend = blend
|
||||
|
||||
// Copy the current rendering result to get the correct blending result.
|
||||
if blend != graphicsdriver.BlendSourceOver && !i.bigOffscreenBufferDirty {
|
||||
srcs := [graphics.ShaderImageCount]*Image{i}
|
||||
vs := graphics.QuadVertices(
|
||||
0, 0, float32(i.width), float32(i.height),
|
||||
2, 0, 0, 2, 0, 0,
|
||||
1, 1, 1, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dstRegion := graphicsdriver.Region{
|
||||
X: 0,
|
||||
Y: 0,
|
||||
Width: float32(i.width * 2),
|
||||
Height: float32(i.height * 2),
|
||||
}
|
||||
i.bigOffscreenBuffer.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true, false)
|
||||
}
|
||||
|
||||
for i := 0; i < len(vertices); i += graphics.VertexFloatCount {
|
||||
vertices[i] *= 2
|
||||
vertices[i+1] *= 2
|
||||
}
|
||||
|
||||
dstRegion.X *= 2
|
||||
dstRegion.Y *= 2
|
||||
dstRegion.Width *= 2
|
||||
dstRegion.Height *= 2
|
||||
|
||||
i.bigOffscreenBuffer.DrawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegion, subimageOffsets, shader, uniforms, evenOdd, canSkipMipmap, false)
|
||||
i.bigOffscreenBufferDirty = true
|
||||
return
|
||||
}
|
||||
|
||||
i.flushBufferIfNeeded()
|
||||
|
||||
var srcMipmaps [graphics.ShaderImageCount]*mipmap.Mipmap
|
||||
@ -73,6 +140,9 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
|
||||
|
||||
func (i *Image) WritePixels(pix []byte, x, y, width, height int) {
|
||||
if width == 1 && height == 1 {
|
||||
// Flush the other buffer to make the buffers exclusive.
|
||||
i.flushBigOffscreenBufferIfNeeded()
|
||||
|
||||
if i.dotsBuffer == nil {
|
||||
i.dotsBuffer = map[[2]int][4]byte{}
|
||||
}
|
||||
@ -83,7 +153,7 @@ func (i *Image) WritePixels(pix []byte, x, y, width, height int) {
|
||||
|
||||
// One square requires 6 indices (= 2 triangles).
|
||||
if len(i.dotsBuffer) >= graphics.IndicesCount/6 {
|
||||
i.flushBufferIfNeeded()
|
||||
i.flushDotsBufferIfNeeded()
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -98,15 +168,17 @@ func (i *Image) ReadPixels(pixels []byte, x, y, width, height int) {
|
||||
return
|
||||
}
|
||||
|
||||
i.flushBigOffscreenBufferIfNeeded()
|
||||
|
||||
if width == 1 && height == 1 {
|
||||
if c, ok := i.dotsBuffer[[2]int{x, y}]; ok {
|
||||
copy(pixels, c[:])
|
||||
return
|
||||
}
|
||||
// Do not call flushBufferIfNeeded here. This would slow (image/draw).Draw.
|
||||
// Do not call flushDotsBufferIfNeeded here. This would slow (image/draw).Draw.
|
||||
// See ebiten.TestImageDrawOver.
|
||||
} else {
|
||||
i.flushBufferIfNeeded()
|
||||
i.flushDotsBufferIfNeeded()
|
||||
}
|
||||
|
||||
if err := theUI.readPixels(i.mipmap, pixels, x, y, width, height); err != nil {
|
||||
@ -122,6 +194,12 @@ func (i *Image) DumpScreenshot(name string, blackbg bool) (string, error) {
|
||||
}
|
||||
|
||||
func (i *Image) flushBufferIfNeeded() {
|
||||
// The buffers are exclusive and the order should not matter.
|
||||
i.flushDotsBufferIfNeeded()
|
||||
i.flushBigOffscreenBufferIfNeeded()
|
||||
}
|
||||
|
||||
func (i *Image) flushDotsBufferIfNeeded() {
|
||||
if len(i.dotsBuffer) == 0 {
|
||||
return
|
||||
}
|
||||
@ -193,6 +271,36 @@ func (i *Image) flushBufferIfNeeded() {
|
||||
i.mipmap.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader.shader, nil, false, true)
|
||||
}
|
||||
|
||||
func (i *Image) flushBigOffscreenBufferIfNeeded() {
|
||||
if !i.bigOffscreenBufferDirty {
|
||||
return
|
||||
}
|
||||
|
||||
// Mark the offscreen clearn earlier to avoid recursive calls.
|
||||
i.bigOffscreenBufferDirty = false
|
||||
|
||||
srcs := [graphics.ShaderImageCount]*Image{i.bigOffscreenBuffer}
|
||||
vs := graphics.QuadVertices(
|
||||
0, 0, float32(i.width*2), float32(i.height*2),
|
||||
0.5, 0, 0, 0.5, 0, 0,
|
||||
1, 1, 1, 1)
|
||||
is := graphics.QuadIndices()
|
||||
dstRegion := graphicsdriver.Region{
|
||||
X: 0,
|
||||
Y: 0,
|
||||
Width: float32(i.width),
|
||||
Height: float32(i.height),
|
||||
}
|
||||
blend := graphicsdriver.BlendSourceOver
|
||||
if i.bigOffscreenBufferBlend != graphicsdriver.BlendSourceOver {
|
||||
blend = graphicsdriver.BlendCopy
|
||||
}
|
||||
i.DrawTriangles(srcs, vs, is, blend, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, LinearFilterShader, nil, false, true, false)
|
||||
|
||||
i.bigOffscreenBuffer.clear()
|
||||
i.bigOffscreenBufferDirty = false
|
||||
}
|
||||
|
||||
func DumpImages(dir string) (string, error) {
|
||||
return theUI.dumpImages(dir)
|
||||
}
|
||||
@ -230,5 +338,5 @@ func (i *Image) Fill(r, g, b, a float32, x, y, width, height int) {
|
||||
|
||||
srcs := [graphics.ShaderImageCount]*Image{emptyImage}
|
||||
|
||||
i.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true)
|
||||
i.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true, false)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user