From 850303b770b4d824b68c2cd5dc12c8a84d15bbe4 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sun, 6 Sep 2020 20:10:33 +0900 Subject: [PATCH] ebiten: Change the type of Uniforms to map[string]interface{} Fixes #1324 --- examples/shader/dissolve.go | 2 +- examples/shader/dissolve_go.go | 2 +- examples/shader/main.go | 8 ++++---- image.go | 21 +++++++++++++-------- shader.go | 32 ++++++++++++++++++++++++++++++-- 5 files changed, 49 insertions(+), 16 deletions(-) diff --git a/examples/shader/dissolve.go b/examples/shader/dissolve.go index b4828bcb2..c82633951 100644 --- a/examples/shader/dissolve.go +++ b/examples/shader/dissolve.go @@ -18,7 +18,7 @@ package main var Time float var Cursor vec2 -var ScreenImage vec2 +var ScreenSize vec2 func Fragment(position vec4, texCoord vec2, color vec4) vec4 { // Triangle wave to go 0-->1-->0... diff --git a/examples/shader/dissolve_go.go b/examples/shader/dissolve_go.go index 992d3ab5e..216272487 100644 --- a/examples/shader/dissolve_go.go +++ b/examples/shader/dissolve_go.go @@ -2,4 +2,4 @@ package main -var dissolve_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 ScreenImage vec2\n\nfunc Fragment(position vec4, texCoord vec2, color vec4) vec4 {\n\t// Triangle wave to go 0-->1-->0...\n\tlimit := abs(2*fract(Time/3) - 1)\n\tlevel := imageSrc3At(texCoord).x\n\n\t// Add a white border\n\tif limit-0.1 < level && level < limit {\n\t\talpha := imageSrc0At(texCoord).w\n\t\treturn vec4(alpha)\n\t}\n\n\treturn step(limit, level) * imageSrc0At(texCoord)\n}\n") +var dissolve_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\t// Triangle wave to go 0-->1-->0...\n\tlimit := abs(2*fract(Time/3) - 1)\n\tlevel := imageSrc3At(texCoord).x\n\n\t// Add a white border\n\tif limit-0.1 < level && level < limit {\n\t\talpha := imageSrc0At(texCoord).w\n\t\treturn vec4(alpha)\n\t}\n\n\treturn step(limit, level) * imageSrc0At(texCoord)\n}\n") diff --git a/examples/shader/main.go b/examples/shader/main.go index 264e9b0ac..a6ff3cc4d 100644 --- a/examples/shader/main.go +++ b/examples/shader/main.go @@ -130,10 +130,10 @@ func (g *Game) Draw(screen *ebiten.Image) { cx, cy := ebiten.CursorPosition() op := &ebiten.DrawRectShaderOptions{} - op.Uniforms = []interface{}{ - float32(g.time) / 60, // Time - []float32{float32(cx), float32(cy)}, // Cursor - []float32{float32(w), float32(h)}, // ScreenSize + op.Uniforms = map[string]interface{}{ + "Time": float32(g.time) / 60, + "Cursor": []float32{float32(cx), float32(cy)}, + "ScreenSize": []float32{float32(w), float32(h)}, } op.Images[0] = gopherImage op.Images[1] = normalImage diff --git a/image.go b/image.go index 6691dcfca..17ea4cb25 100644 --- a/image.go +++ b/image.go @@ -140,7 +140,7 @@ type DrawImageOptions struct { // Uniforms is a set of uniform variables for the shader. // // Uniforms is used only when Shader is not nil. - Uniforms []interface{} + Uniforms map[string]interface{} // Deprecated: (as of 1.5.0) Use SubImage instead. ImageParts ImageParts @@ -288,7 +288,8 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error { return nil } - i.mipmap.DrawTriangles(srcs, vs, is, nil, mode, filter, driver.AddressUnsafe, sr, options.Shader.shader, options.Uniforms, canSkipMipmap(options.GeoM, filter)) + us := options.Shader.convertUniforms(options.Uniforms) + i.mipmap.DrawTriangles(srcs, vs, is, nil, mode, filter, driver.AddressUnsafe, sr, options.Shader.shader, us, canSkipMipmap(options.GeoM, filter)) return nil } @@ -358,7 +359,7 @@ type DrawTrianglesOptions struct { // Uniforms is a set of uniform variables for the shader. // // Uniforms is used only when Shader is not nil. - Uniforms []interface{} + Uniforms map[string]interface{} } // MaxIndicesNum is the maximum number of indices for DrawTriangles. @@ -454,7 +455,9 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.impl, mode, filter, driver.Address(options.Address), sr, nil, nil, false) return } - i.mipmap.DrawTriangles(srcs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, sr, options.Shader.shader, options.Uniforms, false) + + us := options.Shader.convertUniforms(options.Uniforms) + i.mipmap.DrawTriangles(srcs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, sr, options.Shader.shader, us, false) } // DrawRectShaderOptions represents options for DrawRectShader @@ -470,7 +473,7 @@ type DrawRectShaderOptions struct { CompositeMode CompositeMode // Uniforms is a set of uniform variables for the shader. - Uniforms []interface{} + Uniforms map[string]interface{} // Images is a set of the source images. // All the image must be the same size with the rectangle. @@ -542,7 +545,8 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR } } - i.mipmap.DrawTriangles(imgs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, sr, shader.shader, options.Uniforms, canSkipMipmap(options.GeoM, driver.FilterNearest)) + us := shader.convertUniforms(options.Uniforms) + i.mipmap.DrawTriangles(imgs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, sr, shader.shader, us, canSkipMipmap(options.GeoM, driver.FilterNearest)) } // DrawTrianglesShaderOptions represents options for DrawTrianglesShader @@ -554,7 +558,7 @@ type DrawTrianglesShaderOptions struct { CompositeMode CompositeMode // Uniforms is a set of uniform variables for the shader. - Uniforms []interface{} + Uniforms map[string]interface{} // Images is a set of the source images. // All the image must be the same size. @@ -649,7 +653,8 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader } } - i.mipmap.DrawTriangles(imgs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, sr, shader.shader, options.Uniforms, false) + us := shader.convertUniforms(options.Uniforms) + i.mipmap.DrawTriangles(imgs, vs, is, nil, mode, driver.FilterNearest, driver.AddressUnsafe, sr, shader.shader, us, false) } // SubImage returns an image representing the portion of the image p visible through r. diff --git a/shader.go b/shader.go index d90be73ea..79a869994 100644 --- a/shader.go +++ b/shader.go @@ -19,6 +19,7 @@ import ( "fmt" "go/parser" "go/token" + "strings" "github.com/hajimehoshi/ebiten/internal/graphics" "github.com/hajimehoshi/ebiten/internal/mipmap" @@ -102,7 +103,8 @@ func __vertex(position vec2, texCoord vec2, color vec4) (vec4, vec2, vec4) { } type Shader struct { - shader *mipmap.Shader + shader *mipmap.Shader + uniformNames []string } func NewShader(src []byte) (*Shader, error) { @@ -133,7 +135,8 @@ func NewShader(src []byte) (*Shader, error) { } return &Shader{ - shader: mipmap.NewShader(s), + shader: mipmap.NewShader(s), + uniformNames: s.UniformNames, }, nil } @@ -141,3 +144,28 @@ func (s *Shader) Dispose() { s.shader.MarkDisposed() s.shader = nil } + +func (s *Shader) convertUniforms(uniforms map[string]interface{}) []interface{} { + names := map[string]int{} + var idx int + for _, n := range s.uniformNames { + if strings.HasPrefix(n, "__") { + continue + } + names[n] = idx + idx++ + } + + us := make([]interface{}, len(names)) + for n, u := range uniforms { + idx, ok := names[n] + if !ok { + // TODO: Panic here? + continue + } + us[idx] = u + } + + // TODO: Check the uniform variable types? + return us +}