Files
MapLibreParticleLab/test/util/offscreen_texture.test.cpp
2016-10-25 13:52:36 -07:00

156 lines
5.4 KiB
C++

#include <mbgl/test/util.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/platform/default/headless_backend.hpp>
#include <mbgl/platform/default/offscreen_view.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/util/offscreen_texture.hpp>
using namespace mbgl;
TEST(OffscreenTexture, EmptyRed) {
HeadlessBackend backend;
OffscreenView view(backend.getContext(), {{ 512, 256 }});
view.bind();
MBGL_CHECK_ERROR(glClearColor(1.0f, 0.0f, 0.0f, 1.0f));
MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
auto image = view.readStillImage();
test::checkImage("test/fixtures/offscreen_texture/empty-red", image, 0, 0);
}
struct Shader {
Shader(const GLchar* vertex, const GLchar* fragment) {
program = MBGL_CHECK_ERROR(glCreateProgram());
vertexShader = MBGL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER));
fragmentShader = MBGL_CHECK_ERROR(glCreateShader(GL_FRAGMENT_SHADER));
MBGL_CHECK_ERROR(glShaderSource(vertexShader, 1, &vertex, nullptr));
MBGL_CHECK_ERROR(glCompileShader(vertexShader));
MBGL_CHECK_ERROR(glAttachShader(program, vertexShader));
MBGL_CHECK_ERROR(glShaderSource(fragmentShader, 1, &fragment, nullptr));
MBGL_CHECK_ERROR(glCompileShader(fragmentShader));
MBGL_CHECK_ERROR(glAttachShader(program, fragmentShader));
MBGL_CHECK_ERROR(glLinkProgram(program));
a_pos = glGetAttribLocation(program, "a_pos");
}
~Shader() {
MBGL_CHECK_ERROR(glDetachShader(program, vertexShader));
MBGL_CHECK_ERROR(glDetachShader(program, fragmentShader));
MBGL_CHECK_ERROR(glDeleteShader(vertexShader));
MBGL_CHECK_ERROR(glDeleteShader(fragmentShader));
MBGL_CHECK_ERROR(glDeleteProgram(program));
}
GLuint program = 0;
GLuint vertexShader = 0;
GLuint fragmentShader = 0;
GLuint a_pos = 0;
};
struct Buffer {
Buffer(std::vector<GLfloat> data) {
MBGL_CHECK_ERROR(glGenBuffers(1, &buffer));
MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer));
MBGL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(GLfloat), data.data(),
GL_STATIC_DRAW));
}
~Buffer() {
MBGL_CHECK_ERROR(glDeleteBuffers(1, &buffer));
}
GLuint buffer = 0;
};
TEST(OffscreenTexture, RenderToTexture) {
HeadlessBackend backend;
auto& context = backend.getContext();
MBGL_CHECK_ERROR(glEnable(GL_BLEND));
MBGL_CHECK_ERROR(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
Shader paintShader(R"MBGL_SHADER(
attribute vec2 a_pos;
void main() {
gl_Position = vec4(a_pos, 0, 1);
}
)MBGL_SHADER", R"MBGL_SHADER(
void main() {
gl_FragColor = vec4(0, 0.8, 0, 0.8);
}
)MBGL_SHADER");
Shader compositeShader(R"MBGL_SHADER(
attribute vec2 a_pos;
varying vec2 v_texcoord;
void main() {
gl_Position = vec4(a_pos, 0, 1);
v_texcoord = (a_pos + 1.0) / 2.0;
}
)MBGL_SHADER", R"MBGL_SHADER(
uniform sampler2D u_texture;
varying vec2 v_texcoord;
void main() {
gl_FragColor = texture2D(u_texture, v_texcoord);
}
)MBGL_SHADER");
GLuint u_texture = glGetUniformLocation(compositeShader.program, "u_texture");
Buffer triangleBuffer({ 0, 0.5, 0.5, -0.5, -0.5, -0.5 });
Buffer viewportBuffer({ -1, -1, 1, -1, -1, 1, 1, 1 });
// Make sure the texture gets destructed before we call context.reset();
{
OffscreenView view(context, {{ 512, 256 }});
// First, draw red to the bound FBO.
context.clearColor = { 1, 0, 0, 1 };
view.bind();
MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
// Then, create a texture, bind it, and render yellow to that texture. This should not
// affect the originally bound FBO.
OffscreenTexture texture(context, {{ 128, 128 }});
texture.bind();
context.clearColor = { 0, 0, 0, 0 };
MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
context.program = paintShader.program;
MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, triangleBuffer.buffer));
MBGL_CHECK_ERROR(glEnableVertexAttribArray(paintShader.a_pos));
MBGL_CHECK_ERROR(
glVertexAttribPointer(paintShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr));
MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 3));
auto image = texture.readStillImage();
test::checkImage("test/fixtures/offscreen_texture/render-to-texture", image, 0, 0);
// Now reset the FBO back to normal and retrieve the original (restored) framebuffer.
view.bind();
image = view.readStillImage();
test::checkImage("test/fixtures/offscreen_texture/render-to-fbo", image, 0, 0);
// Now, composite the Framebuffer texture we've rendered to onto the main FBO.
context.program = compositeShader.program;
context.bindTexture(texture.getTexture(), 0, gl::TextureFilter::Linear);
MBGL_CHECK_ERROR(glUniform1i(u_texture, 0));
MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, viewportBuffer.buffer));
MBGL_CHECK_ERROR(glEnableVertexAttribArray(compositeShader.a_pos));
MBGL_CHECK_ERROR(
glVertexAttribPointer(compositeShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr));
MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
image = view.readStillImage();
test::checkImage("test/fixtures/offscreen_texture/render-to-fbo-composited", image, 0, 0.1);
}
context.reset();
}