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