#ifndef slic3r_3DScene_hpp_ #define slic3r_3DScene_hpp_ #include "libslic3r/libslic3r.h" #include "libslic3r/Point.hpp" #include "libslic3r/Line.hpp" #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/Geometry.hpp" #include "libslic3r/Color.hpp" // BBS #include "libslic3r/ObjectID.hpp" #include "GLModel.hpp" #include "GLShader.hpp" #include "MeshUtils.hpp" #include #include #ifndef NDEBUG #define HAS_GLSAFE #endif // NDEBUG #ifdef HAS_GLSAFE extern void glAssertRecentCallImpl(const char *file_name, unsigned int line, const char *function_name); inline void glAssertRecentCall() { glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); } #define glsafe(cmd) do { cmd; glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); } while (false) #define glcheck() do { glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); } while (false) #else // HAS_GLSAFE inline void glAssertRecentCall() { } #define glsafe(cmd) cmd #define glcheck() #endif // HAS_GLSAFE extern std::vector get_extruders_colors(); extern float FullyTransparentMaterialThreshold; extern float FullTransparentModdifiedToFixAlpha; extern Slic3r::ColorRGBA adjust_color_for_rendering(const Slic3r::ColorRGBA &colors); namespace Slic3r { class SLAPrintObject; enum SLAPrintObjectStep : unsigned int; class BuildVolume; class DynamicPrintConfig; class ExtrusionPath; class ExtrusionMultiPath; class ExtrusionLoop; class ExtrusionEntity; class ExtrusionEntityCollection; class ModelObject; class ModelVolume; class GLShaderProgram; enum ModelInstanceEPrintVolumeState : unsigned char; using ModelObjectPtrs = std::vector; // Return appropriate color based on the ModelVolume. extern ColorRGBA color_from_model_volume(const ModelVolume& model_volume); class GLVolume { public: std::string name; static ColorRGBA DISABLED_COLOR; static ColorRGBA SLA_SUPPORT_COLOR; static ColorRGBA SLA_PAD_COLOR; static ColorRGBA NEUTRAL_COLOR; static ColorRGBA UNPRINTABLE_COLOR; static std::array MODEL_COLOR; static ColorRGBA MODEL_MIDIFIER_COL; static ColorRGBA MODEL_NEGTIVE_COL; static ColorRGBA SUPPORT_ENFORCER_COL; static ColorRGBA SUPPORT_BLOCKER_COL; static ColorRGBA MODEL_HIDDEN_COL; static void update_render_colors(); static void load_render_colors(); static float explosion_ratio; static float last_explosion_ratio; enum EHoverState : unsigned char { HS_None, HS_Hover, HS_Select, HS_Deselect }; GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f); GLVolume(const ColorRGBA& color) : GLVolume(color.r(), color.g(), color.b(), color.a()) {} virtual ~GLVolume() = default; // BBS protected: Geometry::Transformation m_instance_transformation; Geometry::Transformation m_volume_transformation; // BBS Vec3d m_offset_to_assembly{ 0.0, 0.0, 0.0 }; // Shift in z required by sla supports+pad double m_sla_shift_z; // Bounding box of this volume, in unscaled coordinates. std::optional m_transformed_bounding_box; // Convex hull of the volume, if any. std::shared_ptr m_convex_hull; // Bounding box of this volume, in unscaled coordinates. std::optional m_transformed_convex_hull_bounding_box; // Bounding box of the non sinking part of this volume, in unscaled coordinates. std::optional m_transformed_non_sinking_bounding_box; class SinkingContours { static const float HalfWidth; GLVolume& m_parent; GUI::GLModel m_model; BoundingBoxf3 m_old_box; Vec3d m_shift{ Vec3d::Zero() }; public: SinkingContours(GLVolume& volume) : m_parent(volume) {} void render(); private: void update(); }; SinkingContours m_sinking_contours; public: // Color of the triangles / quads held by this volume. ColorRGBA color; // Color used to render this volume. ColorRGBA render_color; struct CompositeID { CompositeID(int object_id, int volume_id, int instance_id) : object_id(object_id), volume_id(volume_id), instance_id(instance_id) {} CompositeID() : object_id(-1), volume_id(-1), instance_id(-1) {} // Object ID, which is equal to the index of the respective ModelObject in Model.objects array. int object_id; // Volume ID, which is equal to the index of the respective ModelVolume in ModelObject.volumes array. // If negative, it is an index of a geometry produced by the PrintObject for the respective ModelObject, // and which has no associated ModelVolume in ModelObject.volumes. For example, SLA supports. // Volume with a negative volume_id cannot be picked independently, it will pick the associated instance. int volume_id; // Instance ID, which is equal to the index of the respective ModelInstance in ModelObject.instances array. int instance_id; bool operator==(const CompositeID &rhs) const { return object_id == rhs.object_id && volume_id == rhs.volume_id && instance_id == rhs.instance_id; } bool operator!=(const CompositeID &rhs) const { return ! (*this == rhs); } bool operator< (const CompositeID &rhs) const { 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))); } }; CompositeID composite_id; // Fingerprint of the source geometry. For ModelVolumes, it is the ModelVolume::ID and ModelInstanceID, // for generated volumes it is the timestamp generated by PrintState::invalidate() or PrintState::set_done(), // and the associated ModelInstanceID. // Valid geometry_id should always be positive. std::pair geometry_id; // An ID containing the extruder ID (used to select color). int extruder_id; size_t model_object_ID{0}; // Various boolean flags. struct { // Is this object selected? bool selected : 1; // Is this object disabled from selection? bool disabled : 1; // Is this object printable? bool printable : 1; // Is this object visible(in assemble view)? bool visible : 1; // Whether or not this volume is active for rendering bool is_active : 1; // Whether or not to use this volume when applying zoom_to_volumes() bool zoom_to_volumes : 1; // Wheter or not this volume is enabled for outside print volume detection in shader. bool shader_outside_printer_detection_enabled : 1; // Wheter or not this volume is outside print volume. bool is_outside : 1; bool partly_inside : 1; // Wheter or not this volume has been generated from a modifier bool is_modifier : 1; // Wheter or not this volume has been generated from the wipe tower bool is_wipe_tower : 1; // Wheter or not this volume has been generated from an extrusion path bool is_extrusion_path : 1; // Wheter or not to always render this volume using its own alpha bool force_transparent : 1; // Whether or not always use the volume's own color (not using SELECTED/HOVER/DISABLED/OUTSIDE) bool force_native_color : 1; // Whether or not render this volume in neutral bool force_neutral_color : 1; // Whether or not to force rendering of sinking contours bool force_sinking_contours : 1; // Is render for picking bool picking : 1; }; // Is mouse or rectangle selection over this object to select/deselect it ? EHoverState hover; GUI::GLModel model; // raycaster used for picking std::unique_ptr mesh_raycaster; // BBS mutable std::vector mmuseg_models; mutable ObjectBase::Timestamp mmuseg_ts; // Ranges of triangle and quad indices to be rendered. std::pair tverts_range; // If the qverts or tverts contain thick extrusions, then offsets keeps pointers of the starts // of the extrusions per layer. std::vector print_zs; // Offset into qverts & tverts, or offsets into indices stored into an OpenGL name_index_buffer. std::vector offsets; // Bounding box of this volume, in unscaled coordinates. BoundingBoxf3 bounding_box() const { return this->model.get_bounding_box(); } void set_color(const ColorRGBA& rgba) { color = rgba; } void set_render_color(const ColorRGBA& rgba) { render_color = rgba; } // Sets render color in dependence of current state void set_render_color(); // set color according to model volume void set_color_from_model_volume(const ModelVolume& model_volume); const Geometry::Transformation& get_instance_transformation() const { return m_instance_transformation; } void set_instance_transformation(const Geometry::Transformation& transformation) { m_instance_transformation = transformation; set_bounding_boxes_as_dirty(); } const Vec3d& get_instance_offset() const { return m_instance_transformation.get_offset(); } double get_instance_offset(Axis axis) const { return m_instance_transformation.get_offset(axis); } void set_instance_offset(const Vec3d& offset) { m_instance_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); } void set_instance_offset(Axis axis, double offset) { m_instance_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); } const Vec3d& get_instance_rotation() const { return m_instance_transformation.get_rotation(); } double get_instance_rotation(Axis axis) const { return m_instance_transformation.get_rotation(axis); } void set_instance_rotation(const Vec3d& rotation) { m_instance_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); } void set_instance_rotation(Axis axis, double rotation) { m_instance_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); } Vec3d get_instance_scaling_factor() const { return m_instance_transformation.get_scaling_factor(); } double get_instance_scaling_factor(Axis axis) const { return m_instance_transformation.get_scaling_factor(axis); } void set_instance_scaling_factor(const Vec3d& scaling_factor) { m_instance_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); } void set_instance_scaling_factor(Axis axis, double scaling_factor) { m_instance_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); } const Vec3d& get_instance_mirror() const { return m_instance_transformation.get_mirror(); } double get_instance_mirror(Axis axis) const { return m_instance_transformation.get_mirror(axis); } void set_instance_mirror(const Vec3d& mirror) { m_instance_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); } void set_instance_mirror(Axis axis, double mirror) { m_instance_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); } const Geometry::Transformation& get_volume_transformation() const { return m_volume_transformation; } void set_volume_transformation(const Geometry::Transformation& transformation) { m_volume_transformation = transformation; set_bounding_boxes_as_dirty(); } const Vec3d& get_volume_offset() const { return m_volume_transformation.get_offset(); } double get_volume_offset(Axis axis) const { return m_volume_transformation.get_offset(axis); } void set_volume_offset(const Vec3d& offset) { m_volume_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); } void set_volume_offset(Axis axis, double offset) { m_volume_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); } const Vec3d& get_volume_rotation() const { return m_volume_transformation.get_rotation(); } double get_volume_rotation(Axis axis) const { return m_volume_transformation.get_rotation(axis); } void set_volume_rotation(const Vec3d& rotation) { m_volume_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); } void set_volume_rotation(Axis axis, double rotation) { m_volume_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); } const Vec3d& get_volume_scaling_factor() const { return m_volume_transformation.get_scaling_factor(); } double get_volume_scaling_factor(Axis axis) const { return m_volume_transformation.get_scaling_factor(axis); } void set_volume_scaling_factor(const Vec3d& scaling_factor) { m_volume_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); } void set_volume_scaling_factor(Axis axis, double scaling_factor) { m_volume_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); } const Vec3d& get_volume_mirror() const { return m_volume_transformation.get_mirror(); } double get_volume_mirror(Axis axis) const { return m_volume_transformation.get_mirror(axis); } void set_volume_mirror(const Vec3d& mirror) { m_volume_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); } void set_volume_mirror(Axis axis, double mirror) { m_volume_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); } double get_sla_shift_z() const { return m_sla_shift_z; } void set_sla_shift_z(double z) { m_sla_shift_z = z; } void set_convex_hull(std::shared_ptr convex_hull) { m_convex_hull = std::move(convex_hull); } void set_convex_hull(const TriangleMesh &convex_hull) { m_convex_hull = std::make_shared(convex_hull); } void set_convex_hull(TriangleMesh &&convex_hull) { m_convex_hull = std::make_shared(std::move(convex_hull)); } void set_offset_to_assembly(const Vec3d& offset) { m_offset_to_assembly = offset; set_bounding_boxes_as_dirty(); } Vec3d get_offset_to_assembly() { return m_offset_to_assembly; } int object_idx() const { return this->composite_id.object_id; } int volume_idx() const { return this->composite_id.volume_id; } int instance_idx() const { return this->composite_id.instance_id; } Transform3d world_matrix() const; bool is_left_handed() const; const BoundingBoxf3& transformed_bounding_box() const; // non-caching variant BoundingBoxf3 transformed_convex_hull_bounding_box(const Transform3d &trafo) const; // caching variant const BoundingBoxf3& transformed_convex_hull_bounding_box() const; // non-caching variant BoundingBoxf3 transformed_non_sinking_bounding_box(const Transform3d& trafo) const; // caching variant const BoundingBoxf3& transformed_non_sinking_bounding_box() const; // convex hull const TriangleMesh* convex_hull() const { return m_convex_hull.get(); } bool empty() const { return this->model.is_empty(); } void set_range(double low, double high); virtual void render(); //BBS: add outline related logic and add virtual specifier virtual void render_with_outline(const Transform3d &view_model_matrix); //BBS: add simple render function for thumbnail void simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector extruder_colors); void set_bounding_boxes_as_dirty() { m_transformed_bounding_box.reset(); m_transformed_convex_hull_bounding_box.reset(); m_transformed_non_sinking_bounding_box.reset(); } bool is_sla_support() const; bool is_sla_pad() const; bool is_sinking() const; bool is_below_printbed() const; void render_sinking_contours(); // Return an estimate of the memory consumed by this class. size_t cpu_memory_used() const { return sizeof(*this) + this->model.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) + this->offsets.capacity() * sizeof(size_t); } // Return an estimate of the memory held by GPU vertex buffers. size_t gpu_memory_used() const { return this->model.gpu_memory_used(); } size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); } }; // BBS class GLWipeTowerVolume : public GLVolume { public: GLWipeTowerVolume(const std::vector& colors); void render() override; void render_with_outline(const Transform3d &view_model_matrix) override { render(); } std::vector model_per_colors; bool IsTransparent(); private: std::vector m_colors; }; typedef std::vector GLVolumePtrs; typedef std::pair> GLVolumeWithIdAndZ; typedef std::vector GLVolumeWithIdAndZList; class GLVolumeCollection { public: enum class ERenderType : unsigned char { Opaque, Transparent, All }; struct PrintVolume { // see: Bed3D::EShapeType int type{ 0 }; // data contains: // Rectangle: // [0] = min.x, [1] = min.y, [2] = max.x, [3] = max.y // Circle: // [0] = center.x, [1] = center.y, [3] = radius std::array data; // [0] = min z, [1] = max z std::array zs; }; private: PrintVolume m_print_volume; PrintVolume m_render_volume; // z range for clipping in shaders std::array m_z_range; // plane coeffs for clipping in shaders std::array m_clipping_plane; struct Slope { // toggle for slope rendering bool active{ false };//local active bool isGlobalActive{false}; float normal_z; }; Slope m_slope; bool m_show_sinking_contours = false; public: GLVolumePtrs volumes; GLVolumeCollection() { set_default_slope_normal_z(); //BBS init render volume m_render_volume.type = -1; } ~GLVolumeCollection() { clear(); } std::vector load_object( const ModelObject* model_object, int obj_idx, const std::vector& instance_idxs); int load_object_volume( const ModelObject* model_object, int obj_idx, int volume_idx, int instance_idx, bool in_assemble_view = false, bool use_loaded_id = false); // Load SLA auxiliary GLVolumes (for support trees or pad). void load_object_auxiliary( const SLAPrintObject *print_object, int obj_idx, // pairs of const std::vector>& instances, SLAPrintObjectStep milestone, // Timestamp of the last change of the milestone size_t timestamp); int load_wipe_tower_preview( int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width); GLVolume* new_toolpath_volume(const ColorRGBA& rgba); GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba); int get_selection_support_threshold_angle(bool&) const; // Render the volumes by OpenGL. //BBS: add outline drawing logic void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, const Transform3d& projection_matrix, std::function filter_func = std::function(), bool with_outline = true) const; // Clear the geometry void clear() { for (auto *v : volumes) delete v; volumes.clear(); } bool empty() const { return volumes.empty(); } void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); } void set_print_volume(const PrintVolume& print_volume) { m_print_volume = print_volume; } void set_z_range(float min_z, float max_z) { m_z_range[0] = min_z; m_z_range[1] = max_z; } void set_clipping_plane(const std::array& coeffs) { m_clipping_plane = coeffs; } const std::array& get_z_range() const { return m_z_range; } const std::array& get_clipping_plane() const { return m_clipping_plane; } bool is_slope_GlobalActive() const { return m_slope.isGlobalActive; } bool is_slope_active() const { return m_slope.active; } void set_slope_active(bool active) { m_slope.active = active; } void set_slope_GlobalActive(bool active) { m_slope.isGlobalActive = active; } float get_slope_normal_z() const { return m_slope.normal_z; } void set_slope_normal_z(float normal_z) { m_slope.normal_z = normal_z; } void set_default_slope_normal_z() { m_slope.normal_z = -::cos(Geometry::deg2rad(90.0f - 45.0f)); } void set_show_sinking_contours(bool show) { m_show_sinking_contours = show; } // returns true if all the volumes are completely contained in the print volume // returns the containment state in the given out_state, if non-null bool check_outside_state(const Slic3r::BuildVolume& build_volume, ModelInstanceEPrintVolumeState* out_state) const; void reset_outside_state(); void update_colors_by_extruder(const DynamicPrintConfig *config, bool is_update_alpha = true); // Returns a vector containing the sorted list of all the print_zs of the volumes contained in this collection std::vector get_current_print_zs(bool active_only) const; // Return an estimate of the memory consumed by this class. size_t cpu_memory_used() const; // Return an estimate of the memory held by GPU vertex buffers. size_t gpu_memory_used() const; size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); } // Return CPU, GPU and total memory log line. std::string log_memory_info() const; void set_transparency(float alpha); private: GLVolumeCollection(const GLVolumeCollection &other); GLVolumeCollection& operator=(const GLVolumeCollection &); }; GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function filter_func = nullptr); struct _3DScene { static void thick_lines_to_verts(const Lines& lines, const std::vector& widths, const std::vector& heights, bool closed, double top_z, GUI::GLModel::Geometry& geometry); static void thick_lines_to_verts(const Lines3& lines, const std::vector& widths, const std::vector& heights, bool closed, GUI::GLModel::Geometry& geometry); static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry); static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry); static void extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry); static void extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry); static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry); }; } #endif