diff --git a/src/Makefile.am b/src/Makefile.am index c31204a8..b3300841 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -99,6 +99,7 @@ liblol_core_sources = \ gpu/tile.lolfx gpu/palette.lolfx gpu/line.lolfx \ gpu/emptymaterial.lolfx \ gpu/testmaterial.lolfx \ + gpu/blit.lolfx \ gpu/postprocess.lolfx \ \ gpu/lolfx.cpp \ diff --git a/src/gpu/blit.lolfx b/src/gpu/blit.lolfx new file mode 100644 index 00000000..f5ce2e4e --- /dev/null +++ b/src/gpu/blit.lolfx @@ -0,0 +1,33 @@ +[vert.glsl] + +#version 130 + +in vec2 in_position; +out vec2 pass_position; + +void main() +{ + pass_position = in_position; + gl_Position = vec4(in_position, 0.0, 1.0); +} + +[frag.glsl] + +#version 130 + +#if defined GL_ES +precision highp float; +#endif + +uniform sampler2D u_buffer; + +in vec2 pass_position; +out vec4 out_color; + +void main(void) +{ + vec2 pos = pass_position; + vec2 texcoords = pos * 0.5 + vec2(0.5, 0.5); + out_color = vec4(texture2D(u_buffer, texcoords).rgb, 1); +} + diff --git a/src/gpu/postprocess.lolfx b/src/gpu/postprocess.lolfx index a4810768..b6b91a2c 100644 --- a/src/gpu/postprocess.lolfx +++ b/src/gpu/postprocess.lolfx @@ -1,35 +1,44 @@ [vert.glsl] -#version 120 +#version 130 -attribute vec2 in_Position; - -varying vec2 pass_Position; +in vec2 in_position; +out vec2 pass_position; void main() { - pass_Position = in_Position; - gl_Position = vec4(in_Position, 0.0, 1.0); + pass_position = in_position; + gl_Position = vec4(in_position, 0.0, 1.0); } [frag.glsl] -#version 120 +#version 130 #if defined GL_ES precision highp float; #endif -uniform sampler2D u_texture; +uniform sampler2D u_buffer; +uniform sampler2D u_prev_buffer; +uniform sampler2D u_prev_final; -varying vec2 pass_Position; +in vec2 pass_position; +out vec4 out_color; void main(void) { - vec2 pos = pass_Position; + vec2 pos = pass_position; vec2 texcoords = pos * 0.5 + vec2(0.5, 0.5); - vec4 color = vec4(texture2D(u_texture, texcoords).rgb, 1.0); - gl_FragColor = color; + vec4 color = vec4(texture2D(u_buffer, texcoords).rgb, 1.0); + vec4 prev_color = vec4(texture2D(u_prev_buffer, texcoords).rgb, 1.0); + + /* (do stuff with color here) */ + vec4 final_color = mix(color, prev_color, 0.01); + + /* Blend final color with previous frame’s final color */ + vec4 prev_final_color = vec4(texture2D(u_prev_final, texcoords).rgb, 1.0); + out_color = mix(final_color, prev_final_color, vec4(0.5) + 0.3 * (prev_final_color - final_color)); } diff --git a/src/lol-core.vcxproj b/src/lol-core.vcxproj index d3477f45..5b0cbbcf 100644 --- a/src/lol-core.vcxproj +++ b/src/lol-core.vcxproj @@ -366,6 +366,7 @@ + diff --git a/src/scene.cpp b/src/scene.cpp index 6505abaa..b0821510 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -26,6 +26,8 @@ LOLFX_RESOURCE_DECLARE(tile); LOLFX_RESOURCE_DECLARE(palette); LOLFX_RESOURCE_DECLARE(line); + +LOLFX_RESOURCE_DECLARE(blit); LOLFX_RESOURCE_DECLARE(postprocess); namespace lol @@ -136,16 +138,16 @@ private: * the default one created by the app will be used */ SceneDisplay* m_display = nullptr; - /** Back buffer: where to render to. */ - Framebuffer *m_backbuffer = nullptr; + /** Render buffers: where to render to. */ + Framebuffer *m_renderbuffer[4]; struct postprocess { - Shader *m_shader = nullptr; + Shader *m_shader[2]; VertexBuffer *m_vbo = nullptr; VertexDeclaration *m_vdecl = nullptr; - ShaderUniform m_texture; - ShaderAttrib m_coord; + ShaderUniform m_buffer_uni[2][3]; + ShaderAttrib m_coord[2]; } m_pp; @@ -201,11 +203,19 @@ mutex SceneData::m_prim_mutex; Scene::Scene(ivec2 size) : data(new SceneData()) { - data->m_backbuffer = new Framebuffer(size); - data->m_pp.m_shader = Shader::Create(LOLFX_RESOURCE_NAME(postprocess)); - data->m_pp.m_coord = data->m_pp.m_shader->GetAttribLocation(VertexUsage::Position, 0); + data->m_renderbuffer[0] = new Framebuffer(size); + data->m_renderbuffer[1] = new Framebuffer(size); + data->m_renderbuffer[2] = new Framebuffer(size); + data->m_renderbuffer[3] = new Framebuffer(size); + data->m_pp.m_shader[0] = Shader::Create(LOLFX_RESOURCE_NAME(blit)); + data->m_pp.m_shader[1] = Shader::Create(LOLFX_RESOURCE_NAME(postprocess)); + data->m_pp.m_coord[0] = data->m_pp.m_shader[0]->GetAttribLocation(VertexUsage::Position, 0); + data->m_pp.m_coord[1] = data->m_pp.m_shader[1]->GetAttribLocation(VertexUsage::Position, 0); data->m_pp.m_vdecl = new VertexDeclaration(VertexStream(VertexUsage::Position)); - data->m_pp.m_texture = data->m_pp.m_shader->GetUniformLocation("u_texture"); + data->m_pp.m_buffer_uni[0][0] = data->m_pp.m_shader[0]->GetUniformLocation("u_buffer"); + data->m_pp.m_buffer_uni[1][0] = data->m_pp.m_shader[1]->GetUniformLocation("u_buffer"); + data->m_pp.m_buffer_uni[1][1] = data->m_pp.m_shader[1]->GetUniformLocation("u_prev_buffer"); + data->m_pp.m_buffer_uni[1][2] = data->m_pp.m_shader[1]->GetUniformLocation("u_prev_final"); array quad { vec2( 1.0, 1.0), vec2(-1.0, -1.0), vec2( 1.0, -1.0), vec2(-1.0, -1.0), vec2( 1.0, 1.0), vec2(-1.0, 1.0), }; @@ -621,7 +631,9 @@ void Scene::render(float seconds) /* First render into the offline buffer */ if (do_pp) - data->m_backbuffer->Bind(); + { + data->m_renderbuffer[0]->Bind(); + } { RenderContext rc; @@ -641,18 +653,55 @@ void Scene::render(float seconds) if (do_pp) { - data->m_backbuffer->Unbind(); + data->m_renderbuffer[0]->Unbind(); gpu_marker("PostProcess"); - /* Now blit the offline buffer */ - data->m_pp.m_shader->Bind(); - data->m_pp.m_shader->SetUniform(data->m_pp.m_texture, data->m_backbuffer->GetTextureUniform(), 0); - data->m_pp.m_vdecl->SetStream(data->m_pp.m_vbo, data->m_pp.m_coord); + data->m_renderbuffer[3]->Bind(); + + RenderContext rc; + rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f)); + rc.SetClearDepth(1.f); + Renderer::Get()->Clear(ClearMask::Color | ClearMask::Depth); + + /* Execute post process */ + data->m_pp.m_shader[1]->Bind(); + data->m_pp.m_shader[1]->SetUniform(data->m_pp.m_buffer_uni[1][0], data->m_renderbuffer[0]->GetTextureUniform(), 0); + data->m_pp.m_shader[1]->SetUniform(data->m_pp.m_buffer_uni[1][1], data->m_renderbuffer[1]->GetTextureUniform(), 1); + data->m_pp.m_shader[1]->SetUniform(data->m_pp.m_buffer_uni[1][2], data->m_renderbuffer[2]->GetTextureUniform(), 2); + data->m_pp.m_vdecl->SetStream(data->m_pp.m_vbo, data->m_pp.m_coord[1]); + data->m_pp.m_vdecl->Bind(); + data->m_pp.m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6); + data->m_pp.m_vdecl->Unbind(); + data->m_pp.m_shader[1]->Unbind(); + data->m_renderbuffer[3]->Unbind(); + } + + if (do_pp) + { + gpu_marker("Blit frame"); + + data->m_pp.m_shader[0]->Bind(); + + RenderContext rc; + rc.SetClearColor(vec4(0.f, 0.f, 0.f, 1.f)); + rc.SetClearDepth(1.f); + Renderer::Get()->Clear(ClearMask::Color | ClearMask::Depth); + + /* Blit final image to screen */ + data->m_pp.m_shader[0]->SetUniform(data->m_pp.m_buffer_uni[0][0], data->m_renderbuffer[3]->GetTextureUniform(), 3); + data->m_pp.m_vdecl->SetStream(data->m_pp.m_vbo, data->m_pp.m_coord[0]); data->m_pp.m_vdecl->Bind(); data->m_pp.m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, 6); data->m_pp.m_vdecl->Unbind(); - data->m_pp.m_shader->Unbind(); + data->m_pp.m_shader[0]->Unbind(); + } + + if (do_pp) + { + /* Swap back buffers */ + std::swap(data->m_renderbuffer[0], data->m_renderbuffer[1]); + std::swap(data->m_renderbuffer[2], data->m_renderbuffer[3]); } gpu_marker("End Render"); @@ -794,7 +843,6 @@ void Scene::render_tiles() // XXX: rename to Blit() shader->Unbind(); } - #if (defined LOL_USE_GLEW || defined HAVE_GL_2X) && !defined HAVE_GLES_2X glDisable(GL_TEXTURE_2D); #endif