diff --git a/examples/shader/radialblur.go b/examples/shader/radialblur.go index d794d9555..e4eb63eaa 100644 --- a/examples/shader/radialblur.go +++ b/examples/shader/radialblur.go @@ -27,9 +27,8 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 { samples := [...]float{ -22, -14, -8, -4, -2, 2, 4, 8, 14, 22, } - // TODO: Add len(samples) sum := clr - for i := 0; i < 10; i++ { + for i := 0; i < len(samples); i++ { pos := texCoord + dir*samples[i]/imageSrcTextureSize() sum += image2TextureBoundsAt(pos) } diff --git a/examples/shader/radialblur_go.go b/examples/shader/radialblur_go.go index a1e35a010..75c75b82b 100644 --- a/examples/shader/radialblur_go.go +++ b/examples/shader/radialblur_go.go @@ -2,4 +2,4 @@ package main -var radialblur_go = []byte("// Copyright 2020 The Ebiten Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// +build ignore\n\npackage main\n\nvar Time float\nvar Cursor vec2\nvar ScreenSize vec2\n\nfunc Fragment(position vec4, texCoord vec2, color vec4) vec4 {\n\tdir := normalize(position.xy - Cursor)\n\tclr := image2TextureAt(texCoord)\n\n\tsamples := [...]float{\n\t\t-22, -14, -8, -4, -2, 2, 4, 8, 14, 22,\n\t}\n\t// TODO: Add len(samples)\n\tsum := clr\n\tfor i := 0; i < 10; i++ {\n\t\tpos := texCoord + dir*samples[i]/imageSrcTextureSize()\n\t\tsum += image2TextureBoundsAt(pos)\n\t}\n\tsum /= 10 + 1\n\n\tdist := distance(position.xy, Cursor)\n\tt := clamp(dist/256, 0, 1)\n\treturn mix(clr, sum, t)\n}\n") +var radialblur_go = []byte("// Copyright 2020 The Ebiten Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// +build ignore\n\npackage main\n\nvar Time float\nvar Cursor vec2\nvar ScreenSize vec2\n\nfunc Fragment(position vec4, texCoord vec2, color vec4) vec4 {\n\tdir := normalize(position.xy - Cursor)\n\tclr := image2TextureAt(texCoord)\n\n\tsamples := [...]float{\n\t\t-22, -14, -8, -4, -2, 2, 4, 8, 14, 22,\n\t}\n\tsum := clr\n\tfor i := 0; i < len(samples); i++ {\n\t\tpos := texCoord + dir*samples[i]/imageSrcTextureSize()\n\t\tsum += image2TextureBoundsAt(pos)\n\t}\n\tsum /= 10 + 1\n\n\tdist := distance(position.xy, Cursor)\n\tt := clamp(dist/256, 0, 1)\n\treturn mix(clr, sum, t)\n}\n") diff --git a/internal/shader/expr.go b/internal/shader/expr.go index 704880649..c10c69226 100644 --- a/internal/shader/expr.go +++ b/internal/shader/expr.go @@ -220,6 +220,24 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) ([]shaderir.Expr, // For built-in functions, we can call this in this position. Return an expression for the function // call. if callee.Type == shaderir.BuiltinFuncExpr { + if callee.BuiltinFunc == shaderir.Len { + if len(args) != 1 { + cs.addError(e.Pos(), fmt.Sprintf("number of len's arguments must be 1 but %d", len(args))) + return nil, nil, nil, false + } + if argts[0].Main != shaderir.Array { + cs.addError(e.Pos(), fmt.Sprintf("len takes an array but %s", argts[0].String())) + return nil, nil, nil, false + } + return []shaderir.Expr{ + { + Type: shaderir.NumberExpr, + Const: gconstant.MakeInt64(int64(argts[0].Length)), + ConstType: shaderir.ConstTypeInt, + }, + }, []shaderir.Type{{Main: shaderir.Int}}, stmts, true + } + var t shaderir.Type switch callee.BuiltinFunc { case shaderir.BoolF: diff --git a/internal/shader/testdata/len.expected.vs b/internal/shader/testdata/len.expected.vs new file mode 100644 index 000000000..03c8ea0ef --- /dev/null +++ b/internal/shader/testdata/len.expected.vs @@ -0,0 +1,9 @@ +void F0(in vec2 l0, out int l1); + +void F0(in vec2 l0, out int l1) { + int l2[2]; + l2[0] = 0; + l2[1] = 0; + l1 = 2; + return; +} diff --git a/internal/shader/testdata/len.go b/internal/shader/testdata/len.go new file mode 100644 index 000000000..0b4d187ad --- /dev/null +++ b/internal/shader/testdata/len.go @@ -0,0 +1,6 @@ +package main + +func Foo(foo vec2) int { + var a [2]int + return len(a) +} diff --git a/internal/shaderir/program.go b/internal/shaderir/program.go index c1fbcaa25..633bfb529 100644 --- a/internal/shaderir/program.go +++ b/internal/shaderir/program.go @@ -198,6 +198,7 @@ func OpFromToken(t token.Token) (Op, bool) { type BuiltinFunc string const ( + Len BuiltinFunc = "len" BoolF BuiltinFunc = "bool" IntF BuiltinFunc = "int" FloatF BuiltinFunc = "float" @@ -250,7 +251,8 @@ const ( func ParseBuiltinFunc(str string) (BuiltinFunc, bool) { switch BuiltinFunc(str) { - case BoolF, + case Len, + BoolF, IntF, FloatF, Vec2F,