diff --git a/examples/minify/main.go b/examples/minify/main.go index f8847866b..04ee76331 100644 --- a/examples/minify/main.go +++ b/examples/minify/main.go @@ -32,7 +32,7 @@ import ( ) const ( - screenWidth = 800 + screenWidth = 1000 screenHeight = 480 ) @@ -44,20 +44,28 @@ type Game struct { rotate bool clip bool counter int + pause bool } func (g *Game) Update() error { - g.counter++ - if g.counter == 480 { - g.counter = 0 - } - if inpututil.IsKeyJustPressed(ebiten.KeyR) { g.rotate = !g.rotate } if inpututil.IsKeyJustPressed(ebiten.KeyC) { g.clip = !g.clip } + if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) { + g.pause = !g.pause + } + + if g.pause { + return nil + } + + g.counter++ + if g.counter == 480 { + g.counter = 0 + } return nil } @@ -65,7 +73,8 @@ func (g *Game) Draw(screen *ebiten.Image) { s := 1.5 / math.Pow(1.01, float64(g.counter)) clippedGophersImage := gophersImage.SubImage(image.Rect(100, 100, 200, 200)).(*ebiten.Image) - for i, f := range []ebiten.Filter{ebiten.FilterNearest, ebiten.FilterLinear} { + for i := range 3 { + //for i, f := range []ebiten.Filter{ebiten.FilterNearest, ebiten.FilterLinear} { w, h := gophersImage.Bounds().Dx(), gophersImage.Bounds().Dy() op := &ebiten.DrawImageOptions{} @@ -75,8 +84,15 @@ func (g *Game) Draw(screen *ebiten.Image) { op.GeoM.Translate(float64(w)/2, float64(h)/2) } op.GeoM.Scale(s, s) - op.GeoM.Translate(32+float64(i*w)*s+float64(i*4), 64) - op.Filter = f + op.GeoM.Translate(32+float64(i*w)*s+float64(i*4), 100) + if i == 0 { + op.Filter = ebiten.FilterNearest + } else { + op.Filter = ebiten.FilterLinear + } + if i == 2 { + op.DisableMipmaps = true + } if g.clip { screen.DrawImage(clippedGophersImage, op) } else { @@ -84,9 +100,10 @@ func (g *Game) Draw(screen *ebiten.Image) { } } - msg := fmt.Sprintf(`Minifying images (Nearest filter vs Linear filter): + msg := fmt.Sprintf(`Minifying images (Nearest filter, Linear filter (w/ mipmaps), and Linear Filter (w/o mipmaps)): Press R to rotate the images. Press C to clip the images. +Click to pause and resume. Scale: %0.2f`, s) ebitenutil.DebugPrint(screen, msg) } diff --git a/image.go b/image.go index e27577676..93d248071 100644 --- a/image.go +++ b/image.go @@ -144,6 +144,16 @@ type DrawImageOptions struct { // Filter is a type of texture filter. // The default (zero) value is FilterNearest. Filter Filter + + // DisableMipmaps disables mipmaps. + // When Filter is FilterLinear and GeoM shrinks the image, mipmaps are used by default. + // Mipmap is useful to render a shrunk image with high quality. + // However, mipmaps can be expensive, especially on mobiles. + // When DisableMipmaps is true, mipmap is not used. + // When Filter is not FilterLinear, DisableMipmaps is ignored. + // + // The default (zero) value is false. + DisableMipmaps bool } // adjustPosition converts the position in the *ebiten.Image coordinate to the *ui.Image coordinate. @@ -273,7 +283,11 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) { hint = restorable.HintOverwriteDstRegion } - i.image.DrawTriangles(srcs, vs, is, blend, dr, [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRuleFillAll, canSkipMipmap(geoM, filter), false, hint) + skipMipmap := options.DisableMipmaps + if !skipMipmap { + skipMipmap = canSkipMipmap(geoM, filter) + } + i.image.DrawTriangles(srcs, vs, is, blend, dr, [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRuleFillAll, skipMipmap, false, hint) } // overwritesDstRegion reports whether the given parameters overwrite the destination region completely. @@ -447,6 +461,16 @@ type DrawTrianglesOptions struct { // // The default (zero) value is false. AntiAlias bool + + // DisableMipmaps disables mipmaps. + // When Filter is FilterLinear and GeoM shrinks the image, mipmaps are used by default. + // Mipmap is useful to render a shrunk image with high quality. + // However, mipmaps can be expensive, especially on mobiles. + // When DisableMipmaps is true, mipmap is not used. + // When Filter is not FilterLinear, DisableMipmaps is ignored. + // + // The default (zero) value is false. + DisableMipmaps bool } // MaxIndicesCount is the maximum number of indices for DrawTriangles and DrawTrianglesShader. @@ -576,7 +600,11 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o }) } - i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRule(options.FillRule), filter != builtinshader.FilterLinear, options.AntiAlias, restorable.HintNone) + skipMipmap := options.DisableMipmaps + if !skipMipmap { + skipMipmap = filter != builtinshader.FilterLinear + } + i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRule(options.FillRule), skipMipmap, options.AntiAlias, restorable.HintNone) } // DrawTrianglesShaderOptions represents options for DrawTrianglesShader.