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