1 #include "grid.hpp"
2 #include "canvas_gl.hpp"
3 #include "gl_util.hpp"
4 #include <glm/gtc/type_ptr.hpp>
5 #include "util/bbox_accumulator.hpp"
6 
7 namespace horizon {
Grid(const CanvasGL & c)8 Grid::Grid(const CanvasGL &c) : ca(c), spacing(1.25_mm, 1.25_mm), mark_size(5)
9 {
10 }
11 
create_vao(GLuint program)12 static GLuint create_vao(GLuint program)
13 {
14     GLuint position_index = glGetAttribLocation(program, "position");
15     GLuint vao, buffer;
16 
17     /* we need to create a VAO to store the other buffers */
18     glGenVertexArrays(1, &vao);
19     glBindVertexArray(vao);
20 
21     /* this is the VBO that holds the vertex data */
22     glGenBuffers(1, &buffer);
23     glBindBuffer(GL_ARRAY_BUFFER, buffer);
24     // data is buffered lateron
25 
26     static const GLfloat vertices[] = {
27             0, -1, 0, 1, -1, 0, 1, 0, .2, -.2, -.2, -.2, -.2, -.2, -.2, .2, -.2, .2, .2, .2, .2, .2, .2, -.2,
28     };
29     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
30 
31     /* enable and set the position attribute */
32     glEnableVertexAttribArray(position_index);
33     glVertexAttribPointer(position_index, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
34 
35     /* enable and set the color attribute */
36     /* reset the state; we will re-enable the VAO when needed */
37     glBindBuffer(GL_ARRAY_BUFFER, 0);
38     glBindVertexArray(0);
39 
40     glDeleteBuffers(1, &buffer);
41     return vao;
42 }
43 
realize()44 void Grid::realize()
45 {
46     program = gl_create_program_from_resource("/org/horizon-eda/horizon/canvas/shaders/grid-vertex.glsl",
47                                               "/org/horizon-eda/horizon/canvas/shaders/grid-fragment.glsl", nullptr);
48     vao = create_vao(program);
49 
50     GET_LOC(this, screenmat);
51     GET_LOC(this, viewmat);
52     GET_LOC(this, grid_size);
53     GET_LOC(this, grid_0);
54     GET_LOC(this, grid_mod);
55     GET_LOC(this, mark_size);
56     GET_LOC(this, color);
57     GET_LOC(this, angle);
58 }
59 
render()60 void Grid::render()
61 {
62     glUseProgram(program);
63     glBindVertexArray(vao);
64     glUniformMatrix3fv(screenmat_loc, 1, GL_FALSE, glm::value_ptr(ca.screenmat));
65     glUniformMatrix3fv(viewmat_loc, 1, GL_FALSE, glm::value_ptr(ca.viewmat));
66     glUniform1f(mark_size_loc, mark_size);
67     glUniform1f(angle_loc, ca.view_angle);
68     auto color = ca.get_color(ColorP::GRID);
69     glUniform4f(color_loc, color.r, color.g, color.b, ca.appearance.grid_opacity);
70 
71     Coordf sp = spacing;
72     Coordf sp_px = sp * ca.scale;
73     unsigned int newmul = 1;
74     while (sp_px.x < 20 || sp_px.y < 20) {
75         newmul *= 2;
76         sp = spacing * newmul;
77         sp_px = sp * ca.scale;
78     }
79 
80     BBoxAccumulator<Coordf::type> acc;
81     for (const auto x : {0.f, ca.m_width}) {
82         for (const auto y : {0.f, ca.m_height}) {
83             acc.accumulate(ca.screen2canvas({x, y}));
84         }
85     }
86     const auto [a, b] = acc.get();
87 
88     Coord<float> grid_0;
89     grid_0.x = (round((a.x - origin.x) / sp.x) - 1) * sp.x + origin.x;
90     grid_0.y = (round((a.y - origin.y) / sp.y) - 1) * sp.y + origin.y;
91 
92     if (mul != newmul) {
93         mul = newmul;
94         ca.s_signal_grid_mul_changed.emit(mul);
95     }
96 
97     glUniform2f(grid_size_loc, sp.x, sp.y);
98     glUniform2f(grid_0_loc, grid_0.x, grid_0.y);
99 
100     auto spmin = std::min(sp.x, sp.y);
101     glLineWidth(1 * ca.get_scale_factor());
102     if (mark_size > 100) {
103         glUniform1f(mark_size_loc, (b.y - a.y) * ca.scale * 2);
104         int n = (b.x - a.x) / spmin + 4;
105         glUniform1i(grid_mod_loc, n + 1);
106         glDrawArraysInstanced(GL_LINES, 0, 2, n);
107 
108         glUniform1f(mark_size_loc, (b.x - a.x) * ca.scale * 2);
109         n = (b.y - a.y) / spmin + 4;
110         glUniform1i(grid_mod_loc, 1);
111         glDrawArraysInstanced(GL_LINES, 2, 2, n);
112     }
113     else {
114         int mod = ceil((b.x - a.x) / spmin) + 2;
115         glUniform1i(grid_mod_loc, mod);
116         int n = mod * ceil((b.y - a.y) / spmin + 2);
117         glDrawArraysInstanced(GL_LINES, 0, 4, n);
118     }
119 
120     // draw origin
121     grid_0.x = 0;
122     grid_0.y = 0;
123 
124     glUniform2f(grid_size_loc, 0, 0);
125     glUniform2f(grid_0_loc, grid_0.x, grid_0.y);
126     glUniform1i(grid_mod_loc, 1);
127     glUniform1f(mark_size_loc, 15);
128     auto origin_color = ca.get_color(ColorP::ORIGIN);
129     gl_color_to_uniform_4f(color_loc, origin_color);
130 
131     glLineWidth(1 * ca.get_scale_factor());
132     glDrawArraysInstanced(GL_LINES, 0, 4, 1);
133 
134     glBindVertexArray(0);
135     glUseProgram(0);
136 }
137 
render_cursor(Coord<int64_t> & coord)138 void Grid::render_cursor(Coord<int64_t> &coord)
139 {
140     glUseProgram(program);
141     glBindVertexArray(vao);
142     glUniformMatrix3fv(screenmat_loc, 1, GL_FALSE, glm::value_ptr(ca.screenmat));
143     glUniformMatrix3fv(viewmat_loc, 1, GL_FALSE, glm::value_ptr(ca.viewmat));
144     if (ca.cursor_size > 0)
145         glUniform1f(mark_size_loc, ca.cursor_size);
146     else
147         glUniform1f(mark_size_loc, std::max(ca.m_width, ca.m_height));
148 
149     glUniform2f(grid_size_loc, 0, 0);
150     glUniform2f(grid_0_loc, coord.x, coord.y);
151     glUniform1i(grid_mod_loc, 1);
152     glUniform1f(angle_loc, 0);
153 
154     auto bgcolor = ca.get_color(ColorP::BACKGROUND);
155     glUniform4f(color_loc, bgcolor.r, bgcolor.g, bgcolor.b, 1);
156     glLineWidth(4 * ca.get_scale_factor());
157     glDrawArrays(GL_LINES, 0, 12);
158 
159     Color cursor_color;
160     if (ca.target_current.is_valid()) {
161         cursor_color = ca.get_color(ColorP::CURSOR_TARGET);
162     }
163     else {
164         cursor_color = ca.get_color(ColorP::CURSOR_NORMAL);
165     }
166     glUniform4f(color_loc, cursor_color.r, cursor_color.g, cursor_color.b, 1);
167     glLineWidth(1 * ca.get_scale_factor());
168     glDrawArrays(GL_LINES, 0, 12);
169 
170     glBindVertexArray(0);
171     glUseProgram(0);
172 }
173 } // namespace horizon
174