mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Merge remote-tracking branch 'remotes/origin/master' into tm_relative_correction
This commit is contained in:
		
						commit
						0de084df8d
					
				
					 89 changed files with 3808 additions and 2930 deletions
				
			
		|  | @ -39,8 +39,7 @@ static void stl_record_neighbors(stl_file *stl, | |||
|                                  stl_hash_edge *edge_a, stl_hash_edge *edge_b); | ||||
| static void stl_initialize_facet_check_exact(stl_file *stl); | ||||
| static void stl_initialize_facet_check_nearby(stl_file *stl); | ||||
| static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, | ||||
|                                 stl_vertex *a, stl_vertex *b); | ||||
| static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, const stl_vertex *a, const stl_vertex *b); | ||||
| static int stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge, | ||||
|                                 stl_vertex *a, stl_vertex *b, float tolerance); | ||||
| static void insert_hash_edge(stl_file *stl, stl_hash_edge edge, | ||||
|  | @ -60,41 +59,40 @@ extern int stl_check_normal_vector(stl_file *stl, | |||
|                                    int facet_num, int normal_fix_flag); | ||||
| static void stl_update_connects_remove_1(stl_file *stl, int facet_num); | ||||
| 
 | ||||
| 
 | ||||
| void | ||||
| stl_check_facets_exact(stl_file *stl) { | ||||
|   /* This function builds the neighbors list.  No modifications are made
 | ||||
|    *  to any of the facets.  The edges are said to match only if all six | ||||
|    *  floats of the first edge matches all six floats of the second edge. | ||||
|    */ | ||||
| 
 | ||||
|   stl_hash_edge  edge; | ||||
|   stl_facet      facet; | ||||
|   int            i; | ||||
|   int            j; | ||||
| 
 | ||||
|   if (stl->error) return; | ||||
| // This function builds the neighbors list.  No modifications are made
 | ||||
| // to any of the facets.  The edges are said to match only if all six
 | ||||
| // floats of the first edge matches all six floats of the second edge.
 | ||||
| void stl_check_facets_exact(stl_file *stl) | ||||
| { | ||||
|   if (stl->error) | ||||
| 	  return; | ||||
| 
 | ||||
|   stl->stats.connected_edges = 0; | ||||
|   stl->stats.connected_facets_1_edge = 0; | ||||
|   stl->stats.connected_facets_2_edge = 0; | ||||
|   stl->stats.connected_facets_3_edge = 0; | ||||
| 
 | ||||
|   stl_initialize_facet_check_exact(stl); | ||||
|   // If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet.
 | ||||
|   // Do it before the next step, as the next step stores references to the face indices in the hash tables and removing a facet
 | ||||
|   // will break the references.
 | ||||
|   for (int i = 0; i < stl->stats.number_of_facets;) { | ||||
| 	  stl_facet &facet = stl->facet_start[i]; | ||||
| 	  if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) { | ||||
| 		  // Remove the degenerate facet.
 | ||||
| 		  facet = stl->facet_start[--stl->stats.number_of_facets]; | ||||
| 		  stl->stats.facets_removed += 1; | ||||
| 		  stl->stats.degenerate_facets += 1; | ||||
| 	  } else | ||||
| 		  ++ i; | ||||
|   } | ||||
| 
 | ||||
|   for(i = 0; i < stl->stats.number_of_facets; i++) { | ||||
|     facet = stl->facet_start[i]; | ||||
|     // If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet.
 | ||||
|     if (facet.vertex[0] == facet.vertex[1] || | ||||
|         facet.vertex[1] == facet.vertex[2] || | ||||
|         facet.vertex[0] == facet.vertex[2]) { | ||||
|       stl->stats.degenerate_facets += 1; | ||||
|       stl_remove_facet(stl, i); | ||||
|       -- i; | ||||
|       continue; | ||||
|     } | ||||
|     for(j = 0; j < 3; j++) { | ||||
|       edge.facet_number = i; | ||||
|   // Connect neighbor edges.
 | ||||
|   stl_initialize_facet_check_exact(stl); | ||||
|   for (int i = 0; i < stl->stats.number_of_facets; i++) { | ||||
| 	const stl_facet &facet = stl->facet_start[i]; | ||||
|     for (int j = 0; j < 3; j++) { | ||||
| 	  stl_hash_edge  edge; | ||||
| 	  edge.facet_number = i; | ||||
|       edge.which_edge = j; | ||||
|       stl_load_edge_exact(stl, &edge, &facet.vertex[j], &facet.vertex[(j + 1) % 3]); | ||||
|       insert_hash_edge(stl, edge, stl_record_neighbors); | ||||
|  | @ -109,9 +107,7 @@ stl_check_facets_exact(stl_file *stl) { | |||
| #endif | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, | ||||
|                     stl_vertex *a, stl_vertex *b) { | ||||
| static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, const stl_vertex *a, const stl_vertex *b) { | ||||
| 
 | ||||
|   if (stl->error) return; | ||||
| 
 | ||||
|  | @ -333,7 +329,9 @@ static void stl_free_edges(stl_file *stl) | |||
|     } | ||||
|   } | ||||
|   free(stl->heads); | ||||
|   stl->heads = nullptr; | ||||
|   free(stl->tail); | ||||
|   stl->tail = nullptr; | ||||
| } | ||||
| 
 | ||||
| static void stl_initialize_facet_check_nearby(stl_file *stl) | ||||
|  |  | |||
|  | @ -127,7 +127,6 @@ typedef struct { | |||
| typedef struct { | ||||
|   FILE          *fp; | ||||
|   stl_facet     *facet_start; | ||||
|   stl_edge      *edge_start; | ||||
|   stl_hash_edge **heads; | ||||
|   stl_hash_edge *tail; | ||||
|   int           M; | ||||
|  | @ -142,7 +141,6 @@ typedef struct { | |||
| extern void stl_open(stl_file *stl, const char *file); | ||||
| extern void stl_close(stl_file *stl); | ||||
| extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file); | ||||
| extern void stl_print_edges(stl_file *stl, FILE *file); | ||||
| extern void stl_print_neighbors(stl_file *stl, char *file); | ||||
| extern void stl_put_little_int(FILE *fp, int value_in); | ||||
| extern void stl_put_little_float(FILE *fp, float value_in); | ||||
|  |  | |||
|  | @ -33,24 +33,6 @@ | |||
| #define SEEK_END 2 | ||||
| #endif | ||||
| 
 | ||||
| void | ||||
| stl_print_edges(stl_file *stl, FILE *file) { | ||||
|   int i; | ||||
|   int edges_allocated; | ||||
| 
 | ||||
|   if (stl->error) return; | ||||
| 
 | ||||
|   edges_allocated = stl->stats.number_of_facets * 3; | ||||
|   for(i = 0; i < edges_allocated; i++) { | ||||
|     fprintf(file, "%d, %f, %f, %f, %f, %f, %f\n", | ||||
|             stl->edge_start[i].facet_number, | ||||
|             stl->edge_start[i].p1(0), stl->edge_start[i].p1(1), | ||||
|             stl->edge_start[i].p1(2), stl->edge_start[i].p2(0), | ||||
|             stl->edge_start[i].p2(1), stl->edge_start[i].p2(2)); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void | ||||
| stl_stats_out(stl_file *stl, FILE *file, char *input_file) { | ||||
|   if (stl->error) return; | ||||
|  |  | |||
|  | @ -1034,6 +1034,15 @@ void GCode::_do_export(Print &print, FILE *file) | |||
|     } | ||||
|     _write(file, m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100%
 | ||||
|     _write(file, m_writer.postamble()); | ||||
| 
 | ||||
|     // adds tags for time estimators
 | ||||
|     if (print.config().remaining_times.value) | ||||
|     { | ||||
|         _writeln(file, GCodeTimeEstimator::Normal_Last_M73_Output_Placeholder_Tag); | ||||
|         if (m_silent_time_estimator_enabled) | ||||
|             _writeln(file, GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag); | ||||
|     } | ||||
| 
 | ||||
|     print.throw_if_canceled(); | ||||
| 
 | ||||
|     // calculates estimated printing time
 | ||||
|  |  | |||
|  | @ -776,6 +776,9 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ | |||
|     preview_data.ranges.width.update_from(width_range); | ||||
|     preview_data.ranges.feedrate.update_from(feedrate_range); | ||||
|     preview_data.ranges.volumetric_rate.update_from(volumetric_rate_range); | ||||
| 
 | ||||
|     // we need to sort the layers by their z as they can be shuffled in case of sequential prints
 | ||||
|     std::sort(preview_data.extrusion.layers.begin(), preview_data.extrusion.layers.end(), [](const GCodePreviewData::Extrusion::Layer& l1, const GCodePreviewData::Extrusion::Layer& l2)->bool { return l1.z < l2.z; }); | ||||
| } | ||||
| 
 | ||||
| void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, std::function<void()> cancel_callback) | ||||
|  | @ -855,6 +858,11 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s | |||
|     preview_data.ranges.height.update_from(height_range); | ||||
|     preview_data.ranges.width.update_from(width_range); | ||||
|     preview_data.ranges.feedrate.update_from(feedrate_range); | ||||
| 
 | ||||
|     // we need to sort the polylines by their min z as they can be shuffled in case of sequential prints
 | ||||
|     std::sort(preview_data.travel.polylines.begin(), preview_data.travel.polylines.end(), | ||||
|         [](const GCodePreviewData::Travel::Polyline& p1, const GCodePreviewData::Travel::Polyline& p2)->bool | ||||
|     { return unscale<double>(p1.polyline.bounding_box().min(2)) < unscale<double>(p2.polyline.bounding_box().min(2)); }); | ||||
| } | ||||
| 
 | ||||
| void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_data, std::function<void()> cancel_callback) | ||||
|  | @ -877,6 +885,11 @@ void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_da | |||
|         Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())); | ||||
|         preview_data.retraction.positions.emplace_back(position, move.data.width, move.data.height); | ||||
|     } | ||||
| 
 | ||||
|     // we need to sort the positions by their z as they can be shuffled in case of sequential prints
 | ||||
|     std::sort(preview_data.retraction.positions.begin(), preview_data.retraction.positions.end(), | ||||
|         [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2)->bool | ||||
|     { return unscale<double>(p1.position(2)) < unscale<double>(p2.position(2)); }); | ||||
| } | ||||
| 
 | ||||
| void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_data, std::function<void()> cancel_callback) | ||||
|  | @ -899,6 +912,11 @@ void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_ | |||
|         Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())); | ||||
|         preview_data.unretraction.positions.emplace_back(position, move.data.width, move.data.height); | ||||
|     } | ||||
| 
 | ||||
|     // we need to sort the positions by their z as they can be shuffled in case of sequential prints
 | ||||
|     std::sort(preview_data.unretraction.positions.begin(), preview_data.unretraction.positions.end(), | ||||
|         [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2)->bool | ||||
|     { return unscale<double>(p1.position(2)) < unscale<double>(p2.position(2)); }); | ||||
| } | ||||
| 
 | ||||
| // Return an estimate of the memory consumed by the time estimator.
 | ||||
|  |  | |||
|  | @ -171,6 +171,8 @@ namespace Slic3r { | |||
| 
 | ||||
|     const std::string GCodeTimeEstimator::Normal_First_M73_Output_Placeholder_Tag = "; NORMAL_FIRST_M73_OUTPUT_PLACEHOLDER"; | ||||
|     const std::string GCodeTimeEstimator::Silent_First_M73_Output_Placeholder_Tag = "; SILENT_FIRST_M73_OUTPUT_PLACEHOLDER"; | ||||
|     const std::string GCodeTimeEstimator::Normal_Last_M73_Output_Placeholder_Tag = "; NORMAL_LAST_M73_OUTPUT_PLACEHOLDER"; | ||||
|     const std::string GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag = "; SILENT_LAST_M73_OUTPUT_PLACEHOLDER"; | ||||
| 
 | ||||
|     GCodeTimeEstimator::GCodeTimeEstimator(EMode mode) | ||||
|         : _mode(mode) | ||||
|  | @ -306,9 +308,17 @@ namespace Slic3r { | |||
|                 sprintf(time_line, time_mask.c_str(), "0", _get_time_minutes(_time).c_str()); | ||||
|                 gcode_line = time_line; | ||||
|             } | ||||
|             // replaces placeholders for final line M73 with the real lines
 | ||||
|             else if (((_mode == Normal) && (gcode_line == Normal_Last_M73_Output_Placeholder_Tag)) || | ||||
|                      ((_mode == Silent) && (gcode_line == Silent_Last_M73_Output_Placeholder_Tag))) | ||||
|             { | ||||
|                 sprintf(time_line, time_mask.c_str(), "100", "0"); | ||||
|                 gcode_line = time_line; | ||||
|             } | ||||
|             else | ||||
|                gcode_line += "\n"; | ||||
| 
 | ||||
| 
 | ||||
|             // add remaining time lines where needed
 | ||||
|             _parser.parse_line(gcode_line, | ||||
|                 [this, &it_line_id, &g1_lines_count, &last_recorded_time, &time_line, &gcode_line, time_mask, interval](GCodeReader& reader, const GCodeReader::GCodeLine& line) | ||||
|  |  | |||
|  | @ -19,6 +19,8 @@ namespace Slic3r { | |||
|     public: | ||||
|         static const std::string Normal_First_M73_Output_Placeholder_Tag; | ||||
|         static const std::string Silent_First_M73_Output_Placeholder_Tag; | ||||
|         static const std::string Normal_Last_M73_Output_Placeholder_Tag; | ||||
|         static const std::string Silent_Last_M73_Output_Placeholder_Tag; | ||||
| 
 | ||||
|         enum EMode : unsigned char | ||||
|         { | ||||
|  |  | |||
|  | @ -1455,4 +1455,28 @@ Transformation Transformation::operator * (const Transformation& other) const | |||
|     return Transformation(get_matrix() * other.get_matrix()); | ||||
| } | ||||
| 
 | ||||
| Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) | ||||
| { | ||||
|     return | ||||
|         // From the current coordinate system to world.
 | ||||
|         Eigen::AngleAxisd(rot_xyz_to(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(rot_xyz_to(1), Vec3d::UnitY()) * Eigen::AngleAxisd(rot_xyz_to(0), Vec3d::UnitX()) * | ||||
|         // From world to the initial coordinate system.
 | ||||
|         Eigen::AngleAxisd(-rot_xyz_from(0), Vec3d::UnitX()) * Eigen::AngleAxisd(-rot_xyz_from(1), Vec3d::UnitY()) * Eigen::AngleAxisd(-rot_xyz_from(2), Vec3d::UnitZ()); | ||||
| } | ||||
| 
 | ||||
| // This should only be called if it is known, that the two rotations only differ in rotation around the Z axis.
 | ||||
| double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) | ||||
| { | ||||
|     Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); | ||||
|     Vec3d  axis  = angle_axis.axis(); | ||||
|     double angle = angle_axis.angle(); | ||||
| #ifndef NDEBUG | ||||
|     if (std::abs(angle) > 1e-8) { | ||||
|         assert(std::abs(axis.x()) < 1e-8); | ||||
|         assert(std::abs(axis.y()) < 1e-8); | ||||
|     } | ||||
| #endif /* NDEBUG */ | ||||
|     return (axis.z() < 0) ? -angle : angle; | ||||
| } | ||||
| 
 | ||||
| } } | ||||
|  |  | |||
|  | @ -262,6 +262,13 @@ public: | |||
|     Transformation operator * (const Transformation& other) const; | ||||
| }; | ||||
| 
 | ||||
| // Rotation when going from the first coordinate system with rotation rot_xyz_from applied
 | ||||
| // to a coordinate system with rot_xyz_to applied.
 | ||||
| extern Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to); | ||||
| // Rotation by Z to align rot_xyz_from to rot_xyz_to.
 | ||||
| // This should only be called if it is known, that the two rotations only differ in rotation around the Z axis.
 | ||||
| extern double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to); | ||||
| 
 | ||||
| } } | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -556,19 +556,9 @@ std::string Model::propose_export_file_name_and_path() const | |||
|     for (const ModelObject *model_object : this->objects) | ||||
|         for (ModelInstance *model_instance : model_object->instances) | ||||
|             if (model_instance->is_printable()) { | ||||
|                 input_file = model_object->input_file; | ||||
|                 if (! model_object->name.empty()) { | ||||
|                     if (input_file.empty()) | ||||
|                         // model_object->input_file was empty, just use model_object->name
 | ||||
|                         input_file = model_object->name; | ||||
|                     else { | ||||
|                         // Replace file name in input_file with model_object->name, but keep the path and file extension.
 | ||||
| 						input_file = (boost::filesystem::path(model_object->name).parent_path().empty()) ? | ||||
| 							(boost::filesystem::path(input_file).parent_path() / model_object->name).make_preferred().string() : | ||||
| 							model_object->name; | ||||
| 					} | ||||
|                 } | ||||
|                 if (! input_file.empty()) | ||||
|                 input_file = model_object->get_export_filename(); | ||||
| 
 | ||||
|                 if (!input_file.empty()) | ||||
|                     goto end; | ||||
|                 // Other instances will produce the same name, skip them.
 | ||||
|                 break; | ||||
|  | @ -1433,6 +1423,26 @@ void ModelObject::print_info() const | |||
|     cout << "volume = "           << mesh.volume()                  << endl; | ||||
| } | ||||
| 
 | ||||
| std::string ModelObject::get_export_filename() const | ||||
| { | ||||
|     std::string ret = input_file; | ||||
| 
 | ||||
|     if (!name.empty()) | ||||
|     { | ||||
|         if (ret.empty()) | ||||
|             // input_file was empty, just use name
 | ||||
|             ret = name; | ||||
|         else | ||||
|         { | ||||
|             // Replace file name in input_file with name, but keep the path and file extension.
 | ||||
|             ret = (boost::filesystem::path(name).parent_path().empty()) ? | ||||
|                 (boost::filesystem::path(ret).parent_path() / name).make_preferred().string() : name; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| void ModelVolume::set_material_id(t_model_material_id material_id) | ||||
| { | ||||
|     m_material_id = material_id; | ||||
|  |  | |||
|  | @ -275,6 +275,8 @@ public: | |||
|     // Print object statistics to console.
 | ||||
|     void print_info() const; | ||||
| 
 | ||||
|     std::string get_export_filename() const; | ||||
| 
 | ||||
| protected: | ||||
|     friend class Print; | ||||
|     friend class SLAPrint; | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ | |||
| #include "GCode/WipeTowerPrusaMM.hpp" | ||||
| #include "Utils.hpp" | ||||
| 
 | ||||
| #include "PrintExport.hpp" | ||||
| //#include "PrintExport.hpp"
 | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <limits> | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| #include <vector> | ||||
| 
 | ||||
| #include <boost/log/trivial.hpp> | ||||
| #include <boost/filesystem/path.hpp> | ||||
| 
 | ||||
| #include "Rasterizer/Rasterizer.hpp" | ||||
| //#include <tbb/parallel_for.h>
 | ||||
|  | @ -72,7 +73,8 @@ public: | |||
|     void finish_layer(); | ||||
| 
 | ||||
|     // Save all the layers into the file (or dir) specified in the path argument
 | ||||
|     void save(const std::string& path); | ||||
|     // An optional project name can be added to be used for the layer file names
 | ||||
|     void save(const std::string& path, const std::string& projectname = ""); | ||||
| 
 | ||||
|     // Save only the selected layer to the file specified in path argument.
 | ||||
|     void save_layer(unsigned lyr, const std::string& path); | ||||
|  | @ -86,7 +88,8 @@ template<class T = void> struct VeryFalse { static const bool value = false; }; | |||
| template<class Fmt> class LayerWriter { | ||||
| public: | ||||
| 
 | ||||
|     LayerWriter(const std::string& /*zipfile_path*/) { | ||||
|     LayerWriter(const std::string& /*zipfile_path*/) | ||||
|     { | ||||
|         static_assert(VeryFalse<Fmt>::value, | ||||
|                       "No layer writer implementation provided!"); | ||||
|     } | ||||
|  | @ -99,10 +102,6 @@ public: | |||
|     void binary_entry(const std::string& /*fname*/, | ||||
|                       const std::uint8_t* buf, size_t len); | ||||
| 
 | ||||
|     // Get the name of the archive but only the name part without the path or
 | ||||
|     // the extension.
 | ||||
|     std::string get_name() { return ""; } | ||||
| 
 | ||||
|     // Test whether the object can still be used for writing.
 | ||||
|     bool is_ok() { return false; } | ||||
| 
 | ||||
|  | @ -253,12 +252,14 @@ public: | |||
|     } | ||||
| 
 | ||||
|     template<class LyrFmt> | ||||
|     inline void save(const std::string& path) { | ||||
|     inline void save(const std::string& fpath, const std::string& prjname = "") | ||||
|     { | ||||
|         try { | ||||
|             LayerWriter<LyrFmt> writer(path); | ||||
|             LayerWriter<LyrFmt> writer(fpath); | ||||
|             if(!writer.is_ok()) return; | ||||
| 
 | ||||
|             std::string project = writer.get_name(); | ||||
|             std::string project = prjname.empty()? | ||||
|                        boost::filesystem::path(fpath).stem().string() : prjname; | ||||
| 
 | ||||
|             writer.next_entry("config.ini"); | ||||
|             if(!writer.is_ok()) return; | ||||
|  |  | |||
|  | @ -1790,8 +1790,13 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z, | |||
|     if (! volumes.empty()) { | ||||
|         // Compose mesh.
 | ||||
|         //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
 | ||||
|         TriangleMesh mesh(volumes.front()->mesh); | ||||
| 		TriangleMesh mesh(volumes.front()->mesh); | ||||
|         mesh.transform(volumes.front()->get_matrix(), true); | ||||
| 		assert(mesh.repaired); | ||||
| 		if (volumes.size() == 1 && mesh.repaired) { | ||||
| 			//FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it.
 | ||||
| 			stl_check_facets_exact(&mesh.stl); | ||||
| 		} | ||||
|         for (size_t idx_volume = 1; idx_volume < volumes.size(); ++ idx_volume) { | ||||
|             const ModelVolume &model_volume = *volumes[idx_volume]; | ||||
|             TriangleMesh vol_mesh(model_volume.mesh); | ||||
|  | @ -1821,6 +1826,10 @@ std::vector<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &z, | |||
|     //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
 | ||||
|     TriangleMesh mesh(volume.mesh); | ||||
|     mesh.transform(volume.get_matrix(), true); | ||||
| 	if (mesh.repaired) { | ||||
| 		//FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it.
 | ||||
| 		stl_check_facets_exact(&mesh.stl); | ||||
| 	} | ||||
|     if (mesh.stl.stats.number_of_facets > 0) { | ||||
|         mesh.transform(m_trafo, true); | ||||
|         // apply XY shift
 | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ public: | |||
|             float minimal_distance; | ||||
|             float head_diameter; | ||||
|             ///////////////
 | ||||
|             inline float support_force() const { return 10.f / density_relative; } // a force one point can support       (arbitrary force unit)
 | ||||
|             inline float support_force() const { return 7.7f / density_relative; } // a force one point can support       (arbitrary force unit)
 | ||||
|             inline float tear_pressure() const { return 1.f; }  // pressure that the display exerts    (the force unit per mm2)
 | ||||
|         }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
| #include "SLA/SLABasePool.hpp" | ||||
| #include "SLA/SLAAutoSupports.hpp" | ||||
| #include "ClipperUtils.hpp" | ||||
| #include "Geometry.hpp" | ||||
| #include "MTUtils.hpp" | ||||
| 
 | ||||
| #include <unordered_set> | ||||
|  | @ -118,13 +119,18 @@ static Transform3d sla_trafo(const SLAPrint& p, const ModelObject &model_object) | |||
| static std::vector<SLAPrintObject::Instance> sla_instances(const ModelObject &model_object) | ||||
| { | ||||
|     std::vector<SLAPrintObject::Instance> instances; | ||||
|     for (ModelInstance *model_instance : model_object.instances) | ||||
|         if (model_instance->is_printable()) { | ||||
|             instances.emplace_back( | ||||
|                 model_instance->id(), | ||||
|                 Point::new_scale(model_instance->get_offset(X), model_instance->get_offset(Y)), | ||||
|                 float(model_instance->get_rotation(Z))); | ||||
|         } | ||||
|     assert(! model_object.instances.empty()); | ||||
|     if (! model_object.instances.empty()) { | ||||
|         Vec3d rotation0 = model_object.instances.front()->get_rotation(); | ||||
|         rotation0(2) = 0.; | ||||
|         for (ModelInstance *model_instance : model_object.instances) | ||||
|             if (model_instance->is_printable()) { | ||||
|                 instances.emplace_back( | ||||
|                     model_instance->id(), | ||||
|                     Point::new_scale(model_instance->get_offset(X), model_instance->get_offset(Y)), | ||||
| 					float(Geometry::rotation_diff_z(rotation0, model_instance->get_rotation()))); | ||||
|             } | ||||
|     } | ||||
|     return instances; | ||||
| } | ||||
| 
 | ||||
|  | @ -1078,11 +1084,11 @@ void SLAPrint::process() | |||
|                         hole.reserve(h.points.size() + 1); | ||||
| 
 | ||||
|                         if(needreverse) | ||||
|                             for(auto& p : h.points) | ||||
|                                 hole.emplace_back(p.x(), p.y()); | ||||
|                         else | ||||
|                             for(auto it = h.points.rbegin(); it != h.points.rend(); ++it) | ||||
|                                 hole.emplace_back(it->x(), it->y()); | ||||
|                         else | ||||
|                             for(auto& p : h.points) | ||||
|                                 hole.emplace_back(p.x(), p.y()); | ||||
|                     } | ||||
| 
 | ||||
|                     if(is_lefthanded) { | ||||
|  |  | |||
|  | @ -320,10 +320,8 @@ struct SLAPrintStatistics | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| struct SLAminzZipper {}; | ||||
| 
 | ||||
| // The implementation of creating zipped archives with wxWidgets
 | ||||
| template<> class LayerWriter<SLAminzZipper> { | ||||
| template<> class LayerWriter<Zipper> { | ||||
|     Zipper m_zip; | ||||
| public: | ||||
| 
 | ||||
|  | @ -332,16 +330,12 @@ public: | |||
|     void next_entry(const std::string& fname) { m_zip.add_entry(fname); } | ||||
| 
 | ||||
|     void binary_entry(const std::string& fname, | ||||
|                              const std::uint8_t* buf, | ||||
|                              size_t l) | ||||
|                       const std::uint8_t* buf, | ||||
|                       size_t l) | ||||
|     { | ||||
|         m_zip.add_entry(fname, buf, l); | ||||
|     } | ||||
| 
 | ||||
|     std::string get_name() const { | ||||
|         return m_zip.get_name(); | ||||
|     } | ||||
| 
 | ||||
|     template<class T> inline LayerWriter& operator<<(T&& arg) { | ||||
|         m_zip << std::forward<T>(arg); return *this; | ||||
|     } | ||||
|  | @ -389,9 +383,11 @@ public: | |||
|     // Returns true if the last step was finished with success.
 | ||||
|     bool                finished() const override { return this->is_step_done(slaposSliceSupports) && this->Inherited::is_step_done(slapsRasterize); } | ||||
| 
 | ||||
|     template<class Fmt = SLAminzZipper> | ||||
|     void export_raster(const std::string& fname) { | ||||
|         if(m_printer) m_printer->save<Fmt>(fname); | ||||
|     template<class Fmt = Zipper> | ||||
|     inline void export_raster(const std::string& fpath, | ||||
|                        const std::string& projectname = "") | ||||
|     { | ||||
|         if(m_printer) m_printer->save<Fmt>(fpath, projectname); | ||||
|     } | ||||
| 
 | ||||
|     const PrintObjects& objects() const { return m_objects; } | ||||
|  |  | |||
|  | @ -273,6 +273,11 @@ void TriangleMesh::translate(float x, float y, float z) | |||
|     stl_invalidate_shared_vertices(&this->stl); | ||||
| } | ||||
| 
 | ||||
| void TriangleMesh::translate(const Vec3f &displacement) | ||||
| { | ||||
|     translate(displacement(0), displacement(1), displacement(2)); | ||||
| } | ||||
| 
 | ||||
| void TriangleMesh::rotate(float angle, const Axis &axis) | ||||
| { | ||||
|     if (angle == 0.f) | ||||
|  |  | |||
|  | @ -40,6 +40,7 @@ public: | |||
|     void scale(float factor); | ||||
|     void scale(const Vec3d &versor); | ||||
|     void translate(float x, float y, float z); | ||||
|     void translate(const Vec3f &displacement); | ||||
|     void rotate(float angle, const Axis &axis); | ||||
|     void rotate(float angle, const Vec3d& axis); | ||||
|     void rotate_x(float angle) { this->rotate(angle, X); } | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ | |||
| 
 | ||||
| #include "Zipper.hpp" | ||||
| #include "miniz/miniz_zip.h" | ||||
| #include <boost/filesystem/path.hpp> | ||||
| #include <boost/log/trivial.hpp> | ||||
| 
 | ||||
| #include "I18N.hpp" | ||||
|  | @ -213,10 +212,6 @@ void Zipper::finish_entry() | |||
|     m_entry.clear(); | ||||
| } | ||||
| 
 | ||||
| std::string Zipper::get_name() const { | ||||
|     return boost::filesystem::path(m_impl->m_zipname).stem().string(); | ||||
| } | ||||
| 
 | ||||
| void Zipper::finalize() | ||||
| { | ||||
|     finish_entry(); | ||||
|  |  | |||
|  | @ -81,9 +81,6 @@ public: | |||
|     /// file is up to minz after the erroneous write.
 | ||||
|     void finish_entry(); | ||||
| 
 | ||||
|     /// Gets the name of the archive without the path or extension.
 | ||||
|     std::string get_name() const; | ||||
| 
 | ||||
|     void finalize(); | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -397,8 +397,9 @@ int CLI::run(int argc, char **argv) | |||
|                             outfile_final = fff_print.print_statistics().finalize_output_path(outfile); | ||||
|                         } else { | ||||
| 							outfile = sla_print.output_filepath(outfile); | ||||
| 							sla_print.export_raster(outfile); | ||||
| 							outfile_final = sla_print.print_statistics().finalize_output_path(outfile); | ||||
|                             // We need to finalize the filename beforehand because the export function sets the filename inside the zip metadata
 | ||||
|                             outfile_final = sla_print.print_statistics().finalize_output_path(outfile); | ||||
| 							sla_print.export_raster(outfile_final); | ||||
|                         } | ||||
|                         if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final) != 0) { | ||||
| 							boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl; | ||||
|  |  | |||
|  | @ -30,6 +30,9 @@ set(SLIC3R_GUI_SOURCES | |||
|     GUI/GLCanvas3DManager.cpp | ||||
|     GUI/Selection.hpp | ||||
|     GUI/Selection.cpp     | ||||
|     GUI/Gizmos/GLGizmos.hpp | ||||
|     GUI/Gizmos/GLGizmosManager.cpp | ||||
|     GUI/Gizmos/GLGizmosManager.hpp | ||||
|     GUI/Gizmos/GLGizmoBase.cpp | ||||
|     GUI/Gizmos/GLGizmoBase.hpp | ||||
|     GUI/Gizmos/GLGizmoMove.cpp | ||||
|  |  | |||
|  | @ -495,11 +495,11 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const | |||
|     // use anisotropic filter if graphic card allows
 | ||||
|     GLfloat max_anisotropy = 0.0f; | ||||
|     if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) | ||||
|         ::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy); | ||||
|         glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy)); | ||||
| 
 | ||||
|     // use higher resolution images if graphic card allows
 | ||||
|     GLint max_tex_size; | ||||
|     ::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size); | ||||
|     glsafe(::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size)); | ||||
| 
 | ||||
|     // clamp or the texture generation becomes too slow
 | ||||
|     max_tex_size = std::min(max_tex_size, 8192); | ||||
|  | @ -621,7 +621,6 @@ void Bed3D::render_prusa_shader(bool transparent) const | |||
|         m_shader.stop_using(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| void Bed3D::render_prusa(const std::string &key, float theta, bool useVBOs) const | ||||
| { | ||||
|  | @ -629,7 +628,7 @@ void Bed3D::render_prusa(const std::string &key, float theta, bool useVBOs) cons | |||
| 
 | ||||
|     // use higher resolution images if graphic card allows
 | ||||
|     GLint max_tex_size; | ||||
|     ::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size); | ||||
|     glsafe(::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size)); | ||||
| 
 | ||||
|     // temporary set to lowest resolution
 | ||||
|     max_tex_size = 2048; | ||||
|  | @ -644,7 +643,7 @@ void Bed3D::render_prusa(const std::string &key, float theta, bool useVBOs) cons | |||
|     // use anisotropic filter if graphic card allows
 | ||||
|     GLfloat max_anisotropy = 0.0f; | ||||
|     if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) | ||||
|         ::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy); | ||||
|         glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy)); | ||||
| 
 | ||||
|     std::string filename = tex_path + "_top.png"; | ||||
|     if ((m_top_texture.get_id() == 0) || (m_top_texture.get_source() != filename)) | ||||
|  |  | |||
|  | @ -41,6 +41,7 @@ void glAssertRecentCallImpl(const char *file_name, unsigned int line, const char | |||
|     switch (err) { | ||||
|     case GL_INVALID_ENUM:       sErr = "Invalid Enum";      break; | ||||
|     case GL_INVALID_VALUE:      sErr = "Invalid Value";     break; | ||||
|     // be aware that GL_INVALID_OPERATION is generated if glGetError is executed between the execution of glBegin and the corresponding execution of glEnd 
 | ||||
|     case GL_INVALID_OPERATION:  sErr = "Invalid Operation"; break; | ||||
|     case GL_STACK_OVERFLOW:     sErr = "Stack Overflow";    break; | ||||
|     case GL_STACK_UNDERFLOW:    sErr = "Stack Underflow";   break; | ||||
|  | @ -98,25 +99,25 @@ void GLIndexedVertexArray::finalize_geometry(bool use_VBOs) | |||
| 
 | ||||
|     if (use_VBOs) { | ||||
|         if (! empty()) { | ||||
|             glsafe(glGenBuffers(1, &this->vertices_and_normals_interleaved_VBO_id)); | ||||
|             glsafe(glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); | ||||
|             glsafe(glBufferData(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved.size() * 4, this->vertices_and_normals_interleaved.data(), GL_STATIC_DRAW)); | ||||
|             glsafe(glBindBuffer(GL_ARRAY_BUFFER, 0)); | ||||
|             glsafe(::glGenBuffers(1, &this->vertices_and_normals_interleaved_VBO_id)); | ||||
|             glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); | ||||
|             glsafe(::glBufferData(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved.size() * 4, this->vertices_and_normals_interleaved.data(), GL_STATIC_DRAW)); | ||||
|             glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); | ||||
|             this->vertices_and_normals_interleaved.clear(); | ||||
|         } | ||||
|         if (! this->triangle_indices.empty()) { | ||||
|             glsafe(glGenBuffers(1, &this->triangle_indices_VBO_id)); | ||||
|             glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id)); | ||||
|             glsafe(glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices.size() * 4, this->triangle_indices.data(), GL_STATIC_DRAW)); | ||||
|             glsafe(::glGenBuffers(1, &this->triangle_indices_VBO_id)); | ||||
|             glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id)); | ||||
|             glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices.size() * 4, this->triangle_indices.data(), GL_STATIC_DRAW)); | ||||
|             this->triangle_indices.clear(); | ||||
|         } | ||||
|         if (! this->quad_indices.empty()) { | ||||
|             glsafe(glGenBuffers(1, &this->quad_indices_VBO_id)); | ||||
|             glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id)); | ||||
|             glsafe(glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices.size() * 4, this->quad_indices.data(), GL_STATIC_DRAW)); | ||||
|             glsafe(::glGenBuffers(1, &this->quad_indices_VBO_id)); | ||||
|             glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id)); | ||||
|             glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices.size() * 4, this->quad_indices.data(), GL_STATIC_DRAW)); | ||||
|             this->quad_indices.clear(); | ||||
|         } | ||||
|         glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); | ||||
|         glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); | ||||
|     } | ||||
|     this->shrink_to_fit(); | ||||
| } | ||||
|  | @ -124,15 +125,15 @@ void GLIndexedVertexArray::finalize_geometry(bool use_VBOs) | |||
| void GLIndexedVertexArray::release_geometry() | ||||
| { | ||||
|     if (this->vertices_and_normals_interleaved_VBO_id) { | ||||
|         glsafe(glDeleteBuffers(1, &this->vertices_and_normals_interleaved_VBO_id)); | ||||
|         glsafe(::glDeleteBuffers(1, &this->vertices_and_normals_interleaved_VBO_id)); | ||||
|         this->vertices_and_normals_interleaved_VBO_id = 0; | ||||
|     } | ||||
|     if (this->triangle_indices_VBO_id) { | ||||
|         glsafe(glDeleteBuffers(1, &this->triangle_indices_VBO_id)); | ||||
|         glsafe(::glDeleteBuffers(1, &this->triangle_indices_VBO_id)); | ||||
|         this->triangle_indices_VBO_id = 0; | ||||
|     } | ||||
|     if (this->quad_indices_VBO_id) { | ||||
|         glsafe(glDeleteBuffers(1, &this->quad_indices_VBO_id)); | ||||
|         glsafe(::glDeleteBuffers(1, &this->quad_indices_VBO_id)); | ||||
|         this->quad_indices_VBO_id = 0; | ||||
|     } | ||||
|     this->clear(); | ||||
|  | @ -142,42 +143,42 @@ void GLIndexedVertexArray::release_geometry() | |||
| void GLIndexedVertexArray::render() const | ||||
| { | ||||
|     if (this->vertices_and_normals_interleaved_VBO_id) { | ||||
|         glsafe(glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); | ||||
|         glsafe(glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)))); | ||||
|         glsafe(glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr)); | ||||
|         glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); | ||||
|         glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)))); | ||||
|         glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr)); | ||||
|     } else { | ||||
|         glsafe(glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), this->vertices_and_normals_interleaved.data() + 3)); | ||||
|         glsafe(glNormalPointer(GL_FLOAT, 6 * sizeof(float), this->vertices_and_normals_interleaved.data())); | ||||
|         glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), this->vertices_and_normals_interleaved.data() + 3)); | ||||
|         glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), this->vertices_and_normals_interleaved.data())); | ||||
|     } | ||||
|     glsafe(glEnableClientState(GL_VERTEX_ARRAY)); | ||||
|     glsafe(glEnableClientState(GL_NORMAL_ARRAY)); | ||||
|     glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); | ||||
|     glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); | ||||
| 
 | ||||
|     if (this->indexed()) { | ||||
|         if (this->vertices_and_normals_interleaved_VBO_id) { | ||||
|             // Render using the Vertex Buffer Objects.
 | ||||
|             if (this->triangle_indices_size > 0) { | ||||
|                 glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id)); | ||||
|                 glsafe(glDrawElements(GL_TRIANGLES, GLsizei(this->triangle_indices_size), GL_UNSIGNED_INT, nullptr)); | ||||
|                 glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id)); | ||||
|                 glsafe(::glDrawElements(GL_TRIANGLES, GLsizei(this->triangle_indices_size), GL_UNSIGNED_INT, nullptr)); | ||||
|             } | ||||
|             if (this->quad_indices_size > 0) { | ||||
|                 glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id)); | ||||
|                 glsafe(glDrawElements(GL_QUADS, GLsizei(this->quad_indices_size), GL_UNSIGNED_INT, nullptr)); | ||||
|                 glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id)); | ||||
|                 glsafe(::glDrawElements(GL_QUADS, GLsizei(this->quad_indices_size), GL_UNSIGNED_INT, nullptr)); | ||||
|             } | ||||
|             glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); | ||||
|         } else { | ||||
|             // Render in an immediate mode.
 | ||||
|             if (! this->triangle_indices.empty()) | ||||
|                 glsafe(glDrawElements(GL_TRIANGLES, GLsizei(this->triangle_indices_size), GL_UNSIGNED_INT, this->triangle_indices.data())); | ||||
|                 glsafe(::glDrawElements(GL_TRIANGLES, GLsizei(this->triangle_indices_size), GL_UNSIGNED_INT, this->triangle_indices.data())); | ||||
|             if (! this->quad_indices.empty()) | ||||
|                 glsafe(glDrawElements(GL_QUADS, GLsizei(this->quad_indices_size), GL_UNSIGNED_INT, this->quad_indices.data())); | ||||
|                 glsafe(::glDrawElements(GL_QUADS, GLsizei(this->quad_indices_size), GL_UNSIGNED_INT, this->quad_indices.data())); | ||||
|         } | ||||
|     } else | ||||
|         glsafe(glDrawArrays(GL_TRIANGLES, 0, GLsizei(this->vertices_and_normals_interleaved_size / 6))); | ||||
|         glsafe(::glDrawArrays(GL_TRIANGLES, 0, GLsizei(this->vertices_and_normals_interleaved_size / 6))); | ||||
| 
 | ||||
|     if (this->vertices_and_normals_interleaved_VBO_id) | ||||
|         glsafe(glBindBuffer(GL_ARRAY_BUFFER, 0)); | ||||
|     glsafe(glDisableClientState(GL_VERTEX_ARRAY)); | ||||
|     glsafe(glDisableClientState(GL_NORMAL_ARRAY)); | ||||
|         glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); | ||||
|     glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); | ||||
|     glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); | ||||
| } | ||||
| 
 | ||||
| void GLIndexedVertexArray::render( | ||||
|  | @ -190,35 +191,35 @@ void GLIndexedVertexArray::render( | |||
| 
 | ||||
|     if (this->vertices_and_normals_interleaved_VBO_id) { | ||||
|         // Render using the Vertex Buffer Objects.
 | ||||
|         glsafe(glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); | ||||
|         glsafe(glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)))); | ||||
|         glsafe(glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr)); | ||||
|         glsafe(glEnableClientState(GL_VERTEX_ARRAY)); | ||||
|         glsafe(glEnableClientState(GL_NORMAL_ARRAY)); | ||||
|         glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); | ||||
|         glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)))); | ||||
|         glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr)); | ||||
|         glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); | ||||
|         glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); | ||||
|         if (this->triangle_indices_size > 0) { | ||||
|             glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id)); | ||||
|             glsafe(glDrawElements(GL_TRIANGLES, GLsizei(std::min(this->triangle_indices_size, tverts_range.second - tverts_range.first)), GL_UNSIGNED_INT, (const void*)(tverts_range.first * 4))); | ||||
|             glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id)); | ||||
|             glsafe(::glDrawElements(GL_TRIANGLES, GLsizei(std::min(this->triangle_indices_size, tverts_range.second - tverts_range.first)), GL_UNSIGNED_INT, (const void*)(tverts_range.first * 4))); | ||||
|         } | ||||
|         if (this->quad_indices_size > 0) { | ||||
|             glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id)); | ||||
|             glsafe(glDrawElements(GL_QUADS, GLsizei(std::min(this->quad_indices_size, qverts_range.second - qverts_range.first)), GL_UNSIGNED_INT, (const void*)(qverts_range.first * 4))); | ||||
|             glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id)); | ||||
|             glsafe(::glDrawElements(GL_QUADS, GLsizei(std::min(this->quad_indices_size, qverts_range.second - qverts_range.first)), GL_UNSIGNED_INT, (const void*)(qverts_range.first * 4))); | ||||
|         } | ||||
|         glsafe(glBindBuffer(GL_ARRAY_BUFFER, 0)); | ||||
|         glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); | ||||
|         glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); | ||||
|         glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); | ||||
|     } else { | ||||
|         // Render in an immediate mode.
 | ||||
|         glsafe(glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), this->vertices_and_normals_interleaved.data() + 3)); | ||||
|         glsafe(glNormalPointer(GL_FLOAT, 6 * sizeof(float), this->vertices_and_normals_interleaved.data())); | ||||
|         glsafe(glEnableClientState(GL_VERTEX_ARRAY)); | ||||
|         glsafe(glEnableClientState(GL_NORMAL_ARRAY)); | ||||
|         glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), this->vertices_and_normals_interleaved.data() + 3)); | ||||
|         glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), this->vertices_and_normals_interleaved.data())); | ||||
|         glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); | ||||
|         glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); | ||||
|         if (! this->triangle_indices.empty()) | ||||
|             glsafe(glDrawElements(GL_TRIANGLES, GLsizei(std::min(this->triangle_indices_size, tverts_range.second - tverts_range.first)), GL_UNSIGNED_INT, (const void*)(this->triangle_indices.data() + tverts_range.first))); | ||||
|             glsafe(::glDrawElements(GL_TRIANGLES, GLsizei(std::min(this->triangle_indices_size, tverts_range.second - tverts_range.first)), GL_UNSIGNED_INT, (const void*)(this->triangle_indices.data() + tverts_range.first))); | ||||
|         if (! this->quad_indices.empty()) | ||||
|             glsafe(glDrawElements(GL_QUADS, GLsizei(std::min(this->quad_indices_size, qverts_range.second - qverts_range.first)), GL_UNSIGNED_INT, (const void*)(this->quad_indices.data() + qverts_range.first))); | ||||
|             glsafe(::glDrawElements(GL_QUADS, GLsizei(std::min(this->quad_indices_size, qverts_range.second - qverts_range.first)), GL_UNSIGNED_INT, (const void*)(this->quad_indices.data() + qverts_range.first))); | ||||
|     } | ||||
| 
 | ||||
|     glsafe(glDisableClientState(GL_VERTEX_ARRAY)); | ||||
|     glsafe(glDisableClientState(GL_NORMAL_ARRAY)); | ||||
|     glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); | ||||
|     glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); | ||||
| } | ||||
| 
 | ||||
| const float GLVolume::SELECTED_COLOR[4] = { 0.0f, 1.0f, 0.0f, 1.0f }; | ||||
|  | @ -736,7 +737,7 @@ int GLVolumeCollection::load_wipe_tower_preview( | |||
| 
 | ||||
| typedef std::pair<GLVolume*, double> GLVolumeWithZ; | ||||
| typedef std::vector<GLVolumeWithZ> GLVolumesWithZList; | ||||
| static GLVolumesWithZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, std::function<bool(const GLVolume&)> filter_func) | ||||
| static GLVolumesWithZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func) | ||||
| { | ||||
|     GLVolumesWithZList list; | ||||
|     list.reserve(volumes.size()); | ||||
|  | @ -753,12 +754,9 @@ static GLVolumesWithZList volumes_to_render(const GLVolumePtrs& volumes, GLVolum | |||
| 
 | ||||
|     if ((type == GLVolumeCollection::Transparent) && (list.size() > 1)) | ||||
|     { | ||||
|         Transform3d modelview_matrix; | ||||
|         glsafe(::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data())); | ||||
| 
 | ||||
|         for (GLVolumeWithZ& volume : list) | ||||
|         { | ||||
|             volume.second = volume.first->bounding_box.transformed(modelview_matrix * volume.first->world_matrix()).max(2); | ||||
|             volume.second = volume.first->bounding_box.transformed(view_matrix * volume.first->world_matrix()).max(2); | ||||
|         } | ||||
| 
 | ||||
|         std::sort(list.begin(), list.end(), | ||||
|  | @ -769,7 +767,7 @@ static GLVolumesWithZList volumes_to_render(const GLVolumePtrs& volumes, GLVolum | |||
|     return list; | ||||
| } | ||||
| 
 | ||||
| void GLVolumeCollection::render_VBOs(GLVolumeCollection::ERenderType type, bool disable_cullface, std::function<bool(const GLVolume&)> filter_func) const | ||||
| void GLVolumeCollection::render_VBOs(GLVolumeCollection::ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func) const | ||||
| { | ||||
|     glsafe(::glEnable(GL_BLEND)); | ||||
|     glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); | ||||
|  | @ -783,12 +781,13 @@ void GLVolumeCollection::render_VBOs(GLVolumeCollection::ERenderType type, bool | |||
|   | ||||
|     GLint current_program_id; | ||||
|     glsafe(::glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_id)); | ||||
|     GLint color_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "uniform_color") : -1; | ||||
|     GLint z_range_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "z_range") : -1; | ||||
|     GLint print_box_min_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.min") : -1; | ||||
|     GLint print_box_max_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.max") : -1; | ||||
|     GLint print_box_detection_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.volume_detection") : -1; | ||||
|     GLint print_box_worldmatrix_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.volume_world_matrix") : -1; | ||||
|     GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1; | ||||
|     GLint z_range_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "z_range") : -1; | ||||
|     GLint print_box_min_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.min") : -1; | ||||
|     GLint print_box_max_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.max") : -1; | ||||
|     GLint print_box_detection_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.volume_detection") : -1; | ||||
|     GLint print_box_worldmatrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.volume_world_matrix") : -1; | ||||
|     glcheck(); | ||||
| 
 | ||||
|     if (print_box_min_id != -1) | ||||
|         glsafe(::glUniform3fv(print_box_min_id, 1, (const GLfloat*)print_box_min)); | ||||
|  | @ -799,7 +798,7 @@ void GLVolumeCollection::render_VBOs(GLVolumeCollection::ERenderType type, bool | |||
|     if (z_range_id != -1) | ||||
|         glsafe(::glUniform2fv(z_range_id, 1, (const GLfloat*)z_range)); | ||||
| 
 | ||||
|     GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, filter_func); | ||||
|     GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func); | ||||
|     for (GLVolumeWithZ& volume : to_render) { | ||||
|         volume.first->set_render_color(); | ||||
|         volume.first->render_VBOs(color_id, print_box_detection_id, print_box_worldmatrix_id); | ||||
|  | @ -817,32 +816,32 @@ void GLVolumeCollection::render_VBOs(GLVolumeCollection::ERenderType type, bool | |||
|     glsafe(::glDisable(GL_BLEND)); | ||||
| } | ||||
| 
 | ||||
| void GLVolumeCollection::render_legacy(ERenderType type, bool disable_cullface, std::function<bool(const GLVolume&)> filter_func) const | ||||
| void GLVolumeCollection::render_legacy(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func) const | ||||
| { | ||||
|     glsafe(glEnable(GL_BLEND)); | ||||
|     glsafe(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); | ||||
|     glsafe(::glEnable(GL_BLEND)); | ||||
|     glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); | ||||
| 
 | ||||
|     glsafe(glCullFace(GL_BACK)); | ||||
|     glsafe(::glCullFace(GL_BACK)); | ||||
|     if (disable_cullface) | ||||
|         glsafe(::glDisable(GL_CULL_FACE)); | ||||
| 
 | ||||
|     glsafe(glEnableClientState(GL_VERTEX_ARRAY)); | ||||
|     glsafe(glEnableClientState(GL_NORMAL_ARRAY)); | ||||
|     glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); | ||||
|     glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); | ||||
|   | ||||
| 	GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, filter_func); | ||||
|     GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func); | ||||
|     for (GLVolumeWithZ& volume : to_render) | ||||
|     { | ||||
|         volume.first->set_render_color(); | ||||
|         volume.first->render_legacy(); | ||||
|     } | ||||
| 
 | ||||
|     glsafe(glDisableClientState(GL_VERTEX_ARRAY)); | ||||
|     glsafe(glDisableClientState(GL_NORMAL_ARRAY)); | ||||
|     glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); | ||||
|     glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); | ||||
| 
 | ||||
|     if (disable_cullface) | ||||
|         glsafe(::glEnable(GL_CULL_FACE)); | ||||
| 
 | ||||
|     glsafe(glDisable(GL_BLEND)); | ||||
|     glsafe(::glDisable(GL_BLEND)); | ||||
| } | ||||
| 
 | ||||
| bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstance::EPrintVolumeState* out_state) | ||||
|  | @ -1771,7 +1770,8 @@ void GLModel::render_VBOs() const | |||
| 
 | ||||
|     GLint current_program_id; | ||||
|     glsafe(::glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_id)); | ||||
|     GLint color_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "uniform_color") : -1; | ||||
|     GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1; | ||||
|     glcheck(); | ||||
|     m_volume.render_VBOs(color_id, -1, -1); | ||||
| 
 | ||||
|     glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); | ||||
|  |  | |||
|  | @ -19,9 +19,11 @@ | |||
| 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 | ||||
| inline void glAssertRecentCall() { } | ||||
| #define glsafe(cmd) cmd | ||||
| #define glcheck() | ||||
| #endif | ||||
| 
 | ||||
| namespace Slic3r { | ||||
|  | @ -463,8 +465,8 @@ public: | |||
|         int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width); | ||||
| 
 | ||||
|     // Render the volumes by OpenGL.
 | ||||
| 	void render_VBOs(ERenderType type, bool disable_cullface, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const; | ||||
|     void render_legacy(ERenderType type, bool disable_cullface, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const; | ||||
|     void render_VBOs(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const; | ||||
|     void render_legacy(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const; | ||||
| 
 | ||||
|     // Finalize the initialization of the geometry & indices,
 | ||||
|     // upload the geometry and indices to OpenGL VBO objects
 | ||||
|  |  | |||
|  | @ -42,9 +42,7 @@ AboutDialog::AboutDialog() | |||
| 	main_sizer->Add(hsizer, 0, wxEXPAND | wxALL, 20); | ||||
| 
 | ||||
|     // logo
 | ||||
| // 	wxBitmap logo_bmp = wxBitmap(from_u8(Slic3r::var("Slic3r_192px.png")), wxBITMAP_TYPE_PNG);
 | ||||
| //     auto *logo = new wxStaticBitmap(this, wxID_ANY, std::move(logo_bmp));
 | ||||
| 	auto *logo = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("Slic3r_192px.png")); | ||||
| 	auto *logo = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("Slic3r_192px.png", 192)); | ||||
| 	hsizer->Add(logo, 1, wxALIGN_CENTER_VERTICAL); | ||||
|      | ||||
|     wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL); 	 | ||||
|  |  | |||
|  | @ -98,8 +98,9 @@ void BackgroundSlicingProcess::process_sla() | |||
|     m_print->process(); | ||||
|     if (this->set_step_started(bspsGCodeFinalize)) { | ||||
|         if (! m_export_path.empty()) { | ||||
|             m_sla_print->export_raster(m_export_path); | ||||
|             m_print->set_status(100, "Masked SLA file exported to " + m_export_path); | ||||
|         	const std::string export_path = m_sla_print->print_statistics().finalize_output_path(m_export_path); | ||||
|             m_sla_print->export_raster(export_path); | ||||
|             m_print->set_status(100, "Masked SLA file exported to " + export_path); | ||||
|         } else if (! m_upload_job.empty()) { | ||||
|             prepare_upload(); | ||||
|         } else { | ||||
|  | @ -389,7 +390,7 @@ void BackgroundSlicingProcess::prepare_upload() | |||
| 
 | ||||
| 	// Generate a unique temp path to which the gcode/zip file is copied/exported
 | ||||
| 	boost::filesystem::path source_path = boost::filesystem::temp_directory_path() | ||||
| 		/ boost::filesystem::unique_path(".printhost.%%%%-%%%%-%%%%-%%%%.gcode"); | ||||
| 		/ boost::filesystem::unique_path(".Slic3rPE.upload.%%%%-%%%%-%%%%-%%%%"); | ||||
| 
 | ||||
| 	if (m_print == m_fff_print) { | ||||
| 		m_print->set_status(95, "Running post-processing scripts"); | ||||
|  | @ -399,8 +400,8 @@ void BackgroundSlicingProcess::prepare_upload() | |||
| 		run_post_process_scripts(source_path.string(), m_fff_print->config()); | ||||
| 		m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string()); | ||||
|     } else { | ||||
|         m_sla_print->export_raster(source_path.string()); | ||||
| 		// TODO: Also finalize upload path like with FFF when there are statistics for SLA print
 | ||||
| 		m_upload_job.upload_data.upload_path = m_sla_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string()); | ||||
|         m_sla_print->export_raster(source_path.string(), m_upload_job.upload_data.upload_path.string()); | ||||
| 	} | ||||
| 
 | ||||
| 	m_print->set_status(100, (boost::format("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue") % m_upload_job.printhost->get_host()).str()); | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| #include "BitmapCache.hpp" | ||||
| 
 | ||||
| #include "libslic3r/Utils.hpp" | ||||
| 
 | ||||
| #if ! defined(WIN32) && ! defined(__APPLE__) | ||||
| #define BROKEN_ALPHA | ||||
| #endif | ||||
|  | @ -9,6 +11,12 @@ | |||
|     #include <wx/rawbmp.h> | ||||
| #endif /* BROKEN_ALPHA */ | ||||
| 
 | ||||
| #define NANOSVG_IMPLEMENTATION | ||||
| #include "nanosvg/nanosvg.h" | ||||
| #define NANOSVGRAST_IMPLEMENTATION | ||||
| #include "nanosvg/nanosvgrast.h" | ||||
| #include "GUI_App.hpp" | ||||
| 
 | ||||
| namespace Slic3r { namespace GUI { | ||||
| 
 | ||||
| void BitmapCache::clear() | ||||
|  | @ -155,8 +163,91 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *beg | |||
| #endif | ||||
| } | ||||
| 
 | ||||
| wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned int width, unsigned int height, const unsigned char *raw_data) | ||||
| { | ||||
|     wxImage image(width, height); | ||||
|     image.InitAlpha(); | ||||
|     unsigned char *rgb   = image.GetData(); | ||||
|     unsigned char *alpha = image.GetAlpha(); | ||||
|     unsigned int pixels = width * height; | ||||
|     for (unsigned int i = 0; i < pixels; ++ i) { | ||||
|         *rgb   ++ = *raw_data ++; | ||||
|         *rgb   ++ = *raw_data ++; | ||||
|         *rgb   ++ = *raw_data ++; | ||||
|         *alpha ++ = *raw_data ++; | ||||
|     } | ||||
|     return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image))); | ||||
| } | ||||
| 
 | ||||
| wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned int width, unsigned int height) | ||||
| { | ||||
|     std::string bitmap_key = bitmap_name + ( height !=0 ?  | ||||
|                                            "-h" + std::to_string(height) :  | ||||
|                                            "-w" + std::to_string(width)); | ||||
|     auto it = m_map.find(bitmap_key); | ||||
|     if (it != m_map.end()) | ||||
|         return it->second; | ||||
| 
 | ||||
|     wxImage image; | ||||
|     if (! image.LoadFile(Slic3r::GUI::from_u8(Slic3r::var(bitmap_name + ".png")), wxBITMAP_TYPE_PNG) || | ||||
|         image.GetWidth() == 0 || image.GetHeight() == 0) | ||||
|         return nullptr; | ||||
| 
 | ||||
|     if (height != 0 && image.GetHeight() != height) | ||||
|         width   = int(0.5f + float(image.GetWidth()) * height / image.GetHeight()); | ||||
|     else if (width != 0 && image.GetWidth() != width) | ||||
|         height  = int(0.5f + float(image.GetHeight()) * width / image.GetWidth()); | ||||
| 
 | ||||
|     if (height != 0 && width != 0) | ||||
|         image.Rescale(width, height, wxIMAGE_QUALITY_BILINEAR); | ||||
| 
 | ||||
|     return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image))); | ||||
| } | ||||
| 
 | ||||
| wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned int target_width, unsigned int target_height) | ||||
| { | ||||
|     std::string bitmap_key = bitmap_name + (target_height != 0 ? | ||||
|                                             "-h" + std::to_string(target_height) : | ||||
|                                             "-w" + std::to_string(target_width)); | ||||
|     auto it = m_map.find(bitmap_key); | ||||
|     if (it != m_map.end()) | ||||
|         return it->second; | ||||
| 
 | ||||
|     NSVGimage *image = ::nsvgParseFromFile(Slic3r::var(bitmap_name + ".svg").c_str(), "px", 96.0f); | ||||
|     if (image == nullptr) | ||||
|         return nullptr; | ||||
| 
 | ||||
|     float scale = target_height != 0 ?  | ||||
|                   (float)target_height / image->height  : target_width != 0 ? | ||||
|                   (float)target_width / image->width    : 1; | ||||
| 
 | ||||
|     int   width    = (int)(scale * image->width + 0.5f); | ||||
|     int   height   = (int)(scale * image->height + 0.5f); | ||||
|     int   n_pixels = width * height; | ||||
|     if (n_pixels <= 0) { | ||||
|         ::nsvgDelete(image); | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     NSVGrasterizer *rast = ::nsvgCreateRasterizer(); | ||||
|     if (rast == nullptr) { | ||||
|         ::nsvgDelete(image); | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<unsigned char> data(n_pixels * 4, 0); | ||||
|     ::nsvgRasterize(rast, image, 0, 0, scale, data.data(), width, height, width * 4); | ||||
|     ::nsvgDeleteRasterizer(rast); | ||||
|     ::nsvgDelete(image); | ||||
| 
 | ||||
|     return this->insert_raw_rgba(bitmap_key, width, height, data.data()); | ||||
| } | ||||
| 
 | ||||
| wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency) | ||||
| { | ||||
|     width = width * 0.1f * Slic3r::GUI::wxGetApp().em_unit() + 0.5f; | ||||
|     height = height * 0.1f * Slic3r::GUI::wxGetApp().em_unit() + 0.5f; | ||||
| 
 | ||||
|     wxImage image(width, height); | ||||
|     image.InitAlpha(); | ||||
|     unsigned char* imgdata = image.GetData(); | ||||
|  |  | |||
|  | @ -29,6 +29,12 @@ public: | |||
| 	wxBitmap* 		insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3); | ||||
| 	wxBitmap* 		insert(const std::string &name, const std::vector<wxBitmap> &bmps) { return this->insert(name, &bmps.front(), &bmps.front() + bmps.size()); } | ||||
| 	wxBitmap* 		insert(const std::string &name, const wxBitmap *begin, const wxBitmap *end); | ||||
| 	wxBitmap* 		insert_raw_rgba(const std::string &bitmap_key, unsigned int width, unsigned int height, const unsigned char *raw_data); | ||||
| 
 | ||||
| 	// Load png from resources/icons. bitmap_key is given without the .png suffix. Bitmap will be rescaled to provided height/width if nonzero.
 | ||||
| 	wxBitmap* 		load_png(const std::string &bitmap_key, unsigned int width = 0, unsigned int height = 0); | ||||
| 	// Load svg from resources/icons. bitmap_key is given without the .svg suffix. SVG will be rasterized to provided height/width.
 | ||||
|     wxBitmap* 		load_svg(const std::string &bitmap_key, unsigned int width = 0, unsigned int height = 0); | ||||
| 
 | ||||
| 	static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency); | ||||
| 	static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); } | ||||
|  |  | |||
|  | @ -1,9 +1,21 @@ | |||
| #include "libslic3r/libslic3r.h" | ||||
| 
 | ||||
| #include "Camera.hpp" | ||||
| #include "3DScene.hpp" | ||||
| 
 | ||||
| #include <GL/glew.h> | ||||
| 
 | ||||
| static const float GIMBALL_LOCK_THETA_MAX = 180.0f; | ||||
| 
 | ||||
| // phi / theta angles to orient the camera.
 | ||||
| static const float VIEW_DEFAULT[2] = { 45.0f, 45.0f }; | ||||
| static const float VIEW_LEFT[2] = { 90.0f, 90.0f }; | ||||
| static const float VIEW_RIGHT[2] = { -90.0f, 90.0f }; | ||||
| static const float VIEW_TOP[2] = { 0.0f, 0.0f }; | ||||
| static const float VIEW_BOTTOM[2] = { 0.0f, 180.0f }; | ||||
| static const float VIEW_FRONT[2] = { 0.0f, 90.0f }; | ||||
| static const float VIEW_REAR[2] = { 180.0f, 90.0f }; | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
| 
 | ||||
|  | @ -57,6 +69,64 @@ void Camera::set_scene_box(const BoundingBoxf3& box) | |||
|     m_scene_box = box; | ||||
| } | ||||
| 
 | ||||
| bool Camera::select_view(const std::string& direction) | ||||
| { | ||||
|     const float* dir_vec = nullptr; | ||||
| 
 | ||||
|     if (direction == "iso") | ||||
|         dir_vec = VIEW_DEFAULT; | ||||
|     else if (direction == "left") | ||||
|         dir_vec = VIEW_LEFT; | ||||
|     else if (direction == "right") | ||||
|         dir_vec = VIEW_RIGHT; | ||||
|     else if (direction == "top") | ||||
|         dir_vec = VIEW_TOP; | ||||
|     else if (direction == "bottom") | ||||
|         dir_vec = VIEW_BOTTOM; | ||||
|     else if (direction == "front") | ||||
|         dir_vec = VIEW_FRONT; | ||||
|     else if (direction == "rear") | ||||
|         dir_vec = VIEW_REAR; | ||||
| 
 | ||||
|     if (dir_vec != nullptr) | ||||
|     { | ||||
|         phi = dir_vec[0]; | ||||
|         set_theta(dir_vec[1], false); | ||||
|         return true; | ||||
|     } | ||||
|     else | ||||
|         return false; | ||||
| } | ||||
| 
 | ||||
| void Camera::apply_viewport(int x, int y, unsigned int w, unsigned int h) const | ||||
| { | ||||
|     glsafe(::glViewport(0, 0, w, h)); | ||||
|     glsafe(::glGetIntegerv(GL_VIEWPORT, m_viewport.data())); | ||||
| } | ||||
| 
 | ||||
| void Camera::apply_view_matrix() const | ||||
| { | ||||
|     glsafe(::glMatrixMode(GL_MODELVIEW)); | ||||
|     glsafe(::glLoadIdentity()); | ||||
| 
 | ||||
|     glsafe(::glRotatef(-m_theta, 1.0f, 0.0f, 0.0f)); // pitch
 | ||||
|     glsafe(::glRotatef(phi, 0.0f, 0.0f, 1.0f));          // yaw
 | ||||
|     glsafe(::glTranslated(-m_target(0), -m_target(1), -m_target(2))); | ||||
| 
 | ||||
|     glsafe(::glGetDoublev(GL_MODELVIEW_MATRIX, m_view_matrix.data())); | ||||
| } | ||||
| 
 | ||||
| void Camera::apply_ortho_projection(float x_min, float x_max, float y_min, float y_max, float z_min, float z_max) const | ||||
| { | ||||
|     glsafe(::glMatrixMode(GL_PROJECTION)); | ||||
|     glsafe(::glLoadIdentity()); | ||||
| 
 | ||||
|     glsafe(::glOrtho(x_min, x_max, y_min, y_max, z_min, z_max)); | ||||
|     glsafe(::glGetDoublev(GL_PROJECTION_MATRIX, m_projection_matrix.data())); | ||||
| 
 | ||||
|     glsafe(::glMatrixMode(GL_MODELVIEW)); | ||||
| } | ||||
| 
 | ||||
| } // GUI
 | ||||
| } // Slic3r
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| #define slic3r_Camera_hpp_ | ||||
| 
 | ||||
| #include "libslic3r/BoundingBox.hpp" | ||||
| #include <array> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
|  | @ -26,6 +27,10 @@ private: | |||
|     Vec3d m_target; | ||||
|     float m_theta; | ||||
| 
 | ||||
|     mutable std::array<int, 4> m_viewport; | ||||
|     mutable Transform3d m_view_matrix; | ||||
|     mutable Transform3d m_projection_matrix; | ||||
| 
 | ||||
|     BoundingBoxf3 m_scene_box; | ||||
| 
 | ||||
| public: | ||||
|  | @ -41,6 +46,22 @@ public: | |||
| 
 | ||||
|     const BoundingBoxf3& get_scene_box() const { return m_scene_box; } | ||||
|     void set_scene_box(const BoundingBoxf3& box); | ||||
| 
 | ||||
|     bool select_view(const std::string& direction); | ||||
| 
 | ||||
|     const std::array<int, 4>& get_viewport() const { return m_viewport; } | ||||
|     const Transform3d& get_view_matrix() const { return m_view_matrix; } | ||||
|     const Transform3d& get_projection_matrix() const { return m_projection_matrix; } | ||||
| 
 | ||||
|     Vec3d get_dir_right() const { return m_view_matrix.matrix().block(0, 0, 3, 3).row(0); } | ||||
|     Vec3d get_dir_up() const { return m_view_matrix.matrix().block(0, 0, 3, 3).row(1); } | ||||
|     Vec3d get_dir_forward() const { return m_view_matrix.matrix().block(0, 0, 3, 3).row(2); } | ||||
| 
 | ||||
|     Vec3d get_position() const { return m_view_matrix.matrix().block(0, 0, 3, 3).row(3); } | ||||
| 
 | ||||
|     void apply_viewport(int x, int y, unsigned int w, unsigned int h) const; | ||||
|     void apply_view_matrix() const; | ||||
|     void apply_ortho_projection(float x_min, float x_max, float y_min, float y_max, float z_min, float z_max) const; | ||||
| }; | ||||
| 
 | ||||
| } // GUI
 | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -10,6 +10,7 @@ | |||
| #include "3DBed.hpp" | ||||
| #include "Camera.hpp" | ||||
| #include "Selection.hpp" | ||||
| #include "Gizmos/GLGizmosManager.hpp" | ||||
| 
 | ||||
| #include <float.h> | ||||
| 
 | ||||
|  | @ -64,33 +65,6 @@ public: | |||
|     void set_scale_factor(int height); | ||||
| }; | ||||
| 
 | ||||
| class Rect | ||||
| { | ||||
|     float m_left; | ||||
|     float m_top; | ||||
|     float m_right; | ||||
|     float m_bottom; | ||||
| 
 | ||||
| public: | ||||
|     Rect(); | ||||
|     Rect(float left, float top, float right, float bottom); | ||||
| 
 | ||||
|     float get_left() const; | ||||
|     void set_left(float left); | ||||
| 
 | ||||
|     float get_top() const; | ||||
|     void set_top(float top); | ||||
| 
 | ||||
|     float get_right() const; | ||||
|     void set_right(float right); | ||||
| 
 | ||||
|     float get_bottom() const; | ||||
|     void set_bottom(float bottom); | ||||
| 
 | ||||
|     float get_width() const { return m_right - m_left; } | ||||
|     float get_height() const { return m_top - m_bottom; } | ||||
| }; | ||||
| 
 | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); | ||||
| 
 | ||||
| using Vec2dEvent = Event<Vec2d>; | ||||
|  | @ -118,22 +92,6 @@ wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_BED_SHAPE, SimpleEvent); | |||
| wxDECLARE_EVENT(EVT_GLCANVAS_TAB, SimpleEvent); | ||||
| wxDECLARE_EVENT(EVT_GLCANVAS_RESETGIZMOS, SimpleEvent); | ||||
| 
 | ||||
| // this describes events being passed from GLCanvas3D to SlaSupport gizmo
 | ||||
| enum class SLAGizmoEventType { | ||||
|     LeftDown = 1, | ||||
|     LeftUp, | ||||
|     RightDown, | ||||
|     Dragging, | ||||
|     Delete, | ||||
|     SelectAll, | ||||
|     ShiftUp, | ||||
|     ApplyChanges, | ||||
|     DiscardChanges, | ||||
|     AutomaticGeneration, | ||||
|     ManualEditing | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| class GLCanvas3D | ||||
| { | ||||
|     struct GCodePreviewVolumeIndex | ||||
|  | @ -314,7 +272,6 @@ class GLCanvas3D | |||
|         Vec2d position; | ||||
|         Vec3d scene_position; | ||||
|         Drag drag; | ||||
|         bool ignore_up_event; | ||||
| 
 | ||||
|         Mouse(); | ||||
| 
 | ||||
|  | @ -358,118 +315,6 @@ public: | |||
|     }; | ||||
| 
 | ||||
| private: | ||||
|     class Gizmos | ||||
|     { | ||||
|     public: | ||||
| #if ENABLE_SVG_ICONS | ||||
|         static const float Default_Icons_Size; | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
| 
 | ||||
|         enum EType : unsigned char | ||||
|         { | ||||
|             Undefined, | ||||
|             Move, | ||||
|             Scale, | ||||
|             Rotate, | ||||
|             Flatten, | ||||
|             Cut, | ||||
|             SlaSupports, | ||||
|             Num_Types | ||||
|         }; | ||||
| 
 | ||||
|     private: | ||||
|         bool m_enabled; | ||||
|         typedef std::map<EType, GLGizmoBase*> GizmosMap; | ||||
|         GizmosMap m_gizmos; | ||||
| #if ENABLE_SVG_ICONS | ||||
|         mutable GLTexture m_icons_texture; | ||||
|         mutable bool m_icons_texture_dirty; | ||||
| #else | ||||
|         ItemsIconsTexture m_icons_texture; | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
|         BackgroundTexture m_background_texture; | ||||
|         EType m_current; | ||||
| 
 | ||||
| #if ENABLE_SVG_ICONS | ||||
|         float m_overlay_icons_size; | ||||
|         float m_overlay_scale; | ||||
| #else | ||||
|         float m_overlay_icons_scale; | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
|         float m_overlay_border; | ||||
|         float m_overlay_gap_y; | ||||
| 
 | ||||
|     public: | ||||
|         Gizmos(); | ||||
|         ~Gizmos(); | ||||
| 
 | ||||
|         bool init(GLCanvas3D& parent); | ||||
| 
 | ||||
|         bool is_enabled() const; | ||||
|         void set_enabled(bool enable); | ||||
| 
 | ||||
| #if ENABLE_SVG_ICONS | ||||
|         void set_overlay_icon_size(float size); | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
|         void set_overlay_scale(float scale); | ||||
| 
 | ||||
|         std::string update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection); | ||||
|         void update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection); | ||||
|         void update_on_off_state(const Selection& selection); | ||||
|         void reset_all_states(); | ||||
| 
 | ||||
|         void set_hover_id(int id); | ||||
|         void enable_grabber(EType type, unsigned int id, bool enable); | ||||
| 
 | ||||
|         bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const; | ||||
|         bool grabber_contains_mouse() const; | ||||
|         void update(const Linef3& mouse_ray, const Selection& selection, bool shift_down, const Point* mouse_pos = nullptr); | ||||
|         Rect get_reset_rect_viewport(const GLCanvas3D& canvas) const; | ||||
|         EType get_current_type() const; | ||||
| 
 | ||||
|         bool is_running() const; | ||||
|         bool handle_shortcut(int key, const Selection& selection); | ||||
| 
 | ||||
|         bool is_dragging() const; | ||||
|         void start_dragging(const Selection& selection); | ||||
|         void stop_dragging(); | ||||
| 
 | ||||
|         Vec3d get_displacement() const; | ||||
| 
 | ||||
|         Vec3d get_scale() const; | ||||
|         void set_scale(const Vec3d& scale); | ||||
| 
 | ||||
|         Vec3d get_rotation() const; | ||||
|         void set_rotation(const Vec3d& rotation); | ||||
| 
 | ||||
|         Vec3d get_flattening_normal() const; | ||||
| 
 | ||||
|         void set_flattening_data(const ModelObject* model_object); | ||||
| 
 | ||||
|         void set_sla_support_data(ModelObject* model_object, const Selection& selection); | ||||
|         bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false); | ||||
| 
 | ||||
|         void render_current_gizmo(const Selection& selection) const; | ||||
|         void render_current_gizmo_for_picking_pass(const Selection& selection) const; | ||||
| 
 | ||||
|         void render_overlay(const GLCanvas3D& canvas, const Selection& selection) const; | ||||
| 
 | ||||
|     private: | ||||
|         void reset(); | ||||
| 
 | ||||
|         void do_render_overlay(const GLCanvas3D& canvas, const Selection& selection) const; | ||||
|         void do_render_current_gizmo(const Selection& selection) const; | ||||
| 
 | ||||
|         float get_total_overlay_height() const; | ||||
|         float get_total_overlay_width() const; | ||||
| 
 | ||||
|         GLGizmoBase* get_current() const; | ||||
| 
 | ||||
| #if ENABLE_SVG_ICONS | ||||
|         bool generate_icons_texture() const; | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
|     }; | ||||
| 
 | ||||
|     struct SlaCap | ||||
|     { | ||||
|         struct Triangles | ||||
|  | @ -557,7 +402,7 @@ private: | |||
|     LayersEditing m_layers_editing; | ||||
|     Shader m_shader; | ||||
|     Mouse m_mouse; | ||||
|     mutable Gizmos m_gizmos; | ||||
|     mutable GLGizmosManager m_gizmos; | ||||
|     mutable GLToolbar m_toolbar; | ||||
|     ClippingPlane m_clipping_planes[2]; | ||||
|     bool m_use_clipping_planes; | ||||
|  | @ -639,7 +484,7 @@ public: | |||
| 
 | ||||
|     void set_color_by(const std::string& value); | ||||
| 
 | ||||
|     float get_camera_zoom() const; | ||||
|     const Camera& get_camera() const { return m_camera; } | ||||
| 
 | ||||
|     BoundingBoxf3 volumes_bounding_box() const; | ||||
|     BoundingBoxf3 scene_bounding_box() const; | ||||
|  | @ -721,6 +566,19 @@ public: | |||
| 
 | ||||
|     void update_ui_from_settings(); | ||||
| 
 | ||||
|     float get_view_toolbar_height() const { return m_view_toolbar.get_height(); } | ||||
| 
 | ||||
|     int get_move_volume_id() const { return m_mouse.drag.move_volume_idx; } | ||||
|     int get_hover_volume_id() const { return m_hover_volume_id; } | ||||
| 
 | ||||
|     // Returns the view ray line, in world coordinate, at the given mouse position.
 | ||||
|     Linef3 mouse_ray(const Point& mouse_pos); | ||||
| 
 | ||||
|     void set_mouse_as_dragging() { m_mouse.dragging = true; } | ||||
|     void disable_regenerate_volumes() { m_regenerate_volumes = false; } | ||||
|     void refresh_camera_scene_box() { m_camera.set_scene_box(scene_bounding_box()); } | ||||
|     bool is_mouse_dragging() const { return m_mouse.dragging; } | ||||
| 
 | ||||
| private: | ||||
|     bool _is_shown_on_screen() const; | ||||
| 
 | ||||
|  | @ -736,7 +594,6 @@ private: | |||
| 
 | ||||
|     void _refresh_if_shown_on_screen(); | ||||
| 
 | ||||
|     void _camera_tranform() const; | ||||
|     void _picking_pass() const; | ||||
|     void _render_background() const; | ||||
|     void _render_bed(float theta) const; | ||||
|  | @ -760,7 +617,6 @@ private: | |||
|     void _render_selection_sidebar_hints() const; | ||||
| 
 | ||||
|     void _update_volumes_hover_state() const; | ||||
|     void _update_gizmos_data(); | ||||
| 
 | ||||
|     void _perform_layer_editing_action(wxMouseEvent* evt = nullptr); | ||||
| 
 | ||||
|  | @ -771,9 +627,6 @@ private: | |||
|     // Convert the screen space coordinate to world coordinate on the bed.
 | ||||
|     Vec3d _mouse_to_bed_3d(const Point& mouse_pos); | ||||
| 
 | ||||
|     // Returns the view ray line, in world coordinate, at the given mouse position.
 | ||||
|     Linef3 mouse_ray(const Point& mouse_pos); | ||||
| 
 | ||||
|     void _start_timer(); | ||||
|     void _stop_timer(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
| #include "GLShader.hpp" | ||||
| 
 | ||||
| #include "libslic3r/Utils.hpp" | ||||
| #include "3DScene.hpp" | ||||
| #include <boost/nowide/fstream.hpp> | ||||
| 
 | ||||
| #include <string> | ||||
|  | @ -52,21 +53,22 @@ bool GLShader::load_from_text(const char *fragment_shader, const char *vertex_sh | |||
|     } | ||||
| 
 | ||||
|     if (fragment_shader != nullptr) { | ||||
|         this->fragment_program_id = glCreateShader(GL_FRAGMENT_SHADER); | ||||
|         this->fragment_program_id = ::glCreateShader(GL_FRAGMENT_SHADER); | ||||
|         glcheck(); | ||||
|         if (this->fragment_program_id == 0) { | ||||
|             last_error = "glCreateShader(GL_FRAGMENT_SHADER) failed."; | ||||
|             return false; | ||||
|         } | ||||
|         GLint len = (GLint)strlen(fragment_shader); | ||||
|         glShaderSource(this->fragment_program_id, 1, &fragment_shader, &len); | ||||
|         glCompileShader(this->fragment_program_id); | ||||
|         glsafe(::glShaderSource(this->fragment_program_id, 1, &fragment_shader, &len)); | ||||
|         glsafe(::glCompileShader(this->fragment_program_id)); | ||||
|         GLint params; | ||||
|         glGetShaderiv(this->fragment_program_id, GL_COMPILE_STATUS, ¶ms); | ||||
|         glsafe(::glGetShaderiv(this->fragment_program_id, GL_COMPILE_STATUS, ¶ms)); | ||||
|         if (params == GL_FALSE) { | ||||
|             // Compilation failed. Get the log.
 | ||||
|             glGetShaderiv(this->fragment_program_id, GL_INFO_LOG_LENGTH, ¶ms); | ||||
|             glsafe(::glGetShaderiv(this->fragment_program_id, GL_INFO_LOG_LENGTH, ¶ms)); | ||||
|             std::vector<char> msg(params); | ||||
|             glGetShaderInfoLog(this->fragment_program_id, params, ¶ms, msg.data()); | ||||
|             glsafe(::glGetShaderInfoLog(this->fragment_program_id, params, ¶ms, msg.data())); | ||||
|             this->last_error = std::string("Fragment shader compilation failed:\n") + msg.data(); | ||||
|             this->release(); | ||||
|             return false; | ||||
|  | @ -74,22 +76,23 @@ bool GLShader::load_from_text(const char *fragment_shader, const char *vertex_sh | |||
|     } | ||||
| 
 | ||||
|     if (vertex_shader != nullptr) { | ||||
|         this->vertex_program_id = glCreateShader(GL_VERTEX_SHADER); | ||||
|         this->vertex_program_id = ::glCreateShader(GL_VERTEX_SHADER); | ||||
|         glcheck(); | ||||
|         if (this->vertex_program_id == 0) { | ||||
|             last_error = "glCreateShader(GL_VERTEX_SHADER) failed."; | ||||
|             this->release(); | ||||
|             return false; | ||||
|         } | ||||
|         GLint len = (GLint)strlen(vertex_shader); | ||||
|         glShaderSource(this->vertex_program_id, 1, &vertex_shader, &len); | ||||
|         glCompileShader(this->vertex_program_id); | ||||
|         glsafe(::glShaderSource(this->vertex_program_id, 1, &vertex_shader, &len)); | ||||
|         glsafe(::glCompileShader(this->vertex_program_id)); | ||||
|         GLint params; | ||||
|         glGetShaderiv(this->vertex_program_id, GL_COMPILE_STATUS, ¶ms); | ||||
|         glsafe(::glGetShaderiv(this->vertex_program_id, GL_COMPILE_STATUS, ¶ms)); | ||||
|         if (params == GL_FALSE) { | ||||
|             // Compilation failed. Get the log.
 | ||||
|             glGetShaderiv(this->vertex_program_id, GL_INFO_LOG_LENGTH, ¶ms); | ||||
|             glsafe(::glGetShaderiv(this->vertex_program_id, GL_INFO_LOG_LENGTH, ¶ms)); | ||||
|             std::vector<char> msg(params); | ||||
|             glGetShaderInfoLog(this->vertex_program_id, params, ¶ms, msg.data()); | ||||
|             glsafe(::glGetShaderInfoLog(this->vertex_program_id, params, ¶ms, msg.data())); | ||||
|             this->last_error = std::string("Vertex shader compilation failed:\n") + msg.data(); | ||||
|             this->release(); | ||||
|             return false; | ||||
|  | @ -97,7 +100,8 @@ bool GLShader::load_from_text(const char *fragment_shader, const char *vertex_sh | |||
|     } | ||||
| 
 | ||||
|     // Link shaders
 | ||||
|     this->shader_program_id = glCreateProgram(); | ||||
|     this->shader_program_id = ::glCreateProgram(); | ||||
|     glcheck(); | ||||
|     if (this->shader_program_id == 0) { | ||||
|         last_error = "glCreateProgram() failed."; | ||||
|         this->release(); | ||||
|  | @ -105,18 +109,18 @@ bool GLShader::load_from_text(const char *fragment_shader, const char *vertex_sh | |||
|     } | ||||
| 
 | ||||
|     if (this->fragment_program_id) | ||||
|         glAttachShader(this->shader_program_id, this->fragment_program_id); | ||||
|         glsafe(::glAttachShader(this->shader_program_id, this->fragment_program_id)); | ||||
|     if (this->vertex_program_id) | ||||
|         glAttachShader(this->shader_program_id, this->vertex_program_id); | ||||
|     glLinkProgram(this->shader_program_id); | ||||
|         glsafe(::glAttachShader(this->shader_program_id, this->vertex_program_id)); | ||||
|     glsafe(::glLinkProgram(this->shader_program_id)); | ||||
| 
 | ||||
|     GLint params; | ||||
|     glGetProgramiv(this->shader_program_id, GL_LINK_STATUS, ¶ms); | ||||
|     glsafe(::glGetProgramiv(this->shader_program_id, GL_LINK_STATUS, ¶ms)); | ||||
|     if (params == GL_FALSE) { | ||||
|         // Linking failed. Get the log.
 | ||||
|         glGetProgramiv(this->vertex_program_id, GL_INFO_LOG_LENGTH, ¶ms); | ||||
|         glsafe(::glGetProgramiv(this->vertex_program_id, GL_INFO_LOG_LENGTH, ¶ms)); | ||||
|         std::vector<char> msg(params); | ||||
|         glGetProgramInfoLog(this->vertex_program_id, params, ¶ms, msg.data()); | ||||
|         glsafe(::glGetProgramInfoLog(this->vertex_program_id, params, ¶ms, msg.data())); | ||||
|         this->last_error = std::string("Shader linking failed:\n") + msg.data(); | ||||
|         this->release(); | ||||
|         return false; | ||||
|  | @ -165,31 +169,31 @@ void GLShader::release() | |||
| { | ||||
|     if (this->shader_program_id) { | ||||
|         if (this->vertex_program_id) | ||||
|             glDetachShader(this->shader_program_id, this->vertex_program_id); | ||||
|             glsafe(::glDetachShader(this->shader_program_id, this->vertex_program_id)); | ||||
|         if (this->fragment_program_id) | ||||
|             glDetachShader(this->shader_program_id, this->fragment_program_id); | ||||
|         glDeleteProgram(this->shader_program_id); | ||||
|             glsafe(::glDetachShader(this->shader_program_id, this->fragment_program_id)); | ||||
|         glsafe(::glDeleteProgram(this->shader_program_id)); | ||||
|         this->shader_program_id = 0; | ||||
|     } | ||||
| 
 | ||||
|     if (this->vertex_program_id) { | ||||
|         glDeleteShader(this->vertex_program_id); | ||||
|         glsafe(::glDeleteShader(this->vertex_program_id)); | ||||
|         this->vertex_program_id = 0; | ||||
|     } | ||||
|     if (this->fragment_program_id) { | ||||
|         glDeleteShader(this->fragment_program_id); | ||||
|         glsafe(::glDeleteShader(this->fragment_program_id)); | ||||
|         this->fragment_program_id = 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void GLShader::enable() const | ||||
| { | ||||
|     glUseProgram(this->shader_program_id); | ||||
|     glsafe(::glUseProgram(this->shader_program_id)); | ||||
| } | ||||
| 
 | ||||
| void GLShader::disable() const | ||||
| { | ||||
|     glUseProgram(0); | ||||
|     glsafe(::glUseProgram(0)); | ||||
| } | ||||
| 
 | ||||
| // Return shader vertex attribute ID
 | ||||
|  | @ -208,7 +212,7 @@ bool GLShader::set_uniform(const char *name, float value) const | |||
| { | ||||
|     int id = this->get_uniform_location(name); | ||||
|     if (id >= 0) {  | ||||
|         glUniform1fARB(id, value); | ||||
|         glsafe(::glUniform1fARB(id, value)); | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
|  | @ -219,7 +223,7 @@ bool GLShader::set_uniform(const char* name, const float* matrix) const | |||
|     int id = get_uniform_location(name); | ||||
|     if (id >= 0) | ||||
|     { | ||||
|         ::glUniformMatrix4fv(id, 1, GL_FALSE, (const GLfloat*)matrix); | ||||
|         glsafe(::glUniformMatrix4fv(id, 1, GL_FALSE, (const GLfloat*)matrix)); | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
|  | @ -230,7 +234,7 @@ bool GLShader::set_uniform(const char* name, int value) const | |||
|     int id = get_uniform_location(name); | ||||
|     if (id >= 0) | ||||
|     { | ||||
|         ::glUniform1i(id, value); | ||||
|         glsafe(::glUniform1i(id, value)); | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
|  |  | |||
|  | @ -1,6 +1,8 @@ | |||
| #include "libslic3r/libslic3r.h" | ||||
| #include "GLTexture.hpp" | ||||
| 
 | ||||
| #include "3DScene.hpp" | ||||
| 
 | ||||
| #include <GL/glew.h> | ||||
| 
 | ||||
| #include <wx/image.h> | ||||
|  | @ -11,15 +13,11 @@ | |||
| #include <vector> | ||||
| #include <algorithm> | ||||
| 
 | ||||
| #define NANOSVG_IMPLEMENTATION | ||||
| #include "nanosvg/nanosvg.h" | ||||
| #define NANOSVGRAST_IMPLEMENTATION | ||||
| #include "nanosvg/nanosvgrast.h" | ||||
| 
 | ||||
| #include "libslic3r/Utils.hpp" | ||||
| 
 | ||||
| #include "libslic3r/Utils.hpp" | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
| 
 | ||||
|  | @ -177,15 +175,15 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri | |||
|     nsvgDeleteRasterizer(rast); | ||||
| 
 | ||||
|     // sends data to gpu
 | ||||
|     ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | ||||
|     ::glGenTextures(1, &m_id); | ||||
|     ::glBindTexture(GL_TEXTURE_2D, m_id); | ||||
|     ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); | ||||
|     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||||
|     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); | ||||
|     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||||
|     glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); | ||||
|     glsafe(::glGenTextures(1, &m_id)); | ||||
|     glsafe(::glBindTexture(GL_TEXTURE_2D, m_id)); | ||||
|     glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); | ||||
|     glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); | ||||
|     glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); | ||||
|     glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); | ||||
| 
 | ||||
|     ::glBindTexture(GL_TEXTURE_2D, 0); | ||||
|     glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); | ||||
| 
 | ||||
|     m_source = filenames.front(); | ||||
|      | ||||
|  | @ -218,7 +216,7 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector<std::stri | |||
| void GLTexture::reset() | ||||
| { | ||||
|     if (m_id != 0) | ||||
|         ::glDeleteTextures(1, &m_id); | ||||
|         glsafe(::glDeleteTextures(1, &m_id)); | ||||
| 
 | ||||
|     m_id = 0; | ||||
|     m_width = 0; | ||||
|  | @ -233,25 +231,25 @@ void GLTexture::render_texture(unsigned int tex_id, float left, float right, flo | |||
| 
 | ||||
| void GLTexture::render_sub_texture(unsigned int tex_id, float left, float right, float bottom, float top, const GLTexture::Quad_UVs& uvs) | ||||
| { | ||||
|     ::glEnable(GL_BLEND); | ||||
|     ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||
|     glsafe(::glEnable(GL_BLEND)); | ||||
|     glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); | ||||
| 
 | ||||
|     ::glEnable(GL_TEXTURE_2D); | ||||
|     ::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | ||||
|     glsafe(::glEnable(GL_TEXTURE_2D)); | ||||
|     glsafe(::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); | ||||
| 
 | ||||
|     ::glBindTexture(GL_TEXTURE_2D, (GLuint)tex_id); | ||||
|     glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)tex_id)); | ||||
| 
 | ||||
|     ::glBegin(GL_QUADS); | ||||
|     ::glTexCoord2f(uvs.left_bottom.u, uvs.left_bottom.v); ::glVertex2f(left, bottom); | ||||
|     ::glTexCoord2f(uvs.right_bottom.u, uvs.right_bottom.v); ::glVertex2f(right, bottom); | ||||
|     ::glTexCoord2f(uvs.right_top.u, uvs.right_top.v); ::glVertex2f(right, top); | ||||
|     ::glTexCoord2f(uvs.left_top.u, uvs.left_top.v); ::glVertex2f(left, top); | ||||
|     ::glEnd(); | ||||
|     glsafe(::glEnd()); | ||||
| 
 | ||||
|     ::glBindTexture(GL_TEXTURE_2D, 0); | ||||
|     glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); | ||||
| 
 | ||||
|     ::glDisable(GL_TEXTURE_2D); | ||||
|     ::glDisable(GL_BLEND); | ||||
|     glsafe(::glDisable(GL_TEXTURE_2D)); | ||||
|     glsafe(::glDisable(GL_BLEND)); | ||||
| } | ||||
| 
 | ||||
| unsigned int GLTexture::generate_mipmaps(wxImage& image) | ||||
|  | @ -286,7 +284,7 @@ unsigned int GLTexture::generate_mipmaps(wxImage& image) | |||
|             data[data_id + 3] = (img_alpha != nullptr) ? img_alpha[i] : 255; | ||||
|         } | ||||
| 
 | ||||
|         ::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); | ||||
|         glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); | ||||
|     } | ||||
| 
 | ||||
|     return (unsigned int)level; | ||||
|  | @ -334,25 +332,25 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps) | |||
|     } | ||||
| 
 | ||||
|     // sends data to gpu
 | ||||
|     ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | ||||
|     ::glGenTextures(1, &m_id); | ||||
|     ::glBindTexture(GL_TEXTURE_2D, m_id); | ||||
|     ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); | ||||
|     glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); | ||||
|     glsafe(::glGenTextures(1, &m_id)); | ||||
|     glsafe(::glBindTexture(GL_TEXTURE_2D, m_id)); | ||||
|     glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); | ||||
|     if (use_mipmaps) | ||||
|     { | ||||
|         // we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
 | ||||
|         unsigned int levels_count = generate_mipmaps(image); | ||||
|         ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels_count); | ||||
|         ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | ||||
|         glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, levels_count)); | ||||
|         glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||||
|         ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); | ||||
|         glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); | ||||
|         glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); | ||||
|     } | ||||
|     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||||
|     glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); | ||||
| 
 | ||||
|     ::glBindTexture(GL_TEXTURE_2D, 0); | ||||
|     glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); | ||||
| 
 | ||||
|     m_source = filename; | ||||
| 
 | ||||
|  | @ -378,6 +376,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns | |||
|     if (n_pixels <= 0) | ||||
|     { | ||||
|         reset(); | ||||
|         nsvgDelete(image); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|  | @ -395,10 +394,10 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns | |||
|     nsvgRasterize(rast, image, 0, 0, scale, data.data(), m_width, m_height, m_width * 4); | ||||
| 
 | ||||
|     // sends data to gpu
 | ||||
|     ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | ||||
|     ::glGenTextures(1, &m_id); | ||||
|     ::glBindTexture(GL_TEXTURE_2D, m_id); | ||||
|     ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); | ||||
|     glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); | ||||
|     glsafe(::glGenTextures(1, &m_id)); | ||||
|     glsafe(::glBindTexture(GL_TEXTURE_2D, m_id)); | ||||
|     glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); | ||||
|     if (use_mipmaps) | ||||
|     { | ||||
|         // we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards
 | ||||
|  | @ -414,20 +413,20 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns | |||
|             scale /= 2.0f; | ||||
| 
 | ||||
|             nsvgRasterize(rast, image, 0, 0, scale, data.data(), lod_w, lod_h, lod_w * 4); | ||||
|             ::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); | ||||
|             glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); | ||||
|         } | ||||
| 
 | ||||
|         ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level); | ||||
|         ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | ||||
|         glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level)); | ||||
|         glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||||
|         ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); | ||||
|         glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); | ||||
|         glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); | ||||
|     } | ||||
|     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||||
|     glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); | ||||
| 
 | ||||
|     ::glBindTexture(GL_TEXTURE_2D, 0); | ||||
|     glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); | ||||
| 
 | ||||
|     m_source = filename; | ||||
| 
 | ||||
|  |  | |||
|  | @ -388,10 +388,10 @@ void GLToolbar::render(const GLCanvas3D& parent) const | |||
|         generate_icons_texture(); | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
| 
 | ||||
|     ::glDisable(GL_DEPTH_TEST); | ||||
|     glsafe(::glDisable(GL_DEPTH_TEST)); | ||||
| 
 | ||||
|     ::glPushMatrix(); | ||||
|     ::glLoadIdentity(); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glLoadIdentity()); | ||||
| 
 | ||||
|     switch (m_layout.type) | ||||
|     { | ||||
|  | @ -400,7 +400,7 @@ void GLToolbar::render(const GLCanvas3D& parent) const | |||
|     case Layout::Vertical: { render_vertical(parent); break; } | ||||
|     } | ||||
| 
 | ||||
|     ::glPopMatrix(); | ||||
|     glsafe(::glPopMatrix()); | ||||
| } | ||||
| 
 | ||||
| bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent) | ||||
|  | @ -444,11 +444,11 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent) | |||
|         { | ||||
|             m_mouse_capture.left = true; | ||||
|             m_mouse_capture.parent = &parent; | ||||
|             processed = true; | ||||
|             if ((item_id != -2) && !m_items[item_id]->is_separator()) | ||||
|             { | ||||
|                 // mouse is inside an icon
 | ||||
|                 do_action((unsigned int)item_id, parent); | ||||
|                 processed = true; | ||||
|             } | ||||
|         } | ||||
|         else if (evt.MiddleDown()) | ||||
|  | @ -612,7 +612,7 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC | |||
| { | ||||
|     // NB: mouse_pos is already scaled appropriately
 | ||||
| 
 | ||||
|     float zoom = parent.get_camera_zoom(); | ||||
|     float zoom = parent.get_camera().zoom; | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     float factor = m_layout.scale * inv_zoom; | ||||
|  | @ -717,7 +717,7 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan | |||
| { | ||||
|     // NB: mouse_pos is already scaled appropriately
 | ||||
| 
 | ||||
|     float zoom = parent.get_camera_zoom(); | ||||
|     float zoom = parent.get_camera().zoom; | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     float factor = m_layout.scale * inv_zoom; | ||||
|  | @ -834,7 +834,7 @@ int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3 | |||
| { | ||||
|     // NB: mouse_pos is already scaled appropriately
 | ||||
| 
 | ||||
|     float zoom = parent.get_camera_zoom(); | ||||
|     float zoom = parent.get_camera().zoom; | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     float factor = m_layout.scale * inv_zoom; | ||||
|  | @ -917,7 +917,7 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D& | |||
| { | ||||
|     // NB: mouse_pos is already scaled appropriately
 | ||||
| 
 | ||||
|     float zoom = parent.get_camera_zoom(); | ||||
|     float zoom = parent.get_camera().zoom; | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     float factor = m_layout.scale * inv_zoom; | ||||
|  | @ -1013,7 +1013,7 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const | |||
|         return; | ||||
| #endif // !ENABLE_SVG_ICONS
 | ||||
| 
 | ||||
|     float zoom = parent.get_camera_zoom(); | ||||
|     float zoom = parent.get_camera().zoom; | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     float factor = inv_zoom * m_layout.scale; | ||||
|  | @ -1168,7 +1168,7 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const | |||
|         return; | ||||
| #endif // !ENABLE_SVG_ICONS
 | ||||
| 
 | ||||
|     float zoom = parent.get_camera_zoom(); | ||||
|     float zoom = parent.get_camera().zoom; | ||||
|     float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     float factor = inv_zoom * m_layout.scale; | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| 
 | ||||
| #include "GLTexture.hpp" | ||||
| #include "Event.hpp" | ||||
| #include "libslic3r/Point.hpp" | ||||
| 
 | ||||
| class wxEvtHandler; | ||||
| 
 | ||||
|  |  | |||
|  | @ -76,6 +76,24 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension) | |||
| 
 | ||||
| static std::string libslic3r_translate_callback(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str().data(); } | ||||
| 
 | ||||
| static void register_dpi_event() | ||||
| { | ||||
| #ifdef WIN32 | ||||
|     enum { WM_DPICHANGED_ = 0x02e0 }; | ||||
| 
 | ||||
|     wxWindow::MSWRegisterMessageHandler(WM_DPICHANGED_, [](wxWindow *win, WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) { | ||||
|         const int dpi = wParam & 0xffff; | ||||
|         const auto rect = reinterpret_cast<PRECT>(lParam); | ||||
|         const wxRect wxrect(wxPoint(rect->top, rect->left), wxPoint(rect->bottom, rect->right)); | ||||
| 
 | ||||
|         DpiChangedEvent evt(EVT_DPI_CHANGED, dpi, wxrect); | ||||
|         win->GetEventHandler()->AddPendingEvent(evt); | ||||
| 
 | ||||
|         return true; | ||||
|     }); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| IMPLEMENT_APP(GUI_App) | ||||
| 
 | ||||
| GUI_App::GUI_App() | ||||
|  | @ -149,6 +167,8 @@ bool GUI_App::OnInit() | |||
|         show_error(nullptr, ex.what()); | ||||
| 	} | ||||
| 
 | ||||
|     register_dpi_event(); | ||||
| 
 | ||||
|     // Let the libslic3r know the callback, which will translate messages on demand.
 | ||||
|     Slic3r::I18N::set_translate_callback(libslic3r_translate_callback); | ||||
| 
 | ||||
|  |  | |||
|  | @ -62,18 +62,18 @@ ObjectList::ObjectList(wxWindow* parent) : | |||
|     // Fill CATEGORY_ICON
 | ||||
|     { | ||||
|         // ptFFF
 | ||||
| 		CATEGORY_ICON[L("Layers and Perimeters")]	= create_scaled_bitmap("layers.png"); // wxBitmap(from_u8(var("layers.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 		CATEGORY_ICON[L("Infill")]					= create_scaled_bitmap("infill.png"); // wxBitmap(from_u8(var("infill.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 		CATEGORY_ICON[L("Support material")]		= create_scaled_bitmap("building.png"); // wxBitmap(from_u8(var("building.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 		CATEGORY_ICON[L("Speed")]					= create_scaled_bitmap("time.png"); // wxBitmap(from_u8(var("time.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 		CATEGORY_ICON[L("Extruders")]				= create_scaled_bitmap("funnel.png"); // wxBitmap(from_u8(var("funnel.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 		CATEGORY_ICON[L("Extrusion Width")]			= create_scaled_bitmap("funnel.png"); // wxBitmap(from_u8(var("funnel.png")), wxBITMAP_TYPE_PNG);
 | ||||
| // 		CATEGORY_ICON[L("Skirt and brim")]			= create_scaled_bitmap("box.png"); // wxBitmap(from_u8(var("box.png")), wxBITMAP_TYPE_PNG);
 | ||||
| // 		CATEGORY_ICON[L("Speed > Acceleration")]	= create_scaled_bitmap("time.png"); // wxBitmap(from_u8(var("time.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 		CATEGORY_ICON[L("Advanced")]				= create_scaled_bitmap("wand.png"); // wxBitmap(from_u8(var("wand.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 		CATEGORY_ICON[L("Layers and Perimeters")]	= create_scaled_bitmap("layers"); | ||||
| 		CATEGORY_ICON[L("Infill")]					= create_scaled_bitmap("infill"); | ||||
| 		CATEGORY_ICON[L("Support material")]		= create_scaled_bitmap("support"); | ||||
| 		CATEGORY_ICON[L("Speed")]					= create_scaled_bitmap("time"); | ||||
| 		CATEGORY_ICON[L("Extruders")]				= create_scaled_bitmap("funnel"); | ||||
| 		CATEGORY_ICON[L("Extrusion Width")]			= create_scaled_bitmap("funnel"); | ||||
| // 		CATEGORY_ICON[L("Skirt and brim")]			= create_scaled_bitmap("skirt+brim"); 
 | ||||
| // 		CATEGORY_ICON[L("Speed > Acceleration")]	= create_scaled_bitmap("time");
 | ||||
| 		CATEGORY_ICON[L("Advanced")]				= create_scaled_bitmap("wrench"); | ||||
| 		// ptSLA
 | ||||
| 		CATEGORY_ICON[L("Supports")]				= create_scaled_bitmap("building.png"); // wxBitmap(from_u8(var("building.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 		CATEGORY_ICON[L("Pad")]				        = create_scaled_bitmap("brick.png"); // wxBitmap(from_u8(var("brick.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 		CATEGORY_ICON[L("Supports")]				= create_scaled_bitmap("sla_supports"); | ||||
| 		CATEGORY_ICON[L("Pad")]				        = create_scaled_bitmap("brick.png"); | ||||
|     } | ||||
| 
 | ||||
|     // create control
 | ||||
|  | @ -82,13 +82,35 @@ ObjectList::ObjectList(wxWindow* parent) : | |||
|     init_icons(); | ||||
| 
 | ||||
|     // describe control behavior 
 | ||||
|     Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxEvent& event) { | ||||
|     Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxDataViewEvent& event) { | ||||
| #ifndef __APPLE__ | ||||
|         // On Windows and Linux, forces a kill focus emulation on the object manipulator fields because this event handler is called
 | ||||
|         // before the kill focus event handler on the object manipulator when changing selection in the list, invalidating the object
 | ||||
|         // manipulator cache with the following call to selection_changed()
 | ||||
|         wxGetApp().obj_manipul()->emulate_kill_focus(); | ||||
| 
 | ||||
|         // To avoid selection update from SetSelection() and UnselectAll() under osx
 | ||||
|         if (m_prevent_list_events) | ||||
|             return; | ||||
| #endif // __APPLE__
 | ||||
| 
 | ||||
|         /* For multiple selection with pressed SHIFT, 
 | ||||
|          * event.GetItem() returns value of a first item in selection list  | ||||
|          * instead of real last clicked item. | ||||
|          * So, let check last selected item in such strange way | ||||
|          */ | ||||
|         if (wxGetKeyState(WXK_SHIFT)) | ||||
|         { | ||||
|             wxDataViewItemArray sels; | ||||
|             GetSelections(sels); | ||||
|             if (sels.front() == m_last_selected_item) | ||||
|                 m_last_selected_item = sels.back(); | ||||
|             else | ||||
|                 m_last_selected_item = event.GetItem(); | ||||
|         } | ||||
|         else | ||||
|             m_last_selected_item = event.GetItem(); | ||||
| 
 | ||||
|         selection_changed(); | ||||
| #ifndef __WXMSW__ | ||||
|         set_tooltip_for_item(get_mouse_position_in_control()); | ||||
|  | @ -368,13 +390,6 @@ void ObjectList::update_name_in_model(const wxDataViewItem& item) const | |||
| 
 | ||||
| void ObjectList::init_icons() | ||||
| { | ||||
| //     m_bmp_modifiermesh      = wxBitmap(from_u8(var("lambda.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("plugin.png")), wxBITMAP_TYPE_PNG);
 | ||||
| //     m_bmp_solidmesh         = wxBitmap(from_u8(var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 
 | ||||
| //     m_bmp_support_enforcer  = wxBitmap(from_u8(var("support_enforcer_.png")), wxBITMAP_TYPE_PNG);
 | ||||
| //     m_bmp_support_blocker   = wxBitmap(from_u8(var("support_blocker_.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 
 | ||||
| 
 | ||||
|     m_bmp_modifiermesh     = create_scaled_bitmap("lambda.png"); | ||||
|     m_bmp_solidmesh        = create_scaled_bitmap("object.png"); | ||||
|     m_bmp_support_enforcer = create_scaled_bitmap("support_enforcer_.png"); | ||||
|  | @ -389,16 +404,13 @@ void ObjectList::init_icons() | |||
|     m_objects_model->SetVolumeBitmaps(m_bmp_vector); | ||||
| 
 | ||||
|     // init icon for manifold warning
 | ||||
| //     m_bmp_manifold_warning  = wxBitmap(from_u8(var("exclamation_mark_.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("error.png")), wxBITMAP_TYPE_PNG);
 | ||||
|     m_bmp_manifold_warning  = create_scaled_bitmap("exclamation_mark_.png"); | ||||
| 
 | ||||
|     // init bitmap for "Split to sub-objects" context menu
 | ||||
| //     m_bmp_split             = wxBitmap(from_u8(var("split.png")), wxBITMAP_TYPE_PNG);
 | ||||
|     m_bmp_split             = create_scaled_bitmap("split.png"); | ||||
|     m_bmp_split             = create_scaled_bitmap("split_parts"); | ||||
| 
 | ||||
|     // init bitmap for "Add Settings" context menu
 | ||||
| //     m_bmp_cog               = wxBitmap(from_u8(var("cog.png")), wxBITMAP_TYPE_PNG);
 | ||||
|     m_bmp_cog               = create_scaled_bitmap("cog.png"); | ||||
|     m_bmp_cog               = create_scaled_bitmap("cog"); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -509,7 +521,7 @@ void ObjectList::key_event(wxKeyEvent& event) | |||
|         ) { | ||||
|         remove(); | ||||
|     } | ||||
|     else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_SHIFT)) | ||||
|     else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/)) | ||||
|         select_item_all_children(); | ||||
|     else | ||||
|         event.Skip(); | ||||
|  | @ -1005,8 +1017,7 @@ wxMenuItem* ObjectList::append_menu_item_instance_to_object(wxMenu* menu) | |||
| 
 | ||||
| void ObjectList::append_menu_items_osx(wxMenu* menu) | ||||
| { | ||||
|     append_menu_item(menu, wxID_ANY, _(L("Delete item")), "", | ||||
|         [this](wxCommandEvent&) { remove(); }, "", menu); | ||||
|     append_menu_item_delete(menu); | ||||
|      | ||||
|     append_menu_item(menu, wxID_ANY, _(L("Rename")), "", | ||||
|         [this](wxCommandEvent&) { rename_item(); }, "", menu); | ||||
|  | @ -1025,7 +1036,7 @@ void ObjectList::append_menu_item_fix_through_netfabb(wxMenu* menu) | |||
| 
 | ||||
| void ObjectList::append_menu_item_export_stl(wxMenu* menu) const  | ||||
| { | ||||
|     append_menu_item(menu, wxID_ANY, _(L("Export object as STL")) + dots, "", | ||||
|     append_menu_item(menu, wxID_ANY, _(L("Export as STL")) + dots, "", | ||||
|         [](wxCommandEvent&) { wxGetApp().plater()->export_stl(true); }, "", menu); | ||||
|     menu->AppendSeparator(); | ||||
| } | ||||
|  | @ -1061,6 +1072,12 @@ void ObjectList::append_menu_item_change_extruder(wxMenu* menu) const | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void ObjectList::append_menu_item_delete(wxMenu* menu) | ||||
| { | ||||
|     append_menu_item(menu, wxID_ANY, _(L("Delete")), "", | ||||
|         [this](wxCommandEvent&) { remove(); }, "", menu); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::create_object_popupmenu(wxMenu *menu) | ||||
| { | ||||
| #ifdef __WXOSX__   | ||||
|  | @ -1101,6 +1118,7 @@ void ObjectList::create_part_popupmenu(wxMenu *menu) | |||
| #endif // __WXOSX__
 | ||||
| 
 | ||||
|     append_menu_item_fix_through_netfabb(menu); | ||||
|     append_menu_item_export_stl(menu); | ||||
| 
 | ||||
|     m_menu_item_split_part = append_menu_item_split(menu); | ||||
| 
 | ||||
|  | @ -1117,10 +1135,21 @@ void ObjectList::create_part_popupmenu(wxMenu *menu) | |||
| 
 | ||||
| void ObjectList::create_instance_popupmenu(wxMenu*menu) | ||||
| { | ||||
| #ifdef __WXOSX__   | ||||
|     append_menu_item_delete(menu); | ||||
| #endif // __WXOSX__
 | ||||
|     m_menu_item_split_instances = append_menu_item_instance_to_object(menu); | ||||
| 
 | ||||
|     /* New behavior logic:
 | ||||
|      * 1. Split Object to several separated object, if ALL instances are selected | ||||
|      * 2. Separate selected instances from the initial object to the separated object, | ||||
|      *    if some (not all) instances are selected | ||||
|      */ | ||||
|     wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { | ||||
|         evt.Enable(can_split_instances()); }, m_menu_item_split_instances->GetId()); | ||||
| //         evt.Enable(can_split_instances()); }, m_menu_item_split_instances->GetId());
 | ||||
|         evt.SetText(wxGetApp().plater()->canvas3D()->get_selection().is_single_full_object() ?  | ||||
|                     _(L("Set as a Separated Objects")) : _(L("Set as a Separated Object"))); | ||||
|     }, m_menu_item_split_instances->GetId()); | ||||
| } | ||||
| 
 | ||||
| wxMenu* ObjectList::create_settings_popupmenu(wxMenu *parent_menu) | ||||
|  | @ -1551,7 +1580,7 @@ void ObjectList::split() | |||
|         auto opt_keys = model_object->volumes[id]->config.keys(); | ||||
|         if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) { | ||||
|             select_item(m_objects_model->AddSettingsChild(vol_item)); | ||||
|             Collapse(vol_item); | ||||
|             /*Collapse*/Expand(vol_item); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -1638,16 +1667,20 @@ void ObjectList::part_selection_changed() | |||
|     bool update_and_show_manipulations = false; | ||||
|     bool update_and_show_settings = false; | ||||
| 
 | ||||
|     if (multiple_selection()) { | ||||
|     const auto item = GetSelection(); | ||||
| 
 | ||||
|     if ( multiple_selection() || item && m_objects_model->GetItemType(item) == itInstanceRoot )  | ||||
|     { | ||||
|         og_name = _(L("Group manipulation")); | ||||
|         update_and_show_manipulations = true; | ||||
| 
 | ||||
|         const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); | ||||
|         // don't show manipulation panel for case of all Object's parts selection 
 | ||||
|         update_and_show_manipulations = !selection.is_single_full_instance(); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         const auto item = GetSelection(); | ||||
|         if (item) | ||||
|         { | ||||
|             bool is_part = false; | ||||
|             if (m_objects_model->GetParent(item) == wxDataViewItem(0)) { | ||||
|                 obj_idx = m_objects_model->GetIdByItem(item); | ||||
|                 og_name = _(L("Object manipulation")); | ||||
|  | @ -1665,7 +1698,6 @@ void ObjectList::part_selection_changed() | |||
|                     } | ||||
|                     else { | ||||
|                         og_name = _(L("Part Settings to modify")); | ||||
|                         is_part = true; | ||||
|                         auto main_parent = m_objects_model->GetParent(parent); | ||||
|                         obj_idx = m_objects_model->GetIdByItem(main_parent); | ||||
|                         const auto volume_id = m_objects_model->GetVolumeIdByItem(parent); | ||||
|  | @ -1675,7 +1707,6 @@ void ObjectList::part_selection_changed() | |||
|                 } | ||||
|                 else if (m_objects_model->GetItemType(item) == itVolume) { | ||||
|                     og_name = _(L("Part manipulation")); | ||||
|                     is_part = true; | ||||
|                     const auto volume_id = m_objects_model->GetVolumeIdByItem(item); | ||||
|                     m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config; | ||||
|                     update_and_show_manipulations = true; | ||||
|  | @ -1743,7 +1774,7 @@ void ObjectList::add_object_to_list(size_t obj_idx) | |||
|             auto opt_keys = model_object->volumes[id]->config.keys(); | ||||
|             if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) { | ||||
|                 select_item(m_objects_model->AddSettingsChild(vol_item)); | ||||
|                 Collapse(vol_item); | ||||
|                 /*Collapse*/Expand(vol_item); | ||||
|             } | ||||
|         } | ||||
|         Expand(item); | ||||
|  | @ -1757,7 +1788,7 @@ void ObjectList::add_object_to_list(size_t obj_idx) | |||
|     auto opt_keys = model_object->config.keys(); | ||||
|     if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) { | ||||
|         select_item(m_objects_model->AddSettingsChild(item)); | ||||
|         Collapse(item); | ||||
|         /*Collapse*/Expand(item); | ||||
|     } | ||||
| 
 | ||||
| #ifndef __WXOSX__  | ||||
|  | @ -1923,11 +1954,22 @@ bool ObjectList::multiple_selection() const | |||
|     return GetSelectedItemsCount() > 1; | ||||
| } | ||||
| 
 | ||||
| bool ObjectList::is_selected(const ItemType type) const | ||||
| { | ||||
|     const wxDataViewItem& item = GetSelection(); | ||||
|     if (item) | ||||
|         return m_objects_model->GetItemType(item) == type; | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| void ObjectList::update_selections() | ||||
| { | ||||
|     const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); | ||||
|     wxDataViewItemArray sels; | ||||
| 
 | ||||
|     m_selection_mode = smInstance; | ||||
| 
 | ||||
|     // We doesn't update selection if SettingsItem for the current object/part is selected
 | ||||
|     if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings ) | ||||
|     { | ||||
|  | @ -1941,32 +1983,56 @@ void ObjectList::update_selections() | |||
|                 return; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (selection.is_single_full_object()) | ||||
|     else if (selection.is_single_full_object() || selection.is_multiple_full_object()) | ||||
|     { | ||||
|         sels.Add(m_objects_model->GetItemById(selection.get_object_idx())); | ||||
|         const Selection::ObjectIdxsToInstanceIdxsMap& objects_content = selection.get_content(); | ||||
|         for (const auto& object : objects_content) { | ||||
|             if (object.second.size() == 1)          // object with 1 instance                
 | ||||
|                 sels.Add(m_objects_model->GetItemById(object.first)); | ||||
|             else if (object.second.size() > 1)      // object with several instances                
 | ||||
|             { | ||||
|                 wxDataViewItemArray current_sels; | ||||
|                 GetSelections(current_sels); | ||||
|                 const wxDataViewItem frst_inst_item = m_objects_model->GetItemByInstanceId(object.first, 0); | ||||
| 
 | ||||
|                 bool root_is_selected = false; | ||||
|                 for (const auto& item:current_sels) | ||||
|                     if (item == m_objects_model->GetParent(frst_inst_item) ||  | ||||
|                         item == m_objects_model->GetTopParent(frst_inst_item)) { | ||||
|                         root_is_selected = true; | ||||
|                         sels.Add(item); | ||||
|                         break; | ||||
|                     } | ||||
|                 if (root_is_selected) | ||||
|                     continue; | ||||
| 
 | ||||
|                 const Selection::InstanceIdxsList& instances = object.second; | ||||
|                 for (const auto& inst : instances) | ||||
|                     sels.Add(m_objects_model->GetItemByInstanceId(object.first, inst)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     else if (selection.is_single_volume() || selection.is_modifier() ||  | ||||
|              selection.is_multiple_volume() || selection.is_multiple_full_object()) { | ||||
|     else if (selection.is_single_volume() || selection.is_modifier() || selection.is_multiple_volume())  | ||||
|     { | ||||
|         for (auto idx : selection.get_volume_idxs()) { | ||||
|             const auto gl_vol = selection.get_volume(idx); | ||||
|             if (selection.is_multiple_full_object()) | ||||
|                 sels.Add(m_objects_model->GetItemById(gl_vol->object_idx())); | ||||
| 			else if (gl_vol->volume_idx() >= 0) | ||||
| 			if (gl_vol->volume_idx() >= 0) | ||||
|                 // Only add GLVolumes with non-negative volume_ids. GLVolumes with negative volume ids
 | ||||
|                 // are not associated with ModelVolumes, but they are temporarily generated by the backend
 | ||||
|                 // (for example, SLA supports or SLA pad).
 | ||||
|                 sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx())); | ||||
|         } | ||||
|         m_selection_mode = smVolume; | ||||
|     } | ||||
|     else if (selection.is_single_full_instance() || selection.is_multiple_full_instance()) { | ||||
|     else if (selection.is_single_full_instance() || selection.is_multiple_full_instance()) | ||||
|     { | ||||
|         for (auto idx : selection.get_instance_idxs()) {             | ||||
|             sels.Add(m_objects_model->GetItemByInstanceId(selection.get_object_idx(), idx)); | ||||
|         } | ||||
|     } | ||||
|     else if (selection.is_mixed()) | ||||
|     { | ||||
|         auto& objects_content_list = selection.get_content(); | ||||
|         const Selection::ObjectIdxsToInstanceIdxsMap& objects_content_list = selection.get_content(); | ||||
| 
 | ||||
|         for (auto idx : selection.get_volume_idxs()) { | ||||
|             const auto gl_vol = selection.get_volume(idx); | ||||
|  | @ -1999,6 +2065,9 @@ void ObjectList::update_selections() | |||
|                 sels.Add(m_objects_model->GetItemByVolumeId(glv_obj_idx, glv_vol_idx)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (sels.size() == 0) | ||||
|         m_selection_mode = smUndef; | ||||
|      | ||||
|     select_items(sels); | ||||
| 
 | ||||
|  | @ -2034,29 +2103,34 @@ void ObjectList::update_selections_on_canvas() | |||
| 
 | ||||
|     auto add_to_selection = [this](const wxDataViewItem& item, Selection& selection, int instance_idx, bool as_single_selection) | ||||
|     { | ||||
|         if (m_objects_model->GetParent(item) == wxDataViewItem(0)) { | ||||
|             selection.add_object(m_objects_model->GetIdByItem(item), as_single_selection); | ||||
|         const ItemType& type = m_objects_model->GetItemType(item); | ||||
|         if ( type == itInstanceRoot || m_objects_model->GetParent(item) == wxDataViewItem(0) ) { | ||||
|             wxDataViewItem obj_item = type == itInstanceRoot ? m_objects_model->GetParent(item) : item; | ||||
|             selection.add_object(m_objects_model->GetIdByItem(obj_item), as_single_selection); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (m_objects_model->GetItemType(item) == itVolume) { | ||||
|         if (type == itVolume) { | ||||
|             const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item)); | ||||
|             const int vol_idx = m_objects_model->GetVolumeIdByItem(item); | ||||
|             selection.add_volume(obj_idx, vol_idx, std::max(instance_idx, 0), as_single_selection); | ||||
|         } | ||||
|         else if (m_objects_model->GetItemType(item) == itInstance) { | ||||
|         else if (type == itInstance) { | ||||
|             const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); | ||||
|             const int inst_idx = m_objects_model->GetInstanceIdByItem(item); | ||||
|             selection.add_instance(obj_idx, inst_idx, as_single_selection); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     // stores current instance idx before to clear the selection
 | ||||
|     int instance_idx = selection.get_instance_idx(); | ||||
| 
 | ||||
|     if (sel_cnt == 1) { | ||||
|         wxDataViewItem item = GetSelection(); | ||||
|         if (m_objects_model->GetItemType(item) & (itSettings|itInstanceRoot)) | ||||
|             add_to_selection(m_objects_model->GetParent(item), selection, -1, true); | ||||
|             add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, true); | ||||
|         else | ||||
|             add_to_selection(item, selection, -1, true); | ||||
|             add_to_selection(item, selection, instance_idx, true); | ||||
| 
 | ||||
|         wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state(); | ||||
|         return; | ||||
|  | @ -2065,8 +2139,6 @@ void ObjectList::update_selections_on_canvas() | |||
|     wxDataViewItemArray sels; | ||||
|     GetSelections(sels); | ||||
| 
 | ||||
|     // stores current instance idx before to clear the selection
 | ||||
|     int instance_idx = selection.get_instance_idx(); | ||||
|     selection.clear(); | ||||
|     for (auto item: sels) | ||||
|         add_to_selection(item, selection, instance_idx, false); | ||||
|  | @ -2112,22 +2184,101 @@ void ObjectList::select_item_all_children() | |||
|     if (!GetSelection() || m_objects_model->GetItemType(GetSelection()) == itObject) { | ||||
|         for (int i = 0; i < m_objects->size(); i++) | ||||
|             sels.Add(m_objects_model->GetItemById(i)); | ||||
|         m_selection_mode = smInstance; | ||||
|     } | ||||
|     else { | ||||
|         const auto item = GetSelection(); | ||||
|         // Some volume(instance) is selected    =>  select all volumes(instances) inside the current object
 | ||||
|         if (m_objects_model->GetItemType(item) & (itVolume | itInstance)) { | ||||
|         if (m_objects_model->GetItemType(item) & (itVolume | itInstance)) | ||||
|             m_objects_model->GetChildren(m_objects_model->GetParent(item), sels); | ||||
|         } | ||||
| 
 | ||||
|         m_selection_mode = m_objects_model->GetItemType(item)&itVolume ? smVolume : smInstance; | ||||
|     } | ||||
| 
 | ||||
|     SetSelections(sels); | ||||
|     selection_changed(); | ||||
| } | ||||
| 
 | ||||
| // update selection mode for non-multiple selection
 | ||||
| void ObjectList::update_selection_mode() | ||||
| { | ||||
|     // All items are unselected 
 | ||||
|     if (!GetSelection()) | ||||
|     { | ||||
|         m_last_selected_item = wxDataViewItem(0); | ||||
|         m_selection_mode = smUndef; | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const ItemType type = m_objects_model->GetItemType(GetSelection()); | ||||
|     m_selection_mode =  type&itSettings ? smUndef   : | ||||
|                         type&itVolume   ? smVolume  : smInstance; | ||||
| } | ||||
| 
 | ||||
| // check last selected item. If is it possible to select it
 | ||||
| bool ObjectList::check_last_selection(wxString& msg_str) | ||||
| { | ||||
|     if (!m_last_selected_item) | ||||
|         return true; | ||||
|          | ||||
|     const bool is_shift_pressed = wxGetKeyState(WXK_SHIFT); | ||||
| 
 | ||||
|     /* We can't mix Parts and Objects/Instances.
 | ||||
|      * So, show information about it | ||||
|      */ | ||||
|     const ItemType type = m_objects_model->GetItemType(m_last_selected_item); | ||||
| 
 | ||||
|     // check a case of a selection of the Parts from different Objects
 | ||||
|     bool impossible_multipart_selection = false; | ||||
|     if (type & itVolume && m_selection_mode == smVolume) | ||||
|     { | ||||
|         wxDataViewItemArray sels; | ||||
|         GetSelections(sels); | ||||
|         for (const auto& sel: sels) | ||||
|             if (sel != m_last_selected_item &&  | ||||
|                 m_objects_model->GetParent(sel) != m_objects_model->GetParent(m_last_selected_item)) | ||||
|             { | ||||
|                 impossible_multipart_selection = true; | ||||
|                 break; | ||||
|             } | ||||
|     } | ||||
| 
 | ||||
|     if (impossible_multipart_selection || | ||||
|         type & itSettings || | ||||
|         type & itVolume && m_selection_mode == smInstance || | ||||
|         !(type & itVolume) && m_selection_mode == smVolume) | ||||
|     { | ||||
|         // Inform user why selection isn't complited
 | ||||
|         const wxString item_type = m_selection_mode == smInstance ? _(L("Object or Instance")) : _(L("Part")); | ||||
| 
 | ||||
|         msg_str = wxString::Format( _(L("Unsupported selection")) + "\n\n" +  | ||||
|                                     _(L("You started your selection with %s Item.")) + "\n" + | ||||
|                                     _(L("In this mode you can select only other %s Items%s")),  | ||||
|                                     item_type, item_type, | ||||
|                                     m_selection_mode == smInstance ? "." :  | ||||
|                                                         " " + _(L("of a current Object"))); | ||||
| 
 | ||||
|         // Unselect last selected item, if selection is without SHIFT
 | ||||
|         if (!is_shift_pressed) { | ||||
|             Unselect(m_last_selected_item); | ||||
|             show_info(this, msg_str, _(L("Info"))); | ||||
|         } | ||||
|          | ||||
|         return is_shift_pressed; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void ObjectList::fix_multiselection_conflicts() | ||||
| { | ||||
|     if (GetSelectedItemsCount() <= 1) | ||||
|     if (GetSelectedItemsCount() <= 1) { | ||||
|         update_selection_mode(); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     wxString msg_string; | ||||
|     if (!check_last_selection(msg_string)) | ||||
|         return; | ||||
| 
 | ||||
|     m_prevent_list_events = true; | ||||
|  | @ -2135,12 +2286,58 @@ void ObjectList::fix_multiselection_conflicts() | |||
|     wxDataViewItemArray sels; | ||||
|     GetSelections(sels); | ||||
| 
 | ||||
|     for (auto item : sels) { | ||||
|         if (m_objects_model->GetItemType(item) & (itSettings|itInstanceRoot)) | ||||
|             Unselect(item); | ||||
|         else if (m_objects_model->GetParent(item) != wxDataViewItem(0)) | ||||
|             Unselect(m_objects_model->GetParent(item)); | ||||
|     if (m_selection_mode == smVolume) | ||||
|     { | ||||
|         // identify correct parent of the initial selected item
 | ||||
|         const wxDataViewItem& parent = m_objects_model->GetParent(m_last_selected_item == sels.front() ? sels.back() : sels.front()); | ||||
| 
 | ||||
|         sels.clear(); | ||||
|         wxDataViewItemArray children; // selected volumes from current parent
 | ||||
|         m_objects_model->GetChildren(parent, children); | ||||
| 
 | ||||
|         for (const auto child : children) | ||||
|             if (IsSelected(child) && m_objects_model->GetItemType(child)&itVolume) | ||||
|                 sels.Add(child); | ||||
| 
 | ||||
|         // If some part is selected, unselect all items except of selected parts of the current object
 | ||||
|         UnselectAll(); | ||||
|         SetSelections(sels); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         for (const auto item : sels) | ||||
|         { | ||||
|             if (!IsSelected(item)) // if this item is unselected now (from previous actions)
 | ||||
|                 continue; | ||||
| 
 | ||||
|             if (m_objects_model->GetItemType(item) & itSettings) { | ||||
|                 Unselect(item); | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             const wxDataViewItem& parent = m_objects_model->GetParent(item); | ||||
|             if (parent != wxDataViewItem(0) && IsSelected(parent)) | ||||
|                 Unselect(parent); | ||||
|             else | ||||
|             { | ||||
|                 wxDataViewItemArray unsels; | ||||
|                 m_objects_model->GetAllChildren(item, unsels); | ||||
|                 for (const auto unsel_item : unsels) | ||||
|                     Unselect(unsel_item); | ||||
|             } | ||||
| 
 | ||||
|             if (m_objects_model->GetItemType(item) & itVolume) | ||||
|                 Unselect(item); | ||||
| 
 | ||||
|             m_selection_mode = smInstance; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (!msg_string.IsEmpty()) | ||||
|         show_info(this, msg_string, _(L("Info"))); | ||||
| 
 | ||||
|     if (!IsSelected(m_last_selected_item)) | ||||
|         m_last_selected_item = wxDataViewItem(0); | ||||
| 
 | ||||
|     m_prevent_list_events = false; | ||||
| } | ||||
|  | @ -2272,6 +2469,12 @@ void ObjectList::update_object_menu() | |||
| 
 | ||||
| void ObjectList::instances_to_separated_object(const int obj_idx, const std::set<int>& inst_idxs) | ||||
| { | ||||
|     if ((*m_objects)[obj_idx]->instances.size() == inst_idxs.size()) | ||||
|     { | ||||
|         instances_to_separated_objects(obj_idx); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // create new object from selected instance  
 | ||||
|     ModelObject* model_object = (*m_objects)[obj_idx]->get_model()->add_object(*(*m_objects)[obj_idx]); | ||||
|     for (int inst_idx = model_object->instances.size() - 1; inst_idx >= 0; inst_idx--) | ||||
|  | @ -2292,6 +2495,31 @@ void ObjectList::instances_to_separated_object(const int obj_idx, const std::set | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void ObjectList::instances_to_separated_objects(const int obj_idx) | ||||
| { | ||||
|     const int inst_cnt = (*m_objects)[obj_idx]->instances.size(); | ||||
| 
 | ||||
|     for (int i = inst_cnt-1; i > 0 ; i--) | ||||
|     { | ||||
|         // create new object from initial
 | ||||
|         ModelObject* object = (*m_objects)[obj_idx]->get_model()->add_object(*(*m_objects)[obj_idx]); | ||||
|         for (int inst_idx = object->instances.size() - 1; inst_idx >= 0; inst_idx--) | ||||
|         { | ||||
|             if (inst_idx == i) | ||||
|                 continue; | ||||
|             // delete unnecessary instances
 | ||||
|             object->delete_instance(inst_idx); | ||||
|         } | ||||
| 
 | ||||
|         // Add new object to the object_list
 | ||||
|         add_object_to_list(m_objects->size() - 1); | ||||
| 
 | ||||
|         // delete current instance from the initial object
 | ||||
|         del_subobject_from_object(obj_idx, i, itInstance); | ||||
|         delete_instance_from_list(obj_idx, i); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void ObjectList::split_instances() | ||||
| { | ||||
|     const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); | ||||
|  | @ -2299,6 +2527,12 @@ void ObjectList::split_instances() | |||
|     if (obj_idx == -1) | ||||
|         return; | ||||
| 
 | ||||
|     if (selection.is_single_full_object()) | ||||
|     { | ||||
|         instances_to_separated_objects(obj_idx); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const int inst_idx = selection.get_instance_idx(); | ||||
|     const std::set<int> inst_idxs = inst_idx < 0 ? | ||||
|                                     selection.get_instance_idxs() : | ||||
|  | @ -2424,8 +2658,7 @@ void ObjectList::show_multi_selection_menu() | |||
|     wxMenu* menu = new wxMenu(); | ||||
| 
 | ||||
| #ifdef __WXOSX__ | ||||
|     append_menu_item(menu, wxID_ANY, _(L("Delete items")), "", | ||||
|         [this](wxCommandEvent&) { remove(); }, "", menu); | ||||
|     append_menu_item_delete(menu); | ||||
| #endif //__WXOSX__
 | ||||
| 
 | ||||
|     if (extruders_count() > 1) | ||||
|  |  | |||
|  | @ -60,6 +60,12 @@ struct ItemForDelete | |||
| 
 | ||||
| class ObjectList : public wxDataViewCtrl | ||||
| { | ||||
|     enum SELECTION_MODE | ||||
|     { | ||||
|         smUndef, | ||||
|         smVolume, | ||||
|         smInstance | ||||
|     } m_selection_mode {smUndef}; | ||||
| 
 | ||||
|     struct dragged_item_data | ||||
|     { | ||||
|  | @ -135,6 +141,7 @@ class ObjectList : public wxDataViewCtrl | |||
|     bool        m_part_settings_changed = false; | ||||
| 
 | ||||
|     int         m_selected_row = 0; | ||||
|     wxDataViewItem m_last_selected_item {nullptr}; | ||||
| 
 | ||||
| #if 0 | ||||
|     FreqSettingsBundle m_freq_settings_fff; | ||||
|  | @ -188,6 +195,7 @@ public: | |||
|     void                append_menu_item_fix_through_netfabb(wxMenu* menu); | ||||
|     void                append_menu_item_export_stl(wxMenu* menu) const ; | ||||
|     void                append_menu_item_change_extruder(wxMenu* menu) const; | ||||
|     void                append_menu_item_delete(wxMenu* menu); | ||||
|     void                create_object_popupmenu(wxMenu *menu); | ||||
|     void                create_sla_object_popupmenu(wxMenu*menu); | ||||
|     void                create_part_popupmenu(wxMenu*menu); | ||||
|  | @ -251,12 +259,15 @@ public: | |||
| 
 | ||||
|     void init_objects(); | ||||
|     bool multiple_selection() const ; | ||||
|     bool is_selected(const ItemType type) const; | ||||
|     void update_selections(); | ||||
|     void update_selections_on_canvas(); | ||||
|     void select_item(const wxDataViewItem& item); | ||||
|     void select_items(const wxDataViewItemArray& sels); | ||||
|     void select_all(); | ||||
|     void select_item_all_children(); | ||||
|     void update_selection_mode(); | ||||
|     bool check_last_selection(wxString& msg_str); | ||||
|     // correct current selections to avoid of the possible conflicts
 | ||||
|     void fix_multiselection_conflicts(); | ||||
| 
 | ||||
|  | @ -269,6 +280,7 @@ public: | |||
|     void update_object_menu(); | ||||
| 
 | ||||
|     void instances_to_separated_object(const int obj_idx, const std::set<int>& inst_idx); | ||||
|     void instances_to_separated_objects(const int obj_idx); | ||||
|     void split_instances(); | ||||
|     void rename_item(); | ||||
|     void fix_through_netfabb() const; | ||||
|  |  | |||
|  | @ -92,7 +92,6 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : | |||
|         else if (option_name == "Size") { | ||||
|             line.near_label_widget = [this](wxWindow* parent) { | ||||
|                 return new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, | ||||
| //                                           wxBitmap(from_u8(var("one_layer_lock_on.png")), wxBITMAP_TYPE_PNG).GetSize());
 | ||||
|                                           create_scaled_bitmap("one_layer_lock_on.png").GetSize()); | ||||
|             }; | ||||
|         } | ||||
|  | @ -161,6 +160,8 @@ void ObjectManipulation::update_settings_value(const Selection& selection) | |||
| 	m_new_move_label_string   = L("Position"); | ||||
|     m_new_rotate_label_string = L("Rotation"); | ||||
|     m_new_scale_label_string  = L("Scale factors"); | ||||
| 
 | ||||
|     ObjectList* obj_list = wxGetApp().obj_list(); | ||||
|     if (selection.is_single_full_instance()) | ||||
|     { | ||||
|         // all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one
 | ||||
|  | @ -187,7 +188,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) | |||
| 
 | ||||
|         m_new_enabled  = true; | ||||
|     } | ||||
|     else if (selection.is_single_full_object()) | ||||
|     else if (selection.is_single_full_object() && obj_list->is_selected(itObject)) | ||||
|     { | ||||
|         m_cache.instance.reset(); | ||||
| 
 | ||||
|  | @ -212,7 +213,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) | |||
|         m_new_size = (volume->get_volume_transformation().get_matrix(true, true) * volume->bounding_box.size()).cwiseAbs(); | ||||
|         m_new_enabled = true; | ||||
|     } | ||||
|     else if (wxGetApp().obj_list()->multiple_selection()) | ||||
|     else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot)) | ||||
|     { | ||||
|         reset_settings_value(); | ||||
| 		m_new_move_label_string   = L("Translate"); | ||||
|  |  | |||
|  | @ -77,7 +77,6 @@ void ObjectSettings::update_settings_list() | |||
| 		{ | ||||
| 			auto opt_key = (line.get_options())[0].opt_id;  //we assume that we have one option per line
 | ||||
| 
 | ||||
| // 			auto btn = new wxBitmapButton(parent, wxID_ANY, wxBitmap(from_u8(var("colorchange_delete_on.png")), wxBITMAP_TYPE_PNG),
 | ||||
| 			auto btn = new wxBitmapButton(parent, wxID_ANY, create_scaled_bitmap("colorchange_delete_on.png"), | ||||
| 				wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); | ||||
| #ifdef __WXMSW__ | ||||
|  |  | |||
|  | @ -4,9 +4,14 @@ | |||
| #include <boost/lexical_cast.hpp> | ||||
| #include <boost/format.hpp> | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| #include <Windows.h> | ||||
| #endif | ||||
| 
 | ||||
| #include <wx/toplevel.h> | ||||
| #include <wx/sizer.h> | ||||
| #include <wx/checkbox.h> | ||||
| #include <wx/dcclient.h> | ||||
| 
 | ||||
| #include "libslic3r/Config.hpp" | ||||
| 
 | ||||
|  | @ -48,6 +53,64 @@ void on_window_geometry(wxTopLevelWindow *tlw, std::function<void()> callback) | |||
| #endif | ||||
| } | ||||
| 
 | ||||
| wxDEFINE_EVENT(EVT_DPI_CHANGED, DpiChangedEvent); | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| template<class F> typename F::FN winapi_get_function(const wchar_t *dll, const char *fn_name) { | ||||
|     static HINSTANCE dll_handle = LoadLibraryExW(dll, nullptr, 0); | ||||
| 
 | ||||
|     if (dll_handle == nullptr) { return nullptr; } | ||||
|     return (F::FN)GetProcAddress(dll_handle, fn_name); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| int get_dpi_for_window(wxWindow *window) | ||||
| { | ||||
| #ifdef _WIN32 | ||||
|     enum MONITOR_DPI_TYPE_ { | ||||
|         // This enum is inlined here to avoid build-time dependency
 | ||||
|         MDT_EFFECTIVE_DPI_ = 0, | ||||
|         MDT_ANGULAR_DPI_ = 1, | ||||
|         MDT_RAW_DPI_ = 2, | ||||
|         MDT_DEFAULT_ = MDT_EFFECTIVE_DPI_, | ||||
|     }; | ||||
| 
 | ||||
|     // Need strong types for winapi_get_function() to work
 | ||||
|     struct GetDpiForWindow_t { typedef HRESULT (WINAPI *FN)(HWND hwnd); }; | ||||
|     struct GetDpiForMonitor_t { typedef HRESULT (WINAPI *FN)(HMONITOR hmonitor, MONITOR_DPI_TYPE_ dpiType, UINT *dpiX, UINT *dpiY); }; | ||||
| 
 | ||||
|     static auto GetDpiForWindow_fn = winapi_get_function<GetDpiForWindow_t>(L"User32.dll", "GetDpiForWindow"); | ||||
|     static auto GetDpiForMonitor_fn = winapi_get_function<GetDpiForMonitor_t>(L"Shcore.dll", "GetDpiForMonitor"); | ||||
| 
 | ||||
|     const HWND hwnd = window->GetHandle(); | ||||
| 
 | ||||
|     if (GetDpiForWindow_fn != nullptr) { | ||||
|         // We're on Windows 10, we have per-screen DPI settings
 | ||||
|         return GetDpiForWindow_fn(hwnd); | ||||
|     } else if (GetDpiForMonitor_fn != nullptr) { | ||||
|         // We're on Windows 8.1, we have per-system DPI
 | ||||
|         // Note: MonitorFromWindow() is available on all Windows.
 | ||||
| 
 | ||||
|         const HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); | ||||
|         UINT dpiX; | ||||
|         UINT dpiY; | ||||
|         return GetDpiForMonitor_fn(monitor, MDT_EFFECTIVE_DPI_, &dpiX, &dpiY) == S_OK ? dpiX : DPI_DEFAULT; | ||||
|     } else { | ||||
|         // We're on Windows earlier than 8.1, use DC
 | ||||
| 
 | ||||
|         const HDC hdc = GetDC(hwnd); | ||||
|         if (hdc == NULL) { return DPI_DEFAULT; } | ||||
|         return GetDeviceCaps(hdc, LOGPIXELSX); | ||||
|     } | ||||
| #elif defined __linux__ | ||||
|     // TODO
 | ||||
|     return DPI_DEFAULT; | ||||
| #elif defined __APPLE__ | ||||
|     // TODO
 | ||||
|     return DPI_DEFAULT; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| CheckboxFileDialog::ExtraPanel::ExtraPanel(wxWindow *parent) | ||||
|     : wxPanel(parent, wxID_ANY) | ||||
|  |  | |||
|  | @ -8,10 +8,13 @@ | |||
| 
 | ||||
| #include <boost/optional.hpp> | ||||
| 
 | ||||
| #include <wx/frame.h> | ||||
| #include <wx/dialog.h> | ||||
| #include <wx/event.h> | ||||
| #include <wx/filedlg.h> | ||||
| #include <wx/gdicmn.h> | ||||
| #include <wx/panel.h> | ||||
| #include <wx/dcclient.h> | ||||
| #include <wx/debug.h> | ||||
| 
 | ||||
| class wxCheckBox; | ||||
|  | @ -27,6 +30,68 @@ wxTopLevelWindow* find_toplevel_parent(wxWindow *window); | |||
| 
 | ||||
| void on_window_geometry(wxTopLevelWindow *tlw, std::function<void()> callback); | ||||
| 
 | ||||
| enum { DPI_DEFAULT = 96 }; | ||||
| 
 | ||||
| int get_dpi_for_window(wxWindow *window); | ||||
| 
 | ||||
| struct DpiChangedEvent : public wxEvent { | ||||
|     int dpi; | ||||
|     wxRect rect; | ||||
| 
 | ||||
|     DpiChangedEvent(wxEventType eventType, int dpi, wxRect rect) | ||||
|         : wxEvent(0, eventType), dpi(dpi), rect(rect) | ||||
|     {} | ||||
| 
 | ||||
|     virtual wxEvent *Clone() const | ||||
|     { | ||||
|         return new DpiChangedEvent(*this); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| wxDECLARE_EVENT(EVT_DPI_CHANGED, DpiChangedEvent); | ||||
| 
 | ||||
| template<class P> class DPIAware : public P | ||||
| { | ||||
| public: | ||||
|     DPIAware(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &pos=wxDefaultPosition, | ||||
|         const wxSize &size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE, const wxString &name=wxFrameNameStr) | ||||
|         : P(parent, id, title, pos, size, style, name) | ||||
|     { | ||||
|         m_scale_factor = (float)get_dpi_for_window(this) / (float)DPI_DEFAULT; | ||||
|         recalc_font(); | ||||
| 
 | ||||
|         this->Bind(EVT_DPI_CHANGED, [this](const DpiChangedEvent &evt) { | ||||
|             m_scale_factor = (float)evt.dpi / (float)DPI_DEFAULT; | ||||
|             on_dpi_changed(evt.rect); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     virtual ~DPIAware() {} | ||||
| 
 | ||||
|     float scale_factor() const { return m_scale_factor; } | ||||
|     int em_unit() const { return m_em_unit; } | ||||
|     int font_size() const { return m_font_size; } | ||||
| 
 | ||||
| protected: | ||||
|     virtual void on_dpi_changed(const wxRect &suggested_rect) = 0; | ||||
| 
 | ||||
| private: | ||||
|     int m_scale_factor; | ||||
|     int m_em_unit; | ||||
|     int m_font_size; | ||||
| 
 | ||||
|     void recalc_font() | ||||
|     { | ||||
|         wxClientDC dc(this); | ||||
|         const auto metrics = dc.GetFontMetrics(); | ||||
|         m_font_size = metrics.height; | ||||
|         m_em_unit = metrics.averageWidth; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| typedef DPIAware<wxFrame> DPIFrame; | ||||
| typedef DPIAware<wxDialog> DPIDialog; | ||||
| 
 | ||||
| 
 | ||||
| class EventGuard | ||||
| { | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| #include "GLGizmoBase.hpp" | ||||
| #include "slic3r/GUI/GLCanvas3D.hpp" | ||||
| 
 | ||||
| #include <GL/glew.h> | ||||
| 
 | ||||
|  | @ -60,62 +61,62 @@ void GLGizmoBase::Grabber::render(float size, const float* render_color, bool us | |||
|     float half_size = dragging ? get_dragging_half_size(size) : get_half_size(size); | ||||
| 
 | ||||
|     if (use_lighting) | ||||
|         ::glEnable(GL_LIGHTING); | ||||
|         glsafe(::glEnable(GL_LIGHTING)); | ||||
| 
 | ||||
|     ::glColor3fv(render_color); | ||||
|     glsafe(::glColor3fv(render_color)); | ||||
| 
 | ||||
|     ::glPushMatrix(); | ||||
|     ::glTranslated(center(0), center(1), center(2)); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glTranslated(center(0), center(1), center(2))); | ||||
| 
 | ||||
|     ::glRotated(Geometry::rad2deg(angles(2)), 0.0, 0.0, 1.0); | ||||
|     ::glRotated(Geometry::rad2deg(angles(1)), 0.0, 1.0, 0.0); | ||||
|     ::glRotated(Geometry::rad2deg(angles(0)), 1.0, 0.0, 0.0); | ||||
|     glsafe(::glRotated(Geometry::rad2deg(angles(2)), 0.0, 0.0, 1.0)); | ||||
|     glsafe(::glRotated(Geometry::rad2deg(angles(1)), 0.0, 1.0, 0.0)); | ||||
|     glsafe(::glRotated(Geometry::rad2deg(angles(0)), 1.0, 0.0, 0.0)); | ||||
| 
 | ||||
|     // face min x
 | ||||
|     ::glPushMatrix(); | ||||
|     ::glTranslatef(-(GLfloat)half_size, 0.0f, 0.0f); | ||||
|     ::glRotatef(-90.0f, 0.0f, 1.0f, 0.0f); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glTranslatef(-(GLfloat)half_size, 0.0f, 0.0f)); | ||||
|     glsafe(::glRotatef(-90.0f, 0.0f, 1.0f, 0.0f)); | ||||
|     render_face(half_size); | ||||
|     ::glPopMatrix(); | ||||
|     glsafe(::glPopMatrix()); | ||||
| 
 | ||||
|     // face max x
 | ||||
|     ::glPushMatrix(); | ||||
|     ::glTranslatef((GLfloat)half_size, 0.0f, 0.0f); | ||||
|     ::glRotatef(90.0f, 0.0f, 1.0f, 0.0f); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glTranslatef((GLfloat)half_size, 0.0f, 0.0f)); | ||||
|     glsafe(::glRotatef(90.0f, 0.0f, 1.0f, 0.0f)); | ||||
|     render_face(half_size); | ||||
|     ::glPopMatrix(); | ||||
|     glsafe(::glPopMatrix()); | ||||
| 
 | ||||
|     // face min y
 | ||||
|     ::glPushMatrix(); | ||||
|     ::glTranslatef(0.0f, -(GLfloat)half_size, 0.0f); | ||||
|     ::glRotatef(90.0f, 1.0f, 0.0f, 0.0f); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glTranslatef(0.0f, -(GLfloat)half_size, 0.0f)); | ||||
|     glsafe(::glRotatef(90.0f, 1.0f, 0.0f, 0.0f)); | ||||
|     render_face(half_size); | ||||
|     ::glPopMatrix(); | ||||
|     glsafe(::glPopMatrix()); | ||||
| 
 | ||||
|     // face max y
 | ||||
|     ::glPushMatrix(); | ||||
|     ::glTranslatef(0.0f, (GLfloat)half_size, 0.0f); | ||||
|     ::glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glTranslatef(0.0f, (GLfloat)half_size, 0.0f)); | ||||
|     glsafe(::glRotatef(-90.0f, 1.0f, 0.0f, 0.0f)); | ||||
|     render_face(half_size); | ||||
|     ::glPopMatrix(); | ||||
|     glsafe(::glPopMatrix()); | ||||
| 
 | ||||
|     // face min z
 | ||||
|     ::glPushMatrix(); | ||||
|     ::glTranslatef(0.0f, 0.0f, -(GLfloat)half_size); | ||||
|     ::glRotatef(180.0f, 1.0f, 0.0f, 0.0f); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glTranslatef(0.0f, 0.0f, -(GLfloat)half_size)); | ||||
|     glsafe(::glRotatef(180.0f, 1.0f, 0.0f, 0.0f)); | ||||
|     render_face(half_size); | ||||
|     ::glPopMatrix(); | ||||
|     glsafe(::glPopMatrix()); | ||||
| 
 | ||||
|     // face max z
 | ||||
|     ::glPushMatrix(); | ||||
|     ::glTranslatef(0.0f, 0.0f, (GLfloat)half_size); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glTranslatef(0.0f, 0.0f, (GLfloat)half_size)); | ||||
|     render_face(half_size); | ||||
|     ::glPopMatrix(); | ||||
|     glsafe(::glPopMatrix()); | ||||
| 
 | ||||
|     ::glPopMatrix(); | ||||
|     glsafe(::glPopMatrix()); | ||||
| 
 | ||||
|     if (use_lighting) | ||||
|         ::glDisable(GL_LIGHTING); | ||||
|         glsafe(::glDisable(GL_LIGHTING)); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoBase::Grabber::render_face(float half_size) const | ||||
|  | @ -128,7 +129,7 @@ void GLGizmoBase::Grabber::render_face(float half_size) const | |||
|     ::glVertex3f((GLfloat)half_size, (GLfloat)half_size, 0.0f); | ||||
|     ::glVertex3f(-(GLfloat)half_size, (GLfloat)half_size, 0.0f); | ||||
|     ::glVertex3f(-(GLfloat)half_size, -(GLfloat)half_size, 0.0f); | ||||
|     ::glEnd(); | ||||
|     glsafe(::glEnd()); | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_SVG_ICONS | ||||
|  |  | |||
|  | @ -3,7 +3,6 @@ | |||
| 
 | ||||
| #include "libslic3r/Point.hpp" | ||||
| 
 | ||||
| #include "slic3r/GUI/GLCanvas3D.hpp" | ||||
| #include "slic3r/GUI/I18N.hpp" | ||||
| #include "slic3r/GUI/Selection.hpp" | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| // Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
 | ||||
| #include "GLGizmoCut.hpp" | ||||
| #include "slic3r/GUI/GLCanvas3D.hpp" | ||||
| 
 | ||||
| #include <GL/glew.h> | ||||
| 
 | ||||
|  | @ -15,12 +16,6 @@ namespace Slic3r { | |||
| namespace GUI { | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // GLGizmoCut
 | ||||
| 
 | ||||
| class GLGizmoCutPanel : public wxPanel | ||||
| { | ||||
| public: | ||||
|  | @ -141,10 +136,10 @@ void GLGizmoCut::on_render(const Selection& selection) const | |||
|     const float max_x = box.max(0) + Margin; | ||||
|     const float min_y = box.min(1) - Margin; | ||||
|     const float max_y = box.max(1) + Margin; | ||||
|     ::glEnable(GL_DEPTH_TEST); | ||||
|     ::glDisable(GL_CULL_FACE); | ||||
|     ::glEnable(GL_BLEND); | ||||
|     ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||
|     glsafe(::glEnable(GL_DEPTH_TEST)); | ||||
|     glsafe(::glDisable(GL_CULL_FACE)); | ||||
|     glsafe(::glEnable(GL_BLEND)); | ||||
|     glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); | ||||
| 
 | ||||
|     // Draw the cutting plane
 | ||||
|     ::glBegin(GL_QUADS); | ||||
|  | @ -153,10 +148,10 @@ void GLGizmoCut::on_render(const Selection& selection) const | |||
|     ::glVertex3f(max_x, min_y, plane_center(2)); | ||||
|     ::glVertex3f(max_x, max_y, plane_center(2)); | ||||
|     ::glVertex3f(min_x, max_y, plane_center(2)); | ||||
|     ::glEnd(); | ||||
|     glsafe(::glEnd()); | ||||
| 
 | ||||
|     ::glEnable(GL_CULL_FACE); | ||||
|     ::glDisable(GL_BLEND); | ||||
|     glsafe(::glEnable(GL_CULL_FACE)); | ||||
|     glsafe(::glDisable(GL_BLEND)); | ||||
| 
 | ||||
|     // TODO: draw cut part contour?
 | ||||
| 
 | ||||
|  | @ -164,13 +159,13 @@ void GLGizmoCut::on_render(const Selection& selection) const | |||
|     m_grabbers[0].center = plane_center; | ||||
|     m_grabbers[0].center(2) = plane_center(2) + Offset; | ||||
| 
 | ||||
|     ::glDisable(GL_DEPTH_TEST); | ||||
|     ::glLineWidth(m_hover_id != -1 ? 2.0f : 1.5f); | ||||
|     ::glColor3f(1.0, 1.0, 0.0); | ||||
|     glsafe(::glDisable(GL_DEPTH_TEST)); | ||||
|     glsafe(::glLineWidth(m_hover_id != -1 ? 2.0f : 1.5f)); | ||||
|     glsafe(::glColor3f(1.0, 1.0, 0.0)); | ||||
|     ::glBegin(GL_LINES); | ||||
|     ::glVertex3dv(plane_center.data()); | ||||
|     ::glVertex3dv(m_grabbers[0].center.data()); | ||||
|     ::glEnd(); | ||||
|     glsafe(::glEnd()); | ||||
| 
 | ||||
|     std::copy(std::begin(GrabberColor), std::end(GrabberColor), m_grabbers[0].color); | ||||
|     m_grabbers[0].render(m_hover_id == 0, (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0)); | ||||
|  | @ -178,7 +173,7 @@ void GLGizmoCut::on_render(const Selection& selection) const | |||
| 
 | ||||
| void GLGizmoCut::on_render_for_picking(const Selection& selection) const | ||||
| { | ||||
|     ::glDisable(GL_DEPTH_TEST); | ||||
|     glsafe(::glDisable(GL_DEPTH_TEST)); | ||||
| 
 | ||||
|     render_grabbers_for_picking(selection.get_bounding_box()); | ||||
| } | ||||
|  | @ -192,7 +187,7 @@ void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit, co | |||
|     m_imgui->set_next_window_bg_alpha(0.5f); | ||||
|     m_imgui->begin(_(L("Cut")), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); | ||||
| 
 | ||||
|     ImGui::PushItemWidth(100.0f); | ||||
|     ImGui::PushItemWidth(m_imgui->scaled(5.0f)); | ||||
|     bool _value_changed = ImGui::InputDouble("Z", &m_cut_z, 0.0f, 0.0f, "%.2f"); | ||||
| 
 | ||||
|     m_imgui->checkbox(_(L("Keep upper part")), m_keep_upper); | ||||
|  |  | |||
|  | @ -49,67 +49,67 @@ void GLGizmoFlatten::on_start_dragging(const Selection& selection) | |||
| 
 | ||||
| void GLGizmoFlatten::on_render(const Selection& selection) const | ||||
| { | ||||
|     ::glClear(GL_DEPTH_BUFFER_BIT); | ||||
|     glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); | ||||
| 
 | ||||
|     ::glEnable(GL_DEPTH_TEST); | ||||
|     ::glEnable(GL_BLEND); | ||||
|     glsafe(::glEnable(GL_DEPTH_TEST)); | ||||
|     glsafe(::glEnable(GL_BLEND)); | ||||
| 
 | ||||
|     if (selection.is_single_full_instance()) | ||||
|     { | ||||
|         const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); | ||||
|         ::glPushMatrix(); | ||||
|         ::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()); | ||||
|         ::glMultMatrixd(m.data()); | ||||
|         glsafe(::glPushMatrix()); | ||||
|         glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z())); | ||||
|         glsafe(::glMultMatrixd(m.data())); | ||||
|         if (this->is_plane_update_necessary()) | ||||
| 			const_cast<GLGizmoFlatten*>(this)->update_planes(); | ||||
|         for (int i = 0; i < (int)m_planes.size(); ++i) | ||||
|         { | ||||
|             if (i == m_hover_id) | ||||
|                 ::glColor4f(0.9f, 0.9f, 0.9f, 0.75f); | ||||
|                 glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 0.75f)); | ||||
|             else | ||||
|                 ::glColor4f(0.9f, 0.9f, 0.9f, 0.5f); | ||||
|                 glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 0.5f)); | ||||
| 
 | ||||
|             ::glBegin(GL_POLYGON); | ||||
|             for (const Vec3d& vertex : m_planes[i].vertices) | ||||
|             { | ||||
|                 ::glVertex3dv(vertex.data()); | ||||
|             } | ||||
|             ::glEnd(); | ||||
|             glsafe(::glEnd()); | ||||
|         } | ||||
|         ::glPopMatrix(); | ||||
|         glsafe(::glPopMatrix()); | ||||
|     } | ||||
| 
 | ||||
|     ::glEnable(GL_CULL_FACE); | ||||
|     ::glDisable(GL_BLEND); | ||||
|     glsafe(::glEnable(GL_CULL_FACE)); | ||||
|     glsafe(::glDisable(GL_BLEND)); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoFlatten::on_render_for_picking(const Selection& selection) const | ||||
| { | ||||
|     ::glDisable(GL_DEPTH_TEST); | ||||
|     ::glDisable(GL_BLEND); | ||||
|     glsafe(::glDisable(GL_DEPTH_TEST)); | ||||
|     glsafe(::glDisable(GL_BLEND)); | ||||
| 
 | ||||
|     if (selection.is_single_full_instance()) | ||||
|     { | ||||
|         const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(); | ||||
|         ::glPushMatrix(); | ||||
|         ::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z()); | ||||
|         ::glMultMatrixd(m.data()); | ||||
|         glsafe(::glPushMatrix()); | ||||
|         glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z())); | ||||
|         glsafe(::glMultMatrixd(m.data())); | ||||
|         if (this->is_plane_update_necessary()) | ||||
| 			const_cast<GLGizmoFlatten*>(this)->update_planes(); | ||||
|         for (int i = 0; i < (int)m_planes.size(); ++i) | ||||
|         { | ||||
|             ::glColor3fv(picking_color_component(i).data()); | ||||
|             glsafe(::glColor3fv(picking_color_component(i).data())); | ||||
|             ::glBegin(GL_POLYGON); | ||||
|             for (const Vec3d& vertex : m_planes[i].vertices) | ||||
|             { | ||||
|                 ::glVertex3dv(vertex.data()); | ||||
|             } | ||||
|             ::glEnd(); | ||||
|             glsafe(::glEnd()); | ||||
|         } | ||||
|         ::glPopMatrix(); | ||||
|         glsafe(::glPopMatrix()); | ||||
|     } | ||||
| 
 | ||||
|     ::glEnable(GL_CULL_FACE); | ||||
|     glsafe(::glEnable(GL_CULL_FACE)); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) | ||||
|  |  | |||
|  | @ -97,8 +97,8 @@ void GLGizmoMove3D::on_render(const Selection& selection) const | |||
|     else if (!m_grabbers[2].dragging && (m_hover_id == 2)) | ||||
|         set_tooltip("Z"); | ||||
| 
 | ||||
|     ::glClear(GL_DEPTH_BUFFER_BIT); | ||||
|     ::glEnable(GL_DEPTH_TEST); | ||||
|     glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); | ||||
|     glsafe(::glEnable(GL_DEPTH_TEST)); | ||||
| 
 | ||||
|     const BoundingBoxf3& box = selection.get_bounding_box(); | ||||
|     const Vec3d& center = box.center(); | ||||
|  | @ -115,7 +115,7 @@ void GLGizmoMove3D::on_render(const Selection& selection) const | |||
|     m_grabbers[2].center = Vec3d(center(0), center(1), box.max(2) + Offset); | ||||
|     ::memcpy((void*)m_grabbers[2].color, (const void*)&AXES_COLOR[2], 3 * sizeof(float)); | ||||
| 
 | ||||
|     ::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f); | ||||
|     glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); | ||||
| 
 | ||||
|     if (m_hover_id == -1) | ||||
|     { | ||||
|  | @ -124,11 +124,11 @@ void GLGizmoMove3D::on_render(const Selection& selection) const | |||
|         { | ||||
|             if (m_grabbers[i].enabled) | ||||
|             { | ||||
|                 ::glColor3fv(AXES_COLOR[i]); | ||||
|                 glsafe(::glColor3fv(AXES_COLOR[i])); | ||||
|                 ::glBegin(GL_LINES); | ||||
|                 ::glVertex3dv(center.data()); | ||||
|                 ::glVertex3dv(m_grabbers[i].center.data()); | ||||
|                 ::glEnd(); | ||||
|                 glsafe(::glEnd()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | @ -143,11 +143,11 @@ void GLGizmoMove3D::on_render(const Selection& selection) const | |||
|     else | ||||
|     { | ||||
|         // draw axis
 | ||||
|         ::glColor3fv(AXES_COLOR[m_hover_id]); | ||||
|         glsafe(::glColor3fv(AXES_COLOR[m_hover_id])); | ||||
|         ::glBegin(GL_LINES); | ||||
|         ::glVertex3dv(center.data()); | ||||
|         ::glVertex3dv(m_grabbers[m_hover_id].center.data()); | ||||
|         ::glEnd(); | ||||
|         glsafe(::glEnd()); | ||||
| 
 | ||||
|         // draw grabber
 | ||||
|         m_grabbers[m_hover_id].render(true, box.max_size()); | ||||
|  | @ -157,7 +157,7 @@ void GLGizmoMove3D::on_render(const Selection& selection) const | |||
| 
 | ||||
| void GLGizmoMove3D::on_render_for_picking(const Selection& selection) const | ||||
| { | ||||
|     ::glDisable(GL_DEPTH_TEST); | ||||
|     glsafe(::glDisable(GL_DEPTH_TEST)); | ||||
| 
 | ||||
|     const BoundingBoxf3& box = selection.get_bounding_box(); | ||||
|     render_grabbers_for_picking(box); | ||||
|  | @ -229,25 +229,25 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box | |||
|     } | ||||
| 
 | ||||
|     if (!picking) | ||||
|         ::glEnable(GL_LIGHTING); | ||||
|         glsafe(::glEnable(GL_LIGHTING)); | ||||
| 
 | ||||
|     ::glColor3fv(color); | ||||
|     ::glPushMatrix(); | ||||
|     ::glTranslated(m_grabbers[axis].center(0), m_grabbers[axis].center(1), m_grabbers[axis].center(2)); | ||||
|     glsafe(::glColor3fv(color)); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glTranslated(m_grabbers[axis].center(0), m_grabbers[axis].center(1), m_grabbers[axis].center(2))); | ||||
|     if (axis == X) | ||||
|         ::glRotated(90.0, 0.0, 1.0, 0.0); | ||||
|         glsafe(::glRotated(90.0, 0.0, 1.0, 0.0)); | ||||
|     else if (axis == Y) | ||||
|         ::glRotated(-90.0, 1.0, 0.0, 0.0); | ||||
|         glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); | ||||
| 
 | ||||
|     ::glTranslated(0.0, 0.0, 2.0 * size); | ||||
|     glsafe(::glTranslated(0.0, 0.0, 2.0 * size)); | ||||
|     ::gluQuadricOrientation(m_quadric, GLU_OUTSIDE); | ||||
|     ::gluCylinder(m_quadric, 0.75 * size, 0.0, 3.0 * size, 36, 1); | ||||
|     ::gluQuadricOrientation(m_quadric, GLU_INSIDE); | ||||
|     ::gluDisk(m_quadric, 0.0, 0.75 * size, 36, 1); | ||||
|     ::glPopMatrix(); | ||||
|     glsafe(::glPopMatrix()); | ||||
| 
 | ||||
|     if (!picking) | ||||
|         ::glDisable(GL_LIGHTING); | ||||
|         glsafe(::glDisable(GL_LIGHTING)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -155,13 +155,13 @@ void GLGizmoRotate::on_render(const Selection& selection) const | |||
|         m_snap_fine_out_radius = m_radius * (1.0f + ScaleLongTooth); | ||||
|     } | ||||
| 
 | ||||
|     ::glEnable(GL_DEPTH_TEST); | ||||
|     glsafe(::glEnable(GL_DEPTH_TEST)); | ||||
| 
 | ||||
|     ::glPushMatrix(); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     transform_to_local(selection); | ||||
| 
 | ||||
|     ::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f); | ||||
|     ::glColor3fv((m_hover_id != -1) ? m_drag_color : m_highlight_color); | ||||
|     glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); | ||||
|     glsafe(::glColor3fv((m_hover_id != -1) ? m_drag_color : m_highlight_color)); | ||||
| 
 | ||||
|     render_circle(); | ||||
| 
 | ||||
|  | @ -172,7 +172,7 @@ void GLGizmoRotate::on_render(const Selection& selection) const | |||
|         render_reference_radius(); | ||||
|     } | ||||
| 
 | ||||
|     ::glColor3fv(m_highlight_color); | ||||
|     glsafe(::glColor3fv(m_highlight_color)); | ||||
| 
 | ||||
|     if (m_hover_id != -1) | ||||
|         render_angle(); | ||||
|  | @ -180,14 +180,14 @@ void GLGizmoRotate::on_render(const Selection& selection) const | |||
|     render_grabber(box); | ||||
|     render_grabber_extension(box, false); | ||||
| 
 | ||||
|     ::glPopMatrix(); | ||||
|     glsafe(::glPopMatrix()); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoRotate::on_render_for_picking(const Selection& selection) const | ||||
| { | ||||
|     ::glDisable(GL_DEPTH_TEST); | ||||
|     glsafe(::glDisable(GL_DEPTH_TEST)); | ||||
| 
 | ||||
|     ::glPushMatrix(); | ||||
|     glsafe(::glPushMatrix()); | ||||
| 
 | ||||
|     transform_to_local(selection); | ||||
| 
 | ||||
|  | @ -195,7 +195,7 @@ void GLGizmoRotate::on_render_for_picking(const Selection& selection) const | |||
|     render_grabbers_for_picking(box); | ||||
|     render_grabber_extension(box, true); | ||||
| 
 | ||||
|     ::glPopMatrix(); | ||||
|     glsafe(::glPopMatrix()); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoRotate::render_circle() const | ||||
|  | @ -209,7 +209,7 @@ void GLGizmoRotate::render_circle() const | |||
|         float z = 0.0f; | ||||
|         ::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); | ||||
|     } | ||||
|     ::glEnd(); | ||||
|     glsafe(::glEnd()); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoRotate::render_scale() const | ||||
|  | @ -232,7 +232,7 @@ void GLGizmoRotate::render_scale() const | |||
|         ::glVertex3f((GLfloat)in_x, (GLfloat)in_y, (GLfloat)in_z); | ||||
|         ::glVertex3f((GLfloat)out_x, (GLfloat)out_y, (GLfloat)out_z); | ||||
|     } | ||||
|     ::glEnd(); | ||||
|     glsafe(::glEnd()); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoRotate::render_snap_radii() const | ||||
|  | @ -257,7 +257,7 @@ void GLGizmoRotate::render_snap_radii() const | |||
|         ::glVertex3f((GLfloat)in_x, (GLfloat)in_y, (GLfloat)in_z); | ||||
|         ::glVertex3f((GLfloat)out_x, (GLfloat)out_y, (GLfloat)out_z); | ||||
|     } | ||||
|     ::glEnd(); | ||||
|     glsafe(::glEnd()); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoRotate::render_reference_radius() const | ||||
|  | @ -265,7 +265,7 @@ void GLGizmoRotate::render_reference_radius() const | |||
|     ::glBegin(GL_LINES); | ||||
|     ::glVertex3f(0.0f, 0.0f, 0.0f); | ||||
|     ::glVertex3f((GLfloat)(m_radius * (1.0f + GrabberOffset)), 0.0f, 0.0f); | ||||
|     ::glEnd(); | ||||
|     glsafe(::glEnd()); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoRotate::render_angle() const | ||||
|  | @ -282,7 +282,7 @@ void GLGizmoRotate::render_angle() const | |||
|         float z = 0.0f; | ||||
|         ::glVertex3f((GLfloat)x, (GLfloat)y, (GLfloat)z); | ||||
|     } | ||||
|     ::glEnd(); | ||||
|     glsafe(::glEnd()); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const | ||||
|  | @ -291,12 +291,12 @@ void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const | |||
|     m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0); | ||||
|     m_grabbers[0].angles(2) = m_angle; | ||||
| 
 | ||||
|     ::glColor3fv((m_hover_id != -1) ? m_drag_color : m_highlight_color); | ||||
|     glsafe(::glColor3fv((m_hover_id != -1) ? m_drag_color : m_highlight_color)); | ||||
| 
 | ||||
|     ::glBegin(GL_LINES); | ||||
|     ::glVertex3f(0.0f, 0.0f, 0.0f); | ||||
|     ::glVertex3dv(m_grabbers[0].center.data()); | ||||
|     ::glEnd(); | ||||
|     glsafe(::glEnd()); | ||||
| 
 | ||||
|     ::memcpy((void*)m_grabbers[0].color, (const void*)m_highlight_color, 3 * sizeof(float)); | ||||
|     render_grabbers(box); | ||||
|  | @ -320,56 +320,56 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick | |||
|     } | ||||
| 
 | ||||
|     if (!picking) | ||||
|         ::glEnable(GL_LIGHTING); | ||||
|         glsafe(::glEnable(GL_LIGHTING)); | ||||
| 
 | ||||
|     ::glColor3fv(color); | ||||
|     ::glPushMatrix(); | ||||
|     ::glTranslated(m_grabbers[0].center(0), m_grabbers[0].center(1), m_grabbers[0].center(2)); | ||||
|     ::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0); | ||||
|     ::glRotated(90.0, 1.0, 0.0, 0.0); | ||||
|     ::glTranslated(0.0, 0.0, 2.0 * size); | ||||
|     glsafe(::glColor3fv(color)); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glTranslated(m_grabbers[0].center(0), m_grabbers[0].center(1), m_grabbers[0].center(2))); | ||||
|     glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0)); | ||||
|     glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); | ||||
|     glsafe(::glTranslated(0.0, 0.0, 2.0 * size)); | ||||
|     ::gluQuadricOrientation(m_quadric, GLU_OUTSIDE); | ||||
|     ::gluCylinder(m_quadric, 0.75 * size, 0.0, 3.0 * size, 36, 1); | ||||
|     ::gluQuadricOrientation(m_quadric, GLU_INSIDE); | ||||
|     ::gluDisk(m_quadric, 0.0, 0.75 * size, 36, 1); | ||||
|     ::glPopMatrix(); | ||||
|     ::glPushMatrix(); | ||||
|     ::glTranslated(m_grabbers[0].center(0), m_grabbers[0].center(1), m_grabbers[0].center(2)); | ||||
|     ::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0); | ||||
|     ::glRotated(-90.0, 1.0, 0.0, 0.0); | ||||
|     ::glTranslated(0.0, 0.0, 2.0 * size); | ||||
|     glsafe(::glPopMatrix()); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glTranslated(m_grabbers[0].center(0), m_grabbers[0].center(1), m_grabbers[0].center(2))); | ||||
|     glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0)); | ||||
|     glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); | ||||
|     glsafe(::glTranslated(0.0, 0.0, 2.0 * size)); | ||||
|     ::gluQuadricOrientation(m_quadric, GLU_OUTSIDE); | ||||
|     ::gluCylinder(m_quadric, 0.75 * size, 0.0, 3.0 * size, 36, 1); | ||||
|     ::gluQuadricOrientation(m_quadric, GLU_INSIDE); | ||||
|     ::gluDisk(m_quadric, 0.0, 0.75 * size, 36, 1); | ||||
|     ::glPopMatrix(); | ||||
|     glsafe(::glPopMatrix()); | ||||
| 
 | ||||
|     if (!picking) | ||||
|         ::glDisable(GL_LIGHTING); | ||||
|         glsafe(::glDisable(GL_LIGHTING)); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoRotate::transform_to_local(const Selection& selection) const | ||||
| { | ||||
|     ::glTranslated(m_center(0), m_center(1), m_center(2)); | ||||
|     glsafe(::glTranslated(m_center(0), m_center(1), m_center(2))); | ||||
| 
 | ||||
|     if (selection.is_single_volume() || selection.is_single_modifier() || selection.requires_local_axes()) | ||||
|     { | ||||
|         Transform3d orient_matrix = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix(true, false, true, true); | ||||
|         ::glMultMatrixd(orient_matrix.data()); | ||||
|         glsafe(::glMultMatrixd(orient_matrix.data())); | ||||
|     } | ||||
| 
 | ||||
|     switch (m_axis) | ||||
|     { | ||||
|     case X: | ||||
|     { | ||||
|         ::glRotatef(90.0f, 0.0f, 1.0f, 0.0f); | ||||
|         ::glRotatef(-90.0f, 0.0f, 0.0f, 1.0f); | ||||
|         glsafe(::glRotatef(90.0f, 0.0f, 1.0f, 0.0f)); | ||||
|         glsafe(::glRotatef(-90.0f, 0.0f, 0.0f, 1.0f)); | ||||
|         break; | ||||
|     } | ||||
|     case Y: | ||||
|     { | ||||
|         ::glRotatef(-90.0f, 0.0f, 0.0f, 1.0f); | ||||
|         ::glRotatef(-90.0f, 0.0f, 1.0f, 0.0f); | ||||
|         glsafe(::glRotatef(-90.0f, 0.0f, 0.0f, 1.0f)); | ||||
|         glsafe(::glRotatef(-90.0f, 0.0f, 1.0f, 0.0f)); | ||||
|         break; | ||||
|     } | ||||
|     default: | ||||
|  | @ -472,7 +472,7 @@ void GLGizmoRotate3D::on_stop_dragging() | |||
| 
 | ||||
| void GLGizmoRotate3D::on_render(const Selection& selection) const | ||||
| { | ||||
|     ::glClear(GL_DEPTH_BUFFER_BIT); | ||||
|     glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); | ||||
| 
 | ||||
|     if ((m_hover_id == -1) || (m_hover_id == 0)) | ||||
|         m_gizmos[X].render(selection); | ||||
|  |  | |||
|  | @ -108,8 +108,8 @@ void GLGizmoScale3D::on_render(const Selection& selection) const | |||
|         ((m_hover_id == 6) || (m_hover_id == 7) || (m_hover_id == 8) || (m_hover_id == 9))) | ||||
|         set_tooltip("X/Y/Z"); | ||||
| 
 | ||||
|     ::glClear(GL_DEPTH_BUFFER_BIT); | ||||
|     ::glEnable(GL_DEPTH_TEST); | ||||
|     glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); | ||||
|     glsafe(::glEnable(GL_DEPTH_TEST)); | ||||
| 
 | ||||
|     BoundingBoxf3 box; | ||||
|     Transform3d transform = Transform3d::Identity(); | ||||
|  | @ -187,7 +187,7 @@ void GLGizmoScale3D::on_render(const Selection& selection) const | |||
|         m_grabbers[i].angles = angles; | ||||
|     } | ||||
| 
 | ||||
|     ::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f); | ||||
|     glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); | ||||
| 
 | ||||
|     const BoundingBoxf3& selection_box = selection.get_bounding_box(); | ||||
| 
 | ||||
|  | @ -198,20 +198,20 @@ void GLGizmoScale3D::on_render(const Selection& selection) const | |||
|         // draw connections
 | ||||
|         if (m_grabbers[0].enabled && m_grabbers[1].enabled) | ||||
|         { | ||||
|             ::glColor3fv(m_grabbers[0].color); | ||||
|             glsafe(::glColor3fv(m_grabbers[0].color)); | ||||
|             render_grabbers_connection(0, 1); | ||||
|         } | ||||
|         if (m_grabbers[2].enabled && m_grabbers[3].enabled) | ||||
|         { | ||||
|             ::glColor3fv(m_grabbers[2].color); | ||||
|             glsafe(::glColor3fv(m_grabbers[2].color)); | ||||
|             render_grabbers_connection(2, 3); | ||||
|         } | ||||
|         if (m_grabbers[4].enabled && m_grabbers[5].enabled) | ||||
|         { | ||||
|             ::glColor3fv(m_grabbers[4].color); | ||||
|             glsafe(::glColor3fv(m_grabbers[4].color)); | ||||
|             render_grabbers_connection(4, 5); | ||||
|         } | ||||
|         ::glColor3fv(m_base_color); | ||||
|         glsafe(::glColor3fv(m_base_color)); | ||||
|         render_grabbers_connection(6, 7); | ||||
|         render_grabbers_connection(7, 8); | ||||
|         render_grabbers_connection(8, 9); | ||||
|  | @ -222,7 +222,7 @@ void GLGizmoScale3D::on_render(const Selection& selection) const | |||
|     else if ((m_hover_id == 0) || (m_hover_id == 1)) | ||||
|     { | ||||
|         // draw connection
 | ||||
|         ::glColor3fv(m_grabbers[0].color); | ||||
|         glsafe(::glColor3fv(m_grabbers[0].color)); | ||||
|         render_grabbers_connection(0, 1); | ||||
|         // draw grabbers
 | ||||
|         m_grabbers[0].render(true, grabber_mean_size); | ||||
|  | @ -231,7 +231,7 @@ void GLGizmoScale3D::on_render(const Selection& selection) const | |||
|     else if ((m_hover_id == 2) || (m_hover_id == 3)) | ||||
|     { | ||||
|         // draw connection
 | ||||
|         ::glColor3fv(m_grabbers[2].color); | ||||
|         glsafe(::glColor3fv(m_grabbers[2].color)); | ||||
|         render_grabbers_connection(2, 3); | ||||
|         // draw grabbers
 | ||||
|         m_grabbers[2].render(true, grabber_mean_size); | ||||
|  | @ -240,7 +240,7 @@ void GLGizmoScale3D::on_render(const Selection& selection) const | |||
|     else if ((m_hover_id == 4) || (m_hover_id == 5)) | ||||
|     { | ||||
|         // draw connection
 | ||||
|         ::glColor3fv(m_grabbers[4].color); | ||||
|         glsafe(::glColor3fv(m_grabbers[4].color)); | ||||
|         render_grabbers_connection(4, 5); | ||||
|         // draw grabbers
 | ||||
|         m_grabbers[4].render(true, grabber_mean_size); | ||||
|  | @ -249,7 +249,7 @@ void GLGizmoScale3D::on_render(const Selection& selection) const | |||
|     else if (m_hover_id >= 6) | ||||
|     { | ||||
|         // draw connection
 | ||||
|         ::glColor3fv(m_drag_color); | ||||
|         glsafe(::glColor3fv(m_drag_color)); | ||||
|         render_grabbers_connection(6, 7); | ||||
|         render_grabbers_connection(7, 8); | ||||
|         render_grabbers_connection(8, 9); | ||||
|  | @ -264,7 +264,7 @@ void GLGizmoScale3D::on_render(const Selection& selection) const | |||
| 
 | ||||
| void GLGizmoScale3D::on_render_for_picking(const Selection& selection) const | ||||
| { | ||||
|     ::glDisable(GL_DEPTH_TEST); | ||||
|     glsafe(::glDisable(GL_DEPTH_TEST)); | ||||
| 
 | ||||
|     render_grabbers_for_picking(selection.get_bounding_box()); | ||||
| } | ||||
|  | @ -291,7 +291,7 @@ void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int | |||
|         ::glBegin(GL_LINES); | ||||
|         ::glVertex3dv(m_grabbers[id_1].center.data()); | ||||
|         ::glVertex3dv(m_grabbers[id_2].center.data()); | ||||
|         ::glEnd(); | ||||
|         glsafe(::glEnd()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| // Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
 | ||||
| #include "GLGizmoSlaSupports.hpp" | ||||
| #include "slic3r/GUI/GLCanvas3D.hpp" | ||||
| 
 | ||||
| #include <GL/glew.h> | ||||
| 
 | ||||
|  | @ -84,13 +85,13 @@ void GLGizmoSlaSupports::on_render(const Selection& selection) const | |||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     ::glEnable(GL_BLEND); | ||||
|     ::glEnable(GL_DEPTH_TEST); | ||||
|     glsafe(::glEnable(GL_BLEND)); | ||||
|     glsafe(::glEnable(GL_DEPTH_TEST)); | ||||
| 
 | ||||
|     render_points(selection, false); | ||||
|     render_selection_rectangle(); | ||||
| 
 | ||||
|     ::glDisable(GL_BLEND); | ||||
|     glsafe(::glDisable(GL_BLEND)); | ||||
| } | ||||
| 
 | ||||
| void GLGizmoSlaSupports::render_selection_rectangle() const | ||||
|  | @ -98,44 +99,44 @@ void GLGizmoSlaSupports::render_selection_rectangle() const | |||
|     if (!m_selection_rectangle_active) | ||||
|         return; | ||||
| 
 | ||||
|     ::glLineWidth(1.5f); | ||||
|     glsafe(::glLineWidth(1.5f)); | ||||
|     float render_color[3] = {1.f, 0.f, 0.f}; | ||||
|     ::glColor3fv(render_color); | ||||
|     glsafe(::glColor3fv(render_color)); | ||||
| 
 | ||||
|     ::glPushAttrib(GL_TRANSFORM_BIT);   // remember current MatrixMode
 | ||||
|     glsafe(::glPushAttrib(GL_TRANSFORM_BIT));   // remember current MatrixMode
 | ||||
| 
 | ||||
|     ::glMatrixMode(GL_MODELVIEW);       // cache modelview matrix and set to identity
 | ||||
|     ::glPushMatrix(); | ||||
|     ::glLoadIdentity(); | ||||
|     glsafe(::glMatrixMode(GL_MODELVIEW));       // cache modelview matrix and set to identity
 | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glLoadIdentity()); | ||||
| 
 | ||||
|     ::glMatrixMode(GL_PROJECTION);      // cache projection matrix and set to identity
 | ||||
|     ::glPushMatrix(); | ||||
|     ::glLoadIdentity(); | ||||
|     glsafe(::glMatrixMode(GL_PROJECTION));      // cache projection matrix and set to identity
 | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glLoadIdentity()); | ||||
| 
 | ||||
|     ::glOrtho(0.f, m_canvas_width, m_canvas_height, 0.f, -1.f, 1.f); // set projection matrix so that world coords = window coords
 | ||||
|     glsafe(::glOrtho(0.f, m_canvas_width, m_canvas_height, 0.f, -1.f, 1.f)); // set projection matrix so that world coords = window coords
 | ||||
| 
 | ||||
|     // render the selection  rectangle (window coordinates):
 | ||||
|     ::glPushAttrib(GL_ENABLE_BIT); | ||||
|     ::glLineStipple(4, 0xAAAA); | ||||
|     ::glEnable(GL_LINE_STIPPLE); | ||||
|     glsafe(::glPushAttrib(GL_ENABLE_BIT)); | ||||
|     glsafe(::glLineStipple(4, 0xAAAA)); | ||||
|     glsafe(::glEnable(GL_LINE_STIPPLE)); | ||||
| 
 | ||||
|     ::glBegin(GL_LINE_LOOP); | ||||
|     ::glVertex3f((GLfloat)m_selection_rectangle_start_corner(0), (GLfloat)m_selection_rectangle_start_corner(1), (GLfloat)0.5f); | ||||
|     ::glVertex3f((GLfloat)m_selection_rectangle_end_corner(0), (GLfloat)m_selection_rectangle_start_corner(1), (GLfloat)0.5f); | ||||
|     ::glVertex3f((GLfloat)m_selection_rectangle_end_corner(0), (GLfloat)m_selection_rectangle_end_corner(1), (GLfloat)0.5f); | ||||
|     ::glVertex3f((GLfloat)m_selection_rectangle_start_corner(0), (GLfloat)m_selection_rectangle_end_corner(1), (GLfloat)0.5f); | ||||
|     ::glEnd(); | ||||
|     ::glPopAttrib(); | ||||
|     glsafe(::glEnd()); | ||||
|     glsafe(::glPopAttrib()); | ||||
| 
 | ||||
|     ::glPopMatrix();                // restore former projection matrix
 | ||||
|     ::glMatrixMode(GL_MODELVIEW); | ||||
|     ::glPopMatrix();                // restore former modelview matrix
 | ||||
|     ::glPopAttrib();                // restore former MatrixMode
 | ||||
|     glsafe(::glPopMatrix());                // restore former projection matrix
 | ||||
|     glsafe(::glMatrixMode(GL_MODELVIEW)); | ||||
|     glsafe(::glPopMatrix());                // restore former modelview matrix
 | ||||
|     glsafe(::glPopAttrib());                // restore former MatrixMode
 | ||||
| } | ||||
| 
 | ||||
| void GLGizmoSlaSupports::on_render_for_picking(const Selection& selection) const | ||||
| { | ||||
|     ::glEnable(GL_DEPTH_TEST); | ||||
|     glsafe(::glEnable(GL_DEPTH_TEST)); | ||||
| 
 | ||||
|     render_points(selection, true); | ||||
| } | ||||
|  | @ -146,16 +147,16 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) | |||
|         return; | ||||
| 
 | ||||
|     if (!picking) | ||||
|         ::glEnable(GL_LIGHTING); | ||||
|         glsafe(::glEnable(GL_LIGHTING)); | ||||
| 
 | ||||
|     const GLVolume* vol = selection.get_volume(*selection.get_volume_idxs().begin()); | ||||
|     double z_shift = vol->get_sla_shift_z(); | ||||
|     const Transform3d& instance_scaling_matrix_inverse = vol->get_instance_transformation().get_matrix(true, true, false, true).inverse(); | ||||
|     const Transform3d& instance_matrix = vol->get_instance_transformation().get_matrix(); | ||||
| 
 | ||||
|     ::glPushMatrix(); | ||||
|     ::glTranslated(0.0, 0.0, z_shift); | ||||
|     ::glMultMatrixd(instance_matrix.data()); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glTranslated(0.0, 0.0, z_shift)); | ||||
|     glsafe(::glMultMatrixd(instance_matrix.data())); | ||||
| 
 | ||||
|     float render_color[3]; | ||||
|     for (int i = 0; i < (int)m_editing_mode_cache.size(); ++i) | ||||
|  | @ -187,14 +188,14 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) | |||
|                     for (unsigned char i=0; i<3; ++i) render_color[i] = 0.5f; | ||||
|             } | ||||
|         } | ||||
|         ::glColor3fv(render_color); | ||||
|         glsafe(::glColor3fv(render_color)); | ||||
|         float render_color_emissive[4] = { 0.5f * render_color[0], 0.5f * render_color[1], 0.5f * render_color[2], 1.f}; | ||||
|         ::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive); | ||||
|         glsafe(::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive)); | ||||
| 
 | ||||
|         // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
 | ||||
|         ::glPushMatrix(); | ||||
|         ::glTranslated(support_point.pos(0), support_point.pos(1), support_point.pos(2)); | ||||
|         ::glMultMatrixd(instance_scaling_matrix_inverse.data()); | ||||
|         glsafe(::glPushMatrix()); | ||||
|         glsafe(::glTranslated(support_point.pos(0), support_point.pos(1), support_point.pos(2))); | ||||
|         glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data())); | ||||
| 
 | ||||
|         // Matrices set, we can render the point mark now.
 | ||||
|         // If in editing mode, we'll also render a cone pointing to the sphere.
 | ||||
|  | @ -205,31 +206,31 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) | |||
|             Eigen::Quaterniond q; | ||||
|             q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * m_editing_mode_cache[i].normal.cast<double>()); | ||||
|             Eigen::AngleAxisd aa(q); | ||||
|             ::glRotated(aa.angle() * (180./M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2)); | ||||
|             glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2))); | ||||
| 
 | ||||
|             const float cone_radius = 0.25f; // mm
 | ||||
|             const float cone_height = 0.75f; | ||||
|             ::glPushMatrix(); | ||||
|             ::glTranslatef(0.f, 0.f, m_editing_mode_cache[i].support_point.head_front_radius * RenderPointScale); | ||||
|             glsafe(::glPushMatrix()); | ||||
|             glsafe(::glTranslatef(0.f, 0.f, m_editing_mode_cache[i].support_point.head_front_radius * RenderPointScale)); | ||||
|             ::gluCylinder(m_quadric, 0.f, cone_radius, cone_height, 24, 1); | ||||
|             ::glTranslatef(0.f, 0.f, cone_height); | ||||
|             glsafe(::glTranslatef(0.f, 0.f, cone_height)); | ||||
|             ::gluDisk(m_quadric, 0.0, cone_radius, 24, 1); | ||||
|             ::glPopMatrix(); | ||||
|             glsafe(::glPopMatrix()); | ||||
|         } | ||||
|         ::gluSphere(m_quadric, m_editing_mode_cache[i].support_point.head_front_radius * RenderPointScale, 24, 12); | ||||
|         ::glPopMatrix(); | ||||
|         glsafe(::glPopMatrix()); | ||||
|     } | ||||
| 
 | ||||
|     { | ||||
|         // Reset emissive component to zero (the default value)
 | ||||
|         float render_color_emissive[4] = { 0.f, 0.f, 0.f, 1.f }; | ||||
|         ::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive); | ||||
|         glsafe(::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive)); | ||||
|     } | ||||
| 
 | ||||
|     if (!picking) | ||||
|         ::glDisable(GL_LIGHTING); | ||||
|         glsafe(::glDisable(GL_LIGHTING)); | ||||
| 
 | ||||
|     ::glPopMatrix(); | ||||
|     glsafe(::glPopMatrix()); | ||||
| } | ||||
| 
 | ||||
| bool GLGizmoSlaSupports::is_mesh_update_necessary() const | ||||
|  | @ -272,17 +273,15 @@ std::pair<Vec3f, Vec3f> GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse | |||
|     if (m_V.size() == 0) | ||||
|         update_mesh(); | ||||
| 
 | ||||
|     Eigen::Matrix<GLint, 4, 1, Eigen::DontAlign> viewport; | ||||
|     ::glGetIntegerv(GL_VIEWPORT, viewport.data()); | ||||
|     Eigen::Matrix<GLdouble, 4, 4, Eigen::DontAlign> modelview_matrix; | ||||
|     ::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix.data()); | ||||
|     Eigen::Matrix<GLdouble, 4, 4, Eigen::DontAlign> projection_matrix; | ||||
|     ::glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix.data()); | ||||
|     const Camera& camera = m_parent.get_camera(); | ||||
|     const std::array<int, 4>& viewport = camera.get_viewport(); | ||||
|     const Transform3d& modelview_matrix = camera.get_view_matrix(); | ||||
|     const Transform3d& projection_matrix = camera.get_projection_matrix(); | ||||
| 
 | ||||
|     Vec3d point1; | ||||
|     Vec3d point2; | ||||
|     ::gluUnProject(mouse_pos(0), viewport(3)-mouse_pos(1), 0.f, modelview_matrix.data(), projection_matrix.data(), viewport.data(), &point1(0), &point1(1), &point1(2)); | ||||
|     ::gluUnProject(mouse_pos(0), viewport(3)-mouse_pos(1), 1.f, modelview_matrix.data(), projection_matrix.data(), viewport.data(), &point2(0), &point2(1), &point2(2)); | ||||
|     ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 0.f, modelview_matrix.data(), projection_matrix.data(), viewport.data(), &point1(0), &point1(1), &point1(2)); | ||||
|     ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 1.f, modelview_matrix.data(), projection_matrix.data(), viewport.data(), &point2(0), &point2(1), &point2(2)); | ||||
| 
 | ||||
|     igl::Hit hit; | ||||
| 
 | ||||
|  | @ -368,12 +367,10 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous | |||
|         // left up with selection rectangle - select points inside the rectangle:
 | ||||
|         if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp) && m_selection_rectangle_active) { | ||||
|             const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix(); | ||||
|             GLint viewport[4]; | ||||
|             ::glGetIntegerv(GL_VIEWPORT, viewport); | ||||
|             GLdouble modelview_matrix[16]; | ||||
|             ::glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix); | ||||
|             GLdouble projection_matrix[16]; | ||||
|             ::glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix); | ||||
|             const Camera& camera = m_parent.get_camera(); | ||||
|             const std::array<int, 4>& viewport = camera.get_viewport(); | ||||
|             const Transform3d& modelview_matrix = camera.get_view_matrix(); | ||||
|             const Transform3d& projection_matrix = camera.get_projection_matrix(); | ||||
| 
 | ||||
|             const Selection& selection = m_parent.get_selection(); | ||||
|             const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); | ||||
|  | @ -384,7 +381,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous | |||
| 
 | ||||
|             const Transform3d& instance_matrix_no_translation = volume->get_instance_transformation().get_matrix(true); | ||||
|             // we'll recover current look direction from the modelview matrix (in world coords)...
 | ||||
|             Vec3f direction_to_camera(modelview_matrix[2], modelview_matrix[6], modelview_matrix[10]); | ||||
|             Vec3f direction_to_camera = camera.get_dir_forward().cast<float>(); | ||||
|             // ...and transform it to model coords.
 | ||||
|             direction_to_camera = (instance_matrix_no_translation.inverse().cast<float>() * direction_to_camera).normalized().eval(); | ||||
| 
 | ||||
|  | @ -394,8 +391,8 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous | |||
|                 Vec3f pos = instance_matrix.cast<float>() * support_point.pos; | ||||
|                 pos(2) += z_offset; | ||||
|                   GLdouble out_x, out_y, out_z; | ||||
|                  ::gluProject((GLdouble)pos(0), (GLdouble)pos(1), (GLdouble)pos(2), modelview_matrix, projection_matrix, viewport, &out_x, &out_y, &out_z); | ||||
|                  out_y = m_canvas_height - out_y; | ||||
|                   ::gluProject((GLdouble)pos(0), (GLdouble)pos(1), (GLdouble)pos(2), (GLdouble*)modelview_matrix.data(), (GLdouble*)projection_matrix.data(), (GLint*)viewport.data(), &out_x, &out_y, &out_z); | ||||
|                   out_y = m_canvas_height - out_y; | ||||
| 
 | ||||
|                 if (rectangle.contains(Point(out_x, out_y))) { | ||||
|                     bool is_obscured = false; | ||||
|  | @ -729,40 +726,45 @@ std::string GLGizmoSlaSupports::on_get_name() const | |||
| 
 | ||||
| void GLGizmoSlaSupports::on_set_state() | ||||
| { | ||||
|     if (m_state == On && m_old_state != On) { // the gizmo was just turned on
 | ||||
|     // Following is called through CallAfter, because otherwise there was a problem
 | ||||
|     // on OSX with the wxMessageDialog being shown several times when clicked into.
 | ||||
| 
 | ||||
|         if (is_mesh_update_necessary()) | ||||
|             update_mesh(); | ||||
|     wxGetApp().CallAfter([this]() { | ||||
|         if (m_state == On && m_old_state != On) { // the gizmo was just turned on
 | ||||
| 
 | ||||
|         // we'll now reload support points:
 | ||||
|         if (m_model_object) | ||||
|             editing_mode_reload_cache(); | ||||
|             if (is_mesh_update_necessary()) | ||||
|                 update_mesh(); | ||||
| 
 | ||||
|         m_parent.toggle_model_objects_visibility(false); | ||||
|         if (m_model_object) | ||||
|             m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance); | ||||
|             // we'll now reload support points:
 | ||||
|             if (m_model_object) | ||||
|                 editing_mode_reload_cache(); | ||||
| 
 | ||||
|         // Set default head diameter from config.
 | ||||
|         const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; | ||||
|         m_new_point_head_diameter = static_cast<const ConfigOptionFloat*>(cfg.option("support_head_front_diameter"))->value; | ||||
|     } | ||||
|     if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off
 | ||||
|         if (m_model_object) { | ||||
|             if (m_unsaved_changes) { | ||||
|                 wxMessageDialog dlg(GUI::wxGetApp().plater(), _(L("Do you want to save your manually edited support points ?\n")), | ||||
|                                     _(L("Save changes?")), wxICON_QUESTION | wxYES | wxNO); | ||||
|                 if (dlg.ShowModal() == wxID_YES) | ||||
|                     editing_mode_apply_changes(); | ||||
|                 else | ||||
|                     editing_mode_discard_changes(); | ||||
|             } | ||||
|             m_parent.toggle_model_objects_visibility(false); | ||||
|             if (m_model_object) | ||||
|                 m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance); | ||||
| 
 | ||||
|             // Set default head diameter from config.
 | ||||
|             const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config; | ||||
|             m_new_point_head_diameter = static_cast<const ConfigOptionFloat*>(cfg.option("support_head_front_diameter"))->value; | ||||
|         } | ||||
|         if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off
 | ||||
|             if (m_model_object) { | ||||
|                 if (m_unsaved_changes) { | ||||
|                     wxMessageDialog dlg(GUI::wxGetApp().mainframe, _(L("Do you want to save your manually edited support points ?\n")), | ||||
|                                         _(L("Save changes?")), wxICON_QUESTION | wxYES | wxNO); | ||||
|                     if (dlg.ShowModal() == wxID_YES) | ||||
|                         editing_mode_apply_changes(); | ||||
|                     else | ||||
|                         editing_mode_discard_changes(); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         m_parent.toggle_model_objects_visibility(true); | ||||
|         m_editing_mode = false; // so it is not active next time the gizmo opens
 | ||||
|         m_editing_mode_cache.clear(); | ||||
|     } | ||||
|     m_old_state = m_state; | ||||
|             m_parent.toggle_model_objects_visibility(true); | ||||
|             m_editing_mode = false; // so it is not active next time the gizmo opens
 | ||||
|             m_editing_mode_cache.clear(); | ||||
|         } | ||||
|         m_old_state = m_state; | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| #define slic3r_GLGizmoSlaSupports_hpp_ | ||||
| 
 | ||||
| #include "GLGizmoBase.hpp" | ||||
| #include "GLGizmos.hpp" | ||||
| 
 | ||||
| // There is an L function in igl that would be overridden by our localization macro - let's undefine it...
 | ||||
| #undef L | ||||
|  |  | |||
|  | @ -1,6 +1,21 @@ | |||
| #ifndef slic3r_GLGizmos_hpp_ | ||||
| #define slic3r_GLGizmos_hpp_ | ||||
| 
 | ||||
| // this describes events being passed from GLCanvas3D to SlaSupport gizmo
 | ||||
| enum class SLAGizmoEventType { | ||||
|     LeftDown = 1, | ||||
|     LeftUp, | ||||
|     RightDown, | ||||
|     Dragging, | ||||
|     Delete, | ||||
|     SelectAll, | ||||
|     ShiftUp, | ||||
|     ApplyChanges, | ||||
|     DiscardChanges, | ||||
|     AutomaticGeneration, | ||||
|     ManualEditing | ||||
| }; | ||||
| 
 | ||||
| #include "slic3r/GUI/Gizmos/GLGizmoMove.hpp" | ||||
| #include "slic3r/GUI/Gizmos/GLGizmoScale.hpp" | ||||
| #include "slic3r/GUI/Gizmos/GLGizmoRotate.hpp" | ||||
|  |  | |||
							
								
								
									
										1215
									
								
								src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1215
									
								
								src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										184
									
								
								src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,184 @@ | |||
| #ifndef slic3r_GUI_GLGizmosManager_hpp_ | ||||
| #define slic3r_GUI_GLGizmosManager_hpp_ | ||||
| 
 | ||||
| #include "slic3r/GUI/GLTexture.hpp" | ||||
| #include "slic3r/GUI/GLToolbar.hpp" | ||||
| #include "slic3r/GUI/Gizmos/GLGizmos.hpp" | ||||
| 
 | ||||
| #include <map> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
| 
 | ||||
| class Selection; | ||||
| class GLGizmoBase; | ||||
| class GLCanvas3D; | ||||
| 
 | ||||
| class Rect | ||||
| { | ||||
|     float m_left; | ||||
|     float m_top; | ||||
|     float m_right; | ||||
|     float m_bottom; | ||||
| 
 | ||||
| public: | ||||
|     Rect() : m_left(0.0f) , m_top(0.0f) , m_right(0.0f) , m_bottom(0.0f) {} | ||||
| 
 | ||||
|     Rect(float left, float top, float right, float bottom) : m_left(left) , m_top(top) , m_right(right) , m_bottom(bottom) {} | ||||
| 
 | ||||
|     float get_left() const { return m_left; } | ||||
|     void set_left(float left) { m_left = left; } | ||||
| 
 | ||||
|     float get_top() const { return m_top; } | ||||
|     void set_top(float top) { m_top = top; } | ||||
| 
 | ||||
|     float get_right() const { return m_right; } | ||||
|     void set_right(float right) { m_right = right; } | ||||
| 
 | ||||
|     float get_bottom() const { return m_bottom; } | ||||
|     void set_bottom(float bottom) { m_bottom = bottom; } | ||||
| 
 | ||||
|     float get_width() const { return m_right - m_left; } | ||||
|     float get_height() const { return m_top - m_bottom; } | ||||
| }; | ||||
| 
 | ||||
| class GLGizmosManager | ||||
| { | ||||
| public: | ||||
| #if ENABLE_SVG_ICONS | ||||
|     static const float Default_Icons_Size; | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
| 
 | ||||
|     enum EType : unsigned char | ||||
|     { | ||||
|         Undefined, | ||||
|         Move, | ||||
|         Scale, | ||||
|         Rotate, | ||||
|         Flatten, | ||||
|         Cut, | ||||
|         SlaSupports, | ||||
|         Num_Types | ||||
|     }; | ||||
| 
 | ||||
| private: | ||||
|     bool m_enabled; | ||||
|     typedef std::map<EType, GLGizmoBase*> GizmosMap; | ||||
|     GizmosMap m_gizmos; | ||||
| #if ENABLE_SVG_ICONS | ||||
|     mutable GLTexture m_icons_texture; | ||||
|     mutable bool m_icons_texture_dirty; | ||||
| #else | ||||
|     ItemsIconsTexture m_icons_texture; | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
|     BackgroundTexture m_background_texture; | ||||
|     EType m_current; | ||||
| 
 | ||||
| #if ENABLE_SVG_ICONS | ||||
|     float m_overlay_icons_size; | ||||
|     float m_overlay_scale; | ||||
| #else | ||||
|     float m_overlay_icons_scale; | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
|     float m_overlay_border; | ||||
|     float m_overlay_gap_y; | ||||
| 
 | ||||
|     struct MouseCapture | ||||
|     { | ||||
|         bool left; | ||||
|         bool middle; | ||||
|         bool right; | ||||
|         GLCanvas3D* parent; | ||||
| 
 | ||||
|         MouseCapture() { reset(); } | ||||
| 
 | ||||
|         bool any() const { return left || middle || right; } | ||||
|         void reset() { left = middle = right = false; parent = nullptr; } | ||||
|     }; | ||||
| 
 | ||||
|     MouseCapture m_mouse_capture; | ||||
|     std::string m_tooltip; | ||||
| 
 | ||||
| public: | ||||
|     GLGizmosManager(); | ||||
|     ~GLGizmosManager(); | ||||
| 
 | ||||
|     bool init(GLCanvas3D& parent); | ||||
| 
 | ||||
|     bool is_enabled() const { return m_enabled; } | ||||
|     void set_enabled(bool enable) { m_enabled = enable; } | ||||
| 
 | ||||
| #if ENABLE_SVG_ICONS | ||||
|     void set_overlay_icon_size(float size); | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
|     void set_overlay_scale(float scale); | ||||
| 
 | ||||
|     void refresh_on_off_state(const Selection& selection); | ||||
|     void reset_all_states(); | ||||
| 
 | ||||
|     void set_hover_id(int id); | ||||
|     void enable_grabber(EType type, unsigned int id, bool enable); | ||||
| 
 | ||||
|     void update(const Linef3& mouse_ray, const Selection& selection, bool shift_down, const Point* mouse_pos = nullptr); | ||||
|     void update_data(GLCanvas3D& canvas); | ||||
| 
 | ||||
|     Rect get_reset_rect_viewport(const GLCanvas3D& canvas) const; | ||||
|     EType get_current_type() const { return m_current; } | ||||
| 
 | ||||
|     bool is_running() const; | ||||
|     bool handle_shortcut(int key, const Selection& selection); | ||||
| 
 | ||||
|     bool is_dragging() const; | ||||
|     void start_dragging(const Selection& selection); | ||||
|     void stop_dragging(); | ||||
| 
 | ||||
|     Vec3d get_displacement() const; | ||||
| 
 | ||||
|     Vec3d get_scale() const; | ||||
|     void set_scale(const Vec3d& scale); | ||||
| 
 | ||||
|     Vec3d get_rotation() const; | ||||
|     void set_rotation(const Vec3d& rotation); | ||||
| 
 | ||||
|     Vec3d get_flattening_normal() const; | ||||
| 
 | ||||
|     void set_flattening_data(const ModelObject* model_object); | ||||
| 
 | ||||
|     void set_sla_support_data(ModelObject* model_object, const Selection& selection); | ||||
|     bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false); | ||||
| 
 | ||||
|     void render_current_gizmo(const Selection& selection) const; | ||||
|     void render_current_gizmo_for_picking_pass(const Selection& selection) const; | ||||
| 
 | ||||
|     void render_overlay(const GLCanvas3D& canvas, const Selection& selection) const; | ||||
| 
 | ||||
|     const std::string& get_tooltip() const { return m_tooltip; } | ||||
| 
 | ||||
|     bool on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas); | ||||
|     bool on_char(wxKeyEvent& evt, GLCanvas3D& canvas); | ||||
|     bool on_key(wxKeyEvent& evt, GLCanvas3D& canvas); | ||||
| 
 | ||||
| private: | ||||
|     void reset(); | ||||
| 
 | ||||
|     void do_render_overlay(const GLCanvas3D& canvas, const Selection& selection) const; | ||||
| 
 | ||||
|     float get_total_overlay_height() const; | ||||
|     float get_total_overlay_width() const; | ||||
| 
 | ||||
|     GLGizmoBase* get_current() const; | ||||
| 
 | ||||
| #if ENABLE_SVG_ICONS | ||||
|     bool generate_icons_texture() const; | ||||
| #endif // ENABLE_SVG_ICONS
 | ||||
| 
 | ||||
|     void update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection); | ||||
|     std::string update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos); | ||||
|     bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const; | ||||
|     bool grabber_contains_mouse() const; | ||||
| }; | ||||
| 
 | ||||
| } // namespace GUI
 | ||||
| } // namespace Slic3r
 | ||||
| 
 | ||||
| #endif // slic3r_GUI_GLGizmosManager_hpp_
 | ||||
|  | @ -19,6 +19,7 @@ | |||
| 
 | ||||
| #include "libslic3r/libslic3r.h" | ||||
| #include "libslic3r/Utils.hpp" | ||||
| #include "3DScene.hpp" | ||||
| #include "GUI.hpp" | ||||
| 
 | ||||
| namespace Slic3r { | ||||
|  | @ -359,19 +360,19 @@ void ImGuiWrapper::init_font() | |||
| 
 | ||||
|     // Upload texture to graphics system
 | ||||
|     GLint last_texture; | ||||
|     glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); | ||||
|     glGenTextures(1, &m_font_texture); | ||||
|     glBindTexture(GL_TEXTURE_2D, m_font_texture); | ||||
|     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||||
|     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||||
|     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | ||||
|     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); | ||||
|     glsafe(::glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); | ||||
|     glsafe(::glGenTextures(1, &m_font_texture)); | ||||
|     glsafe(::glBindTexture(GL_TEXTURE_2D, m_font_texture)); | ||||
|     glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); | ||||
|     glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); | ||||
|     glsafe(::glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); | ||||
|     glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); | ||||
| 
 | ||||
|     // Store our identifier
 | ||||
|     io.Fonts->TexID = (ImTextureID)(intptr_t)m_font_texture; | ||||
| 
 | ||||
|     // Restore state
 | ||||
|     glBindTexture(GL_TEXTURE_2D, last_texture); | ||||
|     glsafe(::glBindTexture(GL_TEXTURE_2D, last_texture)); | ||||
| } | ||||
| 
 | ||||
| void ImGuiWrapper::init_input() | ||||
|  | @ -466,39 +467,39 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) | |||
| 
 | ||||
|     // We are using the OpenGL fixed pipeline to make the example code simpler to read!
 | ||||
|     // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill.
 | ||||
|     GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); | ||||
|     GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); | ||||
|     GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); | ||||
|     GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);  | ||||
|     glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); | ||||
|     glEnable(GL_BLEND); | ||||
|     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||
|     glDisable(GL_CULL_FACE); | ||||
|     glDisable(GL_DEPTH_TEST); | ||||
|     glDisable(GL_LIGHTING); | ||||
|     glDisable(GL_COLOR_MATERIAL); | ||||
|     glEnable(GL_SCISSOR_TEST); | ||||
|     glEnableClientState(GL_VERTEX_ARRAY); | ||||
|     glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||||
|     glEnableClientState(GL_COLOR_ARRAY); | ||||
|     glEnable(GL_TEXTURE_2D); | ||||
|     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); | ||||
|     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); | ||||
|     GLint last_texture; glsafe(::glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); | ||||
|     GLint last_polygon_mode[2]; glsafe(::glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode)); | ||||
|     GLint last_viewport[4]; glsafe(::glGetIntegerv(GL_VIEWPORT, last_viewport)); | ||||
|     GLint last_scissor_box[4]; glsafe(::glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box)); | ||||
|     glsafe(::glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT)); | ||||
|     glsafe(::glEnable(GL_BLEND)); | ||||
|     glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); | ||||
|     glsafe(::glDisable(GL_CULL_FACE)); | ||||
|     glsafe(::glDisable(GL_DEPTH_TEST)); | ||||
|     glsafe(::glDisable(GL_LIGHTING)); | ||||
|     glsafe(::glDisable(GL_COLOR_MATERIAL)); | ||||
|     glsafe(::glEnable(GL_SCISSOR_TEST)); | ||||
|     glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); | ||||
|     glsafe(::glEnableClientState(GL_TEXTURE_COORD_ARRAY)); | ||||
|     glsafe(::glEnableClientState(GL_COLOR_ARRAY)); | ||||
|     glsafe(::glEnable(GL_TEXTURE_2D)); | ||||
|     glsafe(::glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)); | ||||
|     glsafe(::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)); | ||||
|     GLint texture_env_mode = GL_MODULATE; | ||||
|     glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &texture_env_mode); | ||||
|     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); | ||||
|     glsafe(::glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &texture_env_mode)); | ||||
|     glsafe(::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)); | ||||
|     //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound
 | ||||
| 
 | ||||
|     // Setup viewport, orthographic projection matrix
 | ||||
|     // Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
 | ||||
|     glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); | ||||
|     glMatrixMode(GL_PROJECTION); | ||||
|     glPushMatrix(); | ||||
|     glLoadIdentity(); | ||||
|     glOrtho(draw_data->DisplayPos.x, draw_data->DisplayPos.x + draw_data->DisplaySize.x, draw_data->DisplayPos.y + draw_data->DisplaySize.y, draw_data->DisplayPos.y, -1.0f, +1.0f); | ||||
|     glMatrixMode(GL_MODELVIEW); | ||||
|     glPushMatrix(); | ||||
|     glLoadIdentity(); | ||||
|     glsafe(::glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height)); | ||||
|     glsafe(::glMatrixMode(GL_PROJECTION)); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glLoadIdentity()); | ||||
|     glsafe(::glOrtho(draw_data->DisplayPos.x, draw_data->DisplayPos.x + draw_data->DisplaySize.x, draw_data->DisplayPos.y + draw_data->DisplaySize.y, draw_data->DisplayPos.y, -1.0f, +1.0f)); | ||||
|     glsafe(::glMatrixMode(GL_MODELVIEW)); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glLoadIdentity()); | ||||
| 
 | ||||
|     // Render command lists
 | ||||
|     ImVec2 pos = draw_data->DisplayPos; | ||||
|  | @ -507,9 +508,9 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) | |||
|         const ImDrawList* cmd_list = draw_data->CmdLists[n]; | ||||
|         const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; | ||||
|         const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; | ||||
|         glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, pos))); | ||||
|         glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv))); | ||||
|         glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col))); | ||||
|         glsafe(::glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, pos)))); | ||||
|         glsafe(::glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv)))); | ||||
|         glsafe(::glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col)))); | ||||
| 
 | ||||
|         for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) | ||||
|         { | ||||
|  | @ -525,11 +526,11 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) | |||
|                 if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) | ||||
|                 { | ||||
|                     // Apply scissor/clipping rectangle
 | ||||
|                     glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)); | ||||
|                     glsafe(::glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y))); | ||||
| 
 | ||||
|                     // Bind texture, Draw
 | ||||
|                     glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); | ||||
|                     glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer); | ||||
|                     glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId)); | ||||
|                     glsafe(::glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer)); | ||||
|                 } | ||||
|             } | ||||
|             idx_buffer += pcmd->ElemCount; | ||||
|  | @ -537,19 +538,19 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) | |||
|     } | ||||
| 
 | ||||
|     // Restore modified state
 | ||||
|     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, texture_env_mode); | ||||
|     glDisableClientState(GL_COLOR_ARRAY); | ||||
|     glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||||
|     glDisableClientState(GL_VERTEX_ARRAY); | ||||
|     glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture); | ||||
|     glMatrixMode(GL_MODELVIEW); | ||||
|     glPopMatrix(); | ||||
|     glMatrixMode(GL_PROJECTION); | ||||
|     glPopMatrix(); | ||||
|     glPopAttrib(); | ||||
|     glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]); | ||||
|     glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); | ||||
|     glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); | ||||
|     glsafe(::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, texture_env_mode)); | ||||
|     glsafe(::glDisableClientState(GL_COLOR_ARRAY)); | ||||
|     glsafe(::glDisableClientState(GL_TEXTURE_COORD_ARRAY)); | ||||
|     glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); | ||||
|     glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture)); | ||||
|     glsafe(::glMatrixMode(GL_MODELVIEW)); | ||||
|     glsafe(::glPopMatrix()); | ||||
|     glsafe(::glMatrixMode(GL_PROJECTION)); | ||||
|     glsafe(::glPopMatrix()); | ||||
|     glsafe(::glPopAttrib()); | ||||
|     glsafe(::glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1])); | ||||
|     glsafe(::glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3])); | ||||
|     glsafe(::glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3])); | ||||
| } | ||||
| 
 | ||||
| bool ImGuiWrapper::display_initialized() const | ||||
|  | @ -563,7 +564,7 @@ void ImGuiWrapper::destroy_font() | |||
|     if (m_font_texture != 0) { | ||||
|         ImGuiIO& io = ImGui::GetIO(); | ||||
|         io.Fonts->TexID = 0; | ||||
|         glDeleteTextures(1, &m_font_texture); | ||||
|         glsafe(::glDeleteTextures(1, &m_font_texture)); | ||||
|         m_font_texture = 0; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -17,8 +17,7 @@ KBShortcutsDialog::KBShortcutsDialog() | |||
| 	auto main_sizer = new wxBoxSizer(wxVERTICAL); | ||||
| 
 | ||||
|     // logo
 | ||||
| // 	wxBitmap logo_bmp = wxBitmap(from_u8(Slic3r::var("Slic3r_32px.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 	const wxBitmap logo_bmp = create_scaled_bitmap("Slic3r_32px.png"); | ||||
| 	const wxBitmap logo_bmp = create_scaled_bitmap("Slic3r_32px.png", 32); | ||||
| 
 | ||||
|     // fonts
 | ||||
|     wxFont head_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold(); | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ namespace Slic3r { | |||
| namespace GUI { | ||||
| 
 | ||||
| MainFrame::MainFrame() : | ||||
| wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "mainframe"), | ||||
| DPIFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "mainframe"), | ||||
|         m_printhost_queue_dlg(new PrintHostQueueDialog(this)) | ||||
| { | ||||
|     // Load the icon either from the exe, or from the ico file.
 | ||||
|  | @ -56,9 +56,13 @@ wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAUL | |||
| 
 | ||||
|     // initialize default width_unit according to the width of the one symbol ("x") of the current system font
 | ||||
|     const wxSize size = GetTextExtent("m"); | ||||
| //     wxGetApp().set_em_unit(size.x-1);
 | ||||
|     wxGetApp().set_em_unit(std::max<size_t>(10, size.x - 1)); | ||||
| 
 | ||||
|     /* Load default preset bitmaps before a tabpanel initialization,
 | ||||
|      * but after filling of an em_unit value  | ||||
|      */ | ||||
|     wxGetApp().preset_bundle->load_default_preset_bitmaps(); | ||||
| 
 | ||||
|     // initialize tabpanel and menubar
 | ||||
|     init_tabpanel(); | ||||
|     init_menubar(); | ||||
|  | @ -252,6 +256,11 @@ bool MainFrame::can_delete_all() const | |||
|     return (m_plater != nullptr) ? !m_plater->model().objects.empty() : false; | ||||
| } | ||||
| 
 | ||||
| void MainFrame::on_dpi_changed(const wxRect &suggested_rect) | ||||
| { | ||||
|     // TODO
 | ||||
| } | ||||
| 
 | ||||
| void MainFrame::init_menubar() | ||||
| { | ||||
| #ifdef __APPLE__ | ||||
|  | @ -388,11 +397,11 @@ void MainFrame::init_menubar() | |||
|             windowMenu->AppendSeparator(); | ||||
|         } | ||||
|         append_menu_item(windowMenu, wxID_HIGHEST + 2, _(L("P&rint Settings Tab")) + "\tCtrl+2", _(L("Show the print settings")), | ||||
|             [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 0); }, "cog.png"); | ||||
|             [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 0); }, "cog"); | ||||
|         append_menu_item(windowMenu, wxID_HIGHEST + 3, _(L("&Filament Settings Tab")) + "\tCtrl+3", _(L("Show the filament settings")), | ||||
|             [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 1); }, "spool.png"); | ||||
|         append_menu_item(windowMenu, wxID_HIGHEST + 4, _(L("Print&er Settings Tab")) + "\tCtrl+4", _(L("Show the printer settings")), | ||||
|             [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 2); }, "printer_empty.png"); | ||||
|             [this, tab_offset](wxCommandEvent&) { select_tab(tab_offset + 2); }, "printer"); | ||||
|         if (m_plater) { | ||||
|             windowMenu->AppendSeparator(); | ||||
|             wxMenuItem* item_3d = append_menu_item(windowMenu, wxID_HIGHEST + 5, _(L("3&D")) + "\tCtrl+5", _(L("Show the 3D editing view")), | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| #include <string> | ||||
| #include <map> | ||||
| 
 | ||||
| #include "GUI_Utils.hpp" | ||||
| #include "Plater.hpp" | ||||
| #include "Event.hpp" | ||||
| 
 | ||||
|  | @ -40,7 +41,7 @@ struct PresetTab { | |||
|     PrinterTechnology technology; | ||||
| }; | ||||
| 
 | ||||
| class MainFrame : public wxFrame | ||||
| class MainFrame : public DPIFrame | ||||
| { | ||||
|     bool        m_loaded {false}; | ||||
| 
 | ||||
|  | @ -68,6 +69,9 @@ class MainFrame : public wxFrame | |||
|     bool can_delete() const; | ||||
|     bool can_delete_all() const; | ||||
| 
 | ||||
| protected: | ||||
|     virtual void on_dpi_changed(const wxRect &suggested_rect); | ||||
| 
 | ||||
| public: | ||||
|     MainFrame(); | ||||
|     ~MainFrame() {} | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ namespace GUI { | |||
| 
 | ||||
| 
 | ||||
| MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxWindowID button_id) : | ||||
| 	MsgDialog(parent, title, headline, create_scaled_bitmap("Slic3r_192px.png"), button_id) | ||||
| 	MsgDialog(parent, title, headline, create_scaled_bitmap("Slic3r_192px.png", 192), button_id) | ||||
| {} | ||||
| 
 | ||||
| MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxBitmap bitmap, wxWindowID button_id) : | ||||
|  |  | |||
|  | @ -38,6 +38,8 @@ | |||
| #include "libslic3r/SLA/SLARotfinder.hpp" | ||||
| #include "libslic3r/Utils.hpp" | ||||
| 
 | ||||
| #include "libnest2d/optimizers/nlopt/genetic.hpp" | ||||
| 
 | ||||
| #include "GUI.hpp" | ||||
| #include "GUI_App.hpp" | ||||
| #include "GUI_ObjectList.hpp" | ||||
|  | @ -284,7 +286,7 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 * | |||
| #ifdef __WINDOWS__ | ||||
|     edit_btn->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); | ||||
| #endif | ||||
|     edit_btn->SetBitmap(create_scaled_bitmap("cog.png")); | ||||
|     edit_btn->SetBitmap(create_scaled_bitmap("cog")); | ||||
|     edit_btn->SetToolTip(_(L("Click to edit preset"))); | ||||
| 
 | ||||
|     edit_btn->Bind(wxEVT_BUTTON, ([preset_type, this](wxCommandEvent) | ||||
|  | @ -1199,7 +1201,7 @@ struct Plater::priv | |||
|     BoundingBox scaled_bed_shape_bb() const; | ||||
|     std::vector<size_t> load_files(const std::vector<fs::path>& input_files, bool load_model, bool load_config); | ||||
|     std::vector<size_t> load_model_objects(const ModelObjectPtrs &model_objects); | ||||
|     std::unique_ptr<CheckboxFileDialog> get_export_file(GUI::FileType file_type); | ||||
|     wxString get_export_file(GUI::FileType file_type); | ||||
| 
 | ||||
|     const Selection& get_selection() const; | ||||
|     Selection& get_selection(); | ||||
|  | @ -1617,6 +1619,45 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_ | |||
|                 } | ||||
| #if ENABLE_VOLUMES_CENTERING_FIXES | ||||
|             } | ||||
|             else if ((wxGetApp().get_mode() == comSimple) && (type_3mf || type_any_amf)) | ||||
|             { | ||||
|                 bool advanced = false; | ||||
|                 for (const ModelObject* model_object : model.objects) | ||||
|                 { | ||||
|                     // is there more than one instance ?
 | ||||
|                     if (model_object->instances.size() > 1) | ||||
|                     { | ||||
|                         advanced = true; | ||||
|                         break; | ||||
|                     } | ||||
| 
 | ||||
|                     // is there any modifier ?
 | ||||
|                     for (const ModelVolume* model_volume : model_object->volumes) | ||||
|                     { | ||||
|                         if (!model_volume->is_model_part()) | ||||
|                         { | ||||
|                             advanced = true; | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     if (advanced) | ||||
|                         break; | ||||
|                 } | ||||
| 
 | ||||
|                 if (advanced) | ||||
|                 { | ||||
|                     wxMessageDialog dlg(q, _(L("This file cannot be loaded in simple mode. Do you want to switch to expert mode?\n")), | ||||
|                         _(L("Detected advanced data")), wxICON_WARNING | wxYES | wxNO); | ||||
|                     if (dlg.ShowModal() == wxID_YES) | ||||
|                     { | ||||
|                         Slic3r::GUI::wxGetApp().save_mode(comExpert); | ||||
|                         view3D->set_as_dirty(); | ||||
|                     } | ||||
|                     else | ||||
|                         return obj_idxs; | ||||
|                 } | ||||
|             } | ||||
| #endif // ENABLE_VOLUMES_CENTERING_FIXES
 | ||||
| 
 | ||||
| #if !ENABLE_VOLUMES_CENTERING_FIXES | ||||
|  | @ -1642,7 +1683,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_ | |||
|                         Slic3r::GUI::show_error(nullptr,  | ||||
|                             wxString::Format(_(L("You can't to add the object(s) from %s because of one or some of them is(are) multi-part")),  | ||||
|                                              from_path(filename))); | ||||
|                         return std::vector<size_t>(); | ||||
|                         return obj_idxs; | ||||
|                     } | ||||
|             } | ||||
| 
 | ||||
|  | @ -1784,7 +1825,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode | |||
|     return obj_idxs; | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType file_type) | ||||
| wxString Plater::priv::get_export_file(GUI::FileType file_type) | ||||
| { | ||||
|     wxString wildcard; | ||||
|     switch (file_type) { | ||||
|  | @ -1801,34 +1842,56 @@ std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType | |||
| 
 | ||||
|     // Update printbility state of each of the ModelInstances.
 | ||||
|     this->update_print_volume_state(); | ||||
|     // Find the file name of the first printable object.
 | ||||
| 	fs::path output_file = this->model.propose_export_file_name_and_path(); | ||||
| 
 | ||||
|     const Selection& selection = get_selection(); | ||||
|     int obj_idx = selection.get_object_idx(); | ||||
| 
 | ||||
|     fs::path output_file; | ||||
|     // first try to get the file name from the current selection
 | ||||
|     if ((0 <= obj_idx) && (obj_idx < (int)this->model.objects.size())) | ||||
|         output_file = this->model.objects[obj_idx]->get_export_filename(); | ||||
| 
 | ||||
|     if (output_file.empty()) | ||||
|         // Find the file name of the first printable object.
 | ||||
|         output_file = this->model.propose_export_file_name_and_path(); | ||||
| 
 | ||||
|     wxString dlg_title; | ||||
|     switch (file_type) { | ||||
|         case FT_STL: output_file.replace_extension("stl"); break; | ||||
|         case FT_AMF: output_file.replace_extension("zip.amf"); break;   // XXX: Problem on OS X with double extension?
 | ||||
|         case FT_3MF: output_file.replace_extension("3mf"); break; | ||||
|         case FT_STL: | ||||
|         { | ||||
|             output_file.replace_extension("stl"); | ||||
|             dlg_title = _(L("Export STL file:")); | ||||
|             break; | ||||
|         } | ||||
|         case FT_AMF: | ||||
|         { | ||||
|             // XXX: Problem on OS X with double extension?
 | ||||
|             output_file.replace_extension("zip.amf"); | ||||
|             dlg_title = _(L("Export AMF file:")); | ||||
|             break; | ||||
|         } | ||||
|         case FT_3MF: | ||||
|         { | ||||
|             output_file.replace_extension("3mf"); | ||||
|             dlg_title = _(L("Save file as:")); | ||||
|             break; | ||||
|         } | ||||
|         default: break; | ||||
|     } | ||||
| 
 | ||||
|     auto dlg = Slic3r::make_unique<CheckboxFileDialog>(q, | ||||
|         ((file_type == FT_AMF) || (file_type == FT_3MF)) ? _(L("Export print config")) : "", | ||||
|         true, | ||||
|         _(L("Save file as:")), | ||||
|         from_path(output_file.parent_path()), | ||||
|         from_path(output_file.filename()), | ||||
|         wildcard, | ||||
|         wxFD_SAVE | wxFD_OVERWRITE_PROMPT | ||||
|     ); | ||||
|     wxFileDialog* dlg = new wxFileDialog(q, dlg_title, | ||||
|         from_path(output_file.parent_path()), from_path(output_file.filename()), | ||||
|         wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); | ||||
| 
 | ||||
|     if (dlg->ShowModal() != wxID_OK) { | ||||
|         return nullptr; | ||||
|         return wxEmptyString; | ||||
|     } | ||||
| 
 | ||||
|     fs::path path(into_path(dlg->GetPath())); | ||||
|     wxString out_path = dlg->GetPath(); | ||||
|     fs::path path(into_path(out_path)); | ||||
|     wxGetApp().app_config->update_last_output_dir(path.parent_path().string()); | ||||
| 
 | ||||
|     return dlg; | ||||
|     return out_path; | ||||
| } | ||||
| 
 | ||||
| const Selection& Plater::priv::get_selection() const | ||||
|  | @ -2039,7 +2102,9 @@ void Plater::priv::sla_optimize_rotation() { | |||
|     rotoptimizing.store(true); | ||||
| 
 | ||||
|     int obj_idx = get_selected_object_idx(); | ||||
|     ModelObject * o = model.objects[obj_idx]; | ||||
|     if(obj_idx < 0) { rotoptimizing.store(false); return; } | ||||
| 
 | ||||
|     ModelObject * o = model.objects[size_t(obj_idx)]; | ||||
| 
 | ||||
|     background_process.stop(); | ||||
| 
 | ||||
|  | @ -2047,7 +2112,7 @@ void Plater::priv::sla_optimize_rotation() { | |||
|     statusbar()->set_range(100); | ||||
| 
 | ||||
|     auto stfn = [this] (unsigned st, const std::string& msg) { | ||||
|         statusbar()->set_progress(st); | ||||
|         statusbar()->set_progress(int(st)); | ||||
|         statusbar()->set_status_text(msg); | ||||
| 
 | ||||
|         // could be problematic, but we need the cancel button.
 | ||||
|  | @ -2065,8 +2130,59 @@ void Plater::priv::sla_optimize_rotation() { | |||
|                 [this](){ return !rotoptimizing.load(); } | ||||
|     ); | ||||
| 
 | ||||
|     const auto *bed_shape_opt = config->opt<ConfigOptionPoints>("bed_shape"); | ||||
|     assert(bed_shape_opt); | ||||
| 
 | ||||
|     auto& bedpoints = bed_shape_opt->values; | ||||
|     Polyline bed; bed.points.reserve(bedpoints.size()); | ||||
|     for(auto& v : bedpoints) bed.append(Point::new_scale(v(0), v(1))); | ||||
| 
 | ||||
|     double mindist = 6.0; // FIXME
 | ||||
|     double offs = mindist / 2.0 - EPSILON; | ||||
| 
 | ||||
|     if(rotoptimizing.load()) // wasn't canceled
 | ||||
|     for(ModelInstance * oi : o->instances) oi->set_rotation({r[X], r[Y], r[Z]}); | ||||
|     for(ModelInstance * oi : o->instances) { | ||||
|         oi->set_rotation({r[X], r[Y], r[Z]}); | ||||
| 
 | ||||
|         auto trchull = o->convex_hull_2d(oi->get_transformation().get_matrix()); | ||||
| 
 | ||||
|         namespace opt = libnest2d::opt; | ||||
|         opt::StopCriteria stopcr; | ||||
|         stopcr.relative_score_difference = 0.01; | ||||
|         stopcr.max_iterations = 10000; | ||||
|         stopcr.stop_score = 0.0; | ||||
|         opt::GeneticOptimizer solver(stopcr); | ||||
|         Polygon pbed(bed); | ||||
| 
 | ||||
|         auto bin = pbed.bounding_box(); | ||||
|         double binw = bin.size()(X) * SCALING_FACTOR - offs; | ||||
|         double binh = bin.size()(Y) * SCALING_FACTOR - offs; | ||||
| 
 | ||||
|         auto result = solver.optimize_min([&trchull, binw, binh](double rot){ | ||||
|             auto chull = trchull; | ||||
|             chull.rotate(rot); | ||||
| 
 | ||||
|             auto bb = chull.bounding_box(); | ||||
|             double bbw = bb.size()(X) * SCALING_FACTOR; | ||||
|             double bbh = bb.size()(Y) * SCALING_FACTOR; | ||||
| 
 | ||||
|             auto wdiff = bbw - binw; | ||||
|             auto hdiff = bbh - binh; | ||||
|             double diff = 0; | ||||
|             if(wdiff < 0 && hdiff < 0) diff = wdiff + hdiff; | ||||
|             if(wdiff > 0) diff += wdiff; | ||||
|             if(hdiff > 0) diff += hdiff; | ||||
| 
 | ||||
|             return diff; | ||||
|         }, opt::initvals(0.0), opt::bound(-PI/2, PI/2)); | ||||
| 
 | ||||
|         double r = std::get<0>(result.optimum); | ||||
| 
 | ||||
|         Vec3d rt = oi->get_rotation(); rt(Z) += r; | ||||
|         oi->set_rotation(rt); | ||||
|     } | ||||
| 
 | ||||
|     arr::find_new_position(model, o->instances, coord_t(mindist/SCALING_FACTOR), bed); | ||||
| 
 | ||||
|     // Correct the z offset of the object which was corrupted be the rotation
 | ||||
|     o->ensure_on_bed(); | ||||
|  | @ -2713,12 +2829,15 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ | |||
|     wxMenuItem* item_delete = nullptr; | ||||
|     if (is_part) { | ||||
|         item_delete = append_menu_item(menu, wxID_ANY, _(L("Delete")) + "\tDel", _(L("Remove the selected object")), | ||||
|             [this](wxCommandEvent&) { q->remove_selected(); }, "brick_delete.png"); | ||||
|     } else { | ||||
|             [this](wxCommandEvent&) { q->remove_selected(); }, "remove"); | ||||
| 
 | ||||
|         sidebar->obj_list()->append_menu_item_export_stl(menu); | ||||
|     } | ||||
|     else { | ||||
|         wxMenuItem* item_increase = append_menu_item(menu, wxID_ANY, _(L("Increase copies")) + "\t+", _(L("Place one more copy of the selected object")), | ||||
|             [this](wxCommandEvent&) { q->increase_instances(); }, "add.png"); | ||||
|             [this](wxCommandEvent&) { q->increase_instances(); }, "instance_add"); | ||||
|         wxMenuItem* item_decrease = append_menu_item(menu, wxID_ANY, _(L("Decrease copies")) + "\t-", _(L("Remove one copy of the selected object")), | ||||
|             [this](wxCommandEvent&) { q->decrease_instances(); }, "delete.png"); | ||||
|             [this](wxCommandEvent&) { q->decrease_instances(); }, "instance_remove"); | ||||
|         wxMenuItem* item_set_number_of_copies = append_menu_item(menu, wxID_ANY, _(L("Set number of copies")) + dots, _(L("Change the number of copies of the selected object")), | ||||
|             [this](wxCommandEvent&) { q->set_number_of_copies(); }, "textfield.png"); | ||||
| 
 | ||||
|  | @ -2728,7 +2847,7 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ | |||
| 
 | ||||
|         // Delete menu was moved to be after +/- instace to make it more difficult to be selected by mistake.
 | ||||
|         item_delete = append_menu_item(menu, wxID_ANY, _(L("Delete")) + "\tDel", _(L("Remove the selected object")), | ||||
|             [this](wxCommandEvent&) { q->remove_selected(); }, "brick_delete.png"); | ||||
|             [this](wxCommandEvent&) { q->remove_selected(); }, "remove"); | ||||
| 
 | ||||
|         menu->AppendSeparator(); | ||||
|         wxMenuItem* item_instance_to_object = sidebar->obj_list()->append_menu_item_instance_to_object(menu); | ||||
|  | @ -2745,10 +2864,11 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ | |||
|         append_menu_item(menu, wxID_ANY, _(L("Reload from Disk")), _(L("Reload the selected file from Disk")), | ||||
|             [this](wxCommandEvent&) { reload_from_disk(); }); | ||||
| 
 | ||||
|         append_menu_item(menu, wxID_ANY, _(L("Export object as STL")) + dots, _(L("Export this single object as STL file")), | ||||
|         append_menu_item(menu, wxID_ANY, _(L("Export as STL")) + dots, _(L("Export the selected object as STL file")), | ||||
|             [this](wxCommandEvent&) { q->export_stl(true); }); | ||||
| 
 | ||||
|         menu->AppendSeparator(); | ||||
|     } | ||||
|     menu->AppendSeparator(); | ||||
| 
 | ||||
|     sidebar->obj_list()->append_menu_item_fix_through_netfabb(menu); | ||||
| 
 | ||||
|  | @ -2782,11 +2902,11 @@ bool Plater::priv::complit_init_object_menu() | |||
|         return false; | ||||
| 
 | ||||
|     wxMenuItem* item_split_objects = append_menu_item(split_menu, wxID_ANY, _(L("To objects")), _(L("Split the selected object into individual objects")), | ||||
|         [this](wxCommandEvent&) { split_object(); }, "shape_ungroup_o.png", &object_menu); | ||||
|         [this](wxCommandEvent&) { split_object(); }, "split_objects.png", &object_menu); | ||||
|     wxMenuItem* item_split_volumes = append_menu_item(split_menu, wxID_ANY, _(L("To parts")), _(L("Split the selected object into individual sub-parts")), | ||||
|         [this](wxCommandEvent&) { split_volume(); }, "shape_ungroup_p.png", &object_menu); | ||||
|         [this](wxCommandEvent&) { split_volume(); }, "split_parts.png", &object_menu); | ||||
| 
 | ||||
|     wxMenuItem* item_split = append_submenu(&object_menu, split_menu, wxID_ANY, _(L("Split")), _(L("Split the selected object")), "shape_ungroup.png"); | ||||
|     wxMenuItem* item_split = append_submenu(&object_menu, split_menu, wxID_ANY, _(L("Split")), _(L("Split the selected object"))/*, "shape_ungroup.png"*/); | ||||
|     object_menu.AppendSeparator(); | ||||
| 
 | ||||
|     // "Add (volumes)" popupmenu will be added later in append_menu_items_add_volume()
 | ||||
|  | @ -2907,6 +3027,9 @@ bool Plater::priv::can_split() const | |||
| 
 | ||||
| bool Plater::priv::layers_height_allowed() const | ||||
| { | ||||
|     if (printer_technology != ptFFF) | ||||
|         return false; | ||||
| 
 | ||||
|     int obj_idx = get_selected_object_idx(); | ||||
|     return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && config->opt_bool("variable_layer_height") && view3D->is_layers_editing_allowed(); | ||||
| } | ||||
|  | @ -3243,11 +3366,8 @@ void Plater::export_stl(bool selection_only) | |||
| { | ||||
|     if (p->model.objects.empty()) { return; } | ||||
| 
 | ||||
|     auto dialog = p->get_export_file(FT_STL); | ||||
|     if (! dialog) { return; } | ||||
| 
 | ||||
|     // Store a binary STL
 | ||||
|     const wxString path = dialog->GetPath(); | ||||
|     wxString path = p->get_export_file(FT_STL); | ||||
|     if (path.empty()) { return; } | ||||
|     const std::string path_u8 = into_u8(path); | ||||
| 
 | ||||
|     wxBusyCursor wait; | ||||
|  | @ -3259,10 +3379,25 @@ void Plater::export_stl(bool selection_only) | |||
| 
 | ||||
|         const auto obj_idx = selection.get_object_idx(); | ||||
|         if (obj_idx == -1) { return; } | ||||
|         mesh = p->model.objects[obj_idx]->mesh(); | ||||
|     } else { | ||||
|         mesh = p->model.mesh(); | ||||
| 
 | ||||
|         const ModelObject* model_object = p->model.objects[obj_idx]; | ||||
|         if (selection.get_mode() == Selection::Instance) | ||||
|         { | ||||
|             if (selection.is_single_full_object()) | ||||
|                 mesh = model_object->mesh(); | ||||
|             else | ||||
|                 mesh = model_object->full_raw_mesh(); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); | ||||
|             mesh = model_object->volumes[volume->volume_idx()]->mesh; | ||||
|             mesh.transform(volume->get_volume_transformation().get_matrix()); | ||||
|             mesh.translate(-model_object->origin_translation.cast<float>()); | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|         mesh = p->model.mesh(); | ||||
| 
 | ||||
|     Slic3r::store_stl(path_u8.c_str(), &mesh, true); | ||||
|     p->statusbar()->set_status_text(wxString::Format(_(L("STL file exported to %s")), path)); | ||||
|  | @ -3272,15 +3407,14 @@ void Plater::export_amf() | |||
| { | ||||
|     if (p->model.objects.empty()) { return; } | ||||
| 
 | ||||
|     auto dialog = p->get_export_file(FT_AMF); | ||||
|     if (! dialog) { return; } | ||||
| 
 | ||||
|     const wxString path = dialog->GetPath(); | ||||
|     wxString path = p->get_export_file(FT_AMF); | ||||
|     if (path.empty()) { return; } | ||||
|     const std::string path_u8 = into_u8(path); | ||||
| 
 | ||||
| 	DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure(); | ||||
|     wxBusyCursor wait; | ||||
| 	if (Slic3r::store_amf(path_u8.c_str(), &p->model, dialog->get_checkbox_value() ? &cfg : nullptr)) { | ||||
|     bool export_config = true; | ||||
|     DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure(); | ||||
|     if (Slic3r::store_amf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) { | ||||
|         // Success
 | ||||
|         p->statusbar()->set_status_text(wxString::Format(_(L("AMF file exported to %s")), path)); | ||||
|     } else { | ||||
|  | @ -3297,10 +3431,8 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) | |||
|     bool export_config = true; | ||||
|     if (output_path.empty()) | ||||
|     { | ||||
|         auto dialog = p->get_export_file(FT_3MF); | ||||
|         if (!dialog) { return; } | ||||
|         path = dialog->GetPath(); | ||||
|         export_config = dialog->get_checkbox_value(); | ||||
|         path = p->get_export_file(FT_3MF); | ||||
|         if (path.empty()) { return; } | ||||
|     } | ||||
|     else | ||||
|         path = from_path(output_path); | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| #include "AppConfig.hpp" | ||||
| #include "BitmapCache.hpp" | ||||
| #include "I18N.hpp" | ||||
| #include "wxExtensions.hpp" | ||||
| 
 | ||||
| #ifdef _MSC_VER | ||||
|     #define WIN32_LEAN_AND_MEAN | ||||
|  | @ -798,12 +799,14 @@ bool PresetCollection::delete_current_preset() | |||
| 
 | ||||
| bool PresetCollection::load_bitmap_default(const std::string &file_name) | ||||
| { | ||||
|     return m_bitmap_main_frame->LoadFile(wxString::FromUTF8(Slic3r::var(file_name).c_str()), wxBITMAP_TYPE_PNG); | ||||
| //     return m_bitmap_main_frame->LoadFile(wxString::FromUTF8(Slic3r::var(file_name).c_str()), wxBITMAP_TYPE_PNG);
 | ||||
|     return load_scaled_bitmap(&m_bitmap_main_frame, file_name); | ||||
| } | ||||
| 
 | ||||
| bool PresetCollection::load_bitmap_add(const std::string &file_name) | ||||
| { | ||||
| 	return m_bitmap_add->LoadFile(wxString::FromUTF8(Slic3r::var(file_name).c_str()), wxBITMAP_TYPE_PNG); | ||||
| // 	return m_bitmap_add->LoadFile(wxString::FromUTF8(Slic3r::var(file_name).c_str()), wxBITMAP_TYPE_PNG);
 | ||||
|     return load_scaled_bitmap(&m_bitmap_add, file_name); | ||||
| } | ||||
| 
 | ||||
| const Preset* PresetCollection::get_selected_preset_parent() const | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| #include "BitmapCache.hpp" | ||||
| #include "Plater.hpp" | ||||
| #include "I18N.hpp" | ||||
| #include "wxExtensions.hpp" | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <fstream> | ||||
|  | @ -102,13 +103,14 @@ PresetBundle::PresetBundle() : | |||
|     } | ||||
| 
 | ||||
| 	// Load the default preset bitmaps.
 | ||||
|     this->prints       .load_bitmap_default("cog.png"); | ||||
|     this->sla_prints   .load_bitmap_default("package_green.png"); | ||||
|     this->filaments    .load_bitmap_default("spool.png"); | ||||
|     this->sla_materials.load_bitmap_default("package_green.png"); | ||||
|     this->printers     .load_bitmap_default("printer_empty.png"); | ||||
|     this->printers     .load_bitmap_add("add.png"); | ||||
|     this->load_compatible_bitmaps(); | ||||
| 	// #ys_FIXME_to_delete we'll load them later, using em_unit()
 | ||||
| //     this->prints       .load_bitmap_default("cog");
 | ||||
| //     this->sla_prints   .load_bitmap_default("package_green.png");
 | ||||
| //     this->filaments    .load_bitmap_default("spool.png");
 | ||||
| //     this->sla_materials.load_bitmap_default("package_green.png");
 | ||||
| //     this->printers     .load_bitmap_default("printer_empty.png");
 | ||||
| //     this->printers     .load_bitmap_add("add.png");
 | ||||
| //     this->load_compatible_bitmaps();
 | ||||
| 
 | ||||
|     // Re-activate the default presets, so their "edited" preset copies will be updated with the additional configuration values above.
 | ||||
|     this->prints       .select_preset(0); | ||||
|  | @ -400,14 +402,20 @@ bool PresetBundle::load_compatible_bitmaps() | |||
|     const std::string path_bitmap_incompatible = "flag-red-icon.png"; | ||||
|     const std::string path_bitmap_lock         = "sys_lock.png";//"lock.png";
 | ||||
| 	const std::string path_bitmap_lock_open    = "sys_unlock.png";//"lock_open.png";
 | ||||
|     bool loaded_compatible   = m_bitmapCompatible  ->LoadFile( | ||||
|         wxString::FromUTF8(Slic3r::var(path_bitmap_compatible).c_str()), wxBITMAP_TYPE_PNG); | ||||
|     bool loaded_incompatible = m_bitmapIncompatible->LoadFile( | ||||
|         wxString::FromUTF8(Slic3r::var(path_bitmap_incompatible).c_str()), wxBITMAP_TYPE_PNG); | ||||
|     bool loaded_lock = m_bitmapLock->LoadFile( | ||||
|         wxString::FromUTF8(Slic3r::var(path_bitmap_lock).c_str()), wxBITMAP_TYPE_PNG); | ||||
|     bool loaded_lock_open = m_bitmapLockOpen->LoadFile( | ||||
|         wxString::FromUTF8(Slic3r::var(path_bitmap_lock_open).c_str()), wxBITMAP_TYPE_PNG); | ||||
| //     bool loaded_compatible   = m_bitmapCompatible  ->LoadFile(
 | ||||
| //         wxString::FromUTF8(Slic3r::var(path_bitmap_compatible).c_str()), wxBITMAP_TYPE_PNG);
 | ||||
| //     bool loaded_incompatible = m_bitmapIncompatible->LoadFile(
 | ||||
| //         wxString::FromUTF8(Slic3r::var(path_bitmap_incompatible).c_str()), wxBITMAP_TYPE_PNG);
 | ||||
| //     bool loaded_lock = m_bitmapLock->LoadFile(
 | ||||
| //         wxString::FromUTF8(Slic3r::var(path_bitmap_lock).c_str()), wxBITMAP_TYPE_PNG);
 | ||||
| //     bool loaded_lock_open = m_bitmapLockOpen->LoadFile(
 | ||||
| //         wxString::FromUTF8(Slic3r::var(path_bitmap_lock_open).c_str()), wxBITMAP_TYPE_PNG);
 | ||||
| 
 | ||||
|     bool loaded_compatible = load_scaled_bitmap(&m_bitmapCompatible, path_bitmap_compatible); | ||||
|     bool loaded_incompatible = load_scaled_bitmap(&m_bitmapIncompatible,path_bitmap_incompatible); | ||||
|     bool loaded_lock = load_scaled_bitmap(&m_bitmapLock, path_bitmap_lock); | ||||
|     bool loaded_lock_open = load_scaled_bitmap(&m_bitmapLockOpen, path_bitmap_lock_open); | ||||
| 
 | ||||
|     if (loaded_compatible) { | ||||
|         prints       .set_bitmap_compatible(m_bitmapCompatible); | ||||
|         filaments    .set_bitmap_compatible(m_bitmapCompatible); | ||||
|  | @ -1438,6 +1446,17 @@ bool PresetBundle::parse_color(const std::string &scolor, unsigned char *rgb_out | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void PresetBundle::load_default_preset_bitmaps() | ||||
| { | ||||
|     this->prints.load_bitmap_default("cog"); | ||||
|     this->sla_prints.load_bitmap_default("cog"); | ||||
|     this->filaments.load_bitmap_default("spool.png"); | ||||
|     this->sla_materials.load_bitmap_default("package_green.png"); | ||||
|     this->printers.load_bitmap_default("printer"); | ||||
|     this->printers.load_bitmap_add("add.png"); | ||||
|     this->load_compatible_bitmaps(); | ||||
| } | ||||
| 
 | ||||
| void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui) | ||||
| { | ||||
|     if (ui == nullptr || this->printers.get_edited_preset().printer_technology() == ptSLA || | ||||
|  |  | |||
|  | @ -127,6 +127,8 @@ public: | |||
| 
 | ||||
|     static bool                 parse_color(const std::string &scolor, unsigned char *rgb_out); | ||||
| 
 | ||||
|     void                        load_default_preset_bitmaps(); | ||||
| 
 | ||||
| private: | ||||
|     std::string                 load_system_presets(); | ||||
|     // Merge one vendor's presets with the other vendor's presets, report duplicates.
 | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| #include "GUI_ObjectManipulation.hpp" | ||||
| #include "GUI_ObjectList.hpp" | ||||
| #include "Gizmos/GLGizmoBase.hpp" | ||||
| #include "slic3r/GUI/3DScene.hpp" | ||||
| 
 | ||||
| #include <GL/glew.h> | ||||
| 
 | ||||
|  | @ -75,7 +76,7 @@ Selection::~Selection() | |||
| void Selection::set_volumes(GLVolumePtrs* volumes) | ||||
| { | ||||
|     m_volumes = volumes; | ||||
|     _update_valid(); | ||||
|     update_valid(); | ||||
| } | ||||
| 
 | ||||
| bool Selection::init(bool useVBOs) | ||||
|  | @ -95,7 +96,7 @@ bool Selection::init(bool useVBOs) | |||
| void Selection::set_model(Model* model) | ||||
| { | ||||
|     m_model = model; | ||||
|     _update_valid(); | ||||
|     update_valid(); | ||||
| } | ||||
| 
 | ||||
| void Selection::add(unsigned int volume_idx, bool as_single_selection) | ||||
|  | @ -134,18 +135,18 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection) | |||
|     case Volume: | ||||
|     { | ||||
|         if ((volume->volume_idx() >= 0) && (is_empty() || (volume->instance_idx() == get_instance_idx()))) | ||||
|             _add_volume(volume_idx); | ||||
|             do_add_volume(volume_idx); | ||||
| 
 | ||||
|         break; | ||||
|     } | ||||
|     case Instance: | ||||
|     { | ||||
|         _add_instance(volume->object_idx(), volume->instance_idx()); | ||||
|         do_add_instance(volume->object_idx(), volume->instance_idx()); | ||||
|         break; | ||||
|     } | ||||
|     } | ||||
| 
 | ||||
|     _update_type(); | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
| } | ||||
| 
 | ||||
|  | @ -160,17 +161,17 @@ void Selection::remove(unsigned int volume_idx) | |||
|     { | ||||
|     case Volume: | ||||
|     { | ||||
|         _remove_volume(volume_idx); | ||||
|         do_remove_volume(volume_idx); | ||||
|         break; | ||||
|     } | ||||
|     case Instance: | ||||
|     { | ||||
|         _remove_instance(volume->object_idx(), volume->instance_idx()); | ||||
|         do_remove_instance(volume->object_idx(), volume->instance_idx()); | ||||
|         break; | ||||
|     } | ||||
|     } | ||||
| 
 | ||||
|     _update_type(); | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
| } | ||||
| 
 | ||||
|  | @ -185,9 +186,9 @@ void Selection::add_object(unsigned int object_idx, bool as_single_selection) | |||
| 
 | ||||
|     m_mode = Instance; | ||||
| 
 | ||||
|     _add_object(object_idx); | ||||
|     do_add_object(object_idx); | ||||
| 
 | ||||
|     _update_type(); | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
| } | ||||
| 
 | ||||
|  | @ -196,9 +197,9 @@ void Selection::remove_object(unsigned int object_idx) | |||
|     if (!m_valid) | ||||
|         return; | ||||
| 
 | ||||
|     _remove_object(object_idx); | ||||
|     do_remove_object(object_idx); | ||||
| 
 | ||||
|     _update_type(); | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
| } | ||||
| 
 | ||||
|  | @ -213,9 +214,9 @@ void Selection::add_instance(unsigned int object_idx, unsigned int instance_idx, | |||
| 
 | ||||
|     m_mode = Instance; | ||||
| 
 | ||||
|     _add_instance(object_idx, instance_idx); | ||||
|     do_add_instance(object_idx, instance_idx); | ||||
| 
 | ||||
|     _update_type(); | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
| } | ||||
| 
 | ||||
|  | @ -224,9 +225,9 @@ void Selection::remove_instance(unsigned int object_idx, unsigned int instance_i | |||
|     if (!m_valid) | ||||
|         return; | ||||
| 
 | ||||
|     _remove_instance(object_idx, instance_idx); | ||||
|     do_remove_instance(object_idx, instance_idx); | ||||
| 
 | ||||
|     _update_type(); | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
| } | ||||
| 
 | ||||
|  | @ -247,11 +248,11 @@ void Selection::add_volume(unsigned int object_idx, unsigned int volume_idx, int | |||
|         if ((v->object_idx() == object_idx) && (v->volume_idx() == volume_idx)) | ||||
|         { | ||||
|             if ((instance_idx != -1) && (v->instance_idx() == instance_idx)) | ||||
|                 _add_volume(i); | ||||
|                 do_add_volume(i); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     _update_type(); | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
| } | ||||
| 
 | ||||
|  | @ -264,10 +265,10 @@ void Selection::remove_volume(unsigned int object_idx, unsigned int volume_idx) | |||
|     { | ||||
|         GLVolume* v = (*m_volumes)[i]; | ||||
|         if ((v->object_idx() == object_idx) && (v->volume_idx() == volume_idx)) | ||||
|             _remove_volume(i); | ||||
|             do_remove_volume(i); | ||||
|     } | ||||
| 
 | ||||
|     _update_type(); | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
| } | ||||
| 
 | ||||
|  | @ -282,10 +283,10 @@ void Selection::add_all() | |||
|     for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) | ||||
|     { | ||||
|         if (!(*m_volumes)[i]->is_wipe_tower) | ||||
|             _add_volume(i); | ||||
|             do_add_volume(i); | ||||
|     } | ||||
| 
 | ||||
|     _update_type(); | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
| } | ||||
| 
 | ||||
|  | @ -301,7 +302,7 @@ void Selection::clear() | |||
| 
 | ||||
|     m_list.clear(); | ||||
| 
 | ||||
|     _update_type(); | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
| 
 | ||||
|     // resets the cache in the sidebar
 | ||||
|  | @ -341,11 +342,11 @@ void Selection::volumes_changed(const std::vector<size_t> &map_volume_old_to_new | |||
|             const GLVolume* volume = (*m_volumes)[i]; | ||||
|             for (const std::pair<int, int> &model_instance : model_instances) | ||||
|                 if (volume->object_idx() == model_instance.first && volume->instance_idx() == model_instance.second) | ||||
|                     this->_add_volume(i); | ||||
|                     do_add_volume(i); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     _update_type(); | ||||
|     update_type(); | ||||
|     m_bounding_box_dirty = true; | ||||
| } | ||||
| 
 | ||||
|  | @ -426,7 +427,7 @@ const GLVolume* Selection::get_volume(unsigned int volume_idx) const | |||
| const BoundingBoxf3& Selection::get_bounding_box() const | ||||
| { | ||||
|     if (m_bounding_box_dirty) | ||||
|         _calc_bounding_box(); | ||||
|         calc_bounding_box(); | ||||
| 
 | ||||
|     return m_bounding_box; | ||||
| } | ||||
|  | @ -436,7 +437,7 @@ void Selection::start_dragging() | |||
|     if (!m_valid) | ||||
|         return; | ||||
| 
 | ||||
|     _set_caches(); | ||||
|     set_caches(); | ||||
| } | ||||
| 
 | ||||
| void Selection::translate(const Vec3d& displacement, bool local) | ||||
|  | @ -460,7 +461,7 @@ void Selection::translate(const Vec3d& displacement, bool local) | |||
|         } | ||||
|         else if (m_mode == Instance) | ||||
|         { | ||||
|             if (_is_from_fully_selected_instance(i)) | ||||
|             if (is_from_fully_selected_instance(i)) | ||||
|                 (*m_volumes)[i]->set_instance_offset(m_cache.volumes_data[i].get_instance_position() + displacement); | ||||
|             else | ||||
|             { | ||||
|  | @ -473,38 +474,14 @@ void Selection::translate(const Vec3d& displacement, bool local) | |||
| 
 | ||||
| #if !DISABLE_INSTANCES_SYNCH | ||||
|     if (translation_type == Instance) | ||||
|         _synchronize_unselected_instances(SYNC_ROTATION_NONE); | ||||
|         synchronize_unselected_instances(SYNC_ROTATION_NONE); | ||||
|     else if (translation_type == Volume) | ||||
|         _synchronize_unselected_volumes(); | ||||
|         synchronize_unselected_volumes(); | ||||
| #endif // !DISABLE_INSTANCES_SYNCH
 | ||||
| 
 | ||||
|     m_bounding_box_dirty = true; | ||||
| } | ||||
| 
 | ||||
| static Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) | ||||
| { | ||||
|     return | ||||
|         // From the current coordinate system to world.
 | ||||
|         Eigen::AngleAxisd(rot_xyz_to(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(rot_xyz_to(1), Vec3d::UnitY()) * Eigen::AngleAxisd(rot_xyz_to(0), Vec3d::UnitX()) * | ||||
|         // From world to the initial coordinate system.
 | ||||
|         Eigen::AngleAxisd(-rot_xyz_from(0), Vec3d::UnitX()) * Eigen::AngleAxisd(-rot_xyz_from(1), Vec3d::UnitY()) * Eigen::AngleAxisd(-rot_xyz_from(2), Vec3d::UnitZ()); | ||||
| } | ||||
| 
 | ||||
| // This should only be called if it is known, that the two rotations only differ in rotation around the Z axis.
 | ||||
| static double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) | ||||
| { | ||||
|     Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); | ||||
|     Vec3d  axis = angle_axis.axis(); | ||||
|     double angle = angle_axis.angle(); | ||||
| #ifndef NDEBUG | ||||
|     if (std::abs(angle) > 1e-8) { | ||||
|         assert(std::abs(axis.x()) < 1e-8); | ||||
|         assert(std::abs(axis.y()) < 1e-8); | ||||
|     } | ||||
| #endif /* NDEBUG */ | ||||
|     return (axis.z() < 0) ? -angle : angle; | ||||
| } | ||||
| 
 | ||||
| // Rotate an object around one of the axes. Only one rotation component is expected to be changing.
 | ||||
| void Selection::rotate(const Vec3d& rotation, TransformationType transformation_type) | ||||
| { | ||||
|  | @ -547,7 +524,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ | |||
|                 assert(is_approx(rotation.z(), 0.0)); | ||||
|                 const GLVolume &first_volume = *(*m_volumes)[first_volume_idx]; | ||||
|                 const Vec3d    &rotation = first_volume.get_instance_rotation(); | ||||
|                 double z_diff = rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation()); | ||||
|                 double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation()); | ||||
|                 volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff)); | ||||
|             } | ||||
|             else { | ||||
|  | @ -604,9 +581,9 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ | |||
| 
 | ||||
| #if !DISABLE_INSTANCES_SYNCH | ||||
|     if (m_mode == Instance) | ||||
|         _synchronize_unselected_instances((rot_axis_max == 2) ? SYNC_ROTATION_NONE : SYNC_ROTATION_GENERAL); | ||||
|         synchronize_unselected_instances((rot_axis_max == 2) ? SYNC_ROTATION_NONE : SYNC_ROTATION_GENERAL); | ||||
|     else if (m_mode == Volume) | ||||
|         _synchronize_unselected_volumes(); | ||||
|         synchronize_unselected_volumes(); | ||||
| #endif // !DISABLE_INSTANCES_SYNCH
 | ||||
| 
 | ||||
|     m_bounding_box_dirty = true; | ||||
|  | @ -647,7 +624,7 @@ void Selection::flattening_rotate(const Vec3d& normal) | |||
|     // we want to synchronize z-rotation as well, otherwise the flattening behaves funny
 | ||||
|     // when applied on one of several identical instances
 | ||||
|     if (m_mode == Instance) | ||||
|         _synchronize_unselected_instances(SYNC_ROTATION_FULL); | ||||
|         synchronize_unselected_instances(SYNC_ROTATION_FULL); | ||||
| #endif // !DISABLE_INSTANCES_SYNCH
 | ||||
| 
 | ||||
|     m_bounding_box_dirty = true; | ||||
|  | @ -694,12 +671,12 @@ void Selection::scale(const Vec3d& scale, bool local) | |||
| 
 | ||||
| #if !DISABLE_INSTANCES_SYNCH | ||||
|     if (m_mode == Instance) | ||||
|         _synchronize_unselected_instances(SYNC_ROTATION_NONE); | ||||
|         synchronize_unselected_instances(SYNC_ROTATION_NONE); | ||||
|     else if (m_mode == Volume) | ||||
|         _synchronize_unselected_volumes(); | ||||
|         synchronize_unselected_volumes(); | ||||
| #endif // !DISABLE_INSTANCES_SYNCH
 | ||||
| 
 | ||||
|     _ensure_on_bed(); | ||||
|     ensure_on_bed(); | ||||
| 
 | ||||
|     m_bounding_box_dirty = true; | ||||
| } | ||||
|  | @ -721,9 +698,9 @@ void Selection::mirror(Axis axis) | |||
| 
 | ||||
| #if !DISABLE_INSTANCES_SYNCH | ||||
|     if (m_mode == Instance) | ||||
|         _synchronize_unselected_instances(SYNC_ROTATION_NONE); | ||||
|         synchronize_unselected_instances(SYNC_ROTATION_NONE); | ||||
|     else if (m_mode == Volume) | ||||
|         _synchronize_unselected_volumes(); | ||||
|         synchronize_unselected_volumes(); | ||||
| #endif // !DISABLE_INSTANCES_SYNCH
 | ||||
| 
 | ||||
|     m_bounding_box_dirty = true; | ||||
|  | @ -941,8 +918,8 @@ void Selection::render(float scale_factor) const | |||
|     m_scale_factor = scale_factor; | ||||
| 
 | ||||
|     // render cumulative bounding box of selected volumes
 | ||||
|     _render_selected_volumes(); | ||||
|     _render_synchronized_volumes(); | ||||
|     render_selected_volumes(); | ||||
|     render_synchronized_volumes(); | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_RENDER_SELECTION_CENTER | ||||
|  | @ -953,17 +930,17 @@ void Selection::render_center() const | |||
| 
 | ||||
|     const Vec3d& center = get_bounding_box().center(); | ||||
| 
 | ||||
|     ::glDisable(GL_DEPTH_TEST); | ||||
|     glsafe(::glDisable(GL_DEPTH_TEST))); | ||||
| 
 | ||||
|     ::glEnable(GL_LIGHTING); | ||||
|     glsafe(::glEnable(GL_LIGHTING)); | ||||
| 
 | ||||
|     ::glColor3f(1.0f, 1.0f, 1.0f); | ||||
|     ::glPushMatrix(); | ||||
|     ::glTranslated(center(0), center(1), center(2)); | ||||
|     ::gluSphere(m_quadric, 0.75, 32, 32); | ||||
|     ::glPopMatrix(); | ||||
|     glsafe(::glColor3f(1.0f, 1.0f, 1.0f)); | ||||
|     glsafe(::glPushMatrix()); | ||||
|     glsafe(::glTranslated(center(0), center(1), center(2))); | ||||
|     glsafe(::gluSphere(m_quadric, 0.75, 32, 32)); | ||||
|     glsafe(::glPopMatrix()); | ||||
| 
 | ||||
|     ::glDisable(GL_LIGHTING); | ||||
|     glsafe(::glDisable(GL_LIGHTING)); | ||||
| } | ||||
| #endif // ENABLE_RENDER_SELECTION_CENTER
 | ||||
| 
 | ||||
|  | @ -972,18 +949,18 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field) const | |||
|     if (sidebar_field.empty()) | ||||
|         return; | ||||
| 
 | ||||
|     ::glClear(GL_DEPTH_BUFFER_BIT); | ||||
|     ::glEnable(GL_DEPTH_TEST); | ||||
|     glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); | ||||
|     glsafe(::glEnable(GL_DEPTH_TEST)); | ||||
| 
 | ||||
|     ::glEnable(GL_LIGHTING); | ||||
|     glsafe(::glEnable(GL_LIGHTING)); | ||||
| 
 | ||||
|     ::glPushMatrix(); | ||||
|     glsafe(::glPushMatrix()); | ||||
| 
 | ||||
|     const Vec3d& center = get_bounding_box().center(); | ||||
| 
 | ||||
|     if (is_single_full_instance()) | ||||
|     { | ||||
|         ::glTranslated(center(0), center(1), center(2)); | ||||
|         glsafe(::glTranslated(center(0), center(1), center(2))); | ||||
|         if (!boost::starts_with(sidebar_field, "position")) | ||||
|         { | ||||
|             Transform3d orient_matrix = Transform3d::Identity(); | ||||
|  | @ -1003,40 +980,40 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field) const | |||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             ::glMultMatrixd(orient_matrix.data()); | ||||
|             glsafe(::glMultMatrixd(orient_matrix.data())); | ||||
|         } | ||||
|     } | ||||
|     else if (is_single_volume() || is_single_modifier()) | ||||
|     { | ||||
|         ::glTranslated(center(0), center(1), center(2)); | ||||
|         glsafe(::glTranslated(center(0), center(1), center(2))); | ||||
|         Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); | ||||
|         if (!boost::starts_with(sidebar_field, "position")) | ||||
|             orient_matrix = orient_matrix * (*m_volumes)[*m_list.begin()]->get_volume_transformation().get_matrix(true, false, true, true); | ||||
| 
 | ||||
|         ::glMultMatrixd(orient_matrix.data()); | ||||
|         glsafe(::glMultMatrixd(orient_matrix.data())); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         ::glTranslated(center(0), center(1), center(2)); | ||||
|         glsafe(::glTranslated(center(0), center(1), center(2))); | ||||
|         if (requires_local_axes()) | ||||
|         { | ||||
|             Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true); | ||||
|             ::glMultMatrixd(orient_matrix.data()); | ||||
|             glsafe(::glMultMatrixd(orient_matrix.data())); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (boost::starts_with(sidebar_field, "position")) | ||||
|         _render_sidebar_position_hints(sidebar_field); | ||||
|         render_sidebar_position_hints(sidebar_field); | ||||
|     else if (boost::starts_with(sidebar_field, "rotation")) | ||||
|         _render_sidebar_rotation_hints(sidebar_field); | ||||
|         render_sidebar_rotation_hints(sidebar_field); | ||||
|     else if (boost::starts_with(sidebar_field, "scale")) | ||||
|         _render_sidebar_scale_hints(sidebar_field); | ||||
|         render_sidebar_scale_hints(sidebar_field); | ||||
|     else if (boost::starts_with(sidebar_field, "size")) | ||||
|         _render_sidebar_size_hints(sidebar_field); | ||||
|         render_sidebar_size_hints(sidebar_field); | ||||
| 
 | ||||
|     ::glPopMatrix(); | ||||
|     glsafe(::glPopMatrix()); | ||||
| 
 | ||||
|     ::glDisable(GL_LIGHTING); | ||||
|     glsafe(::glDisable(GL_LIGHTING)); | ||||
| } | ||||
| 
 | ||||
| bool Selection::requires_local_axes() const | ||||
|  | @ -1044,12 +1021,12 @@ bool Selection::requires_local_axes() const | |||
|     return (m_mode == Volume) && is_from_single_instance(); | ||||
| } | ||||
| 
 | ||||
| void Selection::_update_valid() | ||||
| void Selection::update_valid() | ||||
| { | ||||
|     m_valid = (m_volumes != nullptr) && (m_model != nullptr); | ||||
| } | ||||
| 
 | ||||
| void Selection::_update_type() | ||||
| void Selection::update_type() | ||||
| { | ||||
|     m_cache.content.clear(); | ||||
|     m_type = Mixed; | ||||
|  | @ -1147,15 +1124,11 @@ void Selection::_update_type() | |||
|                         } | ||||
| 
 | ||||
|                         if (modifiers_count == 0) | ||||
|                         { | ||||
|                             m_type = MultipleVolume; | ||||
|                             requires_disable = true; | ||||
|                         } | ||||
|                         else if (modifiers_count == (unsigned int)m_list.size()) | ||||
|                         { | ||||
|                             m_type = MultipleModifier; | ||||
|                             requires_disable = true; | ||||
|                         } | ||||
| 
 | ||||
|                         requires_disable = true; | ||||
|                     } | ||||
|                 } | ||||
|                 else if ((selected_instances_count > 1) && (selected_instances_count * volumes_count == (unsigned int)m_list.size())) | ||||
|  | @ -1277,7 +1250,7 @@ void Selection::_update_type() | |||
| #endif // ENABLE_SELECTION_DEBUG_OUTPUT
 | ||||
| } | ||||
| 
 | ||||
| void Selection::_set_caches() | ||||
| void Selection::set_caches() | ||||
| { | ||||
|     m_cache.volumes_data.clear(); | ||||
|     for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) | ||||
|  | @ -1288,33 +1261,33 @@ void Selection::_set_caches() | |||
|     m_cache.dragging_center = get_bounding_box().center(); | ||||
| } | ||||
| 
 | ||||
| void Selection::_add_volume(unsigned int volume_idx) | ||||
| void Selection::do_add_volume(unsigned int volume_idx) | ||||
| { | ||||
|     m_list.insert(volume_idx); | ||||
|     (*m_volumes)[volume_idx]->selected = true; | ||||
| } | ||||
| 
 | ||||
| void Selection::_add_instance(unsigned int object_idx, unsigned int instance_idx) | ||||
| void Selection::do_add_instance(unsigned int object_idx, unsigned int instance_idx) | ||||
| { | ||||
|     for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) | ||||
|     { | ||||
|         GLVolume* v = (*m_volumes)[i]; | ||||
|         if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx)) | ||||
|             _add_volume(i); | ||||
|             do_add_volume(i); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Selection::_add_object(unsigned int object_idx) | ||||
| void Selection::do_add_object(unsigned int object_idx) | ||||
| { | ||||
|     for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) | ||||
|     { | ||||
|         GLVolume* v = (*m_volumes)[i]; | ||||
|         if (v->object_idx() == object_idx) | ||||
|             _add_volume(i); | ||||
|             do_add_volume(i); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Selection::_remove_volume(unsigned int volume_idx) | ||||
| void Selection::do_remove_volume(unsigned int volume_idx) | ||||
| { | ||||
|     IndicesList::iterator v_it = m_list.find(volume_idx); | ||||
|     if (v_it == m_list.end()) | ||||
|  | @ -1325,27 +1298,27 @@ void Selection::_remove_volume(unsigned int volume_idx) | |||
|     (*m_volumes)[volume_idx]->selected = false; | ||||
| } | ||||
| 
 | ||||
| void Selection::_remove_instance(unsigned int object_idx, unsigned int instance_idx) | ||||
| void Selection::do_remove_instance(unsigned int object_idx, unsigned int instance_idx) | ||||
| { | ||||
|     for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) | ||||
|     { | ||||
|         GLVolume* v = (*m_volumes)[i]; | ||||
|         if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx)) | ||||
|             _remove_volume(i); | ||||
|             do_remove_volume(i); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Selection::_remove_object(unsigned int object_idx) | ||||
| void Selection::do_remove_object(unsigned int object_idx) | ||||
| { | ||||
|     for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) | ||||
|     { | ||||
|         GLVolume* v = (*m_volumes)[i]; | ||||
|         if (v->object_idx() == object_idx) | ||||
|             _remove_volume(i); | ||||
|             do_remove_volume(i); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Selection::_calc_bounding_box() const | ||||
| void Selection::calc_bounding_box() const | ||||
| { | ||||
|     m_bounding_box = BoundingBoxf3(); | ||||
|     if (m_valid) | ||||
|  | @ -1358,13 +1331,13 @@ void Selection::_calc_bounding_box() const | |||
|     m_bounding_box_dirty = false; | ||||
| } | ||||
| 
 | ||||
| void Selection::_render_selected_volumes() const | ||||
| void Selection::render_selected_volumes() const | ||||
| { | ||||
|     float color[3] = { 1.0f, 1.0f, 1.0f }; | ||||
|     _render_bounding_box(get_bounding_box(), color); | ||||
|     render_bounding_box(get_bounding_box(), color); | ||||
| } | ||||
| 
 | ||||
| void Selection::_render_synchronized_volumes() const | ||||
| void Selection::render_synchronized_volumes() const | ||||
| { | ||||
|     if (m_mode == Instance) | ||||
|         return; | ||||
|  | @ -1386,12 +1359,12 @@ void Selection::_render_synchronized_volumes() const | |||
|             if ((v->object_idx() != object_idx) || (v->volume_idx() != volume_idx)) | ||||
|                 continue; | ||||
| 
 | ||||
|             _render_bounding_box(v->transformed_convex_hull_bounding_box(), color); | ||||
|             render_bounding_box(v->transformed_convex_hull_bounding_box(), color); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Selection::_render_bounding_box(const BoundingBoxf3& box, float* color) const | ||||
| void Selection::render_bounding_box(const BoundingBoxf3& box, float* color) const | ||||
| { | ||||
|     if (color == nullptr) | ||||
|         return; | ||||
|  | @ -1400,10 +1373,10 @@ void Selection::_render_bounding_box(const BoundingBoxf3& box, float* color) con | |||
|     Vec3f b_max = box.max.cast<float>(); | ||||
|     Vec3f size = 0.2f * box.size().cast<float>(); | ||||
| 
 | ||||
|     ::glEnable(GL_DEPTH_TEST); | ||||
|     glsafe(::glEnable(GL_DEPTH_TEST)); | ||||
| 
 | ||||
|     ::glColor3fv(color); | ||||
|     ::glLineWidth(2.0f * m_scale_factor); | ||||
|     glsafe(::glColor3fv(color)); | ||||
|     glsafe(::glLineWidth(2.0f * m_scale_factor)); | ||||
| 
 | ||||
|     ::glBegin(GL_LINES); | ||||
| 
 | ||||
|  | @ -1439,109 +1412,109 @@ void Selection::_render_bounding_box(const BoundingBoxf3& box, float* color) con | |||
|     ::glVertex3f(b_min(0), b_max(1), b_max(2)); ::glVertex3f(b_min(0), b_max(1) - size(1), b_max(2)); | ||||
|     ::glVertex3f(b_min(0), b_max(1), b_max(2)); ::glVertex3f(b_min(0), b_max(1), b_max(2) - size(2)); | ||||
| 
 | ||||
|     ::glEnd(); | ||||
|     glsafe(::glEnd()); | ||||
| } | ||||
| 
 | ||||
| void Selection::_render_sidebar_position_hints(const std::string& sidebar_field) const | ||||
| void Selection::render_sidebar_position_hints(const std::string& sidebar_field) const | ||||
| { | ||||
|     if (boost::ends_with(sidebar_field, "x")) | ||||
|     { | ||||
|         ::glRotated(-90.0, 0.0, 0.0, 1.0); | ||||
|         _render_sidebar_position_hint(X); | ||||
|         glsafe(::glRotated(-90.0, 0.0, 0.0, 1.0)); | ||||
|         render_sidebar_position_hint(X); | ||||
|     } | ||||
|     else if (boost::ends_with(sidebar_field, "y")) | ||||
|         _render_sidebar_position_hint(Y); | ||||
|         render_sidebar_position_hint(Y); | ||||
|     else if (boost::ends_with(sidebar_field, "z")) | ||||
|     { | ||||
|         ::glRotated(90.0, 1.0, 0.0, 0.0); | ||||
|         _render_sidebar_position_hint(Z); | ||||
|         glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); | ||||
|         render_sidebar_position_hint(Z); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Selection::_render_sidebar_rotation_hints(const std::string& sidebar_field) const | ||||
| void Selection::render_sidebar_rotation_hints(const std::string& sidebar_field) const | ||||
| { | ||||
|     if (boost::ends_with(sidebar_field, "x")) | ||||
|     { | ||||
|         ::glRotated(90.0, 0.0, 1.0, 0.0); | ||||
|         _render_sidebar_rotation_hint(X); | ||||
|         glsafe(::glRotated(90.0, 0.0, 1.0, 0.0)); | ||||
|         render_sidebar_rotation_hint(X); | ||||
|     } | ||||
|     else if (boost::ends_with(sidebar_field, "y")) | ||||
|     { | ||||
|         ::glRotated(-90.0, 1.0, 0.0, 0.0); | ||||
|         _render_sidebar_rotation_hint(Y); | ||||
|         glsafe(::glRotated(-90.0, 1.0, 0.0, 0.0)); | ||||
|         render_sidebar_rotation_hint(Y); | ||||
|     } | ||||
|     else if (boost::ends_with(sidebar_field, "z")) | ||||
|         _render_sidebar_rotation_hint(Z); | ||||
|         render_sidebar_rotation_hint(Z); | ||||
| } | ||||
| 
 | ||||
| void Selection::_render_sidebar_scale_hints(const std::string& sidebar_field) const | ||||
| void Selection::render_sidebar_scale_hints(const std::string& sidebar_field) const | ||||
| { | ||||
|     bool uniform_scale = requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling(); | ||||
| 
 | ||||
|     if (boost::ends_with(sidebar_field, "x") || uniform_scale) | ||||
|     { | ||||
|         ::glPushMatrix(); | ||||
|         ::glRotated(-90.0, 0.0, 0.0, 1.0); | ||||
|         _render_sidebar_scale_hint(X); | ||||
|         ::glPopMatrix(); | ||||
|         glsafe(::glPushMatrix()); | ||||
|         glsafe(::glRotated(-90.0, 0.0, 0.0, 1.0)); | ||||
|         render_sidebar_scale_hint(X); | ||||
|         glsafe(::glPopMatrix()); | ||||
|     } | ||||
| 
 | ||||
|     if (boost::ends_with(sidebar_field, "y") || uniform_scale) | ||||
|     { | ||||
|         ::glPushMatrix(); | ||||
|         _render_sidebar_scale_hint(Y); | ||||
|         ::glPopMatrix(); | ||||
|         glsafe(::glPushMatrix()); | ||||
|         render_sidebar_scale_hint(Y); | ||||
|         glsafe(::glPopMatrix()); | ||||
|     } | ||||
| 
 | ||||
|     if (boost::ends_with(sidebar_field, "z") || uniform_scale) | ||||
|     { | ||||
|         ::glPushMatrix(); | ||||
|         ::glRotated(90.0, 1.0, 0.0, 0.0); | ||||
|         _render_sidebar_scale_hint(Z); | ||||
|         ::glPopMatrix(); | ||||
|         glsafe(::glPushMatrix()); | ||||
|         glsafe(::glRotated(90.0, 1.0, 0.0, 0.0)); | ||||
|         render_sidebar_scale_hint(Z); | ||||
|         glsafe(::glPopMatrix()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Selection::_render_sidebar_size_hints(const std::string& sidebar_field) const | ||||
| void Selection::render_sidebar_size_hints(const std::string& sidebar_field) const | ||||
| { | ||||
|     _render_sidebar_scale_hints(sidebar_field); | ||||
|     render_sidebar_scale_hints(sidebar_field); | ||||
| } | ||||
| 
 | ||||
| void Selection::_render_sidebar_position_hint(Axis axis) const | ||||
| void Selection::render_sidebar_position_hint(Axis axis) const | ||||
| { | ||||
|     m_arrow.set_color(AXES_COLOR[axis], 3); | ||||
|     m_arrow.render(); | ||||
| } | ||||
| 
 | ||||
| void Selection::_render_sidebar_rotation_hint(Axis axis) const | ||||
| void Selection::render_sidebar_rotation_hint(Axis axis) const | ||||
| { | ||||
|     m_curved_arrow.set_color(AXES_COLOR[axis], 3); | ||||
|     m_curved_arrow.render(); | ||||
| 
 | ||||
|     ::glRotated(180.0, 0.0, 0.0, 1.0); | ||||
|     glsafe(::glRotated(180.0, 0.0, 0.0, 1.0)); | ||||
|     m_curved_arrow.render(); | ||||
| } | ||||
| 
 | ||||
| void Selection::_render_sidebar_scale_hint(Axis axis) const | ||||
| void Selection::render_sidebar_scale_hint(Axis axis) const | ||||
| { | ||||
|     m_arrow.set_color(((requires_uniform_scale() || wxGetApp().obj_manipul()->get_uniform_scaling()) ? UNIFORM_SCALE_COLOR : AXES_COLOR[axis]), 3); | ||||
| 
 | ||||
|     ::glTranslated(0.0, 5.0, 0.0); | ||||
|     glsafe(::glTranslated(0.0, 5.0, 0.0)); | ||||
|     m_arrow.render(); | ||||
| 
 | ||||
|     ::glTranslated(0.0, -10.0, 0.0); | ||||
|     ::glRotated(180.0, 0.0, 0.0, 1.0); | ||||
|     glsafe(::glTranslated(0.0, -10.0, 0.0)); | ||||
|     glsafe(::glRotated(180.0, 0.0, 0.0, 1.0)); | ||||
|     m_arrow.render(); | ||||
| } | ||||
| 
 | ||||
| void Selection::_render_sidebar_size_hint(Axis axis, double length) const | ||||
| void Selection::render_sidebar_size_hint(Axis axis, double length) const | ||||
| { | ||||
| } | ||||
| 
 | ||||
| #ifndef NDEBUG | ||||
| static bool is_rotation_xy_synchronized(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) | ||||
| { | ||||
|     Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); | ||||
|     Eigen::AngleAxisd angle_axis(Geometry::rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); | ||||
|     Vec3d  axis = angle_axis.axis(); | ||||
|     double angle = angle_axis.angle(); | ||||
|     if (std::abs(angle) < 1e-8) | ||||
|  | @ -1575,7 +1548,7 @@ static void verify_instances_rotation_synchronized(const Model &model, const GLV | |||
| } | ||||
| #endif /* NDEBUG */ | ||||
| 
 | ||||
| void Selection::_synchronize_unselected_instances(SyncRotationType sync_rotation_type) | ||||
| void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_type) | ||||
| { | ||||
|     std::set<unsigned int> done;  // prevent processing volumes twice
 | ||||
|     done.insert(m_list.begin(), m_list.end()); | ||||
|  | @ -1621,7 +1594,7 @@ void Selection::_synchronize_unselected_instances(SyncRotationType sync_rotation | |||
|                 break; | ||||
|             case SYNC_ROTATION_GENERAL: | ||||
|                 // generic rotation -> update instance z with the delta of the rotation.
 | ||||
|                 double z_diff = rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation()); | ||||
|                 double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation()); | ||||
|                 v->set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff)); | ||||
|                 break; | ||||
|             } | ||||
|  | @ -1638,7 +1611,7 @@ void Selection::_synchronize_unselected_instances(SyncRotationType sync_rotation | |||
| #endif /* NDEBUG */ | ||||
| } | ||||
| 
 | ||||
| void Selection::_synchronize_unselected_volumes() | ||||
| void Selection::synchronize_unselected_volumes() | ||||
| { | ||||
|     for (unsigned int i : m_list) | ||||
|     { | ||||
|  | @ -1671,7 +1644,7 @@ void Selection::_synchronize_unselected_volumes() | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void Selection::_ensure_on_bed() | ||||
| void Selection::ensure_on_bed() | ||||
| { | ||||
|     typedef std::map<std::pair<int, int>, double> InstancesToZMap; | ||||
|     InstancesToZMap instances_min_z; | ||||
|  | @ -1699,7 +1672,7 @@ void Selection::_ensure_on_bed() | |||
|     } | ||||
| } | ||||
| 
 | ||||
| bool Selection::_is_from_fully_selected_instance(unsigned int volume_idx) const | ||||
| bool Selection::is_from_fully_selected_instance(unsigned int volume_idx) const | ||||
| { | ||||
|     struct SameInstance | ||||
|     { | ||||
|  |  | |||
|  | @ -133,10 +133,12 @@ private: | |||
|         const Transform3d& get_instance_full_matrix() const { return m_instance.full_matrix; } | ||||
|     }; | ||||
| 
 | ||||
| public: | ||||
|     typedef std::map<unsigned int, VolumeCache> VolumesCache; | ||||
|     typedef std::set<int> InstanceIdxsList; | ||||
|     typedef std::map<int, InstanceIdxsList> ObjectIdxsToInstanceIdxsMap; | ||||
| 
 | ||||
| private: | ||||
|     struct Cache | ||||
|     { | ||||
|         // Cache of GLVolume derived transformation matrices, valid during mouse dragging.
 | ||||
|  | @ -265,27 +267,27 @@ public: | |||
|     bool requires_local_axes() const; | ||||
| 
 | ||||
| private: | ||||
|     void _update_valid(); | ||||
|     void _update_type(); | ||||
|     void _set_caches(); | ||||
|     void _add_volume(unsigned int volume_idx); | ||||
|     void _add_instance(unsigned int object_idx, unsigned int instance_idx); | ||||
|     void _add_object(unsigned int object_idx); | ||||
|     void _remove_volume(unsigned int volume_idx); | ||||
|     void _remove_instance(unsigned int object_idx, unsigned int instance_idx); | ||||
|     void _remove_object(unsigned int object_idx); | ||||
|     void _calc_bounding_box() const; | ||||
|     void _render_selected_volumes() const; | ||||
|     void _render_synchronized_volumes() const; | ||||
|     void _render_bounding_box(const BoundingBoxf3& box, float* color) const; | ||||
|     void _render_sidebar_position_hints(const std::string& sidebar_field) const; | ||||
|     void _render_sidebar_rotation_hints(const std::string& sidebar_field) const; | ||||
|     void _render_sidebar_scale_hints(const std::string& sidebar_field) const; | ||||
|     void _render_sidebar_size_hints(const std::string& sidebar_field) const; | ||||
|     void _render_sidebar_position_hint(Axis axis) const; | ||||
|     void _render_sidebar_rotation_hint(Axis axis) const; | ||||
|     void _render_sidebar_scale_hint(Axis axis) const; | ||||
|     void _render_sidebar_size_hint(Axis axis, double length) const; | ||||
|     void update_valid(); | ||||
|     void update_type(); | ||||
|     void set_caches(); | ||||
|     void do_add_volume(unsigned int volume_idx); | ||||
|     void do_add_instance(unsigned int object_idx, unsigned int instance_idx); | ||||
|     void do_add_object(unsigned int object_idx); | ||||
|     void do_remove_volume(unsigned int volume_idx); | ||||
|     void do_remove_instance(unsigned int object_idx, unsigned int instance_idx); | ||||
|     void do_remove_object(unsigned int object_idx); | ||||
|     void calc_bounding_box() const; | ||||
|     void render_selected_volumes() const; | ||||
|     void render_synchronized_volumes() const; | ||||
|     void render_bounding_box(const BoundingBoxf3& box, float* color) const; | ||||
|     void render_sidebar_position_hints(const std::string& sidebar_field) const; | ||||
|     void render_sidebar_rotation_hints(const std::string& sidebar_field) const; | ||||
|     void render_sidebar_scale_hints(const std::string& sidebar_field) const; | ||||
|     void render_sidebar_size_hints(const std::string& sidebar_field) const; | ||||
|     void render_sidebar_position_hint(Axis axis) const; | ||||
|     void render_sidebar_rotation_hint(Axis axis) const; | ||||
|     void render_sidebar_scale_hint(Axis axis) const; | ||||
|     void render_sidebar_size_hint(Axis axis, double length) const; | ||||
|     enum SyncRotationType { | ||||
|         // Do not synchronize rotation. Either not rotating at all, or rotating by world Z axis.
 | ||||
|         SYNC_ROTATION_NONE = 0, | ||||
|  | @ -294,10 +296,10 @@ private: | |||
|         // Synchronize after rotation by an axis not parallel with Z.
 | ||||
|         SYNC_ROTATION_GENERAL = 2, | ||||
|     }; | ||||
|     void _synchronize_unselected_instances(SyncRotationType sync_rotation_type); | ||||
|     void _synchronize_unselected_volumes(); | ||||
|     void _ensure_on_bed(); | ||||
|     bool _is_from_fully_selected_instance(unsigned int volume_idx) const; | ||||
|     void synchronize_unselected_instances(SyncRotationType sync_rotation_type); | ||||
|     void synchronize_unselected_volumes(); | ||||
|     void ensure_on_bed(); | ||||
|     bool is_from_fully_selected_instance(unsigned int volume_idx) const; | ||||
| }; | ||||
| 
 | ||||
| } // namespace GUI
 | ||||
|  |  | |||
|  | @ -52,9 +52,7 @@ SysInfoDialog::SysInfoDialog() | |||
| 	main_sizer->Add(hsizer, 1, wxEXPAND | wxALL, 10); | ||||
| 
 | ||||
|     // logo
 | ||||
| // 	wxBitmap logo_bmp = wxBitmap(from_u8(Slic3r::var("Slic3r_192px.png")), wxBITMAP_TYPE_PNG);
 | ||||
| //     auto *logo = new wxStaticBitmap(this, wxID_ANY, std::move(logo_bmp));
 | ||||
|     auto *logo = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("Slic3r_192px.png")); | ||||
|     auto *logo = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("Slic3r_192px.png", 192)); | ||||
| 	hsizer->Add(logo, 0, wxALIGN_CENTER_VERTICAL); | ||||
|      | ||||
|     wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL); | ||||
|  |  | |||
|  | @ -116,18 +116,14 @@ void Tab::create_preset_tab() | |||
| 
 | ||||
| 	//buttons
 | ||||
| 	wxBitmap bmpMenu; | ||||
| // 	bmpMenu = wxBitmap(from_u8(Slic3r::var("disk.png")), wxBITMAP_TYPE_PNG);
 | ||||
|     bmpMenu = create_scaled_bitmap("disk.png"); | ||||
| 	m_btn_save_preset = new wxBitmapButton(panel, wxID_ANY, bmpMenu, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); | ||||
| 	if (wxMSW) m_btn_save_preset->SetBackgroundColour(color); | ||||
| // 	bmpMenu = wxBitmap(from_u8(Slic3r::var("delete.png")), wxBITMAP_TYPE_PNG);
 | ||||
|     bmpMenu = create_scaled_bitmap("delete.png"); | ||||
| 	m_btn_delete_preset = new wxBitmapButton(panel, wxID_ANY, bmpMenu, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); | ||||
| 	if (wxMSW) m_btn_delete_preset->SetBackgroundColour(color); | ||||
| 
 | ||||
| 	m_show_incompatible_presets = false; | ||||
| // 	m_bmp_show_incompatible_presets.LoadFile(from_u8(Slic3r::var("flag-red-icon.png")), wxBITMAP_TYPE_PNG);
 | ||||
| // 	m_bmp_hide_incompatible_presets.LoadFile(from_u8(Slic3r::var("flag-green-icon.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 	m_bmp_show_incompatible_presets = create_scaled_bitmap("flag-red-icon.png"); | ||||
| 	m_bmp_hide_incompatible_presets = create_scaled_bitmap("flag-green-icon.png"); | ||||
| 	m_btn_hide_incompatible_presets = new wxBitmapButton(panel, wxID_ANY, m_bmp_hide_incompatible_presets, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); | ||||
|  | @ -152,15 +148,10 @@ void Tab::create_preset_tab() | |||
| 	// Determine the theme color of OS (dark or light)
 | ||||
|     auto luma = wxGetApp().get_colour_approx_luma(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); | ||||
| 	// Bitmaps to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
 | ||||
| // 	m_bmp_value_lock  	  .LoadFile(from_u8(var("sys_lock.png")),     wxBITMAP_TYPE_PNG);
 | ||||
| // 	m_bmp_value_unlock    .LoadFile(from_u8(var(luma >= 128 ? "sys_unlock.png" : "sys_unlock_grey.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 	m_bmp_value_lock  	   = create_scaled_bitmap("sys_lock.png"); | ||||
| 	m_bmp_value_unlock     = create_scaled_bitmap(luma >= 128 ? "sys_unlock.png" : "sys_unlock_grey.png"); | ||||
| 	m_bmp_non_system = &m_bmp_white_bullet; | ||||
| 	// Bitmaps to be shown on the "Undo user changes" button next to each input field.
 | ||||
| // 	m_bmp_value_revert    .LoadFile(from_u8(var(luma >= 128 ? "action_undo.png" : "action_undo_grey.png")), wxBITMAP_TYPE_PNG);
 | ||||
| // 	m_bmp_white_bullet    .LoadFile(from_u8(var("bullet_white.png")), wxBITMAP_TYPE_PNG);
 | ||||
| // 	m_bmp_question        .LoadFile(from_u8(var("question_mark_01.png")), wxBITMAP_TYPE_PNG);
 | ||||
| 	m_bmp_value_revert    = create_scaled_bitmap(luma >= 128 ? "action_undo.png" : "action_undo_grey.png"); | ||||
| 	m_bmp_white_bullet    = create_scaled_bitmap("bullet_white.png"); | ||||
| 	m_bmp_question        = create_scaled_bitmap("question_mark_01.png"); | ||||
|  | @ -954,7 +945,7 @@ void TabPrint::build() | |||
| 	m_presets = &m_preset_bundle->prints; | ||||
| 	load_initial_data(); | ||||
| 
 | ||||
| 	auto page = add_options_page(_(L("Layers and perimeters")), "layers.png"); | ||||
| 	auto page = add_options_page(_(L("Layers and perimeters")), "layers"); | ||||
| 		auto optgroup = page->new_optgroup(_(L("Layer height"))); | ||||
| 		optgroup->append_single_option_line("layer_height"); | ||||
| 		optgroup->append_single_option_line("first_layer_height"); | ||||
|  | @ -987,7 +978,7 @@ void TabPrint::build() | |||
| 		optgroup->append_single_option_line("seam_position"); | ||||
| 		optgroup->append_single_option_line("external_perimeters_first"); | ||||
| 
 | ||||
| 	page = add_options_page(_(L("Infill")), "infill.png"); | ||||
| 	page = add_options_page(_(L("Infill")), "infill"); | ||||
| 		optgroup = page->new_optgroup(_(L("Infill"))); | ||||
| 		optgroup->append_single_option_line("fill_density"); | ||||
| 		optgroup->append_single_option_line("fill_pattern"); | ||||
|  | @ -1006,7 +997,7 @@ void TabPrint::build() | |||
| 		optgroup->append_single_option_line("only_retract_when_crossing_perimeters"); | ||||
| 		optgroup->append_single_option_line("infill_first"); | ||||
| 
 | ||||
| 	page = add_options_page(_(L("Skirt and brim")), "box.png"); | ||||
| 	page = add_options_page(_(L("Skirt and brim")), "skirt+brim"); | ||||
| 		optgroup = page->new_optgroup(_(L("Skirt"))); | ||||
| 		optgroup->append_single_option_line("skirts"); | ||||
| 		optgroup->append_single_option_line("skirt_distance"); | ||||
|  | @ -1016,7 +1007,7 @@ void TabPrint::build() | |||
| 		optgroup = page->new_optgroup(_(L("Brim"))); | ||||
| 		optgroup->append_single_option_line("brim_width"); | ||||
| 
 | ||||
| 	page = add_options_page(_(L("Support material")), "building.png"); | ||||
| 	page = add_options_page(_(L("Support material")), "support"); | ||||
| 		optgroup = page->new_optgroup(_(L("Support material"))); | ||||
| 		optgroup->append_single_option_line("support_material"); | ||||
| 		optgroup->append_single_option_line("support_material_auto"); | ||||
|  | @ -1041,7 +1032,7 @@ void TabPrint::build() | |||
| 		optgroup->append_single_option_line("dont_support_bridges"); | ||||
| 		optgroup->append_single_option_line("support_material_synchronize_layers"); | ||||
| 
 | ||||
| 	page = add_options_page(_(L("Speed")), "time.png"); | ||||
| 	page = add_options_page(_(L("Speed")), "time"); | ||||
| 		optgroup = page->new_optgroup(_(L("Speed for print moves"))); | ||||
| 		optgroup->append_single_option_line("perimeter_speed"); | ||||
| 		optgroup->append_single_option_line("small_perimeter_speed"); | ||||
|  | @ -1075,7 +1066,7 @@ void TabPrint::build() | |||
| 		optgroup->append_single_option_line("max_volumetric_extrusion_rate_slope_negative"); | ||||
| #endif /* HAS_PRESSURE_EQUALIZER */ | ||||
| 
 | ||||
| 	page = add_options_page(_(L("Multiple Extruders")), "funnel.png"); | ||||
| 	page = add_options_page(_(L("Multiple Extruders")), "funnel"); | ||||
| 		optgroup = page->new_optgroup(_(L("Extruders"))); | ||||
| 		optgroup->append_single_option_line("perimeter_extruder"); | ||||
| 		optgroup->append_single_option_line("infill_extruder"); | ||||
|  | @ -1125,7 +1116,7 @@ void TabPrint::build() | |||
| 		optgroup = page->new_optgroup(_(L("Other"))); | ||||
| 		optgroup->append_single_option_line("clip_multipart_objects"); | ||||
| 
 | ||||
| 	page = add_options_page(_(L("Output options")), "page_white_go.png"); | ||||
| 	page = add_options_page(_(L("Output options")), "output+page_white"); | ||||
| 		optgroup = page->new_optgroup(_(L("Sequential printing"))); | ||||
| 		optgroup->append_single_option_line("complete_objects"); | ||||
| 		line = { _(L("Extruder clearance (mm)")), "" }; | ||||
|  | @ -1446,7 +1437,7 @@ void TabFilament::build() | |||
| 		line.append_option(optgroup->get_option("bed_temperature")); | ||||
| 		optgroup->append_line(line); | ||||
| 
 | ||||
| 	page = add_options_page(_(L("Cooling")), "hourglass.png"); | ||||
| 	page = add_options_page(_(L("Cooling")), "cooling"); | ||||
| 		optgroup = page->new_optgroup(_(L("Enable"))); | ||||
| 		optgroup->append_single_option_line("fan_always_on"); | ||||
| 		optgroup->append_single_option_line("cooling"); | ||||
|  | @ -1520,7 +1511,7 @@ void TabFilament::build() | |||
|         const int gcode_field_height = 15 * m_em_unit; // 150
 | ||||
|         const int notes_field_height = 25 * m_em_unit; // 250
 | ||||
| 
 | ||||
|         page = add_options_page(_(L("Custom G-code")), "cog.png"); | ||||
|         page = add_options_page(_(L("Custom G-code")), "cog"); | ||||
| 		optgroup = page->new_optgroup(_(L("Start G-code")), 0); | ||||
| 		Option option = optgroup->get_option("start_filament_gcode"); | ||||
| 		option.opt.full_width = true; | ||||
|  | @ -1638,7 +1629,8 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup) | |||
| 	} | ||||
| 
 | ||||
| 	auto printhost_browse = [=](wxWindow* parent) { | ||||
| 		auto btn = m_printhost_browse_btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT); | ||||
|         auto btn = m_printhost_browse_btn = new wxButton(parent, wxID_ANY, _(L(" Browse ")) + dots,  | ||||
|             wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); | ||||
| 		btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); | ||||
|         btn->SetBitmap(create_scaled_bitmap("zoom.png")); | ||||
| 		auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
|  | @ -1695,7 +1687,6 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup) | |||
| 
 | ||||
| 		auto printhost_cafile_browse = [this, optgroup] (wxWindow* parent) { | ||||
| 			auto btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT); | ||||
| // 			btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("zoom.png")), wxBITMAP_TYPE_PNG));
 | ||||
| 			btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); | ||||
| 			btn->SetBitmap(create_scaled_bitmap("zoom.png")); | ||||
| 			auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
|  | @ -1768,15 +1759,14 @@ void TabPrinter::build_fff() | |||
| 	m_sys_extruders_count = parent_preset == nullptr ? 0 : | ||||
| 			static_cast<const ConfigOptionFloats*>(parent_preset->config.option("nozzle_diameter"))->values.size(); | ||||
| 
 | ||||
| 	auto page = add_options_page(_(L("General")), "printer_empty.png"); | ||||
| 	auto page = add_options_page(_(L("General")), "printer"); | ||||
| 		auto optgroup = page->new_optgroup(_(L("Size and coordinates"))); | ||||
| 
 | ||||
|         Line line = optgroup->create_single_option_line("bed_shape");//{ _(L("Bed shape")), "" };
 | ||||
| 		line.widget = [this](wxWindow* parent) { | ||||
| 			auto btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); | ||||
|             btn->SetFont(wxGetApp().small_font()); | ||||
| // 			btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("printer_empty.png")), wxBITMAP_TYPE_PNG));
 | ||||
|             btn->SetBitmap(create_scaled_bitmap("printer_empty.png")); | ||||
|             btn->SetBitmap(create_scaled_bitmap("printer")); | ||||
| 
 | ||||
| 			auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
| 			sizer->Add(btn); | ||||
|  | @ -1905,7 +1895,7 @@ void TabPrinter::build_fff() | |||
| 
 | ||||
|     const int gcode_field_height = 15 * m_em_unit; // 150
 | ||||
|     const int notes_field_height = 25 * m_em_unit; // 250
 | ||||
| 	page = add_options_page(_(L("Custom G-code")), "cog.png"); | ||||
| 	page = add_options_page(_(L("Custom G-code")), "cog"); | ||||
| 		optgroup = page->new_optgroup(_(L("Start G-code")), 0); | ||||
| 		option = optgroup->get_option("start_gcode"); | ||||
| 		option.opt.full_width = true; | ||||
|  | @ -1970,15 +1960,14 @@ void TabPrinter::build_sla() | |||
| { | ||||
|     if (!m_pages.empty()) | ||||
|         m_pages.resize(0); | ||||
|     auto page = add_options_page(_(L("General")), "printer_empty.png"); | ||||
|     auto page = add_options_page(_(L("General")), "printer"); | ||||
|     auto optgroup = page->new_optgroup(_(L("Size and coordinates"))); | ||||
| 
 | ||||
|     Line line = optgroup->create_single_option_line("bed_shape");//{ _(L("Bed shape")), "" };
 | ||||
|     line.widget = [this](wxWindow* parent) { | ||||
|         auto btn = new wxButton(parent, wxID_ANY, _(L(" Set ")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); | ||||
|         btn->SetFont(wxGetApp().small_font()); | ||||
| //         btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("printer_empty.png")), wxBITMAP_TYPE_PNG));
 | ||||
|         btn->SetBitmap(create_scaled_bitmap("printer_empty.png")); | ||||
|         btn->SetBitmap(create_scaled_bitmap("printer")); | ||||
| 
 | ||||
|         auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
|         sizer->Add(btn); | ||||
|  | @ -2080,7 +2069,7 @@ void TabPrinter::append_option_line(ConfigOptionsGroupShp optgroup, const std::s | |||
| 
 | ||||
| PageShp TabPrinter::build_kinematics_page() | ||||
| { | ||||
| 	auto page = add_options_page(_(L("Machine limits")), "cog.png", true); | ||||
| 	auto page = add_options_page(_(L("Machine limits")), "cog", true); | ||||
| 
 | ||||
| 	if (m_use_silent_mode)	{ | ||||
| 		// Legend for OptionsGroups
 | ||||
|  | @ -2172,7 +2161,7 @@ void TabPrinter::build_extruder_pages() | |||
| 	} | ||||
| 	if (m_extruders_count > 1 && m_config->opt_bool("single_extruder_multi_material") && !m_has_single_extruder_MM_page) { | ||||
| 		// create a page, but pretend it's an extruder page, so we can add it to m_pages ourselves
 | ||||
| 		auto page = add_options_page(_(L("Single extruder MM setup")), "printer_empty.png", true); | ||||
| 		auto page = add_options_page(_(L("Single extruder MM setup")), "printer", true); | ||||
| 		auto optgroup = page->new_optgroup(_(L("Single extruder multimaterial parameters"))); | ||||
| 		optgroup->append_single_option_line("cooling_tube_retraction"); | ||||
| 		optgroup->append_single_option_line("cooling_tube_length"); | ||||
|  | @ -2188,7 +2177,7 @@ void TabPrinter::build_extruder_pages() | |||
| 		//# build page
 | ||||
| 		char buf[512]; | ||||
| 		sprintf(buf, _CHB(L("Extruder %d")), extruder_idx + 1); | ||||
| 		auto page = add_options_page(from_u8(buf), "funnel.png", true); | ||||
| 		auto page = add_options_page(from_u8(buf), "funnel", true); | ||||
| 		m_pages.insert(m_pages.begin() + n_before_extruders + extruder_idx, page); | ||||
| 			 | ||||
| 			auto optgroup = page->new_optgroup(_(L("Size"))); | ||||
|  | @ -2920,8 +2909,7 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep | |||
| 	deps.btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); | ||||
| 	deps.btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); | ||||
| 
 | ||||
| // 	deps.btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("printer_empty.png")), wxBITMAP_TYPE_PNG));
 | ||||
|     deps.btn->SetBitmap(create_scaled_bitmap("printer_empty.png")); | ||||
|     deps.btn->SetBitmap(create_scaled_bitmap("printer")); | ||||
| 
 | ||||
| 	auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
| 	sizer->Add((deps.checkbox), 0, wxALIGN_CENTER_VERTICAL); | ||||
|  | @ -3112,7 +3100,6 @@ ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_la | |||
|             bmp_name = mode == comExpert   ? "mode_expert_.png" : | ||||
|                        mode == comAdvanced ? "mode_middle_.png" : "mode_simple_.png"; | ||||
|         }                                | ||||
| //         auto bmp = new wxStaticBitmap(parent, wxID_ANY, bmp_name.empty() ? wxNullBitmap : wxBitmap(from_u8(var(bmp_name)), wxBITMAP_TYPE_PNG));
 | ||||
|         auto bmp = new wxStaticBitmap(parent, wxID_ANY, bmp_name.empty() ? wxNullBitmap : create_scaled_bitmap(bmp_name)); | ||||
|         bmp->SetBackgroundStyle(wxBG_STYLE_PAINT); | ||||
|         return bmp; | ||||
|  | @ -3311,13 +3298,13 @@ void TabSLAPrint::build() | |||
|     m_presets = &m_preset_bundle->sla_prints; | ||||
|     load_initial_data(); | ||||
| 
 | ||||
|     auto page = add_options_page(_(L("Layers and perimeters")), "package_green.png"); | ||||
|     auto page = add_options_page(_(L("Layers and perimeters")), "layers"); | ||||
| 
 | ||||
|     auto optgroup = page->new_optgroup(_(L("Layers"))); | ||||
|     optgroup->append_single_option_line("layer_height"); | ||||
|     optgroup->append_single_option_line("faded_layers"); | ||||
| 
 | ||||
|     page = add_options_page(_(L("Supports")), "building.png"); | ||||
|     page = add_options_page(_(L("Supports")), "sla_supports"); | ||||
|     optgroup = page->new_optgroup(_(L("Supports"))); | ||||
|     optgroup->append_single_option_line("supports_enable"); | ||||
| 
 | ||||
|  | @ -3355,17 +3342,17 @@ void TabSLAPrint::build() | |||
| //    optgroup->append_single_option_line("pad_edge_radius");
 | ||||
|     optgroup->append_single_option_line("pad_wall_slope"); | ||||
| 
 | ||||
| 	page = add_options_page(_(L("Advanced")), "wrench.png"); | ||||
| 	page = add_options_page(_(L("Advanced")), "wrench"); | ||||
| 	optgroup = page->new_optgroup(_(L("Slicing"))); | ||||
| 	optgroup->append_single_option_line("slice_closing_radius"); | ||||
| 
 | ||||
| 	page = add_options_page(_(L("Output options")), "page_white_go.png"); | ||||
| 	page = add_options_page(_(L("Output options")), "output+page_white"); | ||||
| 	optgroup = page->new_optgroup(_(L("Output file"))); | ||||
| 	Option option = optgroup->get_option("output_filename_format"); | ||||
| 	option.opt.full_width = true; | ||||
| 	optgroup->append_single_option_line(option); | ||||
| 
 | ||||
|     page = add_options_page(_(L("Dependencies")), "wrench.png"); | ||||
|     page = add_options_page(_(L("Dependencies")), "wrench"); | ||||
|     optgroup = page->new_optgroup(_(L("Profile dependencies"))); | ||||
|     Line line = optgroup->create_single_option_line("compatible_printers");//Line { _(L("Compatible printers")), "" };
 | ||||
|     line.widget = [this](wxWindow* parent) { | ||||
|  |  | |||
|  | @ -8,6 +8,8 @@ | |||
| #include <wx/dcclient.h> | ||||
| #include <wx/numformatter.h> | ||||
| 
 | ||||
| #include <boost/algorithm/string/replace.hpp> | ||||
| 
 | ||||
| #include "BitmapCache.hpp" | ||||
| #include "GUI.hpp" | ||||
| #include "GUI_App.hpp" | ||||
|  | @ -416,31 +418,42 @@ void PrusaCollapsiblePaneMSW::Collapse(bool collapse) | |||
| } | ||||
| #endif //__WXMSW__
 | ||||
| 
 | ||||
| 
 | ||||
| // If an icon has horizontal orientation (width > height) call this function with is_horizontal = true
 | ||||
| bool load_scaled_bitmap(wxBitmap** bmp, const std::string& bmp_name_in, const int px_cnt/* = 16*/, const bool is_horizontal /*= false*/) | ||||
| { | ||||
|     static Slic3r::GUI::BitmapCache cache; | ||||
| 
 | ||||
|     unsigned int height, width = height = 0; | ||||
|     unsigned int& scale_base = is_horizontal ? width : height; | ||||
|     scale_base = (unsigned int)(Slic3r::GUI::wxGetApp().em_unit() * px_cnt * 0.1f + 0.5f); | ||||
| 
 | ||||
|     std::string bmp_name = bmp_name_in; | ||||
| 	boost::replace_last(bmp_name, ".png", ""); | ||||
|     *bmp = cache.load_svg(bmp_name, width, height); | ||||
|     if (*bmp == nullptr) | ||||
|         *bmp = cache.load_png(bmp_name, width, height); | ||||
|     return *bmp != nullptr; | ||||
| } | ||||
| 
 | ||||
| // If an icon has horizontal orientation (width > height) call this function with is_horizontal = true
 | ||||
| wxBitmap create_scaled_bitmap(const std::string& bmp_name_in, const int px_cnt/* = 16*/, const bool is_horizontal /* = false*/) | ||||
| { | ||||
|     wxBitmap *bmp {nullptr}; | ||||
|     load_scaled_bitmap(&bmp, bmp_name_in, px_cnt, is_horizontal); | ||||
|     return *bmp; | ||||
| } | ||||
| 
 | ||||
| // *****************************************************************************
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| // PrusaObjectDataViewModelNode
 | ||||
| // ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| wxBitmap create_scaled_bitmap(const std::string& bmp_name) | ||||
| { | ||||
|     const double scale_f = Slic3r::GUI::wxGetApp().em_unit()* 0.1;//GetContentScaleFactor();
 | ||||
|     if (scale_f == 1.0) | ||||
|         return wxBitmap(Slic3r::GUI::from_u8(Slic3r::var(bmp_name)), wxBITMAP_TYPE_PNG); | ||||
| //     else if (scale_f == 2.0) // use biger icon
 | ||||
| //         return wxBitmap(Slic3r::GUI::from_u8(Slic3r::var(bmp_name_X2)), wxBITMAP_TYPE_PNG);
 | ||||
| 
 | ||||
|     wxImage img = wxImage(Slic3r::GUI::from_u8(Slic3r::var(bmp_name)), wxBITMAP_TYPE_PNG); | ||||
|     const int sz_w = int(img.GetWidth()*scale_f); | ||||
|     const int sz_h = int(img.GetHeight()*scale_f); | ||||
|     img.Rescale(sz_w, sz_h, wxIMAGE_QUALITY_BILINEAR); | ||||
|     return wxBitmap(img); | ||||
| } | ||||
| 
 | ||||
| void PrusaObjectDataViewModelNode::set_object_action_icon() { | ||||
|     m_action_icon = create_scaled_bitmap("add_object.png"); | ||||
| } | ||||
| void  PrusaObjectDataViewModelNode::set_part_action_icon() { | ||||
|     m_action_icon = create_scaled_bitmap(m_type == itVolume ? "cog.png" : "brick_go.png"); | ||||
|     m_action_icon = create_scaled_bitmap(m_type == itVolume ? "cog" : "brick_go.png"); | ||||
| } | ||||
| 
 | ||||
| Slic3r::GUI::BitmapCache *m_bitmap_cache = nullptr; | ||||
|  | @ -1239,6 +1252,32 @@ unsigned int PrusaObjectDataViewModel::GetChildren(const wxDataViewItem &parent, | |||
| 	return count; | ||||
| } | ||||
| 
 | ||||
| void PrusaObjectDataViewModel::GetAllChildren(const wxDataViewItem &parent, wxDataViewItemArray &array) const | ||||
| { | ||||
| 	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)parent.GetID(); | ||||
| 	if (!node) { | ||||
| 		for (auto object : m_objects) | ||||
| 			array.Add(wxDataViewItem((void*)object)); | ||||
| 	} | ||||
| 	else if (node->GetChildCount() == 0) | ||||
| 		return; | ||||
|     else { | ||||
|         const size_t count = node->GetChildren().GetCount(); | ||||
|         for (size_t pos = 0; pos < count; pos++) { | ||||
|             PrusaObjectDataViewModelNode *child = node->GetChildren().Item(pos); | ||||
|             array.Add(wxDataViewItem((void*)child)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     wxDataViewItemArray new_array = array; | ||||
|     for (const auto item : new_array) | ||||
|     { | ||||
|         wxDataViewItemArray children; | ||||
|         GetAllChildren(item, children); | ||||
|         WX_APPEND_ARRAY(array, children); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| ItemType PrusaObjectDataViewModel::GetItemType(const wxDataViewItem &item) const  | ||||
| { | ||||
|     if (!item.IsOk()) | ||||
|  | @ -1456,8 +1495,8 @@ PrusaDoubleSlider::PrusaDoubleSlider(wxWindow *parent, | |||
|     if (!is_osx) | ||||
|         SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX
 | ||||
| 
 | ||||
|     m_bmp_thumb_higher = wxBitmap(create_scaled_bitmap(style == wxSL_HORIZONTAL ? "right_half_circle.png"   : "up_half_circle.png")); | ||||
|     m_bmp_thumb_lower  = wxBitmap(create_scaled_bitmap(style == wxSL_HORIZONTAL ? "left_half_circle.png"    : "down_half_circle.png")); | ||||
|     m_bmp_thumb_higher = wxBitmap(style == wxSL_HORIZONTAL ? create_scaled_bitmap("right_half_circle.png") : create_scaled_bitmap("up_half_circle.png",  16, true)); | ||||
|     m_bmp_thumb_lower  = wxBitmap(style == wxSL_HORIZONTAL ? create_scaled_bitmap("left_half_circle.png" ) : create_scaled_bitmap("down_half_circle.png",16, true)); | ||||
|     m_thumb_size = m_bmp_thumb_lower.GetSize(); | ||||
| 
 | ||||
|     m_bmp_add_tick_on  = create_scaled_bitmap("colorchange_add_on.png"); | ||||
|  |  | |||
|  | @ -31,7 +31,8 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxStrin | |||
| wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, const wxString& description,  | ||||
|     std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler); | ||||
| 
 | ||||
| wxBitmap create_scaled_bitmap(const std::string& bmp_name); | ||||
| bool     load_scaled_bitmap(wxBitmap** bmp, const std::string& bmp_name, const int px_cnt=16, const bool is_horizontal = false); | ||||
| wxBitmap create_scaled_bitmap(const std::string& bmp_name, const int px_cnt=16, const bool is_horizontal = false); | ||||
| 
 | ||||
| class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup | ||||
| { | ||||
|  | @ -511,7 +512,7 @@ public: | |||
| 	virtual bool IsContainer(const wxDataViewItem &item) const override; | ||||
| 	virtual unsigned int GetChildren(const wxDataViewItem &parent, | ||||
| 		wxDataViewItemArray &array) const override; | ||||
| 
 | ||||
|     void GetAllChildren(const wxDataViewItem &parent,wxDataViewItemArray &array) const; | ||||
| 	// Is the container just a header or an item with all columns
 | ||||
| 	// In our case it is an item with all columns 
 | ||||
| 	virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override {	return true; } | ||||
|  |  | |||
|  | @ -212,7 +212,12 @@ int wmain(int argc, wchar_t **argv) | |||
| 	argv_extended.emplace_back(nullptr); | ||||
| 
 | ||||
| 	OpenGLVersionCheck opengl_version_check; | ||||
| 	bool load_mesa = ! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(2, 0); | ||||
| 	bool load_mesa =  | ||||
| 		// Running over a rempote desktop, and the RemoteFX is not enabled, therefore Windows will only provide SW OpenGL 1.1 context.
 | ||||
| 		// In that case, use Mesa.
 | ||||
| 		::GetSystemMetrics(SM_REMOTESESSION) || | ||||
| 		// Try to load the default OpenGL driver and test its context version.
 | ||||
| 		! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(2, 0); | ||||
| 
 | ||||
| 	wchar_t path_to_exe[MAX_PATH + 1] = { 0 }; | ||||
| 	::GetModuleFileNameW(nullptr, path_to_exe, MAX_PATH); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv