mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 03:38:55 +01:00
shader: Implement vertex shader entry point
This commit is contained in:
parent
fa5b2ed730
commit
cd3d396975
@ -25,6 +25,10 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten/internal/shaderir"
|
"github.com/hajimehoshi/ebiten/internal/shaderir"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
vertexEntry = "Vertex"
|
||||||
|
)
|
||||||
|
|
||||||
type variable struct {
|
type variable struct {
|
||||||
name string
|
name string
|
||||||
typ typ
|
typ typ
|
||||||
@ -52,11 +56,26 @@ type compileState struct {
|
|||||||
// uniforms is a collection of uniform variable names.
|
// uniforms is a collection of uniform variable names.
|
||||||
uniforms []string
|
uniforms []string
|
||||||
|
|
||||||
|
// attributes is a collection of attribute variable names.
|
||||||
|
attributes []string
|
||||||
|
|
||||||
|
// varyings is a collection of varying variable names.
|
||||||
|
varyings []string
|
||||||
|
|
||||||
global block
|
global block
|
||||||
|
|
||||||
errs []string
|
errs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cs *compileState) findUniformVariable(name string) (int, bool) {
|
||||||
|
for i, u := range cs.uniforms {
|
||||||
|
if u == name {
|
||||||
|
return i, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
type block struct {
|
type block struct {
|
||||||
types []typ
|
types []typ
|
||||||
vars []variable
|
vars []variable
|
||||||
@ -178,7 +197,12 @@ func (cs *compileState) parseDecl(b *block, d ast.Decl) {
|
|||||||
cs.addError(d.Pos(), "unexpected token")
|
cs.addError(d.Pos(), "unexpected token")
|
||||||
}
|
}
|
||||||
case *ast.FuncDecl:
|
case *ast.FuncDecl:
|
||||||
b.funcs = append(b.funcs, cs.parseFunc(d, b))
|
f := cs.parseFunc(b, d)
|
||||||
|
if b == &cs.global && d.Name.Name == vertexEntry {
|
||||||
|
cs.ir.VertexFunc.Block = f.ir.Block
|
||||||
|
} else {
|
||||||
|
b.funcs = append(b.funcs, f)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
cs.addError(d.Pos(), "unexpected decl")
|
cs.addError(d.Pos(), "unexpected decl")
|
||||||
}
|
}
|
||||||
@ -230,7 +254,7 @@ func (s *compileState) parseConstant(vs *ast.ValueSpec) []constant {
|
|||||||
return cs
|
return cs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *compileState) parseFunc(d *ast.FuncDecl, block *block) function {
|
func (cs *compileState) parseFunc(block *block, d *ast.FuncDecl) function {
|
||||||
if d.Name == nil {
|
if d.Name == nil {
|
||||||
cs.addError(d.Pos(), "function must have a name")
|
cs.addError(d.Pos(), "function must have a name")
|
||||||
return function{}
|
return function{}
|
||||||
@ -242,6 +266,7 @@ func (cs *compileState) parseFunc(d *ast.FuncDecl, block *block) function {
|
|||||||
|
|
||||||
var inT []shaderir.Type
|
var inT []shaderir.Type
|
||||||
var inParams []variable
|
var inParams []variable
|
||||||
|
|
||||||
for _, f := range d.Type.Params.List {
|
for _, f := range d.Type.Params.List {
|
||||||
t := cs.parseType(f.Type)
|
t := cs.parseType(f.Type)
|
||||||
for _, n := range f.Names {
|
for _, n := range f.Names {
|
||||||
@ -255,6 +280,7 @@ func (cs *compileState) parseFunc(d *ast.FuncDecl, block *block) function {
|
|||||||
|
|
||||||
var outT []shaderir.Type
|
var outT []shaderir.Type
|
||||||
var outParams []variable
|
var outParams []variable
|
||||||
|
|
||||||
if d.Type.Results != nil {
|
if d.Type.Results != nil {
|
||||||
for _, f := range d.Type.Results.List {
|
for _, f := range d.Type.Results.List {
|
||||||
t := cs.parseType(f.Type)
|
t := cs.parseType(f.Type)
|
||||||
@ -276,6 +302,32 @@ func (cs *compileState) parseFunc(d *ast.FuncDecl, block *block) function {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if block == &cs.global && d.Name.Name == vertexEntry {
|
||||||
|
for _, v := range inParams {
|
||||||
|
cs.attributes = append(cs.attributes, v.name)
|
||||||
|
}
|
||||||
|
for _, t := range inT {
|
||||||
|
cs.ir.Attributes = append(cs.ir.Attributes, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The first out-param is treated as gl_Position in GLSL.
|
||||||
|
if len(outParams) == 0 {
|
||||||
|
cs.addError(d.Pos(), fmt.Sprintf("vertex entry point must have at least one return vec4 value for a positoin"))
|
||||||
|
return function{}
|
||||||
|
}
|
||||||
|
if outT[0].Main != shaderir.Vec4 {
|
||||||
|
cs.addError(d.Pos(), fmt.Sprintf("vertex entry point must have at least one return vec4 value for a positoin"))
|
||||||
|
return function{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range outParams[1:] {
|
||||||
|
cs.varyings = append(cs.varyings, v.name)
|
||||||
|
}
|
||||||
|
for _, t := range outT[1:] {
|
||||||
|
cs.ir.Varyings = append(cs.ir.Varyings, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
b := cs.parseBlock(block, d.Body, inParams, outParams)
|
b := cs.parseBlock(block, d.Body, inParams, outParams)
|
||||||
|
|
||||||
return function{
|
return function{
|
||||||
@ -458,6 +510,59 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) shaderir.Expr {
|
|||||||
default:
|
default:
|
||||||
cs.addError(e.Pos(), fmt.Sprintf("literal not implemented: %#v", e))
|
cs.addError(e.Pos(), fmt.Sprintf("literal not implemented: %#v", e))
|
||||||
}
|
}
|
||||||
|
case *ast.BinaryExpr:
|
||||||
|
var op shaderir.Op
|
||||||
|
switch e.Op {
|
||||||
|
case token.ADD:
|
||||||
|
op = shaderir.Add
|
||||||
|
case token.SUB:
|
||||||
|
op = shaderir.Sub
|
||||||
|
case token.NOT:
|
||||||
|
op = shaderir.NotOp
|
||||||
|
case token.MUL:
|
||||||
|
op = shaderir.Mul
|
||||||
|
case token.QUO:
|
||||||
|
op = shaderir.Div
|
||||||
|
case token.REM:
|
||||||
|
op = shaderir.ModOp
|
||||||
|
case token.SHL:
|
||||||
|
op = shaderir.LeftShift
|
||||||
|
case token.SHR:
|
||||||
|
op = shaderir.RightShift
|
||||||
|
case token.LSS:
|
||||||
|
op = shaderir.LessThanOp
|
||||||
|
case token.LEQ:
|
||||||
|
op = shaderir.LessThanEqualOp
|
||||||
|
case token.GTR:
|
||||||
|
op = shaderir.GreaterThanOp
|
||||||
|
case token.GEQ:
|
||||||
|
op = shaderir.GreaterThanEqualOp
|
||||||
|
case token.EQL:
|
||||||
|
op = shaderir.EqualOp
|
||||||
|
case token.NEQ:
|
||||||
|
op = shaderir.NotEqualOp
|
||||||
|
case token.AND:
|
||||||
|
op = shaderir.And
|
||||||
|
case token.XOR:
|
||||||
|
op = shaderir.Xor
|
||||||
|
case token.OR:
|
||||||
|
op = shaderir.Or
|
||||||
|
case token.LAND:
|
||||||
|
op = shaderir.AndAnd
|
||||||
|
case token.LOR:
|
||||||
|
op = shaderir.OrOr
|
||||||
|
default:
|
||||||
|
cs.addError(e.Pos(), fmt.Sprintf("unexpected operator: %s", e.Op))
|
||||||
|
return shaderir.Expr{}
|
||||||
|
}
|
||||||
|
return shaderir.Expr{
|
||||||
|
Type: shaderir.Binary,
|
||||||
|
Op: op,
|
||||||
|
Exprs: []shaderir.Expr{
|
||||||
|
cs.parseExpr(block, e.X),
|
||||||
|
cs.parseExpr(block, e.Y),
|
||||||
|
},
|
||||||
|
}
|
||||||
case *ast.CallExpr:
|
case *ast.CallExpr:
|
||||||
exprs := []shaderir.Expr{
|
exprs := []shaderir.Expr{
|
||||||
cs.parseExpr(block, e.Fun),
|
cs.parseExpr(block, e.Fun),
|
||||||
@ -472,15 +577,19 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) shaderir.Expr {
|
|||||||
Exprs: exprs,
|
Exprs: exprs,
|
||||||
}
|
}
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
i, ok := block.findLocalVariable(e.Name)
|
if i, ok := block.findLocalVariable(e.Name); ok {
|
||||||
if ok {
|
|
||||||
return shaderir.Expr{
|
return shaderir.Expr{
|
||||||
Type: shaderir.LocalVariable,
|
Type: shaderir.LocalVariable,
|
||||||
Index: i,
|
Index: i,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f, ok := shaderir.ParseBuiltinFunc(e.Name)
|
if i, ok := cs.findUniformVariable(e.Name); ok {
|
||||||
if ok {
|
return shaderir.Expr{
|
||||||
|
Type: shaderir.UniformVariable,
|
||||||
|
Index: i,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if f, ok := shaderir.ParseBuiltinFunc(e.Name); ok {
|
||||||
return shaderir.Expr{
|
return shaderir.Expr{
|
||||||
Type: shaderir.BuiltinFuncExpr,
|
Type: shaderir.BuiltinFuncExpr,
|
||||||
BuiltinFunc: f,
|
BuiltinFunc: f,
|
||||||
@ -498,6 +607,26 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) shaderir.Expr {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
case *ast.UnaryExpr:
|
||||||
|
var op shaderir.Op
|
||||||
|
switch e.Op {
|
||||||
|
case token.ADD:
|
||||||
|
op = shaderir.Add
|
||||||
|
case token.SUB:
|
||||||
|
op = shaderir.Sub
|
||||||
|
case token.NOT:
|
||||||
|
op = shaderir.NotOp
|
||||||
|
default:
|
||||||
|
cs.addError(e.Pos(), fmt.Sprintf("unexpected operator: %s", e.Op))
|
||||||
|
return shaderir.Expr{}
|
||||||
|
}
|
||||||
|
return shaderir.Expr{
|
||||||
|
Type: shaderir.Unary,
|
||||||
|
Op: op,
|
||||||
|
Exprs: []shaderir.Expr{
|
||||||
|
cs.parseExpr(block, e.X),
|
||||||
|
},
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
cs.addError(e.Pos(), fmt.Sprintf("expression not implemented: %#v", e))
|
cs.addError(e.Pos(), fmt.Sprintf("expression not implemented: %#v", e))
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,37 @@ func Foo(foo vec2) vec4 {
|
|||||||
l2 = vec4(l0, 0.0, 1.0);
|
l2 = vec4(l0, 0.0, 1.0);
|
||||||
l1 = l2;
|
l1 = l2;
|
||||||
return;
|
return;
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "vertex",
|
||||||
|
Src: `package main
|
||||||
|
|
||||||
|
var ScreenSize vec2
|
||||||
|
|
||||||
|
func Vertex(position vec2, texCoord vec2, color vec4) (position vec4, texCoord vec2, color vec4) {
|
||||||
|
projectionMatrix := mat4(
|
||||||
|
2 / ScreenSize.x, 0, 0, 0,
|
||||||
|
0, 2 / ScreenSize.y, 0, 0,
|
||||||
|
0, 0, 1, 0,
|
||||||
|
-1, -1, 0, 1,
|
||||||
|
)
|
||||||
|
return projectionMatrix * vec4(position, 0, 1), texCoord, color
|
||||||
|
}`,
|
||||||
|
VS: `uniform vec2 U0;
|
||||||
|
attribute vec2 A0;
|
||||||
|
attribute vec2 A1;
|
||||||
|
attribute vec4 A2;
|
||||||
|
varying vec2 V0;
|
||||||
|
varying vec4 V1;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
mat4 l0 = mat4(0.0);
|
||||||
|
l0 = mat4((2.0) / ((U0).x), 0.0, 0.0, 0.0, 0.0, (2.0) / ((U0).y), 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -(1.0), -(1.0), 0.0, 1.0);
|
||||||
|
gl_Position = (l0) * (vec4(A0, 0.0, 1.0));
|
||||||
|
V0 = A1;
|
||||||
|
V1 = A2;
|
||||||
|
return;
|
||||||
}`,
|
}`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,9 @@ func (p *Program) Glsl() (vertexShader, fragmentShader string) {
|
|||||||
for i, t := range p.Varyings {
|
for i, t := range p.Varyings {
|
||||||
vslines = append(vslines, fmt.Sprintf("varying %s;", p.glslVarDecl(&t, fmt.Sprintf("V%d", i))))
|
vslines = append(vslines, fmt.Sprintf("varying %s;", p.glslVarDecl(&t, fmt.Sprintf("V%d", i))))
|
||||||
}
|
}
|
||||||
|
if len(vslines) > 0 && len(p.Funcs) > 0 {
|
||||||
|
vslines = append(vslines, "")
|
||||||
|
}
|
||||||
for _, f := range p.Funcs {
|
for _, f := range p.Funcs {
|
||||||
vslines = append(vslines, p.glslFunc(&f)...)
|
vslines = append(vslines, p.glslFunc(&f)...)
|
||||||
}
|
}
|
||||||
@ -285,7 +288,7 @@ func (p *Program) glslBlock(b *Block, level int, localVarIndex int) []string {
|
|||||||
case Unary:
|
case Unary:
|
||||||
var op string
|
var op string
|
||||||
switch e.Op {
|
switch e.Op {
|
||||||
case Add, Sub, Neg:
|
case Add, Sub, NotOp:
|
||||||
op = string(e.Op)
|
op = string(e.Op)
|
||||||
default:
|
default:
|
||||||
op = fmt.Sprintf("?(unexpected op: %s)", string(e.Op))
|
op = fmt.Sprintf("?(unexpected op: %s)", string(e.Op))
|
||||||
|
@ -116,7 +116,7 @@ type Op string
|
|||||||
const (
|
const (
|
||||||
Add Op = "+"
|
Add Op = "+"
|
||||||
Sub Op = "-"
|
Sub Op = "-"
|
||||||
Neg Op = "!"
|
NotOp Op = "!"
|
||||||
Mul Op = "*"
|
Mul Op = "*"
|
||||||
Div Op = "/"
|
Div Op = "/"
|
||||||
ModOp Op = "%"
|
ModOp Op = "%"
|
||||||
|
Loading…
Reference in New Issue
Block a user