1 #pragma once
2 #include <glm/glm.hpp>
3 #include "common/common.hpp"
4 #include "canvas_mesh.hpp"
5 #include "canvas/appearance.hpp"
6 #include "util/uuid.hpp"
7 #include <mutex>
8 #include "cover_renderer.hpp"
9 #include "face_renderer.hpp"
10 #include "wall_renderer.hpp"
11 #include "background_renderer.hpp"
12 #include "point_renderer.hpp"
13 #include "import_step/import.hpp"
14 #include "point.hpp"
15 #include <sigc++/sigc++.h>
16 #include <variant>
17 
18 namespace horizon {
19 
20 class Canvas3DBase {
21 public:
22     Canvas3DBase();
23     friend class CoverRenderer;
24     friend class WallRenderer;
25     friend class FaceRenderer;
26     friend class BackgroundRenderer;
27     friend class PointRenderer;
28     Color get_layer_color(int layer) const;
29 
30     enum class Projection { PERSP, ORTHO };
31 
32 #define GET_SET_X(x_, t_, f_)                                                                                          \
33     const auto &get_##x_() const                                                                                       \
34     {                                                                                                                  \
35         return x_;                                                                                                     \
36     }                                                                                                                  \
37     void set_##x_(const t_ &c)                                                                                         \
38     {                                                                                                                  \
39         x_ = c;                                                                                                        \
40         redraw();                                                                                                      \
41         f_                                                                                                             \
42     }
43 
44 #define GET_SET(x_, t_) GET_SET_X(x_, t_, )
45 #define GET_SET_PICK(x_, t_) GET_SET_X(x_, t_, invalidate_pick();)
46 
GET_SET(background_top_color,Color)47     GET_SET(background_top_color, Color)
48     GET_SET(background_bottom_color, Color)
49     GET_SET_PICK(show_solder_mask, bool)
50     GET_SET_PICK(show_silkscreen, bool)
51     GET_SET_PICK(show_substrate, bool)
52     GET_SET_PICK(show_models, bool)
53     GET_SET_PICK(show_dnp_models, bool)
54     GET_SET_PICK(show_solder_paste, bool)
55     GET_SET_PICK(show_copper, bool)
56     GET_SET_PICK(show_points, bool)
57     GET_SET(use_layer_colors, bool)
58     GET_SET(solder_mask_color, Color)
59     GET_SET(silkscreen_color, Color)
60     GET_SET(substrate_color, Color)
61     GET_SET_PICK(explode, float)
62     GET_SET_PICK(cam_distance, float)
63     GET_SET_PICK(cam_fov, float)
64     GET_SET_PICK(center, glm::vec2)
65     GET_SET_PICK(projection, Projection)
66 
67 #undef GET_SET
68 #undef GET_SET_X
69 #undef GET_SET_PICK
70 
71     const float &get_cam_elevation() const
72     {
73         return cam_elevation;
74     }
75     void set_cam_elevation(const float &ele);
76 
get_cam_azimuth() const77     const float &get_cam_azimuth() const
78     {
79         return cam_azimuth;
80     }
81     void set_cam_azimuth(const float &az);
82 
83 
84     void view_all();
85     void clear_3d_models();
86     void set_point_transform(const glm::dmat4 &mat);
87     void set_points(const std::vector<Point3D> &points);
88 
89     struct BBox {
90         float xl, yl, zl, xh, yh, zh;
91     };
92 
93     BBox get_model_bbox(const std::string &filename) const;
94 
95     typedef sigc::signal<void> type_signal_view_changed;
signal_view_changed()96     type_signal_view_changed signal_view_changed()
97     {
98         return s_signal_view_changed;
99     }
100 
101     bool model_is_loaded(const std::string &filename);
102 
103 protected:
104     CanvasMesh ca;
105 
106     Appearance appearance;
107 
108     Color background_top_color;
109     Color background_bottom_color;
110     bool show_solder_mask = true;
111     bool show_silkscreen = true;
112     bool show_substrate = true;
113     bool show_models = true;
114     bool show_dnp_models = false;
115     bool show_solder_paste = true;
116     bool use_layer_colors = false;
117     bool show_copper = true;
118     bool show_points = false;
119     Color solder_mask_color = {0, .5, 0};
120     Color silkscreen_color = {1, 1, 1};
121     Color substrate_color = {.2, .15, 0};
122     float explode = 0;
123     float highlight_intensity = .5;
124 
125     float cam_azimuth = 90;
126     float cam_elevation = 45;
127     float cam_distance = 20;
128     float cam_fov = 45;
129     glm::vec2 center;
130 
131     Projection projection = Projection::PERSP;
132 
133 
134     int width = 100;
135     int height = 100;
136 
137     CoverRenderer cover_renderer;
138     WallRenderer wall_renderer;
139     FaceRenderer face_renderer;
140     BackgroundRenderer background_renderer;
141     PointRenderer point_renderer;
142 
143     void a_realize();
144     void resize_buffers();
145     void push();
146     enum class RenderBackground { YES, NO };
147     void render(RenderBackground mode = RenderBackground::YES);
148     virtual int a_get_scale_factor() const;
redraw()149     virtual void redraw()
150     {
151     }
152     void invalidate_pick();
153     void prepare();
154     void prepare_packages();
155 
156     unsigned int num_samples = 1;
157 
158     const class Board *brd = nullptr;
159 
160     std::set<UUID> packages_highlight;
161 
162     void load_3d_model(const std::string &filename, const std::string &filename_abs);
163 
164     std::map<std::string, std::string> get_model_filenames(class IPool &pool);
165 
166     std::mutex models_loading_mutex;
167 
168     void update_max_package_height();
169 
170     void queue_pick();
171     typedef sigc::signal<void> type_signal_pick_ready;
signal_pick_ready()172     type_signal_pick_ready signal_pick_ready()
173     {
174         return s_signal_pick_ready;
175     }
176     std::variant<UUID, glm::dvec3> pick_package_or_point(unsigned int x, unsigned int y) const;
177 
178     virtual STEPImporter::Faces import_step(const std::string &filename_rel, const std::string &filename_abs);
179 
180 private:
181     class FaceVertex {
182     public:
FaceVertex(float ix,float iy,float iz,float inx,float iny,float inz,uint8_t ir,uint8_t ig,uint8_t ib)183         FaceVertex(float ix, float iy, float iz, float inx, float iny, float inz, uint8_t ir, uint8_t ig, uint8_t ib)
184             : x(ix), y(iy), z(iz), nx(inx), ny(iny), nz(inz), r(ir), g(ig), b(ib), _pad(0)
185         {
186         }
187         float x;
188         float y;
189         float z;
190         float nx;
191         float ny;
192         float nz;
193 
194         uint8_t r;
195         uint8_t g;
196         uint8_t b;
197         uint8_t _pad;
198     } __attribute__((packed));
199 
200     class ModelTransform {
201     public:
ModelTransform(float ix,float iy,float a,bool flip,bool highlight)202         ModelTransform(float ix, float iy, float a, bool flip, bool highlight)
203             : x(ix), y(iy), angle(a), flags(flip | (highlight << 1))
204         {
205         }
206         float x;
207         float y;
208         uint16_t angle;
209         uint16_t flags;
210 
211         float model_x = 0;
212         float model_y = 0;
213         float model_z = 0;
214         uint16_t model_roll = 0;
215         uint16_t model_pitch = 0;
216         uint16_t model_yaw = 0;
217     } __attribute__((packed));
218 
219     float get_layer_offset(int layer) const;
220     float get_layer_thickness(int layer) const;
221     bool layer_is_visible(int layer) const;
222 
223     std::pair<glm::vec3, glm::vec3> bbox;
224 
225     GLuint renderbuffer;
226     GLuint fbo;
227     GLuint depthrenderbuffer;
228     GLuint pickrenderbuffer;
229 
230     GLuint fbo_downsampled;
231     GLuint pickrenderbuffer_downsampled;
232 
233     enum class PickState { QUEUED, CURRENT, INVALID };
234     PickState pick_state = PickState::INVALID;
235 
236     glm::mat4 viewmat;
237     glm::mat4 projmat;
238     glm::vec3 cam_normal;
239 
240     float package_height_max = 0;
241     std::vector<FaceVertex> face_vertex_buffer;  // vertices of all models, sequentially
242     std::vector<unsigned int> face_index_buffer; // indexes face_vertex_buffer to form triangles
243 
244     class ModelInfo {
245     public:
ModelInfo(size_t o,size_t n)246         ModelInfo(size_t o, size_t n) : face_index_offset(o), count(n)
247         {
248         }
249         const size_t face_index_offset; // offset in face_index_buffer
250         const size_t count;             // number of items in face_index_buffer
251         bool pushed = false;
252     };
253     std::map<std::string, ModelInfo> models; // key: filename
254 
255     std::vector<ModelTransform> package_transforms; // position and rotation of
256                                                     // all board packages,
257                                                     // grouped by package
258 
259     struct PackageInfo {
260         size_t offset; // in package_transforms
261         size_t n_packages;
262         unsigned int pick_base;
263         std::vector<UUID> pkg;
264     };
265 
266     std::map<std::pair<std::string, bool>, PackageInfo> package_infos; // key: first: model filename second: nopopulate
267     std::vector<uint16_t> pick_buf;
268 
269     uint16_t point_pick_base = 0;
270     std::vector<Point3D> points;
271     glm::dmat4 point_mat;
272     size_t n_points = 0;
273 
274     float get_magic_number() const;
275 
276     type_signal_pick_ready s_signal_pick_ready;
277     type_signal_view_changed s_signal_view_changed;
278 };
279 
280 } // namespace horizon
281