//NewShadowFBO will create a new FBO, a new depth texture and the program needed to generate shadow map //currently not optimized, we should probably reuse the FBO and absolutely reuse the program. func NewShadowFBO(width, height int32) (*ShadowFBO, error) { sfbo := ShadowFBO{} fbo := gl2.GenFramebuffer() sfbo.width, sfbo.height = width, height sfbo.framebuffer = fbo fbo.Bind(gl2.FRAMEBUFFER) defer fbo.Unbind(gl2.FRAMEBUFFER) shadowtex := gl2.GenTexture2D() sfbo.texture = shadowtex shadowtex.Bind() defer shadowtex.Unbind() shadowtex.TexParameteriv(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) shadowtex.TexParameteriv(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) shadowtex.TexParameteriv(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) shadowtex.TexParameteriv(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) shadowtex.TexParameteriv(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE) shadowtex.TexParameteriv(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC, gl.LEQUAL) shadowtex.TexImage2D(0, gl.DEPTH_COMPONENT16, width, height, 0, gl.DEPTH_COMPONENT, gl.FLOAT, nil) fbo.Texture(gl2.FRAMEBUFFER, gl2.DEPTH_ATTACHMENT, shadowtex, 0 /*level*/) fbo.DrawBuffer(gl2.NONE) fbo.ReadBuffer(gl2.NONE) if gl.CheckFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE { return &sfbo, errors.New("framebuffer incomplete") } vs, err := CompileShader(_shadowFboVertexShader, gl2.VERTEX_SHADER) if err != nil { return &sfbo, err } defer vs.Delete() fs, err := CompileShader(_shadowFboFragmentShader, gl2.FRAGMENT_SHADER) if err != nil { return &sfbo, err } defer fs.Delete() prog, err := NewProgram(vs, fs) if err != nil { return &sfbo, err } sfbo.program = prog prog.Use() sfbo.mvpUni = prog.GetUniformLocation("mvp") return &sfbo, nil }
func (r *EffectsRenderer) GetError() error { if e := gl.GetError(); e != 0 { return fmt.Errorf("OpenGL error: %X", e) } var status = gl.CheckFramebufferStatus(gl.DRAW_FRAMEBUFFER) switch status { case gl.FRAMEBUFFER_COMPLETE: return nil case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT: return fmt.Errorf("Attachment point unconnected") case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: return fmt.Errorf("Missing attachment") case gl.FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: return fmt.Errorf("Draw buffer") case gl.FRAMEBUFFER_INCOMPLETE_READ_BUFFER: return fmt.Errorf("Read buffer") case gl.FRAMEBUFFER_UNSUPPORTED: return fmt.Errorf("Unsupported config") default: return fmt.Errorf("Unknown framebuffer error: %X", status) } }
//NewPostProcessFramebuffer creates a new PostProcessFramebuffer and allocated all the ressources. //You do not control the vertex shader but you can give a fragment shader. The fragment shader must have the following uniforms: // -resolution: float vec2, representing the size of the texture // -time: float, glfw time since the begining of the program // -tex: sampler2D, the input texture to this post process pass func NewPostProcessFramebuffer(width, height int32, fragmentSource string) (*PostProcessFramebuffer, error) { ppf := PostProcessFramebuffer{} vs, err := CompileShader(_fullscreenVertexShader, gl2.VERTEX_SHADER) if err != nil { return &ppf, err } defer vs.Delete() fs, err := CompileShader(fragmentSource, gl2.FRAGMENT_SHADER) if err != nil { return &ppf, err } defer fs.Delete() prog, err := NewProgram(vs, fs) if err != nil { return &ppf, err } ppf.Prog = prog prog.Use() res := prog.GetUniformLocation("resolution") ppf.source = prog.GetUniformLocation("tex") res.Uniform2f(float32(width), float32(height)) ppf.time = prog.GetUniformLocation("time") ppf.Fb = gl2.GenFramebuffer() ppf.Tex = GenRGBTexture2D(width, height) ppf.Fb.Bind(gl2.FRAMEBUFFER) defer ppf.Fb.Unbind(gl2.FRAMEBUFFER) ppf.Fb.Texture(gl2.FRAMEBUFFER, gl2.COLOR_ATTACHMENT0, ppf.Tex, 0) ppf.Fb.DrawBuffers(gl2.COLOR_ATTACHMENT0) if gl.CheckFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE { return &ppf, errors.New("framebuffer incomplete") } return &ppf, nil }