ebiten: Set zero values for lacking uniform variables

Fixes #1338
This commit is contained in:
Hajime Hoshi 2020-09-13 04:29:28 +09:00
parent 7a06ae4530
commit 5e15ebf580
2 changed files with 90 additions and 6 deletions

View File

@ -24,6 +24,7 @@ import (
"github.com/hajimehoshi/ebiten/internal/graphics" "github.com/hajimehoshi/ebiten/internal/graphics"
"github.com/hajimehoshi/ebiten/internal/mipmap" "github.com/hajimehoshi/ebiten/internal/mipmap"
"github.com/hajimehoshi/ebiten/internal/shader" "github.com/hajimehoshi/ebiten/internal/shader"
"github.com/hajimehoshi/ebiten/internal/shaderir"
) )
var shaderSuffix string var shaderSuffix string
@ -105,6 +106,7 @@ func __vertex(position vec2, texCoord vec2, color vec4) (vec4, vec2, vec4) {
type Shader struct { type Shader struct {
shader *mipmap.Shader shader *mipmap.Shader
uniformNames []string uniformNames []string
uniformTypes []shaderir.Type
} }
func NewShader(src []byte) (*Shader, error) { func NewShader(src []byte) (*Shader, error) {
@ -137,6 +139,7 @@ func NewShader(src []byte) (*Shader, error) {
return &Shader{ return &Shader{
shader: mipmap.NewShader(s), shader: mipmap.NewShader(s),
uniformNames: s.UniformNames, uniformNames: s.UniformNames,
uniformTypes: s.Uniforms,
}, nil }, nil
} }
@ -157,15 +160,67 @@ func (s *Shader) convertUniforms(uniforms map[string]interface{}) []interface{}
} }
us := make([]interface{}, len(names)) us := make([]interface{}, len(names))
for n, u := range uniforms { for name, idx := range names {
idx, ok := names[n] if v, ok := uniforms[name]; ok {
if !ok { // TODO: Check the uniform variable types?
// TODO: Panic here? us[idx] = v
continue continue
} }
us[idx] = u
t := s.uniformTypes[idx]
v := zeroUniformValue(t)
if v == nil {
panic(fmt.Sprintf("ebiten: unexpected uniform variable type: %s", t.String()))
}
us[idx] = v
} }
// TODO: Check the uniform variable types? // TODO: Panic if uniforms include an invalid name
return us return us
} }
func zeroUniformValue(t shaderir.Type) interface{} {
switch t.Main {
case shaderir.Bool:
return false
case shaderir.Int:
return 0
case shaderir.Float:
return float32(0)
case shaderir.Vec2:
return make([]float32, 2)
case shaderir.Vec3:
return make([]float32, 3)
case shaderir.Vec4:
return make([]float32, 4)
case shaderir.Mat2:
return make([]float32, 4)
case shaderir.Mat3:
return make([]float32, 9)
case shaderir.Mat4:
return make([]float32, 16)
case shaderir.Array:
switch t.Sub[0].Main {
case shaderir.Bool:
return make([]bool, t.Length)
case shaderir.Int:
return make([]int, t.Length)
case shaderir.Float:
return make([]float32, t.Length)
case shaderir.Vec2:
return make([]float32, t.Length*2)
case shaderir.Vec3:
return make([]float32, t.Length*3)
case shaderir.Vec4:
return make([]float32, t.Length*4)
case shaderir.Mat2:
return make([]float32, t.Length*4)
case shaderir.Mat3:
return make([]float32, t.Length*9)
case shaderir.Mat4:
return make([]float32, t.Length*16)
}
}
return nil
}

View File

@ -419,3 +419,32 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
t.Errorf("error must be non-nil but was nil") t.Errorf("error must be non-nil but was nil")
} }
} }
func TestShaderUninitializedUniformVariables(t *testing.T) {
const w, h = 16, 16
dst, _ := NewImage(w, h, FilterDefault)
s, err := NewShader([]byte(`package main
var U vec4
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
return U
}
`))
if err != nil {
t.Fatal(err)
}
dst.DrawRectShader(w, h, 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 got != want {
t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want)
}
}
}
}