mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 10:48:53 +01:00
internal/shader: bug fix: % operators for integer vecs didn't work
Closes #1911
This commit is contained in:
parent
0b9cbaa1ed
commit
e9e5d27d2c
@ -228,7 +228,7 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar
|
||||
|
||||
if lhs[0].Const != nil && rhs[0].Const != nil {
|
||||
op := e.Op
|
||||
// https://golang.org/pkg/go/constant/#BinaryOp
|
||||
// https://pkg.go.dev/go/constant/#BinaryOp
|
||||
// "To force integer division of Int operands, use op == token.QUO_ASSIGN instead of
|
||||
// token.QUO; the result is guaranteed to be Int in this case."
|
||||
if op == token.QUO && lhs[0].Const.Kind() == gconstant.Int && rhs[0].Const.Kind() == gconstant.Int {
|
||||
@ -255,25 +255,25 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar
|
||||
v = gconstant.MakeBool(gconstant.Compare(lhs[0].Const, op, rhs[0].Const))
|
||||
}
|
||||
t = shaderir.Type{Main: shaderir.Bool}
|
||||
default:
|
||||
if op == token.REM {
|
||||
if !isModAvailableForConsts(&lhs[0], &rhs[0]) {
|
||||
var wrongTypeName string
|
||||
if lhs[0].Const.Kind() != gconstant.Int {
|
||||
wrongTypeName = goConstantKindString(lhs[0].Const.Kind())
|
||||
} else {
|
||||
wrongTypeName = goConstantKindString(rhs[0].Const.Kind())
|
||||
}
|
||||
cs.addError(e.Pos(), fmt.Sprintf("invalid operation: operator %% not defined on untyped %s", wrongTypeName))
|
||||
return nil, nil, nil, false
|
||||
}
|
||||
if !cs.forceToInt(e, &lhs[0]) {
|
||||
return nil, nil, nil, false
|
||||
}
|
||||
if !cs.forceToInt(e, &rhs[0]) {
|
||||
return nil, nil, nil, false
|
||||
case token.REM:
|
||||
if !isModAvailableForConsts(&lhs[0], &rhs[0]) {
|
||||
var wrongTypeName string
|
||||
if lhs[0].Const.Kind() != gconstant.Int {
|
||||
wrongTypeName = goConstantKindString(lhs[0].Const.Kind())
|
||||
} else {
|
||||
wrongTypeName = goConstantKindString(rhs[0].Const.Kind())
|
||||
}
|
||||
cs.addError(e.Pos(), fmt.Sprintf("invalid operation: operator %% not defined on untyped %s", wrongTypeName))
|
||||
return nil, nil, nil, false
|
||||
}
|
||||
if !cs.forceToInt(e, &lhs[0]) {
|
||||
return nil, nil, nil, false
|
||||
}
|
||||
if !cs.forceToInt(e, &rhs[0]) {
|
||||
return nil, nil, nil, false
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
v = gconstant.BinaryOp(lhs[0].Const, op, rhs[0].Const)
|
||||
if v.Kind() == gconstant.Float {
|
||||
t = shaderir.Type{Main: shaderir.Float}
|
||||
@ -348,6 +348,9 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar
|
||||
cs.addError(e.Pos(), fmt.Sprintf("types don't match: %s %s %s", lhst.String(), e.Op, rhst.String()))
|
||||
return nil, nil, nil, false
|
||||
}
|
||||
if !cs.forceToInt(e, &rhs[0]) {
|
||||
return nil, nil, nil, false
|
||||
}
|
||||
case shaderir.Int:
|
||||
if !canTruncateToInteger(rhs[0].Const) {
|
||||
cs.addError(e.Pos(), fmt.Sprintf("constant %s truncated to integer", rhs[0].Const.String()))
|
||||
|
@ -35,6 +35,30 @@ const (
|
||||
// utilFunctions is GLSL utility functions for old GLSL versions.
|
||||
const utilFunctions = `int modInt(int x, int y) {
|
||||
return x - y*(x/y);
|
||||
}
|
||||
|
||||
ivec2 modInt(ivec2 x, int y) {
|
||||
return x - y*(x/y);
|
||||
}
|
||||
|
||||
ivec3 modInt(ivec3 x, int y) {
|
||||
return x - y*(x/y);
|
||||
}
|
||||
|
||||
ivec4 modInt(ivec4 x, int y) {
|
||||
return x - y*(x/y);
|
||||
}
|
||||
|
||||
ivec2 modInt(ivec2 x, ivec2 y) {
|
||||
return x - y*(x/y);
|
||||
}
|
||||
|
||||
ivec3 modInt(ivec3 x, ivec3 y) {
|
||||
return x - y*(x/y);
|
||||
}
|
||||
|
||||
ivec4 modInt(ivec4 x, ivec4 y) {
|
||||
return x - y*(x/y);
|
||||
}`
|
||||
|
||||
func VertexPrelude(version GLSLVersion) string {
|
||||
|
@ -15,6 +15,7 @@
|
||||
package ebiten_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"math"
|
||||
@ -1503,3 +1504,65 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
|
||||
t.Errorf("got: %v, want: %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShaderIVecMod(t *testing.T) {
|
||||
cases := []struct {
|
||||
source string
|
||||
want color.RGBA
|
||||
}{
|
||||
{
|
||||
source: `a := ivec4(0x24, 0x3f, 0x6a, 0x88)
|
||||
return vec4(a)/255`,
|
||||
want: color.RGBA{0x24, 0x3f, 0x6a, 0x88},
|
||||
},
|
||||
{
|
||||
source: `a := ivec4(0x24, 0x3f, 0x6a, 0x88)
|
||||
a %= 0x85
|
||||
return vec4(a)/255`,
|
||||
want: color.RGBA{0x24, 0x3f, 0x6a, 0x03},
|
||||
},
|
||||
{
|
||||
source: `a := ivec4(0x24, 0x3f, 0x6a, 0x88)
|
||||
a %= ivec4(0x85, 0xa3, 0x08, 0xd3)
|
||||
return vec4(a)/255`,
|
||||
want: color.RGBA{0x24, 0x3f, 0x02, 0x88},
|
||||
},
|
||||
{
|
||||
source: `a := ivec4(0x24, 0x3f, 0x6a, 0x88)
|
||||
b := a % 0x85
|
||||
return vec4(b)/255`,
|
||||
want: color.RGBA{0x24, 0x3f, 0x6a, 0x03},
|
||||
},
|
||||
{
|
||||
source: `a := ivec4(0x24, 0x3f, 0x6a, 0x88)
|
||||
b := a % ivec4(0x85, 0xa3, 0x08, 0xd3)
|
||||
return vec4(b)/255`,
|
||||
want: color.RGBA{0x24, 0x3f, 0x02, 0x88},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
shader := fmt.Sprintf(`package main
|
||||
|
||||
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
|
||||
%s
|
||||
}
|
||||
`, tc.source)
|
||||
const w, h = 1, 1
|
||||
|
||||
dst := ebiten.NewImage(w, h)
|
||||
defer dst.Dispose()
|
||||
|
||||
s, err := ebiten.NewShader([]byte(shader))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer s.Dispose()
|
||||
|
||||
op := &ebiten.DrawRectShaderOptions{}
|
||||
dst.DrawRectShader(w, h, s, op)
|
||||
if got, want := dst.At(0, 0).(color.RGBA), tc.want; !sameColors(got, want, 1) {
|
||||
t.Errorf("%s: got: %v, want: %v", tc.source, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user