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