1 #include "cover_renderer.hpp"
2 #include "board/board_layers.hpp"
3 #include "canvas/gl_util.hpp"
4 #include "canvas3d_base.hpp"
5 #include <cmath>
6 #include <glm/glm.hpp>
7 #include <glm/gtc/matrix_transform.hpp>
8 #include <glm/gtc/type_ptr.hpp>
9 
10 namespace horizon {
CoverRenderer(Canvas3DBase & c)11 CoverRenderer::CoverRenderer(Canvas3DBase &c) : ca(c)
12 {
13 }
14 
create_vao(GLuint program,GLuint & vbo_out)15 static GLuint create_vao(GLuint program, GLuint &vbo_out)
16 {
17     GLuint position_index = glGetAttribLocation(program, "position");
18     GLuint vao, buffer;
19 
20     /* we need to create a VAO to store the other buffers */
21     glGenVertexArrays(1, &vao);
22     glBindVertexArray(vao);
23 
24     /* this is the VBO that holds the vertex data */
25     glGenBuffers(1, &buffer);
26     glBindBuffer(GL_ARRAY_BUFFER, buffer);
27 
28     CanvasMesh::Layer3D::Vertex vertices[] = {
29             //   Position
30             {-5, -5}, {5, -5}, {-5, 5},
31 
32             {5, 5},   {5, -5}, {-5, 5},
33     };
34     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
35 
36     /* enable and set the position attribute */
37     glEnableVertexAttribArray(position_index);
38     glVertexAttribPointer(position_index, 2, GL_FLOAT, GL_FALSE, sizeof(CanvasMesh::Layer3D::Vertex), 0);
39 
40     /* enable and set the color attribute */
41     /* reset the state; we will re-enable the VAO when needed */
42     glBindBuffer(GL_ARRAY_BUFFER, 0);
43     glBindVertexArray(0);
44 
45     // glDeleteBuffers (1, &buffer);
46     vbo_out = buffer;
47 
48     return vao;
49 }
50 
realize()51 void CoverRenderer::realize()
52 {
53     program = gl_create_program_from_resource("/org/horizon-eda/horizon/canvas3d/shaders/cover-vertex.glsl",
54                                               "/org/horizon-eda/horizon/canvas3d/shaders/"
55                                               "cover-fragment.glsl",
56                                               nullptr);
57     vao = create_vao(program, vbo);
58 
59     GET_LOC(this, view);
60     GET_LOC(this, proj);
61     GET_LOC(this, layer_offset);
62     GET_LOC(this, layer_color);
63     GET_LOC(this, cam_normal);
64 }
65 
push()66 void CoverRenderer::push()
67 {
68     glBindBuffer(GL_ARRAY_BUFFER, vbo);
69     n_vertices = 0;
70     for (const auto &it : ca.ca.get_layers()) {
71         n_vertices += it.second.tris.size();
72     }
73     glBufferData(GL_ARRAY_BUFFER, sizeof(CanvasMesh::Layer3D::Vertex) * n_vertices, nullptr, GL_STREAM_DRAW);
74     GL_CHECK_ERROR
75     size_t ofs = 0;
76     layer_offsets.clear();
77     for (const auto &it : ca.ca.get_layers()) {
78         glBufferSubData(GL_ARRAY_BUFFER, ofs * sizeof(CanvasMesh::Layer3D::Vertex),
79                         it.second.tris.size() * sizeof(CanvasMesh::Layer3D::Vertex), it.second.tris.data());
80         layer_offsets[it.first] = ofs;
81         ofs += it.second.tris.size();
82     }
83     glBindBuffer(GL_ARRAY_BUFFER, 0);
84 }
85 
render(int layer)86 void CoverRenderer::render(int layer)
87 {
88     const bool is_opaque = ca.ca.get_layer(layer).alpha == 1;
89     if (!is_opaque)
90         glEnable(GL_BLEND);
91     auto co = ca.get_layer_color(layer);
92     gl_color_to_uniform_4f(layer_color_loc, co, ca.ca.get_layer(layer).alpha);
93     glUniform1f(layer_offset_loc, ca.get_layer_offset(layer));
94     glDrawArrays(GL_TRIANGLES, layer_offsets[layer], ca.ca.get_layer(layer).tris.size());
95     if (is_opaque) {
96         glUniform1f(layer_offset_loc, ca.get_layer_offset(layer) + ca.get_layer_thickness(layer));
97         glDrawArrays(GL_TRIANGLES, layer_offsets[layer], ca.ca.get_layer(layer).tris.size());
98     }
99     glDisable(GL_BLEND);
100 }
101 
render()102 void CoverRenderer::render()
103 {
104     glUseProgram(program);
105     glBindVertexArray(vao);
106 
107     glUniformMatrix4fv(view_loc, 1, GL_FALSE, glm::value_ptr(ca.viewmat));
108     glUniformMatrix4fv(proj_loc, 1, GL_FALSE, glm::value_ptr(ca.projmat));
109     glUniform3fv(cam_normal_loc, 1, glm::value_ptr(ca.cam_normal));
110 
111     for (const auto &it : layer_offsets) {
112         if (ca.ca.get_layer(it.first).alpha == 1 && ca.layer_is_visible(it.first))
113             render(it.first);
114     }
115     for (const auto &it : layer_offsets) {
116         if (ca.ca.get_layer(it.first).alpha != 1 && ca.layer_is_visible(it.first))
117             render(it.first);
118     }
119 }
120 } // namespace horizon
121