1 #ifndef slic3r_3DScene_hpp_
2 #define slic3r_3DScene_hpp_
3 
4 #include "libslic3r/libslic3r.h"
5 #include "libslic3r/Point.hpp"
6 #include "libslic3r/Line.hpp"
7 #include "libslic3r/TriangleMesh.hpp"
8 #include "libslic3r/Utils.hpp"
9 #include "libslic3r/Geometry.hpp"
10 
11 #include <functional>
12 
13 #if ENABLE_OPENGL_ERROR_LOGGING || ! defined(NDEBUG)
14     #define HAS_GLSAFE
15 #endif
16 
17 #ifdef HAS_GLSAFE
18     extern void glAssertRecentCallImpl(const char *file_name, unsigned int line, const char *function_name);
glAssertRecentCall()19     inline void glAssertRecentCall() { glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); }
20     #define glsafe(cmd) do { cmd; glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); } while (false)
21     #define glcheck() do { glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); } while (false)
22 #else // HAS_GLSAFE
glAssertRecentCall()23     inline void glAssertRecentCall() { }
24     #define glsafe(cmd) cmd
25     #define glcheck()
26 #endif // HAS_GLSAFE
27 
28 namespace Slic3r {
29 class SLAPrintObject;
30 enum  SLAPrintObjectStep : unsigned int;
31 class DynamicPrintConfig;
32 class ExtrusionPath;
33 class ExtrusionMultiPath;
34 class ExtrusionLoop;
35 class ExtrusionEntity;
36 class ExtrusionEntityCollection;
37 class ModelObject;
38 class ModelVolume;
39 enum ModelInstanceEPrintVolumeState : unsigned char;
40 
41 // A container for interleaved arrays of 3D vertices and normals,
42 // possibly indexed by triangles and / or quads.
43 class GLIndexedVertexArray {
44 public:
GLIndexedVertexArray()45     GLIndexedVertexArray() :
46         vertices_and_normals_interleaved_VBO_id(0),
47         triangle_indices_VBO_id(0),
48         quad_indices_VBO_id(0)
49         {}
GLIndexedVertexArray(const GLIndexedVertexArray & rhs)50     GLIndexedVertexArray(const GLIndexedVertexArray &rhs) :
51         vertices_and_normals_interleaved(rhs.vertices_and_normals_interleaved),
52         triangle_indices(rhs.triangle_indices),
53         quad_indices(rhs.quad_indices),
54         vertices_and_normals_interleaved_VBO_id(0),
55         triangle_indices_VBO_id(0),
56         quad_indices_VBO_id(0)
57         { assert(! rhs.has_VBOs()); }
GLIndexedVertexArray(GLIndexedVertexArray && rhs)58     GLIndexedVertexArray(GLIndexedVertexArray &&rhs) :
59         vertices_and_normals_interleaved(std::move(rhs.vertices_and_normals_interleaved)),
60         triangle_indices(std::move(rhs.triangle_indices)),
61         quad_indices(std::move(rhs.quad_indices)),
62         vertices_and_normals_interleaved_VBO_id(0),
63         triangle_indices_VBO_id(0),
64         quad_indices_VBO_id(0)
65         { assert(! rhs.has_VBOs()); }
66 
~GLIndexedVertexArray()67     ~GLIndexedVertexArray() { release_geometry(); }
68 
operator =(const GLIndexedVertexArray & rhs)69     GLIndexedVertexArray& operator=(const GLIndexedVertexArray &rhs)
70     {
71         assert(vertices_and_normals_interleaved_VBO_id == 0);
72         assert(triangle_indices_VBO_id == 0);
73         assert(quad_indices_VBO_id == 0);
74         assert(rhs.vertices_and_normals_interleaved_VBO_id == 0);
75         assert(rhs.triangle_indices_VBO_id == 0);
76         assert(rhs.quad_indices_VBO_id == 0);
77         this->vertices_and_normals_interleaved 		 = rhs.vertices_and_normals_interleaved;
78         this->triangle_indices                 		 = rhs.triangle_indices;
79         this->quad_indices                     		 = rhs.quad_indices;
80         this->m_bounding_box                   		 = rhs.m_bounding_box;
81         this->vertices_and_normals_interleaved_size  = rhs.vertices_and_normals_interleaved_size;
82         this->triangle_indices_size                  = rhs.triangle_indices_size;
83         this->quad_indices_size                      = rhs.quad_indices_size;
84         return *this;
85     }
86 
operator =(GLIndexedVertexArray && rhs)87     GLIndexedVertexArray& operator=(GLIndexedVertexArray &&rhs)
88     {
89         assert(vertices_and_normals_interleaved_VBO_id == 0);
90         assert(triangle_indices_VBO_id == 0);
91         assert(quad_indices_VBO_id == 0);
92         assert(rhs.vertices_and_normals_interleaved_VBO_id == 0);
93         assert(rhs.triangle_indices_VBO_id == 0);
94         assert(rhs.quad_indices_VBO_id == 0);
95         this->vertices_and_normals_interleaved 		 = std::move(rhs.vertices_and_normals_interleaved);
96         this->triangle_indices                 		 = std::move(rhs.triangle_indices);
97         this->quad_indices                     		 = std::move(rhs.quad_indices);
98         this->m_bounding_box                   		 = std::move(rhs.m_bounding_box);
99         this->vertices_and_normals_interleaved_size  = rhs.vertices_and_normals_interleaved_size;
100         this->triangle_indices_size                  = rhs.triangle_indices_size;
101         this->quad_indices_size                      = rhs.quad_indices_size;
102         return *this;
103     }
104 
105     // Vertices and their normals, interleaved to be used by void glInterleavedArrays(GL_N3F_V3F, 0, x)
106     std::vector<float> vertices_and_normals_interleaved;
107     std::vector<int>   triangle_indices;
108     std::vector<int>   quad_indices;
109 
110     // When the geometry data is loaded into the graphics card as Vertex Buffer Objects,
111     // the above mentioned std::vectors are cleared and the following variables keep their original length.
112     size_t vertices_and_normals_interleaved_size{ 0 };
113     size_t triangle_indices_size{ 0 };
114     size_t quad_indices_size{ 0 };
115 
116     // IDs of the Vertex Array Objects, into which the geometry has been loaded.
117     // Zero if the VBOs are not sent to GPU yet.
118     unsigned int       vertices_and_normals_interleaved_VBO_id{ 0 };
119     unsigned int       triangle_indices_VBO_id{ 0 };
120     unsigned int       quad_indices_VBO_id{ 0 };
121 
122 #if ENABLE_SMOOTH_NORMALS
123     void load_mesh_full_shading(const TriangleMesh& mesh, bool smooth_normals = false);
load_mesh(const TriangleMesh & mesh,bool smooth_normals=false)124     void load_mesh(const TriangleMesh& mesh, bool smooth_normals = false) { this->load_mesh_full_shading(mesh, smooth_normals); }
125 #else
126     void load_mesh_full_shading(const TriangleMesh& mesh);
load_mesh(const TriangleMesh & mesh)127     void load_mesh(const TriangleMesh& mesh) { this->load_mesh_full_shading(mesh); }
128 #endif // ENABLE_SMOOTH_NORMALS
129 
has_VBOs() const130     inline bool has_VBOs() const { return vertices_and_normals_interleaved_VBO_id != 0; }
131 
reserve(size_t sz)132     inline void reserve(size_t sz) {
133         this->vertices_and_normals_interleaved.reserve(sz * 6);
134         this->triangle_indices.reserve(sz * 3);
135         this->quad_indices.reserve(sz * 4);
136     }
137 
push_geometry(float x,float y,float z,float nx,float ny,float nz)138     inline void push_geometry(float x, float y, float z, float nx, float ny, float nz) {
139         assert(this->vertices_and_normals_interleaved_VBO_id == 0);
140         if (this->vertices_and_normals_interleaved_VBO_id != 0)
141             return;
142 
143         if (this->vertices_and_normals_interleaved.size() + 6 > this->vertices_and_normals_interleaved.capacity())
144             this->vertices_and_normals_interleaved.reserve(next_highest_power_of_2(this->vertices_and_normals_interleaved.size() + 6));
145         this->vertices_and_normals_interleaved.emplace_back(nx);
146         this->vertices_and_normals_interleaved.emplace_back(ny);
147         this->vertices_and_normals_interleaved.emplace_back(nz);
148         this->vertices_and_normals_interleaved.emplace_back(x);
149         this->vertices_and_normals_interleaved.emplace_back(y);
150         this->vertices_and_normals_interleaved.emplace_back(z);
151 
152         this->vertices_and_normals_interleaved_size = this->vertices_and_normals_interleaved.size();
153         m_bounding_box.merge(Vec3f(x, y, z).cast<double>());
154     };
155 
push_geometry(double x,double y,double z,double nx,double ny,double nz)156     inline void push_geometry(double x, double y, double z, double nx, double ny, double nz) {
157         push_geometry(float(x), float(y), float(z), float(nx), float(ny), float(nz));
158     }
159 
push_geometry(const Vec3d & p,const Vec3d & n)160     inline void push_geometry(const Vec3d& p, const Vec3d& n) {
161         push_geometry(p(0), p(1), p(2), n(0), n(1), n(2));
162     }
163 
push_triangle(int idx1,int idx2,int idx3)164     inline void push_triangle(int idx1, int idx2, int idx3) {
165         assert(this->vertices_and_normals_interleaved_VBO_id == 0);
166         if (this->vertices_and_normals_interleaved_VBO_id != 0)
167             return;
168 
169         if (this->triangle_indices.size() + 3 > this->vertices_and_normals_interleaved.capacity())
170             this->triangle_indices.reserve(next_highest_power_of_2(this->triangle_indices.size() + 3));
171         this->triangle_indices.emplace_back(idx1);
172         this->triangle_indices.emplace_back(idx2);
173         this->triangle_indices.emplace_back(idx3);
174         this->triangle_indices_size = this->triangle_indices.size();
175     };
176 
push_quad(int idx1,int idx2,int idx3,int idx4)177     inline void push_quad(int idx1, int idx2, int idx3, int idx4) {
178         assert(this->vertices_and_normals_interleaved_VBO_id == 0);
179         if (this->vertices_and_normals_interleaved_VBO_id != 0)
180             return;
181 
182         if (this->quad_indices.size() + 4 > this->vertices_and_normals_interleaved.capacity())
183             this->quad_indices.reserve(next_highest_power_of_2(this->quad_indices.size() + 4));
184         this->quad_indices.emplace_back(idx1);
185         this->quad_indices.emplace_back(idx2);
186         this->quad_indices.emplace_back(idx3);
187         this->quad_indices.emplace_back(idx4);
188         this->quad_indices_size = this->quad_indices.size();
189     };
190 
191     // Finalize the initialization of the geometry & indices,
192     // upload the geometry and indices to OpenGL VBO objects
193     // and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs.
194     void finalize_geometry(bool opengl_initialized);
195     // Release the geometry data, release OpenGL VBOs.
196     void release_geometry();
197 
198     void render() const;
199     void render(const std::pair<size_t, size_t>& tverts_range, const std::pair<size_t, size_t>& qverts_range) const;
200 
201     // Is there any geometry data stored?
empty() const202     bool empty() const { return vertices_and_normals_interleaved_size == 0; }
203 
clear()204     void clear() {
205         this->vertices_and_normals_interleaved.clear();
206         this->triangle_indices.clear();
207         this->quad_indices.clear();
208         this->m_bounding_box.reset();
209         vertices_and_normals_interleaved_size = 0;
210         triangle_indices_size = 0;
211         quad_indices_size = 0;
212     }
213 
214     // Shrink the internal storage to tighly fit the data stored.
shrink_to_fit()215     void shrink_to_fit() {
216         this->vertices_and_normals_interleaved.shrink_to_fit();
217         this->triangle_indices.shrink_to_fit();
218         this->quad_indices.shrink_to_fit();
219     }
220 
bounding_box() const221     const BoundingBoxf3& bounding_box() const { return m_bounding_box; }
222 
223     // Return an estimate of the memory consumed by this class.
cpu_memory_used() const224     size_t cpu_memory_used() const { return sizeof(*this) + vertices_and_normals_interleaved.capacity() * sizeof(float) + triangle_indices.capacity() * sizeof(int) + quad_indices.capacity() * sizeof(int); }
225     // Return an estimate of the memory held by GPU vertex buffers.
gpu_memory_used() const226     size_t gpu_memory_used() const
227     {
228     	size_t memsize = 0;
229     	if (this->vertices_and_normals_interleaved_VBO_id != 0)
230     		memsize += this->vertices_and_normals_interleaved_size * 4;
231     	if (this->triangle_indices_VBO_id != 0)
232     		memsize += this->triangle_indices_size * 4;
233     	if (this->quad_indices_VBO_id != 0)
234     		memsize += this->quad_indices_size * 4;
235     	return memsize;
236     }
total_memory_used() const237     size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
238 
239 private:
240     BoundingBoxf3 m_bounding_box;
241 };
242 
243 class GLVolume {
244 public:
245     static const float SELECTED_COLOR[4];
246     static const float HOVER_SELECT_COLOR[4];
247     static const float HOVER_DESELECT_COLOR[4];
248     static const float OUTSIDE_COLOR[4];
249     static const float SELECTED_OUTSIDE_COLOR[4];
250     static const float DISABLED_COLOR[4];
251     static const float MODEL_COLOR[4][4];
252     static const float SLA_SUPPORT_COLOR[4];
253     static const float SLA_PAD_COLOR[4];
254     static const float NEUTRAL_COLOR[4];
255 
256     enum EHoverState : unsigned char
257     {
258         HS_None,
259         HS_Select,
260         HS_Deselect
261     };
262 
263     GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f);
GLVolume(const float * rgba)264     GLVolume(const float *rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {}
265 
266 private:
267     Geometry::Transformation m_instance_transformation;
268     Geometry::Transformation m_volume_transformation;
269 
270     // Shift in z required by sla supports+pad
271     double        		  m_sla_shift_z;
272     // Bounding box of this volume, in unscaled coordinates.
273     mutable BoundingBoxf3 m_transformed_bounding_box;
274     // Whether or not is needed to recalculate the transformed bounding box.
275     mutable bool          m_transformed_bounding_box_dirty;
276     // Convex hull of the volume, if any.
277     std::shared_ptr<const TriangleMesh> m_convex_hull;
278     // Bounding box of this volume, in unscaled coordinates.
279     mutable BoundingBoxf3 m_transformed_convex_hull_bounding_box;
280     // Whether or not is needed to recalculate the transformed convex hull bounding box.
281     mutable bool          m_transformed_convex_hull_bounding_box_dirty;
282 
283 public:
284     // Color of the triangles / quads held by this volume.
285     float               color[4];
286     // Color used to render this volume.
287     float               render_color[4];
288     struct CompositeID {
CompositeIDSlic3r::GLVolume::CompositeID289         CompositeID(int object_id, int volume_id, int instance_id) : object_id(object_id), volume_id(volume_id), instance_id(instance_id) {}
CompositeIDSlic3r::GLVolume::CompositeID290         CompositeID() : object_id(-1), volume_id(-1), instance_id(-1) {}
291         // Object ID, which is equal to the index of the respective ModelObject in Model.objects array.
292         int             object_id;
293         // Volume ID, which is equal to the index of the respective ModelVolume in ModelObject.volumes array.
294         // If negative, it is an index of a geometry produced by the PrintObject for the respective ModelObject,
295         // and which has no associated ModelVolume in ModelObject.volumes. For example, SLA supports.
296         // Volume with a negative volume_id cannot be picked independently, it will pick the associated instance.
297         int             volume_id;
298         // Instance ID, which is equal to the index of the respective ModelInstance in ModelObject.instances array.
299         int             instance_id;
operator ==Slic3r::GLVolume::CompositeID300 		bool operator==(const CompositeID &rhs) const { return object_id == rhs.object_id && volume_id == rhs.volume_id && instance_id == rhs.instance_id; }
operator !=Slic3r::GLVolume::CompositeID301 		bool operator!=(const CompositeID &rhs) const { return ! (*this == rhs); }
operator <Slic3r::GLVolume::CompositeID302 		bool operator< (const CompositeID &rhs) const
303 			{ return object_id < rhs.object_id || (object_id == rhs.object_id && (volume_id < rhs.volume_id || (volume_id == rhs.volume_id && instance_id < rhs.instance_id))); }
304     };
305     CompositeID         composite_id;
306     // Fingerprint of the source geometry. For ModelVolumes, it is the ModelVolume::ID and ModelInstanceID,
307     // for generated volumes it is the timestamp generated by PrintState::invalidate() or PrintState::set_done(),
308     // and the associated ModelInstanceID.
309     // Valid geometry_id should always be positive.
310     std::pair<size_t, size_t> geometry_id;
311     // An ID containing the extruder ID (used to select color).
312     int                 	extruder_id;
313 
314     // Various boolean flags.
315     struct {
316 	    // Is this object selected?
317 	    bool                selected : 1;
318 	    // Is this object disabled from selection?
319 	    bool                disabled : 1;
320 	    // Is this object printable?
321 	    bool                printable : 1;
322 	    // Whether or not this volume is active for rendering
323 	    bool                is_active : 1;
324 	    // Whether or not to use this volume when applying zoom_to_volumes()
325 	    bool                zoom_to_volumes : 1;
326 	    // Wheter or not this volume is enabled for outside print volume detection in shader.
327 	    bool                shader_outside_printer_detection_enabled : 1;
328 	    // Wheter or not this volume is outside print volume.
329 	    bool                is_outside : 1;
330 	    // Wheter or not this volume has been generated from a modifier
331 	    bool                is_modifier : 1;
332 	    // Wheter or not this volume has been generated from the wipe tower
333 	    bool                is_wipe_tower : 1;
334 	    // Wheter or not this volume has been generated from an extrusion path
335 	    bool                is_extrusion_path : 1;
336 	    // Wheter or not to always render this volume using its own alpha
337 	    bool                force_transparent : 1;
338 	    // Whether or not always use the volume's own color (not using SELECTED/HOVER/DISABLED/OUTSIDE)
339 	    bool                force_native_color : 1;
340         // Whether or not render this volume in neutral
341         bool                force_neutral_color : 1;
342 	};
343 
344     // Is mouse or rectangle selection over this object to select/deselect it ?
345     EHoverState         	hover;
346 
347     // Interleaved triangles & normals with indexed triangles & quads.
348     GLIndexedVertexArray        indexed_vertex_array;
349     // Ranges of triangle and quad indices to be rendered.
350     std::pair<size_t, size_t>   tverts_range;
351     std::pair<size_t, size_t>   qverts_range;
352 
353     // If the qverts or tverts contain thick extrusions, then offsets keeps pointers of the starts
354     // of the extrusions per layer.
355     std::vector<coordf_t>       print_zs;
356     // Offset into qverts & tverts, or offsets into indices stored into an OpenGL name_index_buffer.
357     std::vector<size_t>         offsets;
358 
359     // Bounding box of this volume, in unscaled coordinates.
bounding_box() const360     const BoundingBoxf3& bounding_box() const { return this->indexed_vertex_array.bounding_box(); }
361 
362     void set_render_color(float r, float g, float b, float a);
363     void set_render_color(const float* rgba, unsigned int size);
364     // Sets render color in dependence of current state
365     void set_render_color();
366     // set color according to model volume
367     void set_color_from_model_volume(const ModelVolume *model_volume);
368 
get_instance_transformation() const369     const Geometry::Transformation& get_instance_transformation() const { return m_instance_transformation; }
set_instance_transformation(const Geometry::Transformation & transformation)370     void set_instance_transformation(const Geometry::Transformation& transformation) { m_instance_transformation = transformation; set_bounding_boxes_as_dirty(); }
371 
get_instance_offset() const372     const Vec3d& get_instance_offset() const { return m_instance_transformation.get_offset(); }
get_instance_offset(Axis axis) const373     double get_instance_offset(Axis axis) const { return m_instance_transformation.get_offset(axis); }
374 
set_instance_offset(const Vec3d & offset)375     void set_instance_offset(const Vec3d& offset) { m_instance_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
set_instance_offset(Axis axis,double offset)376     void set_instance_offset(Axis axis, double offset) { m_instance_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
377 
get_instance_rotation() const378     const Vec3d& get_instance_rotation() const { return m_instance_transformation.get_rotation(); }
get_instance_rotation(Axis axis) const379     double get_instance_rotation(Axis axis) const { return m_instance_transformation.get_rotation(axis); }
380 
set_instance_rotation(const Vec3d & rotation)381     void set_instance_rotation(const Vec3d& rotation) { m_instance_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
set_instance_rotation(Axis axis,double rotation)382     void set_instance_rotation(Axis axis, double rotation) { m_instance_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); }
383 
get_instance_scaling_factor() const384     Vec3d get_instance_scaling_factor() const { return m_instance_transformation.get_scaling_factor(); }
get_instance_scaling_factor(Axis axis) const385     double get_instance_scaling_factor(Axis axis) const { return m_instance_transformation.get_scaling_factor(axis); }
386 
set_instance_scaling_factor(const Vec3d & scaling_factor)387     void set_instance_scaling_factor(const Vec3d& scaling_factor) { m_instance_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
set_instance_scaling_factor(Axis axis,double scaling_factor)388     void set_instance_scaling_factor(Axis axis, double scaling_factor) { m_instance_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
389 
get_instance_mirror() const390     const Vec3d& get_instance_mirror() const { return m_instance_transformation.get_mirror(); }
get_instance_mirror(Axis axis) const391     double get_instance_mirror(Axis axis) const { return m_instance_transformation.get_mirror(axis); }
392 
set_instance_mirror(const Vec3d & mirror)393     void set_instance_mirror(const Vec3d& mirror) { m_instance_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }
set_instance_mirror(Axis axis,double mirror)394     void set_instance_mirror(Axis axis, double mirror) { m_instance_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); }
395 
get_volume_transformation() const396     const Geometry::Transformation& get_volume_transformation() const { return m_volume_transformation; }
set_volume_transformation(const Geometry::Transformation & transformation)397     void set_volume_transformation(const Geometry::Transformation& transformation) { m_volume_transformation = transformation; set_bounding_boxes_as_dirty(); }
398 
get_volume_offset() const399     const Vec3d& get_volume_offset() const { return m_volume_transformation.get_offset(); }
get_volume_offset(Axis axis) const400     double get_volume_offset(Axis axis) const { return m_volume_transformation.get_offset(axis); }
401 
set_volume_offset(const Vec3d & offset)402     void set_volume_offset(const Vec3d& offset) { m_volume_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
set_volume_offset(Axis axis,double offset)403     void set_volume_offset(Axis axis, double offset) { m_volume_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
404 
get_volume_rotation() const405     const Vec3d& get_volume_rotation() const { return m_volume_transformation.get_rotation(); }
get_volume_rotation(Axis axis) const406     double get_volume_rotation(Axis axis) const { return m_volume_transformation.get_rotation(axis); }
407 
set_volume_rotation(const Vec3d & rotation)408     void set_volume_rotation(const Vec3d& rotation) { m_volume_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
set_volume_rotation(Axis axis,double rotation)409     void set_volume_rotation(Axis axis, double rotation) { m_volume_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); }
410 
get_volume_scaling_factor() const411     const Vec3d& get_volume_scaling_factor() const { return m_volume_transformation.get_scaling_factor(); }
get_volume_scaling_factor(Axis axis) const412     double get_volume_scaling_factor(Axis axis) const { return m_volume_transformation.get_scaling_factor(axis); }
413 
set_volume_scaling_factor(const Vec3d & scaling_factor)414     void set_volume_scaling_factor(const Vec3d& scaling_factor) { m_volume_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
set_volume_scaling_factor(Axis axis,double scaling_factor)415     void set_volume_scaling_factor(Axis axis, double scaling_factor) { m_volume_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
416 
get_volume_mirror() const417     const Vec3d& get_volume_mirror() const { return m_volume_transformation.get_mirror(); }
get_volume_mirror(Axis axis) const418     double get_volume_mirror(Axis axis) const { return m_volume_transformation.get_mirror(axis); }
419 
set_volume_mirror(const Vec3d & mirror)420     void set_volume_mirror(const Vec3d& mirror) { m_volume_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }
set_volume_mirror(Axis axis,double mirror)421     void set_volume_mirror(Axis axis, double mirror) { m_volume_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); }
422 
get_sla_shift_z() const423     double get_sla_shift_z() const { return m_sla_shift_z; }
set_sla_shift_z(double z)424     void set_sla_shift_z(double z) { m_sla_shift_z = z; }
425 
set_convex_hull(std::shared_ptr<const TriangleMesh> convex_hull)426     void set_convex_hull(std::shared_ptr<const TriangleMesh> convex_hull) { m_convex_hull = std::move(convex_hull); }
set_convex_hull(const TriangleMesh & convex_hull)427     void set_convex_hull(const TriangleMesh &convex_hull) { m_convex_hull = std::make_shared<const TriangleMesh>(convex_hull); }
set_convex_hull(TriangleMesh && convex_hull)428     void set_convex_hull(TriangleMesh &&convex_hull) { m_convex_hull = std::make_shared<const TriangleMesh>(std::move(convex_hull)); }
429 
object_idx() const430     int                 object_idx() const { return this->composite_id.object_id; }
volume_idx() const431     int                 volume_idx() const { return this->composite_id.volume_id; }
instance_idx() const432     int                 instance_idx() const { return this->composite_id.instance_id; }
433 
434     Transform3d         world_matrix() const;
435     bool                is_left_handed() const;
436 
437     const BoundingBoxf3& transformed_bounding_box() const;
438     // non-caching variant
439     BoundingBoxf3        transformed_convex_hull_bounding_box(const Transform3d &trafo) const;
440     // caching variant
441     const BoundingBoxf3& transformed_convex_hull_bounding_box() const;
442     // convex hull
convex_hull() const443     const TriangleMesh*  convex_hull() const { return m_convex_hull.get(); }
444 
empty() const445     bool                empty() const { return this->indexed_vertex_array.empty(); }
446 
447     void                set_range(double low, double high);
448 
449     void                render() const;
450 
finalize_geometry(bool opengl_initialized)451     void                finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); }
release_geometry()452     void                release_geometry() { this->indexed_vertex_array.release_geometry(); }
453 
set_bounding_boxes_as_dirty()454     void                set_bounding_boxes_as_dirty() { m_transformed_bounding_box_dirty = true; m_transformed_convex_hull_bounding_box_dirty = true; }
455 
456     bool                is_sla_support() const;
457     bool                is_sla_pad() const;
458 
459     // Return an estimate of the memory consumed by this class.
cpu_memory_used() const460     size_t 				cpu_memory_used() const {
461     	//FIXME what to do wih m_convex_hull?
462     	return sizeof(*this) - sizeof(this->indexed_vertex_array) + this->indexed_vertex_array.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) + this->offsets.capacity() * sizeof(size_t);
463     }
464     // Return an estimate of the memory held by GPU vertex buffers.
gpu_memory_used() const465     size_t 				gpu_memory_used() const { return this->indexed_vertex_array.gpu_memory_used(); }
total_memory_used() const466     size_t 				total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
467 };
468 
469 typedef std::vector<GLVolume*> GLVolumePtrs;
470 typedef std::pair<GLVolume*, std::pair<unsigned int, double>> GLVolumeWithIdAndZ;
471 typedef std::vector<GLVolumeWithIdAndZ> GLVolumeWithIdAndZList;
472 
473 class GLVolumeCollection
474 {
475 public:
476     enum ERenderType : unsigned char
477     {
478         Opaque,
479         Transparent,
480         All
481     };
482 
483 private:
484     // min and max vertex of the print box volume
485     float m_print_box_min[3];
486     float m_print_box_max[3];
487 
488     // z range for clipping in shaders
489     float m_z_range[2];
490 
491     // plane coeffs for clipping in shaders
492     float m_clipping_plane[4];
493 
494     struct Slope
495     {
496         // toggle for slope rendering
497         bool active{ false };
498         float normal_z;
499     };
500 
501     Slope m_slope;
502 
503 public:
504     GLVolumePtrs volumes;
505 
GLVolumeCollection()506     GLVolumeCollection() { set_default_slope_normal_z(); }
~GLVolumeCollection()507     ~GLVolumeCollection() { clear(); }
508 
509     std::vector<int> load_object(
510         const ModelObject 		*model_object,
511         int                      obj_idx,
512         const std::vector<int>	&instance_idxs,
513         const std::string 		&color_by,
514         bool 					 opengl_initialized);
515 
516     int load_object_volume(
517         const ModelObject *model_object,
518         int                obj_idx,
519         int                volume_idx,
520         int                instance_idx,
521         const std::string &color_by,
522         bool 			   opengl_initialized);
523 
524     // Load SLA auxiliary GLVolumes (for support trees or pad).
525     void load_object_auxiliary(
526         const SLAPrintObject           *print_object,
527         int                             obj_idx,
528         // pairs of <instance_idx, print_instance_idx>
529         const std::vector<std::pair<size_t, size_t>>& instances,
530         SLAPrintObjectStep              milestone,
531         // Timestamp of the last change of the milestone
532         size_t                          timestamp,
533         bool 			   				opengl_initialized);
534 
535     int load_wipe_tower_preview(
536         int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized);
537 
538     GLVolume* new_toolpath_volume(const float *rgba, size_t reserve_vbo_floats = 0);
539     GLVolume* new_nontoolpath_volume(const float *rgba, size_t reserve_vbo_floats = 0);
540 
541     // Render the volumes by OpenGL.
542     void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const;
543 
544     // Finalize the initialization of the geometry & indices,
545     // upload the geometry and indices to OpenGL VBO objects
546     // and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs.
finalize_geometry(bool opengl_initialized)547     void finalize_geometry(bool opengl_initialized) { for (auto* v : volumes) v->finalize_geometry(opengl_initialized); }
548     // Release the geometry data assigned to the volumes.
549     // If OpenGL VBOs were allocated, an OpenGL context has to be active to release them.
release_geometry()550     void release_geometry() { for (auto *v : volumes) v->release_geometry(); }
551     // Clear the geometry
clear()552     void clear() { for (auto *v : volumes) delete v; volumes.clear(); }
553 
empty() const554     bool empty() const { return volumes.empty(); }
set_range(double low,double high)555     void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); }
556 
set_print_box(float min_x,float min_y,float min_z,float max_x,float max_y,float max_z)557     void set_print_box(float min_x, float min_y, float min_z, float max_x, float max_y, float max_z) {
558         m_print_box_min[0] = min_x; m_print_box_min[1] = min_y; m_print_box_min[2] = min_z;
559         m_print_box_max[0] = max_x; m_print_box_max[1] = max_y; m_print_box_max[2] = max_z;
560     }
561 
set_z_range(float min_z,float max_z)562     void set_z_range(float min_z, float max_z) { m_z_range[0] = min_z; m_z_range[1] = max_z; }
set_clipping_plane(const double * coeffs)563     void set_clipping_plane(const double* coeffs) { m_clipping_plane[0] = coeffs[0]; m_clipping_plane[1] = coeffs[1]; m_clipping_plane[2] = coeffs[2]; m_clipping_plane[3] = coeffs[3]; }
564 
is_slope_active() const565     bool is_slope_active() const { return m_slope.active; }
set_slope_active(bool active)566     void set_slope_active(bool active) { m_slope.active = active; }
567 
get_slope_normal_z() const568     float get_slope_normal_z() const { return m_slope.normal_z; }
set_slope_normal_z(float normal_z)569     void set_slope_normal_z(float normal_z) { m_slope.normal_z = normal_z; }
set_default_slope_normal_z()570     void set_default_slope_normal_z() { m_slope.normal_z = -::cos(Geometry::deg2rad(90.0f - 45.0f)); }
571 
572     // returns true if all the volumes are completely contained in the print volume
573     // returns the containment state in the given out_state, if non-null
574     bool check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state);
575     void reset_outside_state();
576 
577     void update_colors_by_extruder(const DynamicPrintConfig* config);
578 
579     // Returns a vector containing the sorted list of all the print_zs of the volumes contained in this collection
580     std::vector<double> get_current_print_zs(bool active_only) const;
581 
582     // Return an estimate of the memory consumed by this class.
583     size_t 				cpu_memory_used() const;
584     // Return an estimate of the memory held by GPU vertex buffers.
585     size_t 				gpu_memory_used() const;
total_memory_used() const586     size_t 				total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
587     // Return CPU, GPU and total memory log line.
588     std::string         log_memory_info() const;
589 
590     bool                has_toolpaths_to_export() const;
591 
592 private:
593     GLVolumeCollection(const GLVolumeCollection &other);
594     GLVolumeCollection& operator=(const GLVolumeCollection &);
595 };
596 
597 GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = nullptr);
598 
599 struct _3DScene
600 {
601     static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GLVolume& volume);
602     static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GLVolume& volume);
603 	static void extrusionentity_to_verts(const Polyline &polyline, float width, float height, float print_z, GLVolume& volume);
604     static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, GLVolume& volume);
605     static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GLVolume& volume);
606     static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GLVolume& volume);
607     static void extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GLVolume& volume);
608     static void extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GLVolume& volume);
609     static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GLVolume& volume);
610     static void polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume);
611     static void point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume);
612 };
613 
614 static constexpr float BedEpsilon = 3.f * float(EPSILON);
615 
616 }
617 
618 #endif
619