twitchapon-anim

Basic Twitchapon Receiver/Visuals
git clone git://bsandro.tech/twitchapon-anim
Log | Files | Refs | README | LICENSE

glsl.go (15096B)


      1 // Copyright 2020 The Ebiten Authors
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package glsl
     16 
     17 import (
     18 	"fmt"
     19 	"go/constant"
     20 	"go/token"
     21 	"regexp"
     22 	"strings"
     23 
     24 	"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
     25 )
     26 
     27 const FragmentPrelude = `#if defined(GL_ES)
     28 precision highp float;
     29 #else
     30 #define lowp
     31 #define mediump
     32 #define highp
     33 #endif`
     34 
     35 type compileContext struct {
     36 	structNames map[string]string
     37 	structTypes []shaderir.Type
     38 }
     39 
     40 func (c *compileContext) structName(p *shaderir.Program, t *shaderir.Type) string {
     41 	if t.Main != shaderir.Struct {
     42 		panic("glsl: the given type at structName must be a struct")
     43 	}
     44 	s := t.String()
     45 	if n, ok := c.structNames[s]; ok {
     46 		return n
     47 	}
     48 	n := fmt.Sprintf("S%d", len(c.structNames))
     49 	c.structNames[s] = n
     50 	c.structTypes = append(c.structTypes, *t)
     51 	return n
     52 }
     53 
     54 func Compile(p *shaderir.Program) (vertexShader, fragmentShader string) {
     55 	c := &compileContext{
     56 		structNames: map[string]string{},
     57 	}
     58 
     59 	// Vertex func
     60 	var vslines []string
     61 	{
     62 		vslines = append(vslines, "{{.Structs}}")
     63 		if len(p.Uniforms) > 0 || p.TextureNum > 0 || len(p.Attributes) > 0 || len(p.Varyings) > 0 {
     64 			vslines = append(vslines, "")
     65 			for i, t := range p.Uniforms {
     66 				vslines = append(vslines, fmt.Sprintf("uniform %s;", c.glslVarDecl(p, &t, fmt.Sprintf("U%d", i))))
     67 			}
     68 			for i := 0; i < p.TextureNum; i++ {
     69 				vslines = append(vslines, fmt.Sprintf("uniform sampler2D T%d;", i))
     70 			}
     71 			for i, t := range p.Attributes {
     72 				vslines = append(vslines, fmt.Sprintf("attribute %s;", c.glslVarDecl(p, &t, fmt.Sprintf("A%d", i))))
     73 			}
     74 			for i, t := range p.Varyings {
     75 				vslines = append(vslines, fmt.Sprintf("varying %s;", c.glslVarDecl(p, &t, fmt.Sprintf("V%d", i))))
     76 			}
     77 		}
     78 		if len(p.Funcs) > 0 {
     79 			vslines = append(vslines, "")
     80 			for _, f := range p.Funcs {
     81 				vslines = append(vslines, c.glslFunc(p, &f, true)...)
     82 			}
     83 			for _, f := range p.Funcs {
     84 				if len(vslines) > 0 && vslines[len(vslines)-1] != "" {
     85 					vslines = append(vslines, "")
     86 				}
     87 				vslines = append(vslines, c.glslFunc(p, &f, false)...)
     88 			}
     89 		}
     90 
     91 		if p.VertexFunc.Block != nil && len(p.VertexFunc.Block.Stmts) > 0 {
     92 			vslines = append(vslines, "")
     93 			vslines = append(vslines, "void main(void) {")
     94 			vslines = append(vslines, c.glslBlock(p, p.VertexFunc.Block, p.VertexFunc.Block, 0)...)
     95 			vslines = append(vslines, "}")
     96 		}
     97 	}
     98 
     99 	// Fragment func
    100 	var fslines []string
    101 	{
    102 		fslines = append(fslines, strings.Split(FragmentPrelude, "\n")...)
    103 		fslines = append(fslines, "", "{{.Structs}}")
    104 		if len(p.Uniforms) > 0 || p.TextureNum > 0 || len(p.Varyings) > 0 {
    105 			fslines = append(fslines, "")
    106 			for i, t := range p.Uniforms {
    107 				fslines = append(fslines, fmt.Sprintf("uniform %s;", c.glslVarDecl(p, &t, fmt.Sprintf("U%d", i))))
    108 			}
    109 			for i := 0; i < p.TextureNum; i++ {
    110 				fslines = append(fslines, fmt.Sprintf("uniform sampler2D T%d;", i))
    111 			}
    112 			for i, t := range p.Varyings {
    113 				fslines = append(fslines, fmt.Sprintf("varying %s;", c.glslVarDecl(p, &t, fmt.Sprintf("V%d", i))))
    114 			}
    115 		}
    116 		if len(p.Funcs) > 0 {
    117 			fslines = append(fslines, "")
    118 			for _, f := range p.Funcs {
    119 				fslines = append(fslines, c.glslFunc(p, &f, true)...)
    120 			}
    121 			for _, f := range p.Funcs {
    122 				if len(fslines) > 0 && fslines[len(fslines)-1] != "" {
    123 					fslines = append(fslines, "")
    124 				}
    125 				fslines = append(fslines, c.glslFunc(p, &f, false)...)
    126 			}
    127 		}
    128 
    129 		if p.FragmentFunc.Block != nil && len(p.FragmentFunc.Block.Stmts) > 0 {
    130 			fslines = append(fslines, "")
    131 			fslines = append(fslines, "void main(void) {")
    132 			fslines = append(fslines, c.glslBlock(p, p.FragmentFunc.Block, p.FragmentFunc.Block, 0)...)
    133 			fslines = append(fslines, "}")
    134 		}
    135 	}
    136 
    137 	vs := strings.Join(vslines, "\n")
    138 	fs := strings.Join(fslines, "\n")
    139 
    140 	// Struct types are determined after converting the program.
    141 	if len(c.structTypes) > 0 {
    142 		var stlines []string
    143 		for i, t := range c.structTypes {
    144 			stlines = append(stlines, fmt.Sprintf("struct S%d {", i))
    145 			for j, st := range t.Sub {
    146 				stlines = append(stlines, fmt.Sprintf("\t%s;", c.glslVarDecl(p, &st, fmt.Sprintf("M%d", j))))
    147 			}
    148 			stlines = append(stlines, "};")
    149 		}
    150 		st := strings.Join(stlines, "\n")
    151 		vs = strings.ReplaceAll(vs, "{{.Structs}}", st)
    152 		fs = strings.ReplaceAll(fs, "{{.Structs}}", st)
    153 	} else {
    154 		vs = strings.ReplaceAll(vs, "{{.Structs}}", "")
    155 		fs = strings.ReplaceAll(fs, "{{.Structs}}", "")
    156 	}
    157 
    158 	nls := regexp.MustCompile(`\n\n+`)
    159 	vs = nls.ReplaceAllString(vs, "\n\n")
    160 	fs = nls.ReplaceAllString(fs, "\n\n")
    161 
    162 	vs = strings.TrimSpace(vs) + "\n"
    163 	fs = strings.TrimSpace(fs) + "\n"
    164 
    165 	return vs, fs
    166 }
    167 
    168 func (c *compileContext) glslType(p *shaderir.Program, t *shaderir.Type) (string, string) {
    169 	switch t.Main {
    170 	case shaderir.None:
    171 		return "void", ""
    172 	case shaderir.Struct:
    173 		return c.structName(p, t), ""
    174 	default:
    175 		return typeString(t)
    176 	}
    177 }
    178 
    179 func (c *compileContext) glslVarDecl(p *shaderir.Program, t *shaderir.Type, varname string) string {
    180 	switch t.Main {
    181 	case shaderir.None:
    182 		return "?(none)"
    183 	case shaderir.Struct:
    184 		return fmt.Sprintf("%s %s", c.structName(p, t), varname)
    185 	default:
    186 		t0, t1 := typeString(t)
    187 		return fmt.Sprintf("%s %s%s", t0, varname, t1)
    188 	}
    189 }
    190 
    191 func (c *compileContext) glslVarInit(p *shaderir.Program, t *shaderir.Type) string {
    192 	switch t.Main {
    193 	case shaderir.None:
    194 		return "?(none)"
    195 	case shaderir.Array:
    196 		init := c.glslVarInit(p, &t.Sub[0])
    197 		es := make([]string, 0, t.Length)
    198 		for i := 0; i < t.Length; i++ {
    199 			es = append(es, init)
    200 		}
    201 		t0, t1 := typeString(t)
    202 		return fmt.Sprintf("%s%s(%s)", t0, t1, strings.Join(es, ", "))
    203 	case shaderir.Struct:
    204 		panic("not implemented")
    205 	case shaderir.Bool:
    206 		return "false"
    207 	case shaderir.Int:
    208 		return "0"
    209 	case shaderir.Float, shaderir.Vec2, shaderir.Vec3, shaderir.Vec4, shaderir.Mat2, shaderir.Mat3, shaderir.Mat4:
    210 		return fmt.Sprintf("%s(0)", basicTypeString(t.Main))
    211 	default:
    212 		t0, t1 := c.glslType(p, t)
    213 		panic(fmt.Sprintf("?(unexpected type: %s%s)", t0, t1))
    214 	}
    215 }
    216 
    217 func (c *compileContext) glslFunc(p *shaderir.Program, f *shaderir.Func, prototype bool) []string {
    218 	var args []string
    219 	var idx int
    220 	for _, t := range f.InParams {
    221 		args = append(args, "in "+c.glslVarDecl(p, &t, fmt.Sprintf("l%d", idx)))
    222 		idx++
    223 	}
    224 	for _, t := range f.OutParams {
    225 		args = append(args, "out "+c.glslVarDecl(p, &t, fmt.Sprintf("l%d", idx)))
    226 		idx++
    227 	}
    228 	argsstr := "void"
    229 	if len(args) > 0 {
    230 		argsstr = strings.Join(args, ", ")
    231 	}
    232 
    233 	t0, t1 := c.glslType(p, &f.Return)
    234 	sig := fmt.Sprintf("%s%s F%d(%s)", t0, t1, f.Index, argsstr)
    235 
    236 	var lines []string
    237 	if prototype {
    238 		lines = append(lines, fmt.Sprintf("%s;", sig))
    239 		return lines
    240 	}
    241 	lines = append(lines, fmt.Sprintf("%s {", sig))
    242 	lines = append(lines, c.glslBlock(p, f.Block, f.Block, 0)...)
    243 	lines = append(lines, "}")
    244 
    245 	return lines
    246 }
    247 
    248 func constantToNumberLiteral(t shaderir.ConstType, v constant.Value) string {
    249 	switch t {
    250 	case shaderir.ConstTypeNone:
    251 		if v.Kind() == constant.Bool {
    252 			if constant.BoolVal(v) {
    253 				return "true"
    254 			}
    255 			return "false"
    256 		}
    257 		fallthrough
    258 	case shaderir.ConstTypeFloat:
    259 		if i := constant.ToInt(v); i.Kind() == constant.Int {
    260 			x, _ := constant.Int64Val(i)
    261 			return fmt.Sprintf("%d.0", x)
    262 		}
    263 		if i := constant.ToFloat(v); i.Kind() == constant.Float {
    264 			x, _ := constant.Float64Val(i)
    265 			return fmt.Sprintf("%.10e", x)
    266 		}
    267 	case shaderir.ConstTypeInt:
    268 		if i := constant.ToInt(v); i.Kind() == constant.Int {
    269 			x, _ := constant.Int64Val(i)
    270 			return fmt.Sprintf("%d", x)
    271 		}
    272 	}
    273 	return fmt.Sprintf("?(unexpected literal: %s)", v)
    274 }
    275 
    276 func localVariableName(p *shaderir.Program, topBlock, block *shaderir.Block, idx int) string {
    277 	switch topBlock {
    278 	case p.VertexFunc.Block:
    279 		na := len(p.Attributes)
    280 		nv := len(p.Varyings)
    281 		switch {
    282 		case idx < na:
    283 			return fmt.Sprintf("A%d", idx)
    284 		case idx == na:
    285 			return "gl_Position"
    286 		case idx < na+nv+1:
    287 			return fmt.Sprintf("V%d", idx-na-1)
    288 		default:
    289 			return fmt.Sprintf("l%d", idx-(na+nv+1))
    290 		}
    291 	case p.FragmentFunc.Block:
    292 		nv := len(p.Varyings)
    293 		switch {
    294 		case idx == 0:
    295 			return "gl_FragCoord"
    296 		case idx < nv+1:
    297 			return fmt.Sprintf("V%d", idx-1)
    298 		case idx == nv+1:
    299 			return "gl_FragColor"
    300 		default:
    301 			return fmt.Sprintf("l%d", idx-(nv+2))
    302 		}
    303 	default:
    304 		return fmt.Sprintf("l%d", idx)
    305 	}
    306 }
    307 
    308 func (c *compileContext) initVariable(p *shaderir.Program, topBlock, block *shaderir.Block, index int, decl bool, level int) []string {
    309 	idt := strings.Repeat("\t", level+1)
    310 	name := localVariableName(p, topBlock, block, index)
    311 	t := p.LocalVariableType(topBlock, block, index)
    312 
    313 	var lines []string
    314 	switch t.Main {
    315 	case shaderir.Array:
    316 		if decl {
    317 			lines = append(lines, fmt.Sprintf("%s%s;", idt, c.glslVarDecl(p, &t, name)))
    318 		}
    319 		init := c.glslVarInit(p, &t.Sub[0])
    320 		for i := 0; i < t.Length; i++ {
    321 			lines = append(lines, fmt.Sprintf("%s%s[%d] = %s;", idt, name, i, init))
    322 		}
    323 	case shaderir.None:
    324 		// The type is None e.g., when the variable is a for-loop counter.
    325 	default:
    326 		if decl {
    327 			lines = append(lines, fmt.Sprintf("%s%s = %s;", idt, c.glslVarDecl(p, &t, name), c.glslVarInit(p, &t)))
    328 		} else {
    329 			lines = append(lines, fmt.Sprintf("%s%s = %s;", idt, name, c.glslVarInit(p, &t)))
    330 		}
    331 	}
    332 	return lines
    333 }
    334 
    335 func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderir.Block, level int) []string {
    336 	if block == nil {
    337 		return nil
    338 	}
    339 
    340 	var lines []string
    341 	for i := range block.LocalVars {
    342 		lines = append(lines, c.initVariable(p, topBlock, block, block.LocalVarIndexOffset+i, true, level)...)
    343 	}
    344 
    345 	var glslExpr func(e *shaderir.Expr) string
    346 	glslExpr = func(e *shaderir.Expr) string {
    347 		switch e.Type {
    348 		case shaderir.NumberExpr:
    349 			return constantToNumberLiteral(e.ConstType, e.Const)
    350 		case shaderir.UniformVariable:
    351 			return fmt.Sprintf("U%d", e.Index)
    352 		case shaderir.TextureVariable:
    353 			return fmt.Sprintf("T%d", e.Index)
    354 		case shaderir.LocalVariable:
    355 			return localVariableName(p, topBlock, block, e.Index)
    356 		case shaderir.StructMember:
    357 			return fmt.Sprintf("M%d", e.Index)
    358 		case shaderir.BuiltinFuncExpr:
    359 			return builtinFuncString(e.BuiltinFunc)
    360 		case shaderir.SwizzlingExpr:
    361 			if !shaderir.IsValidSwizzling(e.Swizzling) {
    362 				return fmt.Sprintf("?(unexpected swizzling: %s)", e.Swizzling)
    363 			}
    364 			return e.Swizzling
    365 		case shaderir.FunctionExpr:
    366 			return fmt.Sprintf("F%d", e.Index)
    367 		case shaderir.Unary:
    368 			var op string
    369 			switch e.Op {
    370 			case shaderir.Add, shaderir.Sub, shaderir.NotOp:
    371 				op = string(e.Op)
    372 			default:
    373 				op = fmt.Sprintf("?(unexpected op: %s)", string(e.Op))
    374 			}
    375 			return fmt.Sprintf("%s(%s)", op, glslExpr(&e.Exprs[0]))
    376 		case shaderir.Binary:
    377 			return fmt.Sprintf("(%s) %s (%s)", glslExpr(&e.Exprs[0]), e.Op, glslExpr(&e.Exprs[1]))
    378 		case shaderir.Selection:
    379 			return fmt.Sprintf("(%s) ? (%s) : (%s)", glslExpr(&e.Exprs[0]), glslExpr(&e.Exprs[1]), glslExpr(&e.Exprs[2]))
    380 		case shaderir.Call:
    381 			var args []string
    382 			for _, exp := range e.Exprs[1:] {
    383 				args = append(args, glslExpr(&exp))
    384 			}
    385 			// Using parentheses at the callee is illegal.
    386 			return fmt.Sprintf("%s(%s)", glslExpr(&e.Exprs[0]), strings.Join(args, ", "))
    387 		case shaderir.FieldSelector:
    388 			return fmt.Sprintf("(%s).%s", glslExpr(&e.Exprs[0]), glslExpr(&e.Exprs[1]))
    389 		case shaderir.Index:
    390 			return fmt.Sprintf("(%s)[%s]", glslExpr(&e.Exprs[0]), glslExpr(&e.Exprs[1]))
    391 		default:
    392 			return fmt.Sprintf("?(unexpected expr: %d)", e.Type)
    393 		}
    394 	}
    395 
    396 	idt := strings.Repeat("\t", level+1)
    397 	for _, s := range block.Stmts {
    398 		switch s.Type {
    399 		case shaderir.ExprStmt:
    400 			lines = append(lines, fmt.Sprintf("%s%s;", idt, glslExpr(&s.Exprs[0])))
    401 		case shaderir.BlockStmt:
    402 			lines = append(lines, idt+"{")
    403 			lines = append(lines, c.glslBlock(p, topBlock, s.Blocks[0], level+1)...)
    404 			lines = append(lines, idt+"}")
    405 		case shaderir.Assign:
    406 			lhs := s.Exprs[0]
    407 			rhs := s.Exprs[1]
    408 			if lhs.Type == shaderir.LocalVariable {
    409 				if t := p.LocalVariableType(topBlock, block, lhs.Index); t.Main == shaderir.Array {
    410 					for i := 0; i < t.Length; i++ {
    411 						lines = append(lines, fmt.Sprintf("%[1]s%[2]s[%[3]d] = %[4]s[%[3]d];", idt, glslExpr(&lhs), i, glslExpr(&rhs)))
    412 					}
    413 					continue
    414 				}
    415 			}
    416 			lines = append(lines, fmt.Sprintf("%s%s = %s;", idt, glslExpr(&lhs), glslExpr(&rhs)))
    417 		case shaderir.Init:
    418 			lines = append(lines, c.initVariable(p, topBlock, block, s.InitIndex, false, level)...)
    419 		case shaderir.If:
    420 			lines = append(lines, fmt.Sprintf("%sif (%s) {", idt, glslExpr(&s.Exprs[0])))
    421 			lines = append(lines, c.glslBlock(p, topBlock, s.Blocks[0], level+1)...)
    422 			if len(s.Blocks) > 1 {
    423 				lines = append(lines, fmt.Sprintf("%s} else {", idt))
    424 				lines = append(lines, c.glslBlock(p, topBlock, s.Blocks[1], level+1)...)
    425 			}
    426 			lines = append(lines, fmt.Sprintf("%s}", idt))
    427 		case shaderir.For:
    428 			var ct shaderir.ConstType
    429 			switch s.ForVarType.Main {
    430 			case shaderir.Int:
    431 				ct = shaderir.ConstTypeInt
    432 			case shaderir.Float:
    433 				ct = shaderir.ConstTypeFloat
    434 			}
    435 
    436 			v := localVariableName(p, topBlock, block, s.ForVarIndex)
    437 			var delta string
    438 			switch val, _ := constant.Float64Val(s.ForDelta); val {
    439 			case 0:
    440 				delta = fmt.Sprintf("?(unexpected delta: %v)", s.ForDelta)
    441 			case 1:
    442 				delta = fmt.Sprintf("%s++", v)
    443 			case -1:
    444 				delta = fmt.Sprintf("%s--", v)
    445 			default:
    446 				d := s.ForDelta
    447 				if val > 0 {
    448 					delta = fmt.Sprintf("%s += %s", v, constantToNumberLiteral(ct, d))
    449 				} else {
    450 					d = constant.UnaryOp(token.SUB, d, 0)
    451 					delta = fmt.Sprintf("%s -= %s", v, constantToNumberLiteral(ct, d))
    452 				}
    453 			}
    454 			var op string
    455 			switch s.ForOp {
    456 			case shaderir.LessThanOp, shaderir.LessThanEqualOp, shaderir.GreaterThanOp, shaderir.GreaterThanEqualOp, shaderir.EqualOp, shaderir.NotEqualOp:
    457 				op = string(s.ForOp)
    458 			default:
    459 				op = fmt.Sprintf("?(unexpected op: %s)", string(s.ForOp))
    460 			}
    461 
    462 			t := s.ForVarType
    463 			init := constantToNumberLiteral(ct, s.ForInit)
    464 			end := constantToNumberLiteral(ct, s.ForEnd)
    465 			t0, t1 := typeString(&t)
    466 			lines = append(lines, fmt.Sprintf("%sfor (%s %s%s = %s; %s %s %s; %s) {", idt, t0, v, t1, init, v, op, end, delta))
    467 			lines = append(lines, c.glslBlock(p, topBlock, s.Blocks[0], level+1)...)
    468 			lines = append(lines, fmt.Sprintf("%s}", idt))
    469 		case shaderir.Continue:
    470 			lines = append(lines, idt+"continue;")
    471 		case shaderir.Break:
    472 			lines = append(lines, idt+"break;")
    473 		case shaderir.Return:
    474 			if len(s.Exprs) == 0 {
    475 				lines = append(lines, idt+"return;")
    476 			} else {
    477 				lines = append(lines, fmt.Sprintf("%sreturn %s;", idt, glslExpr(&s.Exprs[0])))
    478 			}
    479 		case shaderir.Discard:
    480 			lines = append(lines, idt+"discard;")
    481 		default:
    482 			lines = append(lines, fmt.Sprintf("%s?(unexpected stmt: %d)", idt, s.Type))
    483 		}
    484 	}
    485 
    486 	return lines
    487 }