shader: Implement an array variable

Updates #1235
This commit is contained in:
Hajime Hoshi 2020-07-29 00:57:47 +09:00
parent c032d61f93
commit d9c54bc0d0
6 changed files with 66 additions and 22 deletions

View File

@ -211,7 +211,7 @@ func (cs *compileState) parse(f *ast.File) {
continue
}
inParams, outParams := cs.parseFuncParams(fd)
inParams, outParams := cs.parseFuncParams(&cs.global, fd)
var inT, outT []shaderir.Type
for _, v := range inParams {
inT = append(inT, v.typ)
@ -260,7 +260,7 @@ func (cs *compileState) parseDecl(b *block, d ast.Decl) ([]shaderir.Stmt, bool)
// TODO: Parse other types
for _, s := range d.Specs {
s := s.(*ast.TypeSpec)
t := cs.parseType(s.Type)
t := cs.parseType(b, s.Type)
b.types = append(b.types, typ{
name: s.Name.Name,
ir: t,
@ -269,7 +269,7 @@ func (cs *compileState) parseDecl(b *block, d ast.Decl) ([]shaderir.Stmt, bool)
case token.CONST:
for _, s := range d.Specs {
s := s.(*ast.ValueSpec)
cs := cs.parseConstant(s)
cs := cs.parseConstant(b, s)
b.consts = append(b.consts, cs...)
}
case token.VAR:
@ -385,7 +385,7 @@ func (s *compileState) parseVariable(block *block, vs *ast.ValueSpec) ([]variabl
var declt shaderir.Type
if vs.Type != nil {
declt = s.parseType(vs.Type)
declt = s.parseType(block, vs.Type)
}
var (
@ -480,10 +480,10 @@ func (s *compileState) parseVariable(block *block, vs *ast.ValueSpec) ([]variabl
return vars, inits, stmts, true
}
func (s *compileState) parseConstant(vs *ast.ValueSpec) []constant {
func (s *compileState) parseConstant(block *block, vs *ast.ValueSpec) []constant {
var t shaderir.Type
if vs.Type != nil {
t = s.parseType(vs.Type)
t = s.parseType(block, vs.Type)
}
var cs []constant
@ -497,9 +497,9 @@ func (s *compileState) parseConstant(vs *ast.ValueSpec) []constant {
return cs
}
func (cs *compileState) parseFuncParams(d *ast.FuncDecl) (in, out []variable) {
func (cs *compileState) parseFuncParams(block *block, d *ast.FuncDecl) (in, out []variable) {
for _, f := range d.Type.Params.List {
t := cs.parseType(f.Type)
t := cs.parseType(block, f.Type)
for _, n := range f.Names {
in = append(in, variable{
name: n.Name,
@ -513,7 +513,7 @@ func (cs *compileState) parseFuncParams(d *ast.FuncDecl) (in, out []variable) {
}
for _, f := range d.Type.Results.List {
t := cs.parseType(f.Type)
t := cs.parseType(block, f.Type)
if len(f.Names) == 0 {
out = append(out, variable{
name: "",
@ -541,7 +541,7 @@ func (cs *compileState) parseFunc(block *block, d *ast.FuncDecl) (function, bool
return function{}, false
}
inParams, outParams := cs.parseFuncParams(d)
inParams, outParams := cs.parseFuncParams(block, d)
checkVaryings := func(vs []variable) {
if len(cs.ir.Varyings) != len(vs) {

View File

@ -0,0 +1 @@
uniform vec2[4] U0;

3
internal/shader/testdata/array.go vendored Normal file
View File

@ -0,0 +1,3 @@
package main
var Array [4]vec2

View File

@ -17,13 +17,12 @@ package shader
import (
"fmt"
"go/ast"
gconstant "go/constant"
"github.com/hajimehoshi/ebiten/internal/shaderir"
)
// TODO: What about array types?
func (cs *compileState) parseType(expr ast.Expr) shaderir.Type {
func (cs *compileState) parseType(block *block, expr ast.Expr) shaderir.Type {
switch t := expr.(type) {
case *ast.Ident:
switch t.Name {
@ -49,6 +48,41 @@ func (cs *compileState) parseType(expr ast.Expr) shaderir.Type {
cs.addError(t.Pos(), fmt.Sprintf("unexpected type: %s", t.Name))
return shaderir.Type{}
}
case *ast.ArrayType:
if t.Len == nil {
cs.addError(t.Pos(), fmt.Sprintf("array length must be specified"))
return shaderir.Type{}
}
// TODO: Parse ellipsis
exprs, _, _, ok := cs.parseExpr(block, t.Len)
if !ok {
return shaderir.Type{}
}
if len(exprs) != 1 {
cs.addError(t.Pos(), fmt.Sprintf("invalid length of array"))
return shaderir.Type{}
}
if exprs[0].Type != shaderir.NumberExpr {
cs.addError(t.Pos(), fmt.Sprintf("length of array must be a constant number"))
return shaderir.Type{}
}
len, ok := gconstant.Int64Val(exprs[0].Const)
if !ok {
cs.addError(t.Pos(), fmt.Sprintf("length of array must be an integer"))
return shaderir.Type{}
}
elm := cs.parseType(block, t.Elt)
if elm.Main == shaderir.Array {
cs.addError(t.Pos(), fmt.Sprintf("array of array is forbidden"))
return shaderir.Type{}
}
return shaderir.Type{
Main: shaderir.Array,
Sub: []shaderir.Type{elm},
Length: int(len),
}
case *ast.StructType:
cs.addError(t.Pos(), "struct is not implemented")
return shaderir.Type{}

View File

@ -172,12 +172,10 @@ func (p *Program) glslType(t *Type) string {
switch t.Main {
case None:
return "void"
case Array:
panic("not implemented")
case Struct:
return p.structName(t)
default:
return t.Main.Glsl()
return t.Glsl()
}
}
@ -185,12 +183,10 @@ func (p *Program) glslVarDecl(t *Type, varname string) string {
switch t.Main {
case None:
return "?(none)"
case Array:
panic("not implemented")
case Struct:
return fmt.Sprintf("%s %s", p.structName(t), varname)
default:
return fmt.Sprintf("%s %s", t.Main.Glsl(), varname)
return fmt.Sprintf("%s %s", t.Glsl(), varname)
}
}
@ -432,7 +428,7 @@ func (p *Program) glslBlock(topBlock, block *Block, level int, localVarIndex int
op = fmt.Sprintf("?(unexpected op: %s)", string(s.ForOp))
}
t := s.ForVarType.Main
t := s.ForVarType
init := constantToNumberLiteral(ct, s.ForInit)
end := constantToNumberLiteral(ct, s.ForEnd)
lines = append(lines, fmt.Sprintf("%sfor (%s %s = %s; %s %s %s; %s) {", idt, t.Glsl(), v, init, v, op, end, delta))

View File

@ -85,6 +85,17 @@ func (t *Type) serialize() string {
return t.String()
}
func (t *Type) Glsl() string {
switch t.Main {
case Array:
return fmt.Sprintf("%s[%d]", t.Sub[0].Glsl(), t.Length)
case Struct:
panic("shaderir: a struct is not implemented")
default:
return t.Main.glsl()
}
}
type BasicType int
const (
@ -102,7 +113,7 @@ const (
Struct
)
func (t BasicType) Glsl() string {
func (t BasicType) glsl() string {
switch t {
case None:
return "?(none)"
@ -125,7 +136,6 @@ func (t BasicType) Glsl() string {
case Mat4:
return "mat4"
case Array:
// First-class array is not available on GLSL ES 2.
return "?(array)"
case Struct:
return "?(struct)"