// CreateProgram creates, compiles, and links a gl.Program. func CreateProgram(vertexSrc, fragmentSrc string) (gl.Program, error) { program := gl.CreateProgram() if !program.Valid() { return gl.Program{}, fmt.Errorf("glutil: no programs available") } vertexShader, err := loadShader(gl.VERTEX_SHADER, vertexSrc) if err != nil { return gl.Program{}, err } fragmentShader, err := loadShader(gl.FRAGMENT_SHADER, fragmentSrc) if err != nil { gl.DeleteShader(vertexShader) return gl.Program{}, err } gl.AttachShader(program, vertexShader) gl.AttachShader(program, fragmentShader) gl.LinkProgram(program) // Flag shaders for deletion when program is unlinked. gl.DeleteShader(vertexShader) gl.DeleteShader(fragmentShader) if gl.GetProgrami(program, gl.LINK_STATUS) == 0 { defer gl.DeleteProgram(program) return gl.Program{}, fmt.Errorf("glutil: %s", gl.GetProgramInfoLog(program)) } return program, nil }
func newShaderProgram(ctx *context, vsSource, fsSource string) *shaderProgram { vs := compile(vsSource, gl.VERTEX_SHADER) fs := compile(fsSource, gl.FRAGMENT_SHADER) program := gl.CreateProgram() gl.AttachShader(program, vs) gl.AttachShader(program, fs) gl.LinkProgram(program) if gl.GetProgrami(program, gl.LINK_STATUS) != gl.TRUE { panic(gl.GetProgramInfoLog(program)) } gl.UseProgram(program) checkError() uniformCount := gl.GetProgrami(program, gl.ACTIVE_UNIFORMS) uniforms := make([]shaderUniform, uniformCount) textureUnit := 0 for i := range uniforms { name, size, ty := gl.GetActiveUniform(program, uint32(i)) location := gl.GetUniformLocation(program, name) uniforms[i] = shaderUniform{ name: name, size: size, ty: shaderDataType(ty), location: location, textureUnit: textureUnit, } if ty == gl.SAMPLER_2D { textureUnit++ } } attributeCount := gl.GetProgrami(program, gl.ACTIVE_ATTRIBUTES) attributes := make([]shaderAttribute, attributeCount) for i := range attributes { name, size, ty := gl.GetActiveAttrib(program, uint32(i)) location := gl.GetAttribLocation(program, name) attributes[i] = shaderAttribute{ name: name, size: size, ty: shaderDataType(ty), location: location, } } ctx.stats.shaderProgramCount++ return &shaderProgram{ program: program, uniforms: uniforms, attributes: attributes, } }
func (s *glShader) createShader(name, header, opts, vShader, fShader string) error { program := gl.CreateProgram() vertexShader := gl.CreateShader(gl.VERTEX_SHADER) gl.ShaderSource(vertexShader, strings.Join([]string{header, opts, vShader}, "\n")) gl.CompileShader(vertexShader) status := gl.Enum(gl.GetShaderi(vertexShader, gl.COMPILE_STATUS)) if status != gl.TRUE { return dumpShaderError(vertexShader, name, "vert") } fragmentShader := gl.CreateShader(gl.FRAGMENT_SHADER) gl.ShaderSource(fragmentShader, strings.Join([]string{header, opts, fShader}, "\n")) gl.CompileShader(fragmentShader) status = gl.Enum(gl.GetShaderi(fragmentShader, gl.COMPILE_STATUS)) if status != gl.TRUE { return dumpShaderError(fragmentShader, name, "vert") } gl.AttachShader(program, vertexShader) gl.AttachShader(program, fragmentShader) gl.LinkProgram(program) status = gl.Enum(gl.GetProgrami(program, gl.LINK_STATUS)) if status != gl.TRUE { return dumpProgramError(program, name) } s.vertexAttrib = gl.GetAttribLocation(program, "vertex") s.tcoordAttrib = gl.GetAttribLocation(program, "tcoord") s.program = program s.vertex = vertexShader s.fragment = fragmentShader return nil }