mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-27 04:08:53 +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
|
name string
|
||||||
args []variable
|
args []variable
|
||||||
rets []variable
|
rets []variable
|
||||||
|
body *block
|
||||||
}
|
}
|
||||||
|
|
||||||
type Shader struct {
|
type Shader struct {
|
||||||
@ -89,6 +90,9 @@ func NewShader(src []byte) (*Shader, error) {
|
|||||||
return nil, &ParseError{s.errs}
|
return nil, &ParseError{s.errs}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Resolve identifiers?
|
||||||
|
// TODO: Resolve constants
|
||||||
|
|
||||||
sort.Slice(s.varyings, func(a, b int) bool {
|
sort.Slice(s.varyings, func(a, b int) bool {
|
||||||
return s.varyings[a].name < s.varyings[b].name
|
return s.varyings[a].name < s.varyings[b].name
|
||||||
})
|
})
|
||||||
@ -129,7 +133,14 @@ func (sh *Shader) parse(f *ast.File) {
|
|||||||
case token.VAR:
|
case token.VAR:
|
||||||
for _, s := range d.Specs {
|
for _, s := range d.Specs {
|
||||||
s := s.(*ast.ValueSpec)
|
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:
|
case token.IMPORT:
|
||||||
sh.addError(d.Pos(), "import is forbidden")
|
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) {
|
func (s *Shader) parseVariable(vs *ast.ValueSpec) []variable {
|
||||||
t, err := parseType(vs.Type)
|
var t typ
|
||||||
if err != nil {
|
if vs.Type != nil {
|
||||||
s.addError(vs.Type.Pos(), err.Error())
|
var err error
|
||||||
return
|
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 {
|
for _, n := range vs.Names {
|
||||||
name := n.Name
|
name := n.Name
|
||||||
val := variable{
|
vars = append(vars, variable{
|
||||||
name: name,
|
name: name,
|
||||||
typ: t,
|
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) {
|
func (s *Shader) parseTopLevelConstant(vs *ast.ValueSpec) {
|
||||||
@ -302,10 +314,51 @@ func (sh *Shader) parseFunc(d *ast.FuncDecl) {
|
|||||||
name: d.Name.Name,
|
name: d.Name.Name,
|
||||||
args: args,
|
args: args,
|
||||||
rets: rets,
|
rets: rets,
|
||||||
|
body: sh.parseBlock(d.Body),
|
||||||
}
|
}
|
||||||
sh.funcs = append(sh.funcs, f)
|
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.
|
// Dump dumps the shader state in an intermediate language.
|
||||||
func (s *Shader) Dump() string {
|
func (s *Shader) Dump() string {
|
||||||
var lines []string
|
var lines []string
|
||||||
@ -348,7 +401,10 @@ func (s *Shader) Dump() string {
|
|||||||
if len(rets) > 0 {
|
if len(rets) > 0 {
|
||||||
l += " (" + strings.Join(rets, ", ") + ")"
|
l += " (" + strings.Join(rets, ", ") + ")"
|
||||||
}
|
}
|
||||||
|
l += " {"
|
||||||
lines = append(lines, l)
|
lines = append(lines, l)
|
||||||
|
lines = append(lines, f.body.dump(1)...)
|
||||||
|
lines = append(lines, "}")
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(lines, "\n") + "\n"
|
return strings.Join(lines, "\n") + "\n"
|
||||||
|
@ -44,7 +44,11 @@ var (
|
|||||||
const C1 float = 1
|
const C1 float = 1
|
||||||
const C2, C3 float = 2, 3
|
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
|
Dump: `var Position varying vec4 // position
|
||||||
@ -58,7 +62,11 @@ const C1 float = 1
|
|||||||
const C2 float = 2
|
const C2 float = 2
|
||||||
const C3 float = 3
|
const C3 float = 3
|
||||||
var qux vec4
|
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?
|
// TODO: What about array types?
|
||||||
|
|
||||||
const (
|
const (
|
||||||
typBool typ = iota
|
typNone typ = iota
|
||||||
typInt
|
|
||||||
typFloat
|
typFloat
|
||||||
typVec2
|
typVec2
|
||||||
typVec3
|
typVec3
|
||||||
@ -40,10 +39,6 @@ func parseType(expr ast.Expr) (typ, error) {
|
|||||||
switch t := expr.(type) {
|
switch t := expr.(type) {
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
switch t.Name {
|
switch t.Name {
|
||||||
case "bool":
|
|
||||||
return typBool, nil
|
|
||||||
case "int":
|
|
||||||
return typInt, nil
|
|
||||||
case "float":
|
case "float":
|
||||||
return typFloat, nil
|
return typFloat, nil
|
||||||
case "vec2":
|
case "vec2":
|
||||||
@ -68,10 +63,8 @@ func parseType(expr ast.Expr) (typ, error) {
|
|||||||
|
|
||||||
func (t typ) String() string {
|
func (t typ) String() string {
|
||||||
switch t {
|
switch t {
|
||||||
case typBool:
|
case typNone:
|
||||||
return "bool"
|
return "(none)"
|
||||||
case typInt:
|
|
||||||
return "int"
|
|
||||||
case typFloat:
|
case typFloat:
|
||||||
return "float"
|
return "float"
|
||||||
case typVec2:
|
case typVec2:
|
||||||
@ -94,15 +87,13 @@ func (t typ) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t typ) numeric() bool {
|
func (t typ) numeric() bool {
|
||||||
return t != typSampler2d
|
return t != typNone && t != typSampler2d
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t typ) glslString() string {
|
func (t typ) glslString() string {
|
||||||
switch t {
|
switch t {
|
||||||
case typBool:
|
case typNone:
|
||||||
return "bool"
|
return "?(none)"
|
||||||
case typInt:
|
|
||||||
return "int"
|
|
||||||
case typFloat:
|
case typFloat:
|
||||||
return "float"
|
return "float"
|
||||||
case typVec2:
|
case typVec2:
|
||||||
|
Loading…
Reference in New Issue
Block a user