mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-02-03 22:44:28 +01:00
parent
b297611dd9
commit
0f93535faf
@ -19,6 +19,7 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
_ "image/png"
|
_ "image/png"
|
||||||
"log"
|
"log"
|
||||||
|
"math"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2"
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||||
@ -35,27 +36,40 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Game struct {
|
type Game struct {
|
||||||
|
counter int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Game) Update() error {
|
func (g *Game) Update() error {
|
||||||
|
g.counter++
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Game) Draw(screen *ebiten.Image) {
|
func (g *Game) Draw(screen *ebiten.Image) {
|
||||||
ebitenutil.DebugPrint(screen, "Nearest Filter (default) VS Linear Filter")
|
scale := 2*math.Sin(float64(g.counter%360)*math.Pi/180) + 4
|
||||||
|
|
||||||
|
ebitenutil.DebugPrintAt(screen, "Nearest Filter (default) and Linear Filter", 16, 16)
|
||||||
|
|
||||||
op := &ebiten.DrawImageOptions{}
|
op := &ebiten.DrawImageOptions{}
|
||||||
op.GeoM.Scale(4, 4)
|
op.GeoM.Scale(scale, scale)
|
||||||
op.GeoM.Translate(64, 64)
|
op.GeoM.Translate(64, 64)
|
||||||
// By default, nearest filter is used.
|
// By default, nearest filter is used.
|
||||||
screen.DrawImage(ebitenImage, op)
|
screen.DrawImage(ebitenImage, op)
|
||||||
|
|
||||||
op = &ebiten.DrawImageOptions{}
|
op = &ebiten.DrawImageOptions{}
|
||||||
op.GeoM.Scale(4, 4)
|
op.GeoM.Scale(scale, scale)
|
||||||
op.GeoM.Translate(64, 64+240)
|
op.GeoM.Translate(64+240, 64)
|
||||||
// Specify linear filter.
|
// Specify linear filter.
|
||||||
op.Filter = ebiten.FilterLinear
|
op.Filter = ebiten.FilterLinear
|
||||||
screen.DrawImage(ebitenImage, op)
|
screen.DrawImage(ebitenImage, op)
|
||||||
|
|
||||||
|
ebitenutil.DebugPrintAt(screen, "Pixelated Filter", 16, 16+200)
|
||||||
|
|
||||||
|
op = &ebiten.DrawImageOptions{}
|
||||||
|
op.GeoM.Scale(scale, scale)
|
||||||
|
op.GeoM.Translate(64, 64+200)
|
||||||
|
// Specify pixelated filter.
|
||||||
|
op.Filter = ebiten.FilterPixelated
|
||||||
|
screen.DrawImage(ebitenImage, op)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||||
|
18
gameforui.go
18
gameforui.go
@ -15,10 +15,8 @@
|
|||||||
package ebiten
|
package ebiten
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"image"
|
"image"
|
||||||
"math"
|
"math"
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
"github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
||||||
@ -131,25 +129,12 @@ func (g *gameForUI) DrawFinalScreen(scale, offsetX, offsetY float64) {
|
|||||||
DefaultDrawFinalScreen(g.screen, g.offscreen, geoM)
|
DefaultDrawFinalScreen(g.screen, g.offscreen, geoM)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
theScreenShader *Shader
|
|
||||||
theScreenShaderOnce sync.Once
|
|
||||||
)
|
|
||||||
|
|
||||||
// DefaultDrawFinalScreen is the default implementation of [FinalScreenDrawer.DrawFinalScreen],
|
// DefaultDrawFinalScreen is the default implementation of [FinalScreenDrawer.DrawFinalScreen],
|
||||||
// used when a [Game] doesn't implement [FinalScreenDrawer].
|
// used when a [Game] doesn't implement [FinalScreenDrawer].
|
||||||
//
|
//
|
||||||
// You can use DefaultDrawFinalScreen when you need the default implementation of [FinalScreenDrawer.DrawFinalScreen]
|
// You can use DefaultDrawFinalScreen when you need the default implementation of [FinalScreenDrawer.DrawFinalScreen]
|
||||||
// in your implementation of [FinalScreenDrawer], for example.
|
// in your implementation of [FinalScreenDrawer], for example.
|
||||||
func DefaultDrawFinalScreen(screen FinalScreen, offscreen *Image, geoM GeoM) {
|
func DefaultDrawFinalScreen(screen FinalScreen, offscreen *Image, geoM GeoM) {
|
||||||
theScreenShaderOnce.Do(func() {
|
|
||||||
s, err := newShader([]byte(builtinshader.ScreenShaderSource), "screen")
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("ebiten: compiling the screen shader failed: %v", err))
|
|
||||||
}
|
|
||||||
theScreenShader = s
|
|
||||||
})
|
|
||||||
|
|
||||||
scale := geoM.Element(0, 0)
|
scale := geoM.Element(0, 0)
|
||||||
switch {
|
switch {
|
||||||
case !screenFilterEnabled.Load(), math.Floor(scale) == scale:
|
case !screenFilterEnabled.Load(), math.Floor(scale) == scale:
|
||||||
@ -166,6 +151,7 @@ func DefaultDrawFinalScreen(screen FinalScreen, offscreen *Image, geoM GeoM) {
|
|||||||
op.Images[0] = offscreen
|
op.Images[0] = offscreen
|
||||||
op.GeoM = geoM
|
op.GeoM = geoM
|
||||||
w, h := offscreen.Bounds().Dx(), offscreen.Bounds().Dy()
|
w, h := offscreen.Bounds().Dx(), offscreen.Bounds().Dy()
|
||||||
screen.DrawRectShader(w, h, theScreenShader, op)
|
screenShader := builtinShader(builtinshader.FilterPixelated, builtinshader.AddressUnsafe, false)
|
||||||
|
screen.DrawRectShader(w, h, screenShader, op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,10 @@ const (
|
|||||||
|
|
||||||
// FilterLinear represents linear filter
|
// FilterLinear represents linear filter
|
||||||
FilterLinear Filter = Filter(builtinshader.FilterLinear)
|
FilterLinear Filter = Filter(builtinshader.FilterLinear)
|
||||||
|
|
||||||
|
// FilterPixelated represents a pixelated filter.
|
||||||
|
// FilterPixelated is similar to FilterNearest, but it preserves the pixelated appearance even when scaled to non-integer sizes.
|
||||||
|
FilterPixelated Filter = Filter(builtinshader.FilterPixelated)
|
||||||
)
|
)
|
||||||
|
|
||||||
// GraphicsLibrary represents graphics libraries supported by the engine.
|
// GraphicsLibrary represents graphics libraries supported by the engine.
|
||||||
|
@ -39,19 +39,37 @@ const _ = "//kage:unit pixels\n\npackage main\n\n\n\n\nfunc adjustSrcPosForAddre
|
|||||||
const _ = "//kage:unit pixels\n\npackage main\n\n\nvar ColorMBody mat4\nvar ColorMTranslation vec4\n\n\n\nfunc adjustSrcPosForAddressRepeat(p vec2) vec2 {\n\torigin := imageSrc0Origin()\n\tsize := imageSrc0Size()\n\treturn mod(p - origin, size) + origin\n}\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\n\tclr := imageSrc0At(adjustSrcPosForAddressRepeat(srcPos))\n\n\n\n\n\t// Un-premultiply alpha.\n\t// When the alpha is 0, 1-sign(alpha) is 1.0, which means division does nothing.\n\tclr.rgb /= clr.a + (1-sign(clr.a))\n\t// Apply the clr matrix.\n\tclr = (ColorMBody * clr) + ColorMTranslation\n\t// Premultiply alpha\n\tclr.rgb *= clr.a\n\t// Apply the color scale.\n\tclr *= color\n\t// Clamp the output.\n\tclr.rgb = min(clr.rgb, clr.a)\n\n\n\treturn clr\n}\n\n"
|
const _ = "//kage:unit pixels\n\npackage main\n\n\nvar ColorMBody mat4\nvar ColorMTranslation vec4\n\n\n\nfunc adjustSrcPosForAddressRepeat(p vec2) vec2 {\n\torigin := imageSrc0Origin()\n\tsize := imageSrc0Size()\n\treturn mod(p - origin, size) + origin\n}\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\n\tclr := imageSrc0At(adjustSrcPosForAddressRepeat(srcPos))\n\n\n\n\n\t// Un-premultiply alpha.\n\t// When the alpha is 0, 1-sign(alpha) is 1.0, which means division does nothing.\n\tclr.rgb /= clr.a + (1-sign(clr.a))\n\t// Apply the clr matrix.\n\tclr = (ColorMBody * clr) + ColorMTranslation\n\t// Premultiply alpha\n\tclr.rgb *= clr.a\n\t// Apply the color scale.\n\tclr *= color\n\t// Clamp the output.\n\tclr.rgb = min(clr.rgb, clr.a)\n\n\n\treturn clr\n}\n\n"
|
||||||
|
|
||||||
//ebitengine:shader
|
//ebitengine:shader
|
||||||
const _ = "//kage:unit pixels\n\npackage main\n\n\n\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\tp0 := srcPos - 1/2.0\n\tp1 := srcPos + 1/2.0\n\n\n\n\n\tc0 := imageSrc0UnsafeAt(p0)\n\tc1 := imageSrc0UnsafeAt(vec2(p1.x, p0.y))\n\tc2 := imageSrc0UnsafeAt(vec2(p0.x, p1.y))\n\tc3 := imageSrc0UnsafeAt(p1)\n\n\n\trate := fract(p1)\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Apply the color scale.\n\tclr *= color\n\n\n\treturn clr\n}\n\n"
|
const _ = "//kage:unit pixels\n\npackage main\n\n\n\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\n\tp0 := srcPos - 1/2.0\n\tp1 := srcPos + 1/2.0\n\n\n\n\n\n\tc0 := imageSrc0UnsafeAt(p0)\n\tc1 := imageSrc0UnsafeAt(vec2(p1.x, p0.y))\n\tc2 := imageSrc0UnsafeAt(vec2(p0.x, p1.y))\n\tc3 := imageSrc0UnsafeAt(p1)\n\n\n\n\trate := fract(p1)\n\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Apply the color scale.\n\tclr *= color\n\n\n\treturn clr\n}\n\n"
|
||||||
|
|
||||||
//ebitengine:shader
|
//ebitengine:shader
|
||||||
const _ = "//kage:unit pixels\n\npackage main\n\n\nvar ColorMBody mat4\nvar ColorMTranslation vec4\n\n\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\tp0 := srcPos - 1/2.0\n\tp1 := srcPos + 1/2.0\n\n\n\n\n\tc0 := imageSrc0UnsafeAt(p0)\n\tc1 := imageSrc0UnsafeAt(vec2(p1.x, p0.y))\n\tc2 := imageSrc0UnsafeAt(vec2(p0.x, p1.y))\n\tc3 := imageSrc0UnsafeAt(p1)\n\n\n\trate := fract(p1)\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Un-premultiply alpha.\n\t// When the alpha is 0, 1-sign(alpha) is 1.0, which means division does nothing.\n\tclr.rgb /= clr.a + (1-sign(clr.a))\n\t// Apply the clr matrix.\n\tclr = (ColorMBody * clr) + ColorMTranslation\n\t// Premultiply alpha\n\tclr.rgb *= clr.a\n\t// Apply the color scale.\n\tclr *= color\n\t// Clamp the output.\n\tclr.rgb = min(clr.rgb, clr.a)\n\n\n\treturn clr\n}\n\n"
|
const _ = "//kage:unit pixels\n\npackage main\n\n\nvar ColorMBody mat4\nvar ColorMTranslation vec4\n\n\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\n\tp0 := srcPos - 1/2.0\n\tp1 := srcPos + 1/2.0\n\n\n\n\n\n\tc0 := imageSrc0UnsafeAt(p0)\n\tc1 := imageSrc0UnsafeAt(vec2(p1.x, p0.y))\n\tc2 := imageSrc0UnsafeAt(vec2(p0.x, p1.y))\n\tc3 := imageSrc0UnsafeAt(p1)\n\n\n\n\trate := fract(p1)\n\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Un-premultiply alpha.\n\t// When the alpha is 0, 1-sign(alpha) is 1.0, which means division does nothing.\n\tclr.rgb /= clr.a + (1-sign(clr.a))\n\t// Apply the clr matrix.\n\tclr = (ColorMBody * clr) + ColorMTranslation\n\t// Premultiply alpha\n\tclr.rgb *= clr.a\n\t// Apply the color scale.\n\tclr *= color\n\t// Clamp the output.\n\tclr.rgb = min(clr.rgb, clr.a)\n\n\n\treturn clr\n}\n\n"
|
||||||
|
|
||||||
//ebitengine:shader
|
//ebitengine:shader
|
||||||
const _ = "//kage:unit pixels\n\npackage main\n\n\n\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\tp0 := srcPos - 1/2.0\n\tp1 := srcPos + 1/2.0\n\n\n\n\n\tc0 := imageSrc0At(p0)\n\tc1 := imageSrc0At(vec2(p1.x, p0.y))\n\tc2 := imageSrc0At(vec2(p0.x, p1.y))\n\tc3 := imageSrc0At(p1)\n\n\n\trate := fract(p1)\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Apply the color scale.\n\tclr *= color\n\n\n\treturn clr\n}\n\n"
|
const _ = "//kage:unit pixels\n\npackage main\n\n\n\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\n\tp0 := srcPos - 1/2.0\n\tp1 := srcPos + 1/2.0\n\n\n\n\n\n\tc0 := imageSrc0At(p0)\n\tc1 := imageSrc0At(vec2(p1.x, p0.y))\n\tc2 := imageSrc0At(vec2(p0.x, p1.y))\n\tc3 := imageSrc0At(p1)\n\n\n\n\trate := fract(p1)\n\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Apply the color scale.\n\tclr *= color\n\n\n\treturn clr\n}\n\n"
|
||||||
|
|
||||||
//ebitengine:shader
|
//ebitengine:shader
|
||||||
const _ = "//kage:unit pixels\n\npackage main\n\n\nvar ColorMBody mat4\nvar ColorMTranslation vec4\n\n\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\tp0 := srcPos - 1/2.0\n\tp1 := srcPos + 1/2.0\n\n\n\n\n\tc0 := imageSrc0At(p0)\n\tc1 := imageSrc0At(vec2(p1.x, p0.y))\n\tc2 := imageSrc0At(vec2(p0.x, p1.y))\n\tc3 := imageSrc0At(p1)\n\n\n\trate := fract(p1)\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Un-premultiply alpha.\n\t// When the alpha is 0, 1-sign(alpha) is 1.0, which means division does nothing.\n\tclr.rgb /= clr.a + (1-sign(clr.a))\n\t// Apply the clr matrix.\n\tclr = (ColorMBody * clr) + ColorMTranslation\n\t// Premultiply alpha\n\tclr.rgb *= clr.a\n\t// Apply the color scale.\n\tclr *= color\n\t// Clamp the output.\n\tclr.rgb = min(clr.rgb, clr.a)\n\n\n\treturn clr\n}\n\n"
|
const _ = "//kage:unit pixels\n\npackage main\n\n\nvar ColorMBody mat4\nvar ColorMTranslation vec4\n\n\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\n\tp0 := srcPos - 1/2.0\n\tp1 := srcPos + 1/2.0\n\n\n\n\n\n\tc0 := imageSrc0At(p0)\n\tc1 := imageSrc0At(vec2(p1.x, p0.y))\n\tc2 := imageSrc0At(vec2(p0.x, p1.y))\n\tc3 := imageSrc0At(p1)\n\n\n\n\trate := fract(p1)\n\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Un-premultiply alpha.\n\t// When the alpha is 0, 1-sign(alpha) is 1.0, which means division does nothing.\n\tclr.rgb /= clr.a + (1-sign(clr.a))\n\t// Apply the clr matrix.\n\tclr = (ColorMBody * clr) + ColorMTranslation\n\t// Premultiply alpha\n\tclr.rgb *= clr.a\n\t// Apply the color scale.\n\tclr *= color\n\t// Clamp the output.\n\tclr.rgb = min(clr.rgb, clr.a)\n\n\n\treturn clr\n}\n\n"
|
||||||
|
|
||||||
//ebitengine:shader
|
//ebitengine:shader
|
||||||
const _ = "//kage:unit pixels\n\npackage main\n\n\n\n\nfunc adjustSrcPosForAddressRepeat(p vec2) vec2 {\n\torigin := imageSrc0Origin()\n\tsize := imageSrc0Size()\n\treturn mod(p - origin, size) + origin\n}\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\tp0 := srcPos - 1/2.0\n\tp1 := srcPos + 1/2.0\n\n\n\tp0 = adjustSrcPosForAddressRepeat(p0)\n\tp1 = adjustSrcPosForAddressRepeat(p1)\n\n\n\n\tc0 := imageSrc0At(p0)\n\tc1 := imageSrc0At(vec2(p1.x, p0.y))\n\tc2 := imageSrc0At(vec2(p0.x, p1.y))\n\tc3 := imageSrc0At(p1)\n\n\n\trate := fract(p1)\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Apply the color scale.\n\tclr *= color\n\n\n\treturn clr\n}\n\n"
|
const _ = "//kage:unit pixels\n\npackage main\n\n\n\n\nfunc adjustSrcPosForAddressRepeat(p vec2) vec2 {\n\torigin := imageSrc0Origin()\n\tsize := imageSrc0Size()\n\treturn mod(p - origin, size) + origin\n}\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\n\tp0 := srcPos - 1/2.0\n\tp1 := srcPos + 1/2.0\n\n\n\n\tp0 = adjustSrcPosForAddressRepeat(p0)\n\tp1 = adjustSrcPosForAddressRepeat(p1)\n\n\n\n\tc0 := imageSrc0At(p0)\n\tc1 := imageSrc0At(vec2(p1.x, p0.y))\n\tc2 := imageSrc0At(vec2(p0.x, p1.y))\n\tc3 := imageSrc0At(p1)\n\n\n\n\trate := fract(p1)\n\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Apply the color scale.\n\tclr *= color\n\n\n\treturn clr\n}\n\n"
|
||||||
|
|
||||||
//ebitengine:shader
|
//ebitengine:shader
|
||||||
const _ = "//kage:unit pixels\n\npackage main\n\n\nvar ColorMBody mat4\nvar ColorMTranslation vec4\n\n\n\nfunc adjustSrcPosForAddressRepeat(p vec2) vec2 {\n\torigin := imageSrc0Origin()\n\tsize := imageSrc0Size()\n\treturn mod(p - origin, size) + origin\n}\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\tp0 := srcPos - 1/2.0\n\tp1 := srcPos + 1/2.0\n\n\n\tp0 = adjustSrcPosForAddressRepeat(p0)\n\tp1 = adjustSrcPosForAddressRepeat(p1)\n\n\n\n\tc0 := imageSrc0At(p0)\n\tc1 := imageSrc0At(vec2(p1.x, p0.y))\n\tc2 := imageSrc0At(vec2(p0.x, p1.y))\n\tc3 := imageSrc0At(p1)\n\n\n\trate := fract(p1)\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Un-premultiply alpha.\n\t// When the alpha is 0, 1-sign(alpha) is 1.0, which means division does nothing.\n\tclr.rgb /= clr.a + (1-sign(clr.a))\n\t// Apply the clr matrix.\n\tclr = (ColorMBody * clr) + ColorMTranslation\n\t// Premultiply alpha\n\tclr.rgb *= clr.a\n\t// Apply the color scale.\n\tclr *= color\n\t// Clamp the output.\n\tclr.rgb = min(clr.rgb, clr.a)\n\n\n\treturn clr\n}\n\n"
|
const _ = "//kage:unit pixels\n\npackage main\n\n\nvar ColorMBody mat4\nvar ColorMTranslation vec4\n\n\n\nfunc adjustSrcPosForAddressRepeat(p vec2) vec2 {\n\torigin := imageSrc0Origin()\n\tsize := imageSrc0Size()\n\treturn mod(p - origin, size) + origin\n}\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\n\tp0 := srcPos - 1/2.0\n\tp1 := srcPos + 1/2.0\n\n\n\n\tp0 = adjustSrcPosForAddressRepeat(p0)\n\tp1 = adjustSrcPosForAddressRepeat(p1)\n\n\n\n\tc0 := imageSrc0At(p0)\n\tc1 := imageSrc0At(vec2(p1.x, p0.y))\n\tc2 := imageSrc0At(vec2(p0.x, p1.y))\n\tc3 := imageSrc0At(p1)\n\n\n\n\trate := fract(p1)\n\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Un-premultiply alpha.\n\t// When the alpha is 0, 1-sign(alpha) is 1.0, which means division does nothing.\n\tclr.rgb /= clr.a + (1-sign(clr.a))\n\t// Apply the clr matrix.\n\tclr = (ColorMBody * clr) + ColorMTranslation\n\t// Premultiply alpha\n\tclr.rgb *= clr.a\n\t// Apply the color scale.\n\tclr *= color\n\t// Clamp the output.\n\tclr.rgb = min(clr.rgb, clr.a)\n\n\n\treturn clr\n}\n\n"
|
||||||
|
|
||||||
|
//ebitengine:shader
|
||||||
|
const _ = "//kage:unit pixels\n\npackage main\n\n\n\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\n\t// inversedScale is the size of the region on the source image.\n\t// The size is the inverse of the geometry-matrix scale.\n\tinversedScale := vec2(abs(dfdx(srcPos.x)), abs(dfdy(srcPos.y)))\n\t// Cap the inversedScale to 1 as dfdx/dfdy is not accurate on some machines (#3182).\n\tinversedScale = min(inversedScale, vec2(1))\n\tp0 := srcPos - inversedScale/2.0\n\tp1 := srcPos + inversedScale/2.0\n\n\n\n\n\n\tc0 := imageSrc0UnsafeAt(p0)\n\tc1 := imageSrc0UnsafeAt(vec2(p1.x, p0.y))\n\tc2 := imageSrc0UnsafeAt(vec2(p0.x, p1.y))\n\tc3 := imageSrc0UnsafeAt(p1)\n\n\n\n\trate := clamp(fract(p1)/inversedScale, 0, 1)\n\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Apply the color scale.\n\tclr *= color\n\n\n\treturn clr\n}\n\n"
|
||||||
|
|
||||||
|
//ebitengine:shader
|
||||||
|
const _ = "//kage:unit pixels\n\npackage main\n\n\nvar ColorMBody mat4\nvar ColorMTranslation vec4\n\n\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\n\t// inversedScale is the size of the region on the source image.\n\t// The size is the inverse of the geometry-matrix scale.\n\tinversedScale := vec2(abs(dfdx(srcPos.x)), abs(dfdy(srcPos.y)))\n\t// Cap the inversedScale to 1 as dfdx/dfdy is not accurate on some machines (#3182).\n\tinversedScale = min(inversedScale, vec2(1))\n\tp0 := srcPos - inversedScale/2.0\n\tp1 := srcPos + inversedScale/2.0\n\n\n\n\n\n\tc0 := imageSrc0UnsafeAt(p0)\n\tc1 := imageSrc0UnsafeAt(vec2(p1.x, p0.y))\n\tc2 := imageSrc0UnsafeAt(vec2(p0.x, p1.y))\n\tc3 := imageSrc0UnsafeAt(p1)\n\n\n\n\trate := clamp(fract(p1)/inversedScale, 0, 1)\n\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Un-premultiply alpha.\n\t// When the alpha is 0, 1-sign(alpha) is 1.0, which means division does nothing.\n\tclr.rgb /= clr.a + (1-sign(clr.a))\n\t// Apply the clr matrix.\n\tclr = (ColorMBody * clr) + ColorMTranslation\n\t// Premultiply alpha\n\tclr.rgb *= clr.a\n\t// Apply the color scale.\n\tclr *= color\n\t// Clamp the output.\n\tclr.rgb = min(clr.rgb, clr.a)\n\n\n\treturn clr\n}\n\n"
|
||||||
|
|
||||||
|
//ebitengine:shader
|
||||||
|
const _ = "//kage:unit pixels\n\npackage main\n\n\n\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\n\t// inversedScale is the size of the region on the source image.\n\t// The size is the inverse of the geometry-matrix scale.\n\tinversedScale := vec2(abs(dfdx(srcPos.x)), abs(dfdy(srcPos.y)))\n\t// Cap the inversedScale to 1 as dfdx/dfdy is not accurate on some machines (#3182).\n\tinversedScale = min(inversedScale, vec2(1))\n\tp0 := srcPos - inversedScale/2.0\n\tp1 := srcPos + inversedScale/2.0\n\n\n\n\n\n\tc0 := imageSrc0At(p0)\n\tc1 := imageSrc0At(vec2(p1.x, p0.y))\n\tc2 := imageSrc0At(vec2(p0.x, p1.y))\n\tc3 := imageSrc0At(p1)\n\n\n\n\trate := clamp(fract(p1)/inversedScale, 0, 1)\n\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Apply the color scale.\n\tclr *= color\n\n\n\treturn clr\n}\n\n"
|
||||||
|
|
||||||
|
//ebitengine:shader
|
||||||
|
const _ = "//kage:unit pixels\n\npackage main\n\n\nvar ColorMBody mat4\nvar ColorMTranslation vec4\n\n\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\n\t// inversedScale is the size of the region on the source image.\n\t// The size is the inverse of the geometry-matrix scale.\n\tinversedScale := vec2(abs(dfdx(srcPos.x)), abs(dfdy(srcPos.y)))\n\t// Cap the inversedScale to 1 as dfdx/dfdy is not accurate on some machines (#3182).\n\tinversedScale = min(inversedScale, vec2(1))\n\tp0 := srcPos - inversedScale/2.0\n\tp1 := srcPos + inversedScale/2.0\n\n\n\n\n\n\tc0 := imageSrc0At(p0)\n\tc1 := imageSrc0At(vec2(p1.x, p0.y))\n\tc2 := imageSrc0At(vec2(p0.x, p1.y))\n\tc3 := imageSrc0At(p1)\n\n\n\n\trate := clamp(fract(p1)/inversedScale, 0, 1)\n\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Un-premultiply alpha.\n\t// When the alpha is 0, 1-sign(alpha) is 1.0, which means division does nothing.\n\tclr.rgb /= clr.a + (1-sign(clr.a))\n\t// Apply the clr matrix.\n\tclr = (ColorMBody * clr) + ColorMTranslation\n\t// Premultiply alpha\n\tclr.rgb *= clr.a\n\t// Apply the color scale.\n\tclr *= color\n\t// Clamp the output.\n\tclr.rgb = min(clr.rgb, clr.a)\n\n\n\treturn clr\n}\n\n"
|
||||||
|
|
||||||
|
//ebitengine:shader
|
||||||
|
const _ = "//kage:unit pixels\n\npackage main\n\n\n\n\nfunc adjustSrcPosForAddressRepeat(p vec2) vec2 {\n\torigin := imageSrc0Origin()\n\tsize := imageSrc0Size()\n\treturn mod(p - origin, size) + origin\n}\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\n\t// inversedScale is the size of the region on the source image.\n\t// The size is the inverse of the geometry-matrix scale.\n\tinversedScale := vec2(abs(dfdx(srcPos.x)), abs(dfdy(srcPos.y)))\n\t// Cap the inversedScale to 1 as dfdx/dfdy is not accurate on some machines (#3182).\n\tinversedScale = min(inversedScale, vec2(1))\n\tp0 := srcPos - inversedScale/2.0\n\tp1 := srcPos + inversedScale/2.0\n\n\n\n\tp0 = adjustSrcPosForAddressRepeat(p0)\n\tp1 = adjustSrcPosForAddressRepeat(p1)\n\n\n\n\tc0 := imageSrc0At(p0)\n\tc1 := imageSrc0At(vec2(p1.x, p0.y))\n\tc2 := imageSrc0At(vec2(p0.x, p1.y))\n\tc3 := imageSrc0At(p1)\n\n\n\n\trate := clamp(fract(p1)/inversedScale, 0, 1)\n\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Apply the color scale.\n\tclr *= color\n\n\n\treturn clr\n}\n\n"
|
||||||
|
|
||||||
|
//ebitengine:shader
|
||||||
|
const _ = "//kage:unit pixels\n\npackage main\n\n\nvar ColorMBody mat4\nvar ColorMTranslation vec4\n\n\n\nfunc adjustSrcPosForAddressRepeat(p vec2) vec2 {\n\torigin := imageSrc0Origin()\n\tsize := imageSrc0Size()\n\treturn mod(p - origin, size) + origin\n}\n\n\nfunc Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {\n\n\n\t// inversedScale is the size of the region on the source image.\n\t// The size is the inverse of the geometry-matrix scale.\n\tinversedScale := vec2(abs(dfdx(srcPos.x)), abs(dfdy(srcPos.y)))\n\t// Cap the inversedScale to 1 as dfdx/dfdy is not accurate on some machines (#3182).\n\tinversedScale = min(inversedScale, vec2(1))\n\tp0 := srcPos - inversedScale/2.0\n\tp1 := srcPos + inversedScale/2.0\n\n\n\n\tp0 = adjustSrcPosForAddressRepeat(p0)\n\tp1 = adjustSrcPosForAddressRepeat(p1)\n\n\n\n\tc0 := imageSrc0At(p0)\n\tc1 := imageSrc0At(vec2(p1.x, p0.y))\n\tc2 := imageSrc0At(vec2(p0.x, p1.y))\n\tc3 := imageSrc0At(p1)\n\n\n\n\trate := clamp(fract(p1)/inversedScale, 0, 1)\n\n\tclr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)\n\n\n\n\t// Un-premultiply alpha.\n\t// When the alpha is 0, 1-sign(alpha) is 1.0, which means division does nothing.\n\tclr.rgb /= clr.a + (1-sign(clr.a))\n\t// Apply the clr matrix.\n\tclr = (ColorMBody * clr) + ColorMTranslation\n\t// Premultiply alpha\n\tclr.rgb *= clr.a\n\t// Apply the color scale.\n\tclr *= color\n\t// Clamp the output.\n\tclr.rgb = min(clr.rgb, clr.a)\n\n\n\treturn clr\n}\n\n"
|
||||||
|
@ -29,9 +29,10 @@ type Filter int
|
|||||||
const (
|
const (
|
||||||
FilterNearest Filter = iota
|
FilterNearest Filter = iota
|
||||||
FilterLinear
|
FilterLinear
|
||||||
|
FilterPixelated
|
||||||
)
|
)
|
||||||
|
|
||||||
const FilterCount = 2
|
const FilterCount = 3
|
||||||
|
|
||||||
type Address int
|
type Address int
|
||||||
|
|
||||||
@ -79,9 +80,19 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
|
|||||||
{{else if eq .Address .AddressRepeat}}
|
{{else if eq .Address .AddressRepeat}}
|
||||||
clr := imageSrc0At(adjustSrcPosForAddressRepeat(srcPos))
|
clr := imageSrc0At(adjustSrcPosForAddressRepeat(srcPos))
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else if eq .Filter .FilterLinear}}
|
{{else}}
|
||||||
|
{{if eq .Filter .FilterLinear}}
|
||||||
p0 := srcPos - 1/2.0
|
p0 := srcPos - 1/2.0
|
||||||
p1 := srcPos + 1/2.0
|
p1 := srcPos + 1/2.0
|
||||||
|
{{else if eq .Filter .FilterPixelated}}
|
||||||
|
// inversedScale is the size of the region on the source image.
|
||||||
|
// The size is the inverse of the geometry-matrix scale.
|
||||||
|
inversedScale := vec2(abs(dfdx(srcPos.x)), abs(dfdy(srcPos.y)))
|
||||||
|
// Cap the inversedScale to 1 as dfdx/dfdy is not accurate on some machines (#3182).
|
||||||
|
inversedScale = min(inversedScale, vec2(1))
|
||||||
|
p0 := srcPos - inversedScale/2.0
|
||||||
|
p1 := srcPos + inversedScale/2.0
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{if eq .Address .AddressRepeat}}
|
{{if eq .Address .AddressRepeat}}
|
||||||
p0 = adjustSrcPosForAddressRepeat(p0)
|
p0 = adjustSrcPosForAddressRepeat(p0)
|
||||||
@ -100,7 +111,11 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
|
|||||||
c3 := imageSrc0At(p1)
|
c3 := imageSrc0At(p1)
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{if eq .Filter .FilterLinear}}
|
||||||
rate := fract(p1)
|
rate := fract(p1)
|
||||||
|
{{else if eq .Filter .FilterPixelated}}
|
||||||
|
rate := clamp(fract(p1)/inversedScale, 0, 1)
|
||||||
|
{{end}}
|
||||||
clr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)
|
clr := mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
@ -146,6 +161,7 @@ func ShaderSource(filter Filter, address Address, useColorM bool) []byte {
|
|||||||
Filter Filter
|
Filter Filter
|
||||||
FilterNearest Filter
|
FilterNearest Filter
|
||||||
FilterLinear Filter
|
FilterLinear Filter
|
||||||
|
FilterPixelated Filter
|
||||||
Address Address
|
Address Address
|
||||||
AddressUnsafe Address
|
AddressUnsafe Address
|
||||||
AddressClampToZero Address
|
AddressClampToZero Address
|
||||||
@ -155,6 +171,7 @@ func ShaderSource(filter Filter, address Address, useColorM bool) []byte {
|
|||||||
Filter: filter,
|
Filter: filter,
|
||||||
FilterNearest: FilterNearest,
|
FilterNearest: FilterNearest,
|
||||||
FilterLinear: FilterLinear,
|
FilterLinear: FilterLinear,
|
||||||
|
FilterPixelated: FilterPixelated,
|
||||||
Address: address,
|
Address: address,
|
||||||
AddressUnsafe: AddressUnsafe,
|
AddressUnsafe: AddressUnsafe,
|
||||||
AddressClampToZero: AddressClampToZero,
|
AddressClampToZero: AddressClampToZero,
|
||||||
@ -169,28 +186,6 @@ func ShaderSource(filter Filter, address Address, useColorM bool) []byte {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
//ebitengine:shader
|
|
||||||
const ScreenShaderSource = `//kage:unit pixels
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
func Fragment(dstPos vec4, srcPos vec2) vec4 {
|
|
||||||
// Blend source colors in a square region, which size is 1/scale.
|
|
||||||
scale := imageDstSize()/imageSrc0Size()
|
|
||||||
p0 := srcPos - 1/2.0/scale
|
|
||||||
p1 := srcPos + 1/2.0/scale
|
|
||||||
|
|
||||||
// Texels must be in the source rect, so it is not necessary to check.
|
|
||||||
c0 := imageSrc0UnsafeAt(p0)
|
|
||||||
c1 := imageSrc0UnsafeAt(vec2(p1.x, p0.y))
|
|
||||||
c2 := imageSrc0UnsafeAt(vec2(p0.x, p1.y))
|
|
||||||
c3 := imageSrc0UnsafeAt(p1)
|
|
||||||
|
|
||||||
rate := clamp(fract(p1)*scale, 0, 1)
|
|
||||||
return mix(mix(c0, c1, rate.x), mix(c2, c3, rate.x), rate.y)
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
//ebitengine:shader
|
//ebitengine:shader
|
||||||
const ClearShaderSource = `//kage:unit pixels
|
const ClearShaderSource = `//kage:unit pixels
|
||||||
|
|
||||||
|
@ -113,7 +113,8 @@ func builtinShader(filter builtinshader.Filter, address builtinshader.Address, u
|
|||||||
}
|
}
|
||||||
|
|
||||||
var shader *Shader
|
var shader *Shader
|
||||||
if address == builtinshader.AddressUnsafe && !useColorM {
|
if (filter == builtinshader.FilterNearest || filter == builtinshader.FilterLinear) &&
|
||||||
|
address == builtinshader.AddressUnsafe && !useColorM {
|
||||||
switch filter {
|
switch filter {
|
||||||
case builtinshader.FilterNearest:
|
case builtinshader.FilterNearest:
|
||||||
shader = &Shader{shader: ui.NearestFilterShader}
|
shader = &Shader{shader: ui.NearestFilterShader}
|
||||||
@ -128,6 +129,8 @@ func builtinShader(filter builtinshader.Filter, address builtinshader.Address, u
|
|||||||
name = "nearest"
|
name = "nearest"
|
||||||
case builtinshader.FilterLinear:
|
case builtinshader.FilterLinear:
|
||||||
name = "linear"
|
name = "linear"
|
||||||
|
case builtinshader.FilterPixelated:
|
||||||
|
name = "pixelated"
|
||||||
}
|
}
|
||||||
switch address {
|
switch address {
|
||||||
case builtinshader.AddressClampToZero:
|
case builtinshader.AddressClampToZero:
|
||||||
|
Loading…
Reference in New Issue
Block a user