From 3c1e64dd67397399cf02a406a54c11c097797f7f Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Fri, 4 Mar 2022 18:05:42 +0900 Subject: [PATCH] internal/shaderir/metal: bug fix: define the 'mod' function correctly Closes #2006 --- internal/shaderir/metal/metal.go | 7 ++++++- internal/shaderir/metal/type.go | 3 ++- shader_test.go | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/internal/shaderir/metal/metal.go b/internal/shaderir/metal/metal.go index 52b2f5371..f45659884 100644 --- a/internal/shaderir/metal/metal.go +++ b/internal/shaderir/metal/metal.go @@ -52,7 +52,12 @@ const Prelude = `#include using namespace metal; -constexpr sampler texture_sampler{filter::nearest};` +constexpr sampler texture_sampler{filter::nearest}; + +template +T mod(T x, T y) { + return x - y * floor(x/y); +}` func Compile(p *shaderir.Program, vertex, fragment string) (shader string) { c := &compileContext{ diff --git a/internal/shaderir/metal/type.go b/internal/shaderir/metal/type.go index 4de13f331..a1843a529 100644 --- a/internal/shaderir/metal/type.go +++ b/internal/shaderir/metal/type.go @@ -103,7 +103,8 @@ func builtinFuncString(f shaderir.BuiltinFunc) string { case shaderir.Inversesqrt: return "rsqrt" case shaderir.Mod: - return "fmod" + // mod is a special function that Metal doesn't originally has (#2006). + return "mod" case shaderir.Texture2DF: return "?(texture2D)" } diff --git a/shader_test.go b/shader_test.go index 43e18b496..9a997e40e 100644 --- a/shader_test.go +++ b/shader_test.go @@ -1677,3 +1677,35 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 { } } } + +// Issue #2006 +func TestShaderFuncMod(t *testing.T) { + const w, h = 16, 16 + + dst := ebiten.NewImage(w, h) + s, err := ebiten.NewShader([]byte(`package main + +func Fragment(position vec4, texCoord vec2, color vec4) vec4 { + r := mod(-0.25, 1.0) + return vec4(r, 0, 0, 1) +} +`)) + if err != nil { + t.Fatal(err) + } + + dst.DrawRectShader(w/2, h/2, s, nil) + + for j := 0; j < h; j++ { + for i := 0; i < w; i++ { + got := dst.At(i, j).(color.RGBA) + var want color.RGBA + if i < w/2 && j < h/2 { + want = color.RGBA{0xc0, 0, 0, 0xff} + } + if !sameColors(got, want, 2) { + t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want) + } + } + } +}