mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 11:18:54 +01:00
shader: Parse block variables
This commit is contained in:
parent
e848eacedf
commit
5e6be91eac
42
internal/shader/block.go
Normal file
42
internal/shader/block.go
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright 2020 The Ebiten Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package shader
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/token"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type block struct {
|
||||
vars []variable
|
||||
stmts []stmt
|
||||
pos token.Pos
|
||||
}
|
||||
|
||||
func (b *block) dump(indent int) []string {
|
||||
idt := strings.Repeat("\t", indent)
|
||||
|
||||
var lines []string
|
||||
|
||||
for _, v := range b.vars {
|
||||
lines = append(lines, fmt.Sprintf("%svar %s %s", idt, v.name, v.typ))
|
||||
}
|
||||
|
||||
return lines
|
||||
}
|
||||
|
||||
type stmt struct {
|
||||
}
|
@ -43,6 +43,7 @@ type function struct {
|
||||
name string
|
||||
args []variable
|
||||
rets []variable
|
||||
body *block
|
||||
}
|
||||
|
||||
type Shader struct {
|
||||
@ -89,6 +90,9 @@ func NewShader(src []byte) (*Shader, error) {
|
||||
return nil, &ParseError{s.errs}
|
||||
}
|
||||
|
||||
// TODO: Resolve identifiers?
|
||||
// TODO: Resolve constants
|
||||
|
||||
sort.Slice(s.varyings, func(a, b int) bool {
|
||||
return s.varyings[a].name < s.varyings[b].name
|
||||
})
|
||||
@ -129,7 +133,14 @@ func (sh *Shader) parse(f *ast.File) {
|
||||
case token.VAR:
|
||||
for _, s := range d.Specs {
|
||||
s := s.(*ast.ValueSpec)
|
||||
sh.parseTopLevelVariable(s)
|
||||
vs := sh.parseVariable(s)
|
||||
for _, v := range vs {
|
||||
if 'A' <= v.name[0] && v.name[0] <= 'Z' {
|
||||
sh.uniforms = append(sh.uniforms, v)
|
||||
} else {
|
||||
sh.globals = append(sh.globals, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
case token.IMPORT:
|
||||
sh.addError(d.Pos(), "import is forbidden")
|
||||
@ -200,25 +211,26 @@ func (sh *Shader) parseVaryingStruct(t *ast.TypeSpec) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Shader) parseTopLevelVariable(vs *ast.ValueSpec) {
|
||||
t, err := parseType(vs.Type)
|
||||
if err != nil {
|
||||
s.addError(vs.Type.Pos(), err.Error())
|
||||
return
|
||||
func (s *Shader) parseVariable(vs *ast.ValueSpec) []variable {
|
||||
var t typ
|
||||
if vs.Type != nil {
|
||||
var err error
|
||||
t, err = parseType(vs.Type)
|
||||
if err != nil {
|
||||
s.addError(vs.Type.Pos(), err.Error())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var vars []variable
|
||||
for _, n := range vs.Names {
|
||||
name := n.Name
|
||||
val := variable{
|
||||
vars = append(vars, variable{
|
||||
name: name,
|
||||
typ: t,
|
||||
}
|
||||
// TODO: Parse initial value.
|
||||
if 'A' <= name[0] && name[0] <= 'Z' {
|
||||
s.uniforms = append(s.uniforms, val)
|
||||
} else {
|
||||
s.globals = append(s.globals, val)
|
||||
}
|
||||
})
|
||||
}
|
||||
return vars
|
||||
}
|
||||
|
||||
func (s *Shader) parseTopLevelConstant(vs *ast.ValueSpec) {
|
||||
@ -302,10 +314,51 @@ func (sh *Shader) parseFunc(d *ast.FuncDecl) {
|
||||
name: d.Name.Name,
|
||||
args: args,
|
||||
rets: rets,
|
||||
body: sh.parseBlock(d.Body),
|
||||
}
|
||||
sh.funcs = append(sh.funcs, f)
|
||||
}
|
||||
|
||||
func (sh *Shader) parseBlock(b *ast.BlockStmt) *block {
|
||||
block := &block{}
|
||||
|
||||
for _, l := range b.List {
|
||||
switch l := l.(type) {
|
||||
case *ast.AssignStmt:
|
||||
if l.Tok == token.DEFINE {
|
||||
for _, s := range l.Lhs {
|
||||
ident := s.(*ast.Ident)
|
||||
block.vars = append(block.vars, variable{
|
||||
name: ident.Name,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// TODO
|
||||
}
|
||||
case *ast.DeclStmt:
|
||||
switch d := l.Decl.(type) {
|
||||
case *ast.GenDecl:
|
||||
switch d.Tok {
|
||||
case token.VAR:
|
||||
for _, s := range d.Specs {
|
||||
s := s.(*ast.ValueSpec)
|
||||
vs := sh.parseVariable(s)
|
||||
block.vars = append(block.vars, vs...)
|
||||
}
|
||||
}
|
||||
}
|
||||
case *ast.ReturnStmt:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(block.vars, func(a, b int) bool {
|
||||
return block.vars[a].name < block.vars[b].name
|
||||
})
|
||||
|
||||
return block
|
||||
}
|
||||
|
||||
// Dump dumps the shader state in an intermediate language.
|
||||
func (s *Shader) Dump() string {
|
||||
var lines []string
|
||||
@ -348,7 +401,10 @@ func (s *Shader) Dump() string {
|
||||
if len(rets) > 0 {
|
||||
l += " (" + strings.Join(rets, ", ") + ")"
|
||||
}
|
||||
l += " {"
|
||||
lines = append(lines, l)
|
||||
lines = append(lines, f.body.dump(1)...)
|
||||
lines = append(lines, "}")
|
||||
}
|
||||
|
||||
return strings.Join(lines, "\n") + "\n"
|
||||
|
@ -44,7 +44,11 @@ var (
|
||||
const C1 float = 1
|
||||
const C2, C3 float = 2, 3
|
||||
|
||||
func foo(a, b vec2) vec4 {
|
||||
func F1(a, b vec2) vec4 {
|
||||
var c0 vec2 = a
|
||||
var c1 = b
|
||||
c2 := vec4{c0, c1}
|
||||
return c2
|
||||
}
|
||||
`,
|
||||
Dump: `var Position varying vec4 // position
|
||||
@ -58,7 +62,11 @@ const C1 float = 1
|
||||
const C2 float = 2
|
||||
const C3 float = 3
|
||||
var qux vec4
|
||||
func foo(a vec2, b vec2) (_ vec4)
|
||||
func F1(a vec2, b vec2) (_ vec4) {
|
||||
var c0 vec2
|
||||
var c1 (none)
|
||||
var c2 (none)
|
||||
}
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
@ -24,8 +24,7 @@ type typ int
|
||||
// TODO: What about array types?
|
||||
|
||||
const (
|
||||
typBool typ = iota
|
||||
typInt
|
||||
typNone typ = iota
|
||||
typFloat
|
||||
typVec2
|
||||
typVec3
|
||||
@ -40,10 +39,6 @@ func parseType(expr ast.Expr) (typ, error) {
|
||||
switch t := expr.(type) {
|
||||
case *ast.Ident:
|
||||
switch t.Name {
|
||||
case "bool":
|
||||
return typBool, nil
|
||||
case "int":
|
||||
return typInt, nil
|
||||
case "float":
|
||||
return typFloat, nil
|
||||
case "vec2":
|
||||
@ -68,10 +63,8 @@ func parseType(expr ast.Expr) (typ, error) {
|
||||
|
||||
func (t typ) String() string {
|
||||
switch t {
|
||||
case typBool:
|
||||
return "bool"
|
||||
case typInt:
|
||||
return "int"
|
||||
case typNone:
|
||||
return "(none)"
|
||||
case typFloat:
|
||||
return "float"
|
||||
case typVec2:
|
||||
@ -94,15 +87,13 @@ func (t typ) String() string {
|
||||
}
|
||||
|
||||
func (t typ) numeric() bool {
|
||||
return t != typSampler2d
|
||||
return t != typNone && t != typSampler2d
|
||||
}
|
||||
|
||||
func (t typ) glslString() string {
|
||||
switch t {
|
||||
case typBool:
|
||||
return "bool"
|
||||
case typInt:
|
||||
return "int"
|
||||
case typNone:
|
||||
return "?(none)"
|
||||
case typFloat:
|
||||
return "float"
|
||||
case typVec2:
|
||||
|
Loading…
Reference in New Issue
Block a user