func (s *shaderProgram) bind(ctx *context, vb *vertexBuffer, uniforms uniformBindings) { gl.UseProgram(s.program) 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.ty != vs.ty { panic(fmt.Errorf("Attribute '%s' type '%s' does not match stream type '%s'", a.name, a.ty, vs.ty)) } elementCount := a.ty.vectorElementCount() elementTy := a.ty.vectorElementType() ctx.getOrCreateVertexStreamContext(vs).bind() a.enableArray() a.attribPointer(int32(elementCount), uint32(elementTy), false, 0, 0) } for _, u := range s.uniforms { v, found := uniforms[u.name] if !found { panic(fmt.Errorf("Uniforms missing '%s'", u.name)) } u.bind(ctx, v) } checkError() }
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 (p *glParams) renderFlush() { c := p.context if len(c.calls) > 0 { gl.UseProgram(c.shader.program) gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) gl.Enable(gl.CULL_FACE) gl.CullFace(gl.BACK) gl.FrontFace(gl.CCW) gl.Enable(gl.BLEND) gl.Disable(gl.DEPTH_TEST) gl.Disable(gl.SCISSOR_TEST) gl.ColorMask(true, true, true, true) gl.StencilMask(0xffffffff) gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP) gl.StencilFunc(gl.ALWAYS, 0, 0xffffffff) gl.ActiveTexture(gl.TEXTURE0) gl.BindTexture(gl.TEXTURE_2D, gl.Texture{}) c.stencilMask = 0xffffffff c.stencilFunc = gl.ALWAYS c.stencilFuncRef = 0 c.stencilFuncMask = 0xffffffff b := castFloat32ToByte(c.vertexes) //dumpLog("vertex:", c.vertexes) // Upload vertex data gl.BindBuffer(gl.ARRAY_BUFFER, c.vertexBuffer) gl.BufferData(gl.ARRAY_BUFFER, b, gl.STREAM_DRAW) gl.EnableVertexAttribArray(c.shader.vertexAttrib) gl.EnableVertexAttribArray(c.shader.tcoordAttrib) gl.VertexAttribPointer(c.shader.vertexAttrib, 2, gl.FLOAT, false, 4*4, 0) gl.VertexAttribPointer(c.shader.tcoordAttrib, 2, gl.FLOAT, false, 4*4, 8) // Set view and texture just once per frame. gl.Uniform1i(c.shader.locations[glnvgLocTEX], 0) gl.Uniform2fv(c.shader.locations[glnvgLocVIEWSIZE], c.view[:]) for i := range c.calls { call := &c.calls[i] switch call.callType { case glnvgFILL: c.fill(call) case glnvgCONVEXFILL: c.convexFill(call) case glnvgSTROKE: c.stroke(call) case glnvgTRIANGLES: c.triangles(call) } } gl.DisableVertexAttribArray(c.shader.vertexAttrib) gl.DisableVertexAttribArray(c.shader.tcoordAttrib) gl.Disable(gl.CULL_FACE) gl.BindBuffer(gl.ARRAY_BUFFER, gl.Buffer{}) gl.UseProgram(gl.Program{}) c.bindTexture(nil) } c.vertexes = c.vertexes[:0] c.paths = c.paths[:0] c.calls = c.calls[:0] c.uniforms = c.uniforms[:0] }