forked from google/gxui
/
shader_program.go
116 lines (99 loc) · 2.88 KB
/
shader_program.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gl
import (
"fmt"
"github.com/go-gl-legacy/gl"
)
type UniformBindings map[string]interface{}
type ShaderProgram struct {
Program gl.Program
Uniforms []ShaderUniform
Attributes []ShaderAttribute
}
func compile(source string, ty gl.GLenum) gl.Shader {
s := gl.CreateShader(ty)
s.Source(source)
s.Compile()
if s.Get(gl.COMPILE_STATUS) != gl.TRUE {
panic(s.GetInfoLog())
}
return s
}
func CreateShaderProgram(ctx *Context, vsSource, fsSource string) *ShaderProgram {
vs := compile(vsSource, gl.VERTEX_SHADER)
fs := compile(fsSource, gl.FRAGMENT_SHADER)
program := gl.CreateProgram()
program.AttachShader(vs)
program.AttachShader(fs)
program.Link()
program.Validate()
if program.Get(gl.LINK_STATUS) != gl.TRUE {
panic(program.GetInfoLog())
}
program.Use()
CheckError()
uniformCount := program.Get(gl.ACTIVE_UNIFORMS)
uniforms := make([]ShaderUniform, uniformCount)
textureUnit := 0
for i := 0; i < uniformCount; i++ {
size, ty, name := program.GetActiveUniform(i)
location := program.GetUniformLocation(name)
uniforms[i] = CreateShaderUniform(name, size, ShaderDataType(ty), location, textureUnit)
if ty == gl.SAMPLER_2D {
textureUnit++
}
}
attributeCount := program.Get(gl.ACTIVE_ATTRIBUTES)
attributes := make([]ShaderAttribute, attributeCount)
for i := 0; i < attributeCount; i++ {
size, ty, name := program.GetActiveAttrib(i)
location := program.GetAttribLocation(name)
attributes[i] = CreateShaderAttribute(name, size, ShaderDataType(ty), location)
}
ctx.Stats().ShaderProgramCount++
return &ShaderProgram{
Program: program,
Uniforms: uniforms,
Attributes: attributes,
}
}
func (s *ShaderProgram) Destroy(ctx *Context) {
s.Program.Delete()
s.Program = gl.Program(0)
// TODO: Delete shaders.
ctx.Stats().ShaderProgramCount--
}
func (s *ShaderProgram) Bind(ctx *Context, vb *VertexBuffer, uniforms UniformBindings) {
s.Program.Use()
for _, a := range s.Attributes {
vs, found := vb.Streams[a.Name]
if !found {
panic(fmt.Errorf("VertexBuffer missing required stream '%s'", a.Name))
}
if a.Type != vs.Type() {
panic(fmt.Errorf("Attribute '%s' type '%s' does not match stream type '%s'",
a.Name, a.Type, vs.Type()))
}
elementCount := a.Type.VectorElementCount()
elementTy := a.Type.VectorElementType()
ctx.GetOrCreateVertexStreamContext(vs).Bind()
a.Location.EnableArray()
a.Location.AttribPointer(uint(elementCount), gl.GLenum(elementTy), false, 0, nil)
CheckError()
}
for _, u := range s.Uniforms {
v, found := uniforms[u.Name]
if !found {
panic(fmt.Errorf("Uniforms missing '%s'", u.Name))
}
u.Bind(ctx, v)
}
}
func (s *ShaderProgram) Unbind(ctx *Context) {
for _, a := range s.Attributes {
a.Location.DisableArray()
}
CheckError()
}