Skip to content

Commit

Permalink
Merge pull request #2193 from wily-coyote/gl-shader-stacking
Browse files Browse the repository at this point in the history
feat(gl): proper shader stacking
  • Loading branch information
K4thos authored Dec 18, 2024
2 parents 3afee7f + 1ca2f81 commit cf41622
Show file tree
Hide file tree
Showing 2 changed files with 246 additions and 69 deletions.
148 changes: 118 additions & 30 deletions src/render_gl.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,9 @@ type Renderer_GL21 struct {
cubemapFilteringShader *ShaderProgram_GL21
stageVertexBuffer uint32
stageIndexBuffer uint32
// Postprocessing
fbo_pp uint32
fbo_pp_texture uint32

enableModel bool
enableShadow bool
Expand Down Expand Up @@ -457,6 +460,8 @@ func (r *Renderer_GL21) Init() {
}

gl.ActiveTexture(gl.TEXTURE0)

// create a texture for r.fbo
gl.GenTextures(1, &r.fbo_texture)

if sys.multisampleAntialiasing > 0 {
Expand All @@ -469,13 +474,52 @@ func (r *Renderer_GL21) Init() {
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)


// Shaders might use negative values, so
// we specify that we want signed pixels
if sys.multisampleAntialiasing > 0 {
gl.TexImage2DMultisample(gl.TEXTURE_2D_MULTISAMPLE, sys.multisampleAntialiasing, gl.RGBA, sys.scrrect[2], sys.scrrect[3], true)
gl.TexImage2DMultisample(
gl.TEXTURE_2D_MULTISAMPLE,
sys.multisampleAntialiasing,
gl.RGBA8_SNORM,
sys.scrrect[2],
sys.scrrect[3],
true,
)
} else {
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sys.scrrect[2], sys.scrrect[3], 0, gl.RGBA, gl.UNSIGNED_BYTE, nil)
gl.TexImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA8_SNORM,
sys.scrrect[2],
sys.scrrect[3],
0,
gl.RGBA,
gl.UNSIGNED_BYTE,
nil,
)
}

// r.fbo_pp_texture
gl.GenTextures(1, &r.fbo_pp_texture)
gl.BindTexture(gl.TEXTURE_2D, r.fbo_pp_texture)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
gl.TexImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA8_SNORM,
sys.scrrect[2],
sys.scrrect[3],
0,
gl.RGBA,
gl.UNSIGNED_BYTE,
nil,
)

// done with r.fbo_texture, unbind it
gl.BindTexture(gl.TEXTURE_2D, 0)

//r.rbo_depth = gl.CreateRenderbuffer()
Expand All @@ -499,6 +543,7 @@ func (r *Renderer_GL21) Init() {
//gl.BindRenderbuffer(gl.RENDERBUFFER, gl.NoRenderbuffer)
}

// create an FBO for our r.fbo, which is then for r.fbo_texture
gl.GenFramebuffers(1, &r.fbo)
gl.BindFramebuffer(gl.FRAMEBUFFER, r.fbo)

Expand All @@ -516,6 +561,13 @@ func (r *Renderer_GL21) Init() {
gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, r.fbo_texture, 0)
gl.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, r.rbo_depth)
}

// create an FBO for our postprocessing needs
gl.GenFramebuffers(1, &r.fbo_pp)
gl.BindFramebuffer(gl.FRAMEBUFFER, r.fbo_pp)
gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, r.fbo_pp_texture, 0)

// create an FBO for our model stuff
if r.enableModel {
if r.enableShadow {
gl.GenFramebuffersEXT(1, &r.fbo_shadow)
Expand Down Expand Up @@ -572,51 +624,87 @@ func (r *Renderer_GL21) BlendReset() {
gl.BlendFunc(r.MapBlendFunction(BlendSrcAlpha), r.MapBlendFunction(BlendOneMinusSrcAlpha))
}
func (r *Renderer_GL21) EndFrame() {
x, y, width, height := int32(0), int32(0), int32(sys.scrrect[2]), int32(sys.scrrect[3])
time := glfw.GetTime() // consistent time across all shaders

if sys.multisampleAntialiasing > 0 {
gl.BindFramebuffer(gl.DRAW_FRAMEBUFFER, r.fbo_f)
gl.BindFramebuffer(gl.READ_FRAMEBUFFER, r.fbo)
gl.BlitFramebuffer(0, 0, sys.scrrect[2], sys.scrrect[3], 0, 0, sys.scrrect[2], sys.scrrect[3], gl.COLOR_BUFFER_BIT, gl.LINEAR)
gl.BlitFramebuffer(x, y, width, height, x, y, width, height, gl.COLOR_BUFFER_BIT, gl.LINEAR)
}

x, y, resizedWidth, resizedHeight := sys.window.GetScaledViewportSize()
postShader := r.postShaderSelect[len(sys.externalShaderList)]

var scaleMode int32 // GL enum
if sys.windowScaleMode == true {
if sys.windowScaleMode {
scaleMode = gl.LINEAR
} else {
scaleMode = gl.NEAREST
}

gl.Viewport(x, y, int32(resizedWidth), int32(resizedHeight))
gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
// set the viewport to the unscaled bounds for post-processing
gl.Viewport(x, y, width, height)
gl.BindFramebuffer(gl.FRAMEBUFFER, r.fbo_pp) // our postprocessing FBO is the output
gl.Clear(gl.COLOR_BUFFER_BIT) // clear that FBO
gl.ActiveTexture(gl.TEXTURE0) // later referred to by Texture_GL32

gl.UseProgram(postShader.program)
gl.Disable(gl.BLEND)

gl.ActiveTexture(gl.TEXTURE0)
fbo := r.fbo
fbo_texture := r.fbo_texture
if sys.multisampleAntialiasing > 0 {
gl.BindTexture(gl.TEXTURE_2D, r.fbo_f_texture.handle)
} else {
gl.BindTexture(gl.TEXTURE_2D, r.fbo_texture)
fbo = r.fbo_f
fbo_texture = r.fbo_f_texture.handle
}

// set post-processing parameters
gl.Uniform1i(postShader.u["Texture_GL21"], 0)
gl.Uniform2f(postShader.u["TextureSize"], float32(resizedWidth), float32(resizedHeight))
gl.Uniform1f(postShader.u["CurrentTime"], float32(glfw.GetTime()))
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, scaleMode)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, scaleMode)
// disable blending
gl.Disable(gl.BLEND)

gl.BindBuffer(gl.ARRAY_BUFFER, r.postVertBuffer)
for i := 0; i < len(r.postShaderSelect); i++ {
postShader := r.postShaderSelect[i]

// this is here because it is undefined
// behavior to write to the same FBO
if(i%2==0){
// ping!
gl.BindFramebuffer(gl.FRAMEBUFFER, r.fbo_pp) // our post-processing FBO is the output
gl.BindTexture(gl.TEXTURE_2D, fbo_texture) // the previous texture is our input
} else {
// pong!
gl.BindFramebuffer(gl.FRAMEBUFFER, fbo) // the reverse
gl.BindTexture(gl.TEXTURE_2D, r.fbo_pp_texture)
}

loc := postShader.a["VertCoord"]
gl.EnableVertexAttribArray(uint32(loc))
gl.VertexAttribPointerWithOffset(uint32(loc), 2, gl.FLOAT, false, 0, 0)
if(i >= len(r.postShaderSelect)-1){
// this is the last shader,
// so we ask GL to scale it and output it
// to FB0, the default frame buffer that the user sees
x, y, width, height := sys.window.GetScaledViewportSize()
gl.Viewport(x, y, width, height)
gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
// clear FB0 just to make sure
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
}

gl.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)
gl.DisableVertexAttribArray(uint32(loc))
// tell GL we want to use our shader program
gl.UseProgram(postShader.program)

// set post-processing parameters
gl.Uniform1i(postShader.u["Texture_GL21"], 0)
gl.Uniform2f(postShader.u["TextureSize"], float32(width), float32(height))
gl.Uniform1f(postShader.u["CurrentTime"], float32(time))
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, scaleMode)
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, scaleMode)

// this actually draws the image to the FBO
// by constructing a quad (2 tris)
gl.BindBuffer(gl.ARRAY_BUFFER, r.postVertBuffer)

// construct the UVs of the quad
loc := postShader.a["VertCoord"]
gl.EnableVertexAttribArray(uint32(loc))
gl.VertexAttribPointer(uint32(loc), 2, gl.FLOAT, false, 0, nil)

// construct the quad and draw it
gl.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)
gl.DisableVertexAttribArray(uint32(loc))
}
}

func (r *Renderer_GL21) Await() {
Expand Down
Loading

0 comments on commit cf41622

Please sign in to comment.