mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 11:18:54 +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"
|
||||
)
|
||||
|
||||
const (
|
||||
vertexEntry = "Vertex"
|
||||
)
|
||||
|
||||
type variable struct {
|
||||
name string
|
||||
typ typ
|
||||
@ -52,11 +56,26 @@ type compileState struct {
|
||||
// uniforms is a collection of uniform variable names.
|
||||
uniforms []string
|
||||
|
||||
// attributes is a collection of attribute variable names.
|
||||
attributes []string
|
||||
|
||||
// varyings is a collection of varying variable names.
|
||||
varyings []string
|
||||
|
||||
global block
|
||||
|
||||
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 {
|
||||
types []typ
|
||||
vars []variable
|
||||
@ -178,7 +197,12 @@ func (cs *compileState) parseDecl(b *block, d ast.Decl) {
|
||||
cs.addError(d.Pos(), "unexpected token")
|
||||
}
|
||||
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:
|
||||
cs.addError(d.Pos(), "unexpected decl")
|
||||
}
|
||||
@ -230,7 +254,7 @@ func (s *compileState) parseConstant(vs *ast.ValueSpec) []constant {
|
||||
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 {
|
||||
cs.addError(d.Pos(), "function must have a name")
|
||||
return function{}
|
||||
@ -242,6 +266,7 @@ func (cs *compileState) parseFunc(d *ast.FuncDecl, block *block) function {
|
||||
|
||||
var inT []shaderir.Type
|
||||
var inParams []variable
|
||||
|
||||
for _, f := range d.Type.Params.List {
|
||||
t := cs.parseType(f.Type)
|
||||
for _, n := range f.Names {
|
||||
@ -255,6 +280,7 @@ func (cs *compileState) parseFunc(d *ast.FuncDecl, block *block) function {
|
||||
|
||||
var outT []shaderir.Type
|
||||
var outParams []variable
|
||||
|
||||
if d.Type.Results != nil {
|
||||
for _, f := range d.Type.Results.List {
|
||||
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)
|
||||
|
||||
return function{
|
||||
@ -458,6 +510,59 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) shaderir.Expr {
|
||||
default:
|
||||
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:
|
||||
exprs := []shaderir.Expr{
|
||||
cs.parseExpr(block, e.Fun),
|
||||
@ -472,15 +577,19 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) shaderir.Expr {
|
||||
Exprs: exprs,
|
||||
}
|
||||
case *ast.Ident:
|
||||
i, ok := block.findLocalVariable(e.Name)
|
||||
if ok {
|
||||
if i, ok := block.findLocalVariable(e.Name); ok {
|
||||
return shaderir.Expr{
|
||||
Type: shaderir.LocalVariable,
|
||||
Index: i,
|
||||
}
|
||||
}
|
||||
f, ok := shaderir.ParseBuiltinFunc(e.Name)
|
||||
if ok {
|
||||
if i, ok := cs.findUniformVariable(e.Name); ok {
|
||||
return shaderir.Expr{
|
||||
Type: shaderir.UniformVariable,
|
||||
Index: i,
|
||||
}
|
||||
}
|
||||
if f, ok := shaderir.ParseBuiltinFunc(e.Name); ok {
|
||||
return shaderir.Expr{
|
||||
Type: shaderir.BuiltinFuncExpr,
|
||||
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:
|
||||
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);
|
||||
l1 = l2;
|
||||
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 {
|
||||
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 {
|
||||
vslines = append(vslines, p.glslFunc(&f)...)
|
||||
}
|
||||
@ -285,7 +288,7 @@ func (p *Program) glslBlock(b *Block, level int, localVarIndex int) []string {
|
||||
case Unary:
|
||||
var op string
|
||||
switch e.Op {
|
||||
case Add, Sub, Neg:
|
||||
case Add, Sub, NotOp:
|
||||
op = string(e.Op)
|
||||
default:
|
||||
op = fmt.Sprintf("?(unexpected op: %s)", string(e.Op))
|
||||
|
@ -116,7 +116,7 @@ type Op string
|
||||
const (
|
||||
Add Op = "+"
|
||||
Sub Op = "-"
|
||||
Neg Op = "!"
|
||||
NotOp Op = "!"
|
||||
Mul Op = "*"
|
||||
Div Op = "/"
|
||||
ModOp Op = "%"
|
||||
|
Loading…
Reference in New Issue
Block a user