1 #include "picture_renderer.hpp"
2 #include "canvas_gl.hpp"
3 #include "gl_util.hpp"
4 #include "util/picture_util.hpp"
5 #include <glm/gtc/type_ptr.hpp>
6 
7 namespace horizon {
create_vao(GLuint program)8 static GLuint create_vao(GLuint program)
9 {
10     GLuint vao, buffer;
11     GLuint position_index = glGetAttribLocation(program, "position");
12 
13 
14     /* we need to create a VAO to store the other buffers */
15     glGenVertexArrays(1, &vao);
16     glBindVertexArray(vao);
17 
18     /* this is the VBO that holds the vertex data */
19     glGenBuffers(1, &buffer);
20     glBindBuffer(GL_ARRAY_BUFFER, buffer);
21     // data is buffered lateron
22 
23     float vertices[] = {//   Position
24                         -1, 1, 1, 1, -1, -1, 1, -1};
25     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
26 
27     /* enable and set the position attribute */
28     glEnableVertexAttribArray(position_index);
29     glVertexAttribPointer(position_index, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
30 
31     /* enable and set the color attribute */
32     /* reset the state; we will re-enable the VAO when needed */
33     glBindBuffer(GL_ARRAY_BUFFER, 0);
34     glBindVertexArray(0);
35 
36     return vao;
37 }
38 
PictureRenderer(const CanvasGL & c)39 PictureRenderer::PictureRenderer(const CanvasGL &c) : ca(c)
40 {
41 }
42 
realize()43 void PictureRenderer::realize()
44 {
45     program = gl_create_program_from_resource(
46             "/org/horizon-eda/horizon/canvas/shaders/"
47             "picture-vertex.glsl",
48             "/org/horizon-eda/horizon/canvas/shaders/"
49             "picture-fragment.glsl",
50             nullptr);
51     vao = create_vao(program);
52 
53     GET_LOC(this, screenmat);
54     GET_LOC(this, viewmat);
55     GET_LOC(this, scale);
56     GET_LOC(this, size);
57     GET_LOC(this, shift);
58     GET_LOC(this, angle);
59     GET_LOC(this, tex);
60     GET_LOC(this, opacity);
61 }
62 
render(bool on_top)63 void PictureRenderer::render(bool on_top)
64 {
65     glUseProgram(program);
66     glBindVertexArray(vao);
67     glUniformMatrix3fv(screenmat_loc, 1, GL_FALSE, glm::value_ptr(ca.screenmat));
68     glUniformMatrix3fv(viewmat_loc, 1, GL_FALSE, glm::value_ptr(ca.viewmat));
69     glUniform1f(scale_loc, ca.scale);
70 
71     glActiveTexture(GL_TEXTURE1);
72     glUniform1i(tex_loc, 1);
73 
74     for (const auto &it : ca.pictures) {
75         if (it.on_top == on_top) {
76             const auto &tex = textures.at(it.data->uuid);
77             glBindTexture(GL_TEXTURE_2D, tex.second);
78             glUniform2f(shift_loc, it.x, it.y);
79             glUniform2f(size_loc, tex.first->width * it.px_size / 2, tex.first->height * it.px_size / 2);
80             glUniform1f(angle_loc, it.angle);
81             glUniform1f(opacity_loc, it.opacity);
82 
83             glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
84         }
85     }
86 
87 
88     glBindVertexArray(0);
89     glUseProgram(0);
90 }
91 
cache_picture(std::shared_ptr<const PictureData> d)92 void PictureRenderer::cache_picture(std::shared_ptr<const PictureData> d)
93 {
94     if (textures.count(d->uuid))
95         return;
96     GLuint tex = 0;
97     glGenTextures(1, &tex);
98     glActiveTexture(GL_TEXTURE1);
99     glBindTexture(GL_TEXTURE_2D, tex);
100     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, d->width, d->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, d->data.data());
101     glGenerateMipmap(GL_TEXTURE_2D);
102     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
103     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
104     textures.emplace(std::piecewise_construct, std::forward_as_tuple(d->uuid), std::forward_as_tuple(d, tex));
105 }
106 
uncache_picture(const UUID & uu)107 void PictureRenderer::uncache_picture(const UUID &uu)
108 {
109     glDeleteTextures(1, &textures.at(uu).second);
110     textures.erase(uu);
111 }
112 
push()113 void PictureRenderer::push()
114 {
115     std::set<UUID> pics_to_evict, pics_needed;
116     for (const auto &it : ca.pictures) {
117         if (!textures.count(it.data->uuid))
118             cache_picture(it.data);
119         pics_needed.insert(it.data->uuid);
120     }
121     for (const auto &it : textures) {
122         if (!pics_needed.count(it.first))
123             pics_to_evict.insert(it.first);
124     }
125     for (const auto &it : pics_to_evict) {
126         uncache_picture(it);
127     }
128 }
129 
130 } // namespace horizon
131