#include "picture_renderer.hpp" #include "canvas_gl.hpp" #include "gl_util.hpp" #include "util/picture_util.hpp" #include namespace horizon { static GLuint create_vao(GLuint program) { GLuint vao, buffer; GLuint position_index = glGetAttribLocation(program, "position"); /* we need to create a VAO to store the other buffers */ glGenVertexArrays(1, &vao); glBindVertexArray(vao); /* this is the VBO that holds the vertex data */ glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); // data is buffered lateron float vertices[] = {// Position -1, 1, 1, 1, -1, -1, 1, -1}; glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); /* enable and set the position attribute */ glEnableVertexAttribArray(position_index); glVertexAttribPointer(position_index, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0); /* enable and set the color attribute */ /* reset the state; we will re-enable the VAO when needed */ glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); return vao; } PictureRenderer::PictureRenderer(const CanvasGL &c) : ca(c) { } void PictureRenderer::realize() { program = gl_create_program_from_resource( "/org/horizon-eda/horizon/canvas/shaders/" "picture-vertex.glsl", "/org/horizon-eda/horizon/canvas/shaders/" "picture-fragment.glsl", nullptr); vao = create_vao(program); GET_LOC(this, screenmat); GET_LOC(this, viewmat); GET_LOC(this, scale); GET_LOC(this, size); GET_LOC(this, shift); GET_LOC(this, angle); GET_LOC(this, tex); GET_LOC(this, opacity); } void PictureRenderer::render(bool on_top) { glUseProgram(program); glBindVertexArray(vao); glUniformMatrix3fv(screenmat_loc, 1, GL_FALSE, glm::value_ptr(ca.screenmat)); glUniformMatrix3fv(viewmat_loc, 1, GL_FALSE, glm::value_ptr(ca.viewmat)); glUniform1f(scale_loc, ca.scale); glActiveTexture(GL_TEXTURE1); glUniform1i(tex_loc, 1); for (const auto &it : ca.pictures) { if (it.on_top == on_top) { const auto &tex = textures.at(it.data->uuid); glBindTexture(GL_TEXTURE_2D, tex.second); glUniform2f(shift_loc, it.x, it.y); glUniform2f(size_loc, tex.first->width * it.px_size / 2, tex.first->height * it.px_size / 2); glUniform1f(angle_loc, it.angle); glUniform1f(opacity_loc, it.opacity); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } } glBindVertexArray(0); glUseProgram(0); } void PictureRenderer::cache_picture(std::shared_ptr d) { if (textures.count(d->uuid)) return; GLuint tex = 0; glGenTextures(1, &tex); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, tex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, d->width, d->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, d->data.data()); glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); textures.emplace(std::piecewise_construct, std::forward_as_tuple(d->uuid), std::forward_as_tuple(d, tex)); } void PictureRenderer::uncache_picture(const UUID &uu) { glDeleteTextures(1, &textures.at(uu).second); textures.erase(uu); } void PictureRenderer::push() { std::set pics_to_evict, pics_needed; for (const auto &it : ca.pictures) { if (!textures.count(it.data->uuid)) cache_picture(it.data); pics_needed.insert(it.data->uuid); } for (const auto &it : textures) { if (!pics_needed.count(it.first)) pics_to_evict.insert(it.first); } for (const auto &it : pics_to_evict) { uncache_picture(it); } } } // namespace horizon