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