| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- // Copyright 2016 The G3N 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 renderer implements the scene renderer.
- package renderer
- import "github.com/g3n/engine/gls"
- type Postprocessor struct {
- Width int32
- Height int32
- Fbo uint32
- Tex uint32
- Vao uint32
- Prg *gls.Program
- screen []float32
- Renderer *Renderer
- }
- func (r *Renderer) CreatePostprocessor(width, height int32, vertexShaderSource, fragmentShaderSource string) *Postprocessor {
- pp := &Postprocessor{
- Width: width,
- Height: height,
- Renderer: r,
- screen: []float32{
- // xyz color texture coords
- -1, 1, 0, 1, 1, 1, 0, 1,
- -1, -1, 0, 1, 1, 1, 0, 0,
- 1, -1, 0, 1, 1, 1, 1, 0,
- 1, 1, 0, 1, 1, 1, 1, 1,
- -1, 1, 0, 1, 1, 1, 0, 1,
- 1, -1, 0, 1, 1, 1, 1, 0,
- },
- }
- pp.Fbo = r.gs.GenFramebuffer()
- r.gs.BindFramebuffer(pp.Fbo)
- // set up a texture to render into
- pp.Tex = r.gs.GenTexture()
- r.gs.BindTexture(gls.TEXTURE_2D, pp.Tex)
- r.gs.TexImage2D(gls.TEXTURE_2D, 0, gls.RGB, width, height, gls.RGB, gls.UNSIGNED_BYTE, nil)
- r.gs.TexParameteri(gls.TEXTURE_2D, gls.TEXTURE_WRAP_S, gls.CLAMP_TO_EDGE)
- r.gs.TexParameteri(gls.TEXTURE_2D, gls.TEXTURE_WRAP_T, gls.CLAMP_TO_EDGE)
- r.gs.TexParameteri(gls.TEXTURE_2D, gls.TEXTURE_MIN_FILTER, gls.NEAREST)
- r.gs.TexParameteri(gls.TEXTURE_2D, gls.TEXTURE_MAG_FILTER, gls.NEAREST)
- r.gs.BindTexture(gls.TEXTURE_2D, 0)
- r.gs.FramebufferTexture2D(gls.COLOR_ATTACHMENT0, gls.TEXTURE_2D, pp.Tex)
- // attach depth and stencil buffers
- rbo := r.gs.GenRenderbuffer()
- r.gs.BindRenderbuffer(rbo)
- r.gs.RenderbufferStorage(gls.DEPTH24_STENCIL8, int(width), int(height))
- r.gs.BindRenderbuffer(0)
- r.gs.FramebufferRenderbuffer(gls.DEPTH_STENCIL_ATTACHMENT, rbo)
- // check the framebuffer status
- if r.gs.CheckFramebufferStatus() != gls.FRAMEBUFFER_COMPLETE {
- log.Fatal("Can't create frame buffer")
- }
- r.gs.BindFramebuffer(0)
- // create the "screen" quad
- vbo := r.gs.GenBuffer()
- r.gs.BindBuffer(gls.ARRAY_BUFFER, vbo)
- r.gs.BufferData(gls.ARRAY_BUFFER, 4*len(pp.screen), pp.screen, gls.STATIC_DRAW)
- pp.Vao = r.gs.GenVertexArray()
- r.gs.BindVertexArray(pp.Vao)
- r.gs.BindBuffer(gls.ARRAY_BUFFER, vbo)
- var offset uint32
- // position attribute
- r.gs.VertexAttribPointer(0, 3, gls.FLOAT, false, 8*4, offset)
- r.gs.EnableVertexAttribArray(0)
- offset += 3 * 4
- // color attribute
- r.gs.VertexAttribPointer(1, 3, gls.FLOAT, false, 8*4, offset)
- r.gs.EnableVertexAttribArray(1)
- offset += 3 * 4
- // texture coord attribute
- r.gs.VertexAttribPointer(2, 2, gls.FLOAT, false, 8*4, offset)
- r.gs.EnableVertexAttribArray(2)
- offset += 2 * 4
- // the screen shaders
- pp.Prg = r.gs.NewProgram()
- pp.Prg.AddShader(gls.VERTEX_SHADER, vertexShaderSource)
- pp.Prg.AddShader(gls.FRAGMENT_SHADER, fragmentShaderSource)
- err := pp.Prg.Build()
- if err != nil {
- log.Fatal("can't create shader: %e", err)
- }
- return pp
- }
- func (pp *Postprocessor) Render(fbwidth, fbheight int, render func()) {
- // render into the low-res texture
- gs := pp.Renderer.gs
- gs.Viewport(0, 0, pp.Width, pp.Height)
- gs.BindFramebuffer(pp.Fbo)
- gs.Enable(gls.DEPTH_TEST)
- render()
- // show texture on screen
- gs.Viewport(0, 0, int32(fbwidth), int32(fbheight))
- gs.BindFramebuffer(0)
- gs.ClearColor(1, 1, 1, 1)
- gs.Clear(gls.COLOR_BUFFER_BIT)
- gs.UseProgram(pp.Prg)
- gs.Disable(gls.DEPTH_TEST)
- gs.BindTexture(gls.TEXTURE_2D, pp.Tex)
- gs.BindVertexArray(pp.Vao)
- gs.DrawArrays(gls.TRIANGLES, 0, int32(len(pp.screen)/8))
- }
|