Mdel preview renders the actual colors of the filaments based on the filaments currently loaded in the AMS
Ported from BambuStudio
This commit is contained in:
parent
4590c765c6
commit
27f140fb18
20 changed files with 1441 additions and 400 deletions
|
@ -1,5 +1,6 @@
|
|||
#version 110
|
||||
|
||||
uniform bool ban_light;
|
||||
uniform vec4 uniform_color;
|
||||
uniform float emission_factor;
|
||||
|
||||
|
@ -12,5 +13,9 @@ void main()
|
|||
{
|
||||
if (world_pos.z < 0.0)
|
||||
discard;
|
||||
gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
|
||||
if(ban_light){
|
||||
gl_FragColor = uniform_color;
|
||||
} else{
|
||||
gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#version 140
|
||||
|
||||
uniform bool ban_light;
|
||||
uniform vec4 uniform_color;
|
||||
uniform float emission_factor;
|
||||
|
||||
|
@ -12,5 +13,9 @@ void main()
|
|||
{
|
||||
if (world_pos.z < 0.0)
|
||||
discard;
|
||||
gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
|
||||
if(ban_light){
|
||||
gl_FragColor = uniform_color;
|
||||
} else{
|
||||
gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -30,8 +30,26 @@ namespace IO {
|
|||
#define JSON_ASSEMPLE_OBJECT_POS_Z "pos_z"
|
||||
#define JSON_ASSEMPLE_OBJECT_ASSEMBLE_INDEX "assemble_index"
|
||||
#define JSON_ASSEMPLE_OBJECT_PRINT_PARAMS "print_params"
|
||||
#define JSON_ASSEMPLE_ASSEMBLE_PARAMS "assembled_params"
|
||||
|
||||
|
||||
#define JSON_ASSEMPLE_OBJECT_MIN_Z "min_z"
|
||||
#define JSON_ASSEMPLE_OBJECT_MAX_Z "max_z"
|
||||
#define JSON_ASSEMPLE_OBJECT_HEIGHT_RANGES "height_ranges"
|
||||
#define JSON_ASSEMPLE_OBJECT_RANGE_PARAMS "range_params"
|
||||
|
||||
typedef struct _height_range_info {
|
||||
float min_z;
|
||||
float max_z;
|
||||
|
||||
std::map<std::string, std::string> range_params;
|
||||
}height_range_info_t;
|
||||
|
||||
typedef struct _assembled_param_info {
|
||||
std::map<std::string, std::string> print_params;
|
||||
std::vector<height_range_info_t> height_ranges;
|
||||
}assembled_param_info_t;
|
||||
|
||||
typedef struct _assemble_object_info {
|
||||
std::string path;
|
||||
int count;
|
||||
|
@ -42,6 +60,7 @@ typedef struct _assemble_object_info {
|
|||
std::vector<float> pos_y;
|
||||
std::vector<float> pos_z;
|
||||
std::map<std::string, std::string> print_params;
|
||||
std::vector<height_range_info_t> height_ranges;
|
||||
}assemble_object_info_t;
|
||||
|
||||
typedef struct _assemble_plate_info {
|
||||
|
@ -52,9 +71,32 @@ typedef struct _assemble_plate_info {
|
|||
std::map<std::string, std::string> plate_params;
|
||||
std::vector<assemble_object_info_t> assemble_obj_list;
|
||||
std::vector<ModelObject *> loaded_obj_list;
|
||||
std::map<int, assembled_param_info_t> assembled_param_list;
|
||||
}assemble_plate_info_t;
|
||||
|
||||
|
||||
typedef struct _printer_plate_info {
|
||||
std::string printer_name;
|
||||
int printable_width{0};
|
||||
int printable_depth{0};
|
||||
int printable_height{0};
|
||||
|
||||
int exclude_width{0};
|
||||
int exclude_depth{0};
|
||||
int exclude_x{0};
|
||||
int exclude_y{0};
|
||||
}printer_plate_info_t;
|
||||
|
||||
typedef struct _plate_obj_size_info {
|
||||
bool has_wipe_tower{false};
|
||||
float wipe_x{0.f};
|
||||
float wipe_y{0.f};
|
||||
float wipe_width{0.f};
|
||||
float wipe_depth{0.f};
|
||||
BoundingBoxf3 obj_bbox;
|
||||
}plate_obj_size_info_t;
|
||||
|
||||
|
||||
class CLI {
|
||||
public:
|
||||
int run(int argc, char **argv);
|
||||
|
@ -74,17 +116,20 @@ private:
|
|||
void print_help(bool include_print_options = false, PrinterTechnology printer_technology = ptAny) const;
|
||||
|
||||
/// Exports loaded models to a file of the specified format, according to the options affecting output filename.
|
||||
bool export_models(IO::ExportFormat format);
|
||||
bool export_models(IO::ExportFormat format, std::string path = std::string());
|
||||
//BBS: add export_project function
|
||||
bool export_project(Model *model, std::string& path, PlateDataPtrs &partplate_data, std::vector<Preset*>& project_presets,
|
||||
std::vector<ThumbnailData*>& thumbnails, std::vector<ThumbnailData*>& top_thumbnails, std::vector<ThumbnailData*>& pick_thumbnails,
|
||||
std::vector<ThumbnailData *> &thumbnails,
|
||||
std::vector<ThumbnailData *> &no_light_thumbnails,
|
||||
std::vector<ThumbnailData *> &top_thumbnails,
|
||||
std::vector<ThumbnailData *> &pick_thumbnails,
|
||||
std::vector<ThumbnailData*>& calibration_thumbnails,
|
||||
std::vector<PlateBBoxData*>& plate_bboxes, const DynamicPrintConfig* config, bool minimum_save, int plate_to_export = -1);
|
||||
|
||||
bool has_print_action() const { return m_config.opt_bool("export_gcode") || m_config.opt_bool("export_sla"); }
|
||||
|
||||
std::string output_filepath(const Model &model, IO::ExportFormat format) const;
|
||||
std::string output_filepath(const ModelObject &object, unsigned int index, IO::ExportFormat format) const;
|
||||
std::string output_filepath(const ModelObject &object, unsigned int index, IO::ExportFormat format, std::string path_dir) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -91,8 +91,10 @@ public:
|
|||
bool operator != (const ColorRGBA& other) const { return !operator==(other); }
|
||||
bool operator < (const ColorRGBA& other) const;
|
||||
bool operator > (const ColorRGBA& other) const;
|
||||
float operator[](int i) const { return m_data[i]; }
|
||||
float& operator[](int i) { return m_data[i]; }
|
||||
|
||||
ColorRGBA operator + (const ColorRGBA& other) const;
|
||||
ColorRGBA operator + (const ColorRGBA& other) const;
|
||||
ColorRGBA operator * (float value) const;
|
||||
|
||||
const float* const data() const { return m_data.data(); }
|
||||
|
|
|
@ -292,6 +292,7 @@ static constexpr const char* OTHER_LAYERS_PRINT_SEQUENCE_NUMS_ATTR = "other_laye
|
|||
static constexpr const char* SPIRAL_VASE_MODE = "spiral_mode";
|
||||
static constexpr const char* GCODE_FILE_ATTR = "gcode_file";
|
||||
static constexpr const char* THUMBNAIL_FILE_ATTR = "thumbnail_file";
|
||||
static constexpr const char* NO_LIGHT_THUMBNAIL_FILE_ATTR = "thumbnail_no_light_file";
|
||||
static constexpr const char* TOP_FILE_ATTR = "top_file";
|
||||
static constexpr const char* PICK_FILE_ATTR = "pick_file";
|
||||
static constexpr const char* PATTERN_FILE_ATTR = "pattern_file";
|
||||
|
@ -1491,6 +1492,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
|||
boost::algorithm::replace_all(plate->thumbnail_file, ".gcode", ".png");
|
||||
}
|
||||
//plate->pattern_file = it->second->pattern_file;
|
||||
plate->no_light_thumbnail_file = it->second->no_light_thumbnail_file;
|
||||
plate->top_file = it->second->top_file;
|
||||
plate->pick_file = it->second->pick_file.empty();
|
||||
plate->pattern_bbox_file = it->second->pattern_bbox_file.empty();
|
||||
|
@ -1502,7 +1504,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
|||
return mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, pixels.data(), pixels.size(), 0);
|
||||
});
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", plate %1%, thumbnail_file=%2%")%it->first %plate->thumbnail_file;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", plate %1%, thumbnail_file=%2%, no_light_thumbnail_file=%3%")%it->first %plate->thumbnail_file %plate->no_light_thumbnail_file;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", top_thumbnail_file=%1%, pick_thumbnail_file=%2%")%plate->top_file %plate->pick_file;
|
||||
it++;
|
||||
}
|
||||
|
@ -2136,13 +2138,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
|||
plate_data_list[it->first-1]->warnings = it->second->warnings;
|
||||
plate_data_list[it->first-1]->thumbnail_file = (m_load_restore || it->second->thumbnail_file.empty()) ? it->second->thumbnail_file : m_backup_path + "/" + it->second->thumbnail_file;
|
||||
//plate_data_list[it->first-1]->pattern_file = (m_load_restore || it->second->pattern_file.empty()) ? it->second->pattern_file : m_backup_path + "/" + it->second->pattern_file;
|
||||
plate_data_list[it->first-1]->no_light_thumbnail_file = (m_load_restore || it->second->no_light_thumbnail_file.empty()) ? it->second->no_light_thumbnail_file : m_backup_path + "/" + it->second->no_light_thumbnail_file;
|
||||
plate_data_list[it->first-1]->top_file = (m_load_restore || it->second->top_file.empty()) ? it->second->top_file : m_backup_path + "/" + it->second->top_file;
|
||||
plate_data_list[it->first-1]->pick_file = (m_load_restore || it->second->pick_file.empty()) ? it->second->pick_file : m_backup_path + "/" + it->second->pick_file;
|
||||
plate_data_list[it->first-1]->pattern_bbox_file = (m_load_restore || it->second->pattern_bbox_file.empty()) ? it->second->pattern_bbox_file : m_backup_path + "/" + it->second->pattern_bbox_file;
|
||||
plate_data_list[it->first-1]->config = it->second->config;
|
||||
|
||||
current_plate_data = plate_data_list[it->first - 1];
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", plate %1%, thumbnail_file=%2%")%it->first %plate_data_list[it->first-1]->thumbnail_file;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", plate %1%, thumbnail_file=%2%, no_light_thumbnail_file=%3%")%it->first %plate_data_list[it->first-1]->thumbnail_file %plate_data_list[it->first-1]->no_light_thumbnail_file;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(", top_thumbnail_file=%1%, pick_thumbnail_file=%2%")%plate_data_list[it->first-1]->top_file %plate_data_list[it->first-1]->pick_file;
|
||||
it++;
|
||||
|
||||
|
@ -4115,6 +4118,10 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
|||
{
|
||||
m_curr_plater->thumbnail_file = value;
|
||||
}
|
||||
else if (key == NO_LIGHT_THUMBNAIL_FILE_ATTR)
|
||||
{
|
||||
m_curr_plater->no_light_thumbnail_file = value;
|
||||
}
|
||||
else if (key == TOP_FILE_ATTR)
|
||||
{
|
||||
m_curr_plater->top_file = value;
|
||||
|
@ -5470,6 +5477,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
|||
std::vector<Preset*>& project_presets,
|
||||
const DynamicPrintConfig* config,
|
||||
const std::vector<ThumbnailData*>& thumbnail_data,
|
||||
const std::vector<ThumbnailData *>& no_light_thumbnail_data,
|
||||
const std::vector<ThumbnailData*>& top_thumbnail_data,
|
||||
const std::vector<ThumbnailData*>& pick_thumbnail_data,
|
||||
Export3mfProgressFn proFn,
|
||||
|
@ -5556,7 +5564,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
|||
boost::filesystem::remove(filename + ".tmp", ec);
|
||||
|
||||
bool result = _save_model_to_file(filename + ".tmp", *store_params.model, store_params.plate_data_list, store_params.project_presets, store_params.config,
|
||||
store_params.thumbnail_data, store_params.top_thumbnail_data, store_params.pick_thumbnail_data, store_params.proFn,
|
||||
store_params.thumbnail_data, store_params.no_light_thumbnail_data, store_params.top_thumbnail_data, store_params.pick_thumbnail_data,
|
||||
store_params.proFn,
|
||||
store_params.calibration_thumbnail_data, store_params.id_bboxes, store_params.project, store_params.export_plate_idx);
|
||||
if (result) {
|
||||
boost::filesystem::rename(filename + ".tmp", filename, ec);
|
||||
|
@ -5632,6 +5641,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
|||
std::vector<Preset*>& project_presets,
|
||||
const DynamicPrintConfig* config,
|
||||
const std::vector<ThumbnailData*>& thumbnail_data,
|
||||
const std::vector<ThumbnailData*>& no_light_thumbnail_data,
|
||||
const std::vector<ThumbnailData*>& top_thumbnail_data,
|
||||
const std::vector<ThumbnailData*>& pick_thumbnail_data,
|
||||
Export3mfProgressFn proFn,
|
||||
|
@ -5696,6 +5706,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
|||
//BBS: add thumbnail for each plate
|
||||
if (!m_skip_static) {
|
||||
std::vector<bool> thumbnail_status(plate_data_list.size(), false);
|
||||
std::vector<bool> no_light_thumbnail_status(plate_data_list.size(), false);
|
||||
std::vector<bool> top_thumbnail_status(plate_data_list.size(), false);
|
||||
std::vector<bool> pick_thumbnail_status(plate_data_list.size(), false);
|
||||
|
||||
|
@ -5704,6 +5715,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
|||
% thumbnail_data.size() %plate_data_list.size();
|
||||
return false;
|
||||
}
|
||||
if ((no_light_thumbnail_data.size() > 0) && (no_light_thumbnail_data.size() > plate_data_list.size())) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", no_light_thumbnail_data size %1% > plate count %2%") %
|
||||
no_light_thumbnail_data.size() % plate_data_list.size();
|
||||
return false;
|
||||
}
|
||||
if ((top_thumbnail_data.size() > 0)&&(top_thumbnail_data.size() > plate_data_list.size())) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", top_thumbnail_data size %1% > plate count %2%")
|
||||
% top_thumbnail_data.size() %plate_data_list.size();
|
||||
|
@ -5739,6 +5755,16 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
|||
}
|
||||
}
|
||||
|
||||
for (unsigned int index = 0; index < no_light_thumbnail_data.size(); index++) {
|
||||
if (no_light_thumbnail_data[index]->is_valid()) {
|
||||
if (!_add_thumbnail_file_to_archive(archive, *no_light_thumbnail_data[index], "Metadata/plate_no_light", index)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" << __LINE__ << boost::format(",add no light thumbnail %1%'s data into 3mf") % (index + 1);
|
||||
thumbnail_status[index] = true;
|
||||
}
|
||||
}
|
||||
// Adds the file Metadata/top_i.png and Metadata/pick_i.png
|
||||
for (unsigned int index = 0; index < top_thumbnail_data.size(); index++)
|
||||
{
|
||||
|
@ -5774,6 +5800,16 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
|||
}
|
||||
}
|
||||
|
||||
if (!no_light_thumbnail_status[i] && !plate_data->no_light_thumbnail_file.empty() && (boost::filesystem::exists(plate_data->no_light_thumbnail_file))){
|
||||
std::string dst_in_3mf = (boost::format("Metadata/plate_no_light_%1%.png") % (i + 1)).str();
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", add no light thumbnail %1% from file %2%") % (i+1) %plate_data->no_light_thumbnail_file;
|
||||
|
||||
if (!_add_file_to_archive(archive, dst_in_3mf, plate_data->no_light_thumbnail_file)) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ":" << __LINE__ << boost::format(", add no light thumbnail %1% from file %2% failed\n") % (i+1) %plate_data->no_light_thumbnail_file;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!top_thumbnail_status[i] && !plate_data->top_file.empty() && (boost::filesystem::exists(plate_data->top_file))){
|
||||
std::string dst_in_3mf = (boost::format("Metadata/top_%1%.png") % (i + 1)).str();
|
||||
|
||||
|
@ -7468,6 +7504,11 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
|
|||
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << THUMBNAIL_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << thumbnail_file_in_3mf << "\"/>\n";
|
||||
}
|
||||
|
||||
if (!plate_data->no_light_thumbnail_file.empty()){
|
||||
std::string no_light_thumbnail_file_in_3mf = (boost::format(NO_LIGHT_THUMBNAIL_FILE_FORMAT) % (plate_data->plate_index + 1)).str();
|
||||
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << NO_LIGHT_THUMBNAIL_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << no_light_thumbnail_file_in_3mf << "\"/>\n";
|
||||
}
|
||||
|
||||
if (!plate_data->top_file.empty()) {
|
||||
std::string top_file_in_3mf = (boost::format(TOP_FILE_FORMAT) % (plate_data->plate_index + 1)).str();
|
||||
stream << " <" << METADATA_TAG << " " << KEY_ATTR << "=\"" << TOP_FILE_ATTR << "\" " << VALUE_ATTR << "=\"" << std::boolalpha << top_file_in_3mf << "\"/>\n";
|
||||
|
|
|
@ -21,6 +21,7 @@ struct ThumbnailData;
|
|||
|
||||
#define GCODE_FILE_FORMAT "Metadata/plate_%1%.gcode"
|
||||
#define THUMBNAIL_FILE_FORMAT "Metadata/plate_%1%.png"
|
||||
#define NO_LIGHT_THUMBNAIL_FILE_FORMAT "Metadata/plate_no_light_%1%.png"
|
||||
#define TOP_FILE_FORMAT "Metadata/top_%1%.png"
|
||||
#define PICK_FILE_FORMAT "Metadata/pick_%1%.png"
|
||||
//#define PATTERN_FILE_FORMAT "Metadata/plate_%1%_pattern_layer_0.png"
|
||||
|
@ -75,6 +76,7 @@ struct PlateData
|
|||
std::string gcode_file;
|
||||
std::string gcode_file_md5;
|
||||
std::string thumbnail_file;
|
||||
std::string no_light_thumbnail_file;
|
||||
ThumbnailData plate_thumbnail;
|
||||
std::string top_file;
|
||||
std::string pick_file;
|
||||
|
@ -213,6 +215,7 @@ struct StoreParams
|
|||
std::vector<Preset*> project_presets;
|
||||
DynamicPrintConfig* config;
|
||||
std::vector<ThumbnailData*> thumbnail_data;
|
||||
std::vector<ThumbnailData*> no_light_thumbnail_data;
|
||||
std::vector<ThumbnailData*> top_thumbnail_data;
|
||||
std::vector<ThumbnailData*> pick_thumbnail_data;
|
||||
std::vector<ThumbnailData*> calibration_thumbnail_data;
|
||||
|
|
|
@ -6657,9 +6657,14 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
|||
|
||||
def = this->add("export_stl", coBool);
|
||||
def->label = "Export STL";
|
||||
def->tooltip = "Export the objects as multiple STL.";
|
||||
def->tooltip = "Export the objects as single STL.";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("export_stls", coString);
|
||||
def->label = "Export multiple stls";
|
||||
def->tooltip = "Export the objects as multiple stls to directory";
|
||||
def->set_default_value(new ConfigOptionString("stl_path"));
|
||||
|
||||
/*def = this->add("export_gcode", coBool);
|
||||
def->label = L("Export G-code");
|
||||
def->tooltip = L("Slice the model and export toolpaths as G-code.");
|
||||
|
@ -6692,6 +6697,12 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
|||
def->cli = "uptodate";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("downward_check", coStrings);
|
||||
def->label = "downward machines check";
|
||||
def->tooltip = "check whether current machine downward compatible with the machines in the list";
|
||||
def->cli_params = "\"machine1.json;machine2.json;...\"";
|
||||
def->set_default_value(new ConfigOptionStrings());
|
||||
|
||||
def = this->add("load_defaultfila", coBool);
|
||||
def->label = "Load default filaments";
|
||||
def->tooltip = "Load first filament as default for those not loaded";
|
||||
|
@ -6945,6 +6956,17 @@ CLIMiscConfigDef::CLIMiscConfigDef()
|
|||
def->cli_params = "\"filament1.json;filament2.json;...\"";
|
||||
def->set_default_value(new ConfigOptionStrings());
|
||||
|
||||
def = this->add("downward_check", coBool);
|
||||
def->label = "downward machines check";
|
||||
def->tooltip = "if enabled, check whether current machine downward compatible with the machines in the list";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("downward_settings", coStrings);
|
||||
def->label = "downward machines settings";
|
||||
def->tooltip = "the machine settings list need to do downward checking";
|
||||
def->cli_params = "\"machine1.json;machine2.json;...\"";
|
||||
def->set_default_value(new ConfigOptionStrings());
|
||||
|
||||
def = this->add("load_assemble_list", coString);
|
||||
def->label = "Load assemble list";
|
||||
def->tooltip = "Load assemble object list from config file";
|
||||
|
|
|
@ -66,17 +66,22 @@ void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char
|
|||
// BBS
|
||||
std::vector<Slic3r::ColorRGBA> get_extruders_colors()
|
||||
{
|
||||
Slic3r::ColorRGBA rgba_color;
|
||||
std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
|
||||
unsigned char rgba_color[4] = {};
|
||||
std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
|
||||
std::vector<Slic3r::ColorRGBA> colors_out(colors.size());
|
||||
for (const std::string &color : colors) {
|
||||
Slic3r::decode_color(color, rgba_color);
|
||||
Slic3r::GUI::BitmapCache::parse_color4(color, rgba_color);
|
||||
size_t color_idx = &color - &colors.front();
|
||||
colors_out[color_idx] = rgba_color;
|
||||
colors_out[color_idx] = {
|
||||
float(rgba_color[0]) / 255.f,
|
||||
float(rgba_color[1]) / 255.f,
|
||||
float(rgba_color[2]) / 255.f,
|
||||
float(rgba_color[3]) / 255.f,
|
||||
};
|
||||
}
|
||||
|
||||
return colors_out;
|
||||
}
|
||||
|
||||
float FullyTransparentMaterialThreshold = 0.1f;
|
||||
float FullTransparentModdifiedToFixAlpha = 0.3f;
|
||||
float FULL_BLACK_THRESHOLD = 0.18f;
|
||||
|
@ -464,7 +469,7 @@ void GLVolume::render_with_outline(const Transform3d &view_model_matrix)
|
|||
}
|
||||
|
||||
//BBS add render for simple case
|
||||
void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector<ColorRGBA> extruder_colors)
|
||||
void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector<ColorRGBA>& extruder_colors, bool ban_light)
|
||||
{
|
||||
if (this->is_left_handed())
|
||||
glFrontFace(GL_CW);
|
||||
|
@ -510,22 +515,36 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj
|
|||
if (!m.is_initialized())
|
||||
continue;
|
||||
|
||||
if (idx == 0) {
|
||||
int extruder_id = model_volume->extruder_id();
|
||||
//to make black not too hard too see
|
||||
ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[extruder_id - 1]);
|
||||
m.set_color(new_color);
|
||||
}
|
||||
else {
|
||||
if (idx <= extruder_colors.size()) {
|
||||
if (shader) {
|
||||
if (idx == 0) {
|
||||
int extruder_id = model_volume->extruder_id();
|
||||
//to make black not too hard too see
|
||||
ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[idx - 1]);
|
||||
ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[extruder_id - 1]);
|
||||
if (ban_light) {
|
||||
new_color[3] = (255 - (extruder_id - 1))/255.0f;
|
||||
}
|
||||
m.set_color(new_color);
|
||||
// shader->set_uniform("uniform_color", new_color);
|
||||
}
|
||||
else {
|
||||
//to make black not too hard too see
|
||||
ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[0]);
|
||||
m.set_color(new_color);
|
||||
if (idx <= extruder_colors.size()) {
|
||||
//to make black not too hard too see
|
||||
ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[idx - 1]);
|
||||
if (ban_light) {
|
||||
new_color[3] = (255 - (idx - 1))/255.0f;
|
||||
}
|
||||
m.set_color(new_color);
|
||||
// shader->set_uniform("uniform_color", new_color);
|
||||
}
|
||||
else {
|
||||
//to make black not too hard too see
|
||||
ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[0]);
|
||||
if (ban_light) {
|
||||
new_color[3] = (255 - 0) / 255.0f;
|
||||
}
|
||||
m.set_color(new_color);
|
||||
// shader->set_uniform("uniform_color", new_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tverts_range == std::make_pair<size_t, size_t>(0, -1))
|
||||
|
|
|
@ -325,7 +325,7 @@ public:
|
|||
virtual void render_with_outline(const Transform3d &view_model_matrix);
|
||||
|
||||
//BBS: add simple render function for thumbnail
|
||||
void simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector<ColorRGBA> extruder_colors);
|
||||
void simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector<ColorRGBA>& extruder_colors, bool ban_light =false);
|
||||
|
||||
void set_bounding_boxes_as_dirty() {
|
||||
m_transformed_bounding_box.reset();
|
||||
|
|
|
@ -2051,13 +2051,24 @@ void GLCanvas3D::render(bool only_init)
|
|||
m_render_stats.increment_fps_counter();
|
||||
}
|
||||
|
||||
void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, Camera::EType camera_type, bool use_top_view, bool for_picking)
|
||||
void GLCanvas3D::render_thumbnail(ThumbnailData & thumbnail_data,
|
||||
unsigned int w,
|
||||
unsigned int h,
|
||||
const ThumbnailsParams &thumbnail_params,
|
||||
Camera::EType camera_type,
|
||||
bool use_top_view,
|
||||
bool for_picking,
|
||||
bool ban_light)
|
||||
{
|
||||
render_thumbnail(thumbnail_data, w, h, thumbnail_params, m_volumes, camera_type, use_top_view, for_picking);
|
||||
render_thumbnail(thumbnail_data, w, h, thumbnail_params, m_volumes, camera_type, use_top_view, for_picking, ban_light);
|
||||
}
|
||||
|
||||
void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
||||
const GLVolumeCollection& volumes, Camera::EType camera_type, bool use_top_view, bool for_picking)
|
||||
const GLVolumeCollection &volumes,
|
||||
Camera::EType camera_type,
|
||||
bool use_top_view,
|
||||
bool for_picking,
|
||||
bool ban_light)
|
||||
{
|
||||
GLShaderProgram* shader = nullptr;
|
||||
if (for_picking)
|
||||
|
@ -2069,14 +2080,19 @@ void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w,
|
|||
switch (OpenGLManager::get_framebuffers_type())
|
||||
{
|
||||
case OpenGLManager::EFramebufferType::Arb:
|
||||
{ render_thumbnail_framebuffer(thumbnail_data, w, h, thumbnail_params,
|
||||
wxGetApp().plater()->get_partplate_list(), model_objects, volumes, colors, shader, camera_type, use_top_view, for_picking); break; }
|
||||
{ render_thumbnail_framebuffer(thumbnail_data, w, h, thumbnail_params, wxGetApp().plater()->get_partplate_list(), model_objects, volumes, colors, shader, camera_type,
|
||||
use_top_view, for_picking, ban_light);
|
||||
break;
|
||||
}
|
||||
case OpenGLManager::EFramebufferType::Ext:
|
||||
{ render_thumbnail_framebuffer_ext(thumbnail_data, w, h, thumbnail_params,
|
||||
wxGetApp().plater()->get_partplate_list(), model_objects, volumes, colors, shader, camera_type, use_top_view, for_picking); break; }
|
||||
{ render_thumbnail_framebuffer_ext(thumbnail_data, w, h, thumbnail_params, wxGetApp().plater()->get_partplate_list(), model_objects, volumes, colors, shader, camera_type,
|
||||
use_top_view, for_picking, ban_light);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{ render_thumbnail_legacy(thumbnail_data, w, h, thumbnail_params,
|
||||
wxGetApp().plater()->get_partplate_list(), model_objects, volumes, colors, shader, camera_type); break; }
|
||||
{ render_thumbnail_legacy(thumbnail_data, w, h, thumbnail_params, wxGetApp().plater()->get_partplate_list(), model_objects, volumes, colors, shader, camera_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5733,7 +5749,7 @@ static void debug_output_thumbnail(const ThumbnailData& thumbnail_data)
|
|||
|
||||
void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params,
|
||||
PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector<ColorRGBA>& extruder_colors,
|
||||
GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view, bool for_picking)
|
||||
GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view, bool for_picking, bool ban_light)
|
||||
{
|
||||
//BBS modify visible calc function
|
||||
int plate_idx = thumbnail_params.plate_id;
|
||||
|
@ -5849,7 +5865,9 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const
|
|||
|
||||
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
if (ban_light) {
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
const Transform3d &projection_matrix = camera.get_projection_matrix();
|
||||
|
||||
if (for_picking) {
|
||||
|
@ -5903,12 +5921,16 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const
|
|||
else {
|
||||
shader->start_using();
|
||||
shader->set_uniform("emission_factor", 0.1f);
|
||||
shader->set_uniform("ban_light", ban_light);
|
||||
for (GLVolume* vol : visible_volumes) {
|
||||
//BBS set render color for thumbnails
|
||||
curr_color = vol->color;
|
||||
|
||||
ColorRGBA new_color = adjust_color_for_rendering(curr_color);
|
||||
vol->model.set_color(new_color);
|
||||
if (ban_light) {
|
||||
new_color[3] = (255 - vol->extruder_id) / 255.0f;
|
||||
}
|
||||
vol->model.set_color(new_color);
|
||||
shader->set_uniform("volume_world_matrix", vol->world_matrix());
|
||||
//BBS set all volume to orange
|
||||
//shader->set_uniform("uniform_color", orange);
|
||||
|
@ -5926,7 +5948,7 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const
|
|||
shader->set_uniform("projection_matrix", projection_matrix);
|
||||
const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose();
|
||||
shader->set_uniform("view_normal_matrix", view_normal_matrix);
|
||||
vol->simple_render(shader, model_objects, extruder_colors);
|
||||
vol->simple_render(shader, model_objects, extruder_colors, ban_light);
|
||||
vol->is_active = is_active;
|
||||
}
|
||||
shader->stop_using();
|
||||
|
@ -5945,7 +5967,7 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const
|
|||
|
||||
void GLCanvas3D::render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
||||
PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector<ColorRGBA>& extruder_colors,
|
||||
GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view, bool for_picking)
|
||||
GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view, bool for_picking, bool ban_light)
|
||||
{
|
||||
thumbnail_data.set(w, h);
|
||||
if (!thumbnail_data.is_valid())
|
||||
|
@ -5998,7 +6020,8 @@ void GLCanvas3D::render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, uns
|
|||
glsafe(::glDrawBuffers(1, drawBufs));
|
||||
|
||||
if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
|
||||
render_thumbnail_internal(thumbnail_data, thumbnail_params, partplate_list, model_objects, volumes, extruder_colors, shader, camera_type, use_top_view, for_picking);
|
||||
render_thumbnail_internal(thumbnail_data, thumbnail_params, partplate_list, model_objects, volumes, extruder_colors, shader,
|
||||
camera_type, use_top_view, for_picking,ban_light);
|
||||
|
||||
if (multisample) {
|
||||
GLuint resolve_fbo;
|
||||
|
@ -6053,7 +6076,7 @@ void GLCanvas3D::render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, uns
|
|||
|
||||
void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
||||
PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector<ColorRGBA>& extruder_colors,
|
||||
GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view, bool for_picking)
|
||||
GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view, bool for_picking, bool ban_light)
|
||||
{
|
||||
thumbnail_data.set(w, h);
|
||||
if (!thumbnail_data.is_valid())
|
||||
|
@ -6105,7 +6128,8 @@ void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data,
|
|||
glsafe(::glDrawBuffers(1, drawBufs));
|
||||
|
||||
if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT) {
|
||||
render_thumbnail_internal(thumbnail_data, thumbnail_params, partplate_list, model_objects, volumes, extruder_colors, shader, camera_type, use_top_view, for_picking);
|
||||
render_thumbnail_internal(thumbnail_data, thumbnail_params, partplate_list, model_objects, volumes, extruder_colors, shader, camera_type, use_top_view, for_picking,
|
||||
ban_light);
|
||||
|
||||
if (multisample) {
|
||||
GLuint resolve_fbo;
|
||||
|
|
|
@ -874,20 +874,27 @@ public:
|
|||
// printable_only == false -> render also non printable volumes as grayed
|
||||
// parts_only == false -> render also sla support and pad
|
||||
void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
||||
Camera::EType camera_type, bool use_top_view = false, bool for_picking = false);
|
||||
Camera::EType camera_type,
|
||||
bool use_top_view = false,
|
||||
bool for_picking = false,
|
||||
bool ban_light = false);
|
||||
void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
||||
const GLVolumeCollection& volumes, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false);
|
||||
const GLVolumeCollection &volumes,
|
||||
Camera::EType camera_type,
|
||||
bool use_top_view = false,
|
||||
bool for_picking = false,
|
||||
bool ban_light = false);
|
||||
static void render_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, ModelObjectPtrs& model_objects,
|
||||
const GLVolumeCollection& volumes, std::vector<ColorRGBA>& extruder_colors,
|
||||
GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false);
|
||||
GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false, bool ban_light = false);
|
||||
// render thumbnail using an off-screen framebuffer
|
||||
static void render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
||||
PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector<ColorRGBA>& extruder_colors,
|
||||
GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false);
|
||||
GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false, bool ban_light = false);
|
||||
// render thumbnail using an off-screen framebuffer when GLEW_EXT_framebuffer_object is supported
|
||||
static void render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
||||
PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector<ColorRGBA>& extruder_colors,
|
||||
GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false);
|
||||
GLShaderProgram* shader, Camera::EType camera_type, bool use_top_view = false, bool for_picking = false, bool ban_light = false);
|
||||
|
||||
//BBS use gcoder viewer render calibration thumbnails
|
||||
void render_calibration_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params);
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#define TIMEOUT_RESPONSE 15
|
||||
|
||||
#define BE_UNACTED_ON 0x00200001
|
||||
#define SHOW_BACKGROUND_BITMAP_PIXEL_THRESHOLD 80
|
||||
#ifndef _MSW_DARK_MODE
|
||||
#define _MSW_DARK_MODE 1
|
||||
#endif // _MSW_DARK_MODE
|
||||
|
|
|
@ -287,7 +287,7 @@ PrintSequence PartPlate::get_real_print_seq(bool* plate_same_as_global) const
|
|||
if (curr_plate_seq == PrintSequence::ByDefault) {
|
||||
curr_plate_seq = global_print_seq;
|
||||
}
|
||||
|
||||
|
||||
if(plate_same_as_global)
|
||||
*plate_same_as_global = (curr_plate_seq == global_print_seq);
|
||||
|
||||
|
@ -2145,6 +2145,27 @@ int PartPlate::remove_instance(int obj_id, int instance_id)
|
|||
return result;
|
||||
}
|
||||
|
||||
BoundingBoxf3 PartPlate::get_objects_bounding_box()
|
||||
{
|
||||
BoundingBoxf3 bbox;
|
||||
for (std::set<std::pair<int, int>>::iterator it = obj_to_instance_set.begin(); it != obj_to_instance_set.end(); ++it)
|
||||
{
|
||||
int obj_id = it->first;
|
||||
int instance_id = it->second;
|
||||
|
||||
if ((obj_id >= 0) && (obj_id < m_model->objects.size()))
|
||||
{
|
||||
ModelObject* object = m_model->objects[obj_id];
|
||||
if ((instance_id >= 0) && (instance_id < object->instances.size()))
|
||||
{
|
||||
BoundingBoxf3 instance_bbox = object->instance_bounding_box(instance_id);
|
||||
bbox.merge(instance_bbox);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bbox;
|
||||
}
|
||||
|
||||
//translate instance on the plate
|
||||
void PartPlate::translate_all_instance(Vec3d position)
|
||||
{
|
||||
|
@ -4083,6 +4104,7 @@ int PartPlateList::notify_instance_update(int obj_id, int instance_id, bool is_n
|
|||
PartPlate* plate = m_plate_list[obj_id - 1000];
|
||||
plate->update_slice_result_valid_state( false );
|
||||
plate->thumbnail_data.reset();
|
||||
plate->no_light_thumbnail_data.reset();
|
||||
plate->top_thumbnail_data.reset();
|
||||
plate->pick_thumbnail_data.reset();
|
||||
|
||||
|
@ -4113,12 +4135,14 @@ int PartPlateList::notify_instance_update(int obj_id, int instance_id, bool is_n
|
|||
plate->update_states();
|
||||
plate->update_slice_result_valid_state();
|
||||
plate->thumbnail_data.reset();
|
||||
plate->no_light_thumbnail_data.reset();
|
||||
plate->top_thumbnail_data.reset();
|
||||
plate->pick_thumbnail_data.reset();
|
||||
return 0;
|
||||
}
|
||||
plate->update_slice_result_valid_state();
|
||||
plate->thumbnail_data.reset();
|
||||
plate->no_light_thumbnail_data.reset();
|
||||
plate->top_thumbnail_data.reset();
|
||||
plate->pick_thumbnail_data.reset();
|
||||
}
|
||||
|
@ -4164,7 +4188,7 @@ int PartPlateList::notify_instance_update(int obj_id, int instance_id, bool is_n
|
|||
{
|
||||
//found a new plate, add it to plate
|
||||
plate->add_instance(obj_id, instance_id, false, &boundingbox);
|
||||
|
||||
|
||||
// spiral mode, update object setting
|
||||
if (plate->config()->has("spiral_mode") && plate->config()->opt_bool("spiral_mode") && !is_object_config_compatible_with_spiral_vase(object)) {
|
||||
if (!is_new) {
|
||||
|
@ -4180,6 +4204,7 @@ int PartPlateList::notify_instance_update(int obj_id, int instance_id, bool is_n
|
|||
|
||||
plate->update_slice_result_valid_state();
|
||||
plate->thumbnail_data.reset();
|
||||
plate->no_light_thumbnail_data.reset();
|
||||
plate->top_thumbnail_data.reset();
|
||||
plate->pick_thumbnail_data.reset();
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": add it to new plate %1%") % i;
|
||||
|
@ -4217,6 +4242,7 @@ int PartPlateList::notify_instance_removed(int obj_id, int instance_id)
|
|||
plate->remove_instance(obj_id, instance_to_delete);
|
||||
plate->update_slice_result_valid_state();
|
||||
plate->thumbnail_data.reset();
|
||||
plate->no_light_thumbnail_data.reset();
|
||||
plate->top_thumbnail_data.reset();
|
||||
plate->pick_thumbnail_data.reset();
|
||||
}
|
||||
|
@ -5141,6 +5167,8 @@ int PartPlateList::store_to_3mf_structure(PlateDataPtrs& plate_data_list, bool w
|
|||
%(i+1) %plate_data_item->plate_thumbnail.width %plate_data_item->plate_thumbnail.height %plate_data_item->plate_thumbnail.pixels.size();
|
||||
plate_data_item->config.apply(*m_plate_list[i]->config());
|
||||
|
||||
if (m_plate_list[i]->no_light_thumbnail_data.is_valid())
|
||||
plate_data_item->no_light_thumbnail_file = "valid_no_light";
|
||||
if (m_plate_list[i]->top_thumbnail_data.is_valid())
|
||||
plate_data_item->top_file = "valid_top";
|
||||
if (m_plate_list[i]->pick_thumbnail_data.is_valid())
|
||||
|
@ -5256,6 +5284,13 @@ int PartPlateList::load_from_3mf_structure(PlateDataPtrs& plate_data_list)
|
|||
}
|
||||
}
|
||||
|
||||
if (m_plater && !plate_data_list[i]->no_light_thumbnail_file.empty()) {
|
||||
if (boost::filesystem::exists(plate_data_list[i]->no_light_thumbnail_file)) {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": plate %1%, load no_light_thumbnail_file from %2%.")%(i+1) %plate_data_list[i]->no_light_thumbnail_file;
|
||||
m_plate_list[index]->load_thumbnail_data(plate_data_list[i]->no_light_thumbnail_file, m_plate_list[index]->no_light_thumbnail_data);
|
||||
}
|
||||
}
|
||||
|
||||
/*if (m_plater && !plate_data_list[i]->pattern_file.empty()) {
|
||||
if (boost::filesystem::exists(plate_data_list[i]->pattern_file)) {
|
||||
//no need to load pattern data currently
|
||||
|
|
|
@ -246,6 +246,7 @@ public:
|
|||
//static const int plate_x_offset = 20; //mm
|
||||
//static const double plate_x_gap = 0.2;
|
||||
ThumbnailData thumbnail_data;
|
||||
ThumbnailData no_light_thumbnail_data;
|
||||
static const int plate_thumbnail_width = 512;
|
||||
static const int plate_thumbnail_height = 512;
|
||||
|
||||
|
@ -295,6 +296,7 @@ public:
|
|||
ModelObjectPtrs get_objects() { return m_model->objects; }
|
||||
ModelObjectPtrs get_objects_on_this_plate();
|
||||
ModelInstance* get_instance(int obj_id, int instance_id);
|
||||
BoundingBoxf3 get_objects_bounding_box();
|
||||
|
||||
Vec3d get_origin() { return m_origin; }
|
||||
Vec3d estimate_wipe_tower_size(const DynamicPrintConfig & config, const double w, const double d, int plate_extruder_size = 0, bool use_global_objects = false) const;
|
||||
|
|
|
@ -2555,7 +2555,7 @@ struct Plater::priv
|
|||
|
||||
//BBS: add plate_id for thumbnail
|
||||
void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
||||
Camera::EType camera_type, bool use_top_view = false, bool for_picking = false);
|
||||
Camera::EType camera_type, bool use_top_view = false, bool for_picking = false,bool ban_light = false);
|
||||
ThumbnailsList generate_thumbnails(const ThumbnailsParams& params, Camera::EType camera_type);
|
||||
//BBS
|
||||
void generate_calibration_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params);
|
||||
|
@ -7482,10 +7482,9 @@ void Plater::priv::on_3dcanvas_mouse_dragging_finished(SimpleEvent&)
|
|||
}
|
||||
|
||||
//BBS: add plate id for thumbnail generate param
|
||||
void Plater::priv::generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
||||
Camera::EType camera_type, bool use_top_view, bool for_picking)
|
||||
void Plater::priv::generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, Camera::EType camera_type, bool use_top_view, bool for_picking, bool ban_light)
|
||||
{
|
||||
view3D->get_canvas3d()->render_thumbnail(data, w, h, thumbnail_params, camera_type, use_top_view, for_picking);
|
||||
view3D->get_canvas3d()->render_thumbnail(data, w, h, thumbnail_params, camera_type, use_top_view, for_picking, ban_light);
|
||||
}
|
||||
|
||||
//BBS: add plate id for thumbnail generate param
|
||||
|
@ -9978,6 +9977,10 @@ void Plater::update_all_plate_thumbnails(bool force_update)
|
|||
if (force_update || !plate->thumbnail_data.is_valid()) {
|
||||
get_view3D_canvas3D()->render_thumbnail(plate->thumbnail_data, plate->plate_thumbnail_width, plate->plate_thumbnail_height, thumbnail_params, Camera::EType::Ortho);
|
||||
}
|
||||
if (force_update || !plate->no_light_thumbnail_data.is_valid()) {
|
||||
get_view3D_canvas3D()->render_thumbnail(plate->no_light_thumbnail_data, plate->plate_thumbnail_width, plate->plate_thumbnail_height, thumbnail_params,
|
||||
Camera::EType::Ortho,false,false,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9990,6 +9993,7 @@ void Plater::invalid_all_plate_thumbnails()
|
|||
for (int i = 0; i < get_partplate_list().get_plate_count(); i++) {
|
||||
PartPlate* plate = get_partplate_list().get_plate(i);
|
||||
plate->thumbnail_data.reset();
|
||||
plate->no_light_thumbnail_data.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11819,6 +11823,7 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy
|
|||
|
||||
//BBS: add plate logic for thumbnail generate
|
||||
std::vector<ThumbnailData*> thumbnails;
|
||||
std::vector<ThumbnailData*> no_light_thumbnails;
|
||||
std::vector<ThumbnailData*> calibration_thumbnails;
|
||||
std::vector<ThumbnailData*> top_thumbnails;
|
||||
std::vector<ThumbnailData*> picking_thumbnails;
|
||||
|
@ -11839,6 +11844,17 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy
|
|||
}
|
||||
thumbnails.push_back(thumbnail_data);
|
||||
|
||||
ThumbnailData *no_light_thumbnail_data = &p->partplate_list.get_plate(i)->no_light_thumbnail_data;
|
||||
if (p->partplate_list.get_plate(i)->no_light_thumbnail_data.is_valid() && using_exported_file()) {
|
||||
// no need to generate thumbnail
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": non need to re-generate thumbnail for gcode/exported mode of plate %1%") % i;
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": re-generate thumbnail for plate %1%") % i;
|
||||
const ThumbnailsParams thumbnail_params = {{}, false, true, true, true, i};
|
||||
p->generate_thumbnail(p->partplate_list.get_plate(i)->no_light_thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second,
|
||||
thumbnail_params, Camera::EType::Ortho,false,false,true);
|
||||
}
|
||||
no_light_thumbnails.push_back(no_light_thumbnail_data);
|
||||
//ThumbnailData* calibration_data = &p->partplate_list.get_plate(i)->cali_thumbnail_data;
|
||||
//calibration_thumbnails.push_back(calibration_data);
|
||||
PlateBBoxData* plate_bbox_data = &p->partplate_list.get_plate(i)->cali_bboxes_data;
|
||||
|
@ -11902,6 +11918,7 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy
|
|||
store_params.project_presets = project_presets;
|
||||
store_params.config = export_config ? &cfg : nullptr;
|
||||
store_params.thumbnail_data = thumbnails;
|
||||
store_params.no_light_thumbnail_data = no_light_thumbnails;
|
||||
store_params.top_thumbnail_data = top_thumbnails;
|
||||
store_params.pick_thumbnail_data = picking_thumbnails;
|
||||
store_params.calibration_thumbnail_data = calibration_thumbnails;
|
||||
|
@ -11995,6 +12012,10 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy
|
|||
//release the data here, as it will always be generated when export
|
||||
calibration_thumbnails[i]->reset();
|
||||
}
|
||||
for (unsigned int i = 0; i < no_light_thumbnails.size(); i++) {
|
||||
// release the data here, as it will always be generated when export
|
||||
no_light_thumbnails[i]->reset();
|
||||
}
|
||||
for (unsigned int i = 0; i < top_thumbnails.size(); i++)
|
||||
{
|
||||
//release the data here, as it will always be generated when export
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <miniz.h>
|
||||
#include <algorithm>
|
||||
#include "Plater.hpp"
|
||||
#include "Notebook.hpp"
|
||||
#include "BitmapCache.hpp"
|
||||
#include "BindDialog.hpp"
|
||||
|
||||
|
@ -1825,6 +1826,10 @@ void SelectMachineDialog::sync_ams_mapping_result(std::vector<FilamentInfo> &res
|
|||
iter++;
|
||||
}
|
||||
}
|
||||
auto tab_index = (MainFrame::TabPosition) dynamic_cast<Notebook *>(wxGetApp().tab_panel())->GetSelection();
|
||||
if (tab_index == MainFrame::TabPosition::tp3DEditor || tab_index == MainFrame::TabPosition::tpPreview) {
|
||||
updata_thumbnail_data_after_connected_printer();
|
||||
}
|
||||
}
|
||||
|
||||
void print_ams_mapping_result(std::vector<FilamentInfo>& result)
|
||||
|
@ -1843,7 +1848,7 @@ void print_ams_mapping_result(std::vector<FilamentInfo>& result)
|
|||
bool SelectMachineDialog::do_ams_mapping(MachineObject *obj_)
|
||||
{
|
||||
if (!obj_) return false;
|
||||
|
||||
obj_->get_ams_colors(m_cur_colors_in_thumbnail);
|
||||
// try color and type mapping
|
||||
int result = obj_->ams_filament_mapping(m_filaments, m_ams_mapping_result);
|
||||
if (result == 0) {
|
||||
|
@ -2574,6 +2579,7 @@ void SelectMachineDialog::on_ok_btn(wxCommandEvent &event)
|
|||
if (!obj_->nozzle_type.empty() && (m_print_type == PrintFromType::FROM_NORMAL)) {
|
||||
if (!is_same_nozzle_diameters(tag_nozzle_type, nozzle_diameter)) {
|
||||
has_slice_warnings = true;
|
||||
is_printing_block = true;
|
||||
|
||||
wxString nozzle_in_preset = wxString::Format(_L("nozzle in preset: %s %s"),nozzle_diameter, "");
|
||||
wxString nozzle_in_printer = wxString::Format(_L("nozzle memorized: %.2f %s"), obj_->nozzle_diameter, "");
|
||||
|
@ -2945,6 +2951,14 @@ void SelectMachineDialog::on_set_finish_mapping(wxCommandEvent &evt)
|
|||
BOOST_LOG_TRIVIAL(info) << "The ams mapping selection result: data is " << selection_data;
|
||||
|
||||
if (selection_data_arr.size() == 6) {
|
||||
auto ams_colour = wxColour(wxAtoi(selection_data_arr[0]), wxAtoi(selection_data_arr[1]), wxAtoi(selection_data_arr[2]), wxAtoi(selection_data_arr[3]));
|
||||
int old_filament_id = (int) wxAtoi(selection_data_arr[5]);
|
||||
if (m_print_type == PrintFromType::FROM_NORMAL) {//todo:support sd card
|
||||
change_default_normal(old_filament_id, ams_colour);
|
||||
final_deal_edge_pixels_data(m_preview_thumbnail_data);
|
||||
set_default_normal(m_preview_thumbnail_data); // do't reset ams
|
||||
}
|
||||
|
||||
int ctype = 0;
|
||||
std::vector<wxColour> material_cols;
|
||||
std::vector<std::string> tray_cols;
|
||||
|
@ -3350,8 +3364,6 @@ void SelectMachineDialog::on_selection_changed(wxCommandEvent &event)
|
|||
|
||||
show_status(PrintDialogStatus::PrintStatusInit);
|
||||
|
||||
reset_ams_material();
|
||||
|
||||
update_show_status();
|
||||
}
|
||||
|
||||
|
@ -3926,20 +3938,399 @@ void SelectMachineDialog::set_default()
|
|||
m_checkbox_list["use_ams"]->SetValue(true);
|
||||
|
||||
if (m_print_type == PrintFromType::FROM_NORMAL) {
|
||||
set_default_normal();
|
||||
reset_and_sync_ams_list();
|
||||
set_default_normal(m_plater->get_partplate_list().get_curr_plate()->thumbnail_data);
|
||||
}
|
||||
else if (m_print_type == PrintFromType::FROM_SDCARD_VIEW) {
|
||||
//todo:unify_deal_thumbnail_data(input_data, no_light_data);this include m_print_type = PrintFromType::FROM_SDCARD_VIEW
|
||||
//and notice update_page_turn_state(true)
|
||||
set_default_from_sdcard();
|
||||
}
|
||||
|
||||
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
|
||||
void SelectMachineDialog::set_default_normal()
|
||||
void SelectMachineDialog::reset_and_sync_ams_list()
|
||||
{
|
||||
// for black list
|
||||
std::vector<std::string> materials;
|
||||
std::vector<std::string> brands;
|
||||
std::vector<std::string> display_materials;
|
||||
std::vector<std::string> m_filaments_id;
|
||||
auto preset_bundle = wxGetApp().preset_bundle;
|
||||
|
||||
for (auto filament_name : preset_bundle->filament_presets) {
|
||||
for (int f_index = 0; f_index < preset_bundle->filaments.size(); f_index++) {
|
||||
PresetCollection *filament_presets = &wxGetApp().preset_bundle->filaments;
|
||||
Preset * preset = &filament_presets->preset(f_index);
|
||||
|
||||
if (preset && filament_name.compare(preset->name) == 0) {
|
||||
std::string display_filament_type;
|
||||
std::string filament_type = preset->config.get_filament_type(display_filament_type);
|
||||
std::string m_filament_id = preset->filament_id;
|
||||
display_materials.push_back(display_filament_type);
|
||||
materials.push_back(filament_type);
|
||||
m_filaments_id.push_back(m_filament_id);
|
||||
|
||||
std::string m_vendor_name = "";
|
||||
auto vendor = dynamic_cast<ConfigOptionStrings *>(preset->config.option("filament_vendor"));
|
||||
if (vendor && (vendor->values.size() > 0)) {
|
||||
std::string vendor_name = vendor->values[0];
|
||||
m_vendor_name = vendor_name;
|
||||
}
|
||||
brands.push_back(m_vendor_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto extruders = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_used_extruders();
|
||||
BitmapCache bmcache;
|
||||
MaterialHash::iterator iter = m_materialList.begin();
|
||||
while (iter != m_materialList.end()) {
|
||||
int id = iter->first;
|
||||
Material *item = iter->second;
|
||||
item->item->Destroy();
|
||||
delete item;
|
||||
iter++;
|
||||
}
|
||||
|
||||
m_sizer_material->Clear();
|
||||
m_materialList.clear();
|
||||
m_filaments.clear();
|
||||
|
||||
for (auto i = 0; i < extruders.size(); i++) {
|
||||
auto extruder = extruders[i] - 1;
|
||||
auto colour = wxGetApp().preset_bundle->project_config.opt_string("filament_colour", (unsigned int) extruder);
|
||||
unsigned char rgb[4];
|
||||
bmcache.parse_color4(colour, rgb);
|
||||
|
||||
auto colour_rgb = wxColour((int) rgb[0], (int) rgb[1], (int) rgb[2], (int) rgb[3]);
|
||||
if (extruder >= materials.size() || extruder < 0 || extruder >= display_materials.size()) continue;
|
||||
|
||||
MaterialItem *item = new MaterialItem(m_scrollable_region, colour_rgb, _L(display_materials[extruder]));
|
||||
m_sizer_material->Add(item, 0, wxALL, FromDIP(4));
|
||||
|
||||
item->Bind(wxEVT_LEFT_UP, [this, item, materials, extruder](wxMouseEvent &e) {});
|
||||
item->Bind(wxEVT_LEFT_DOWN, [this, item, materials, extruder](wxMouseEvent &e) {
|
||||
MaterialHash::iterator iter = m_materialList.begin();
|
||||
while (iter != m_materialList.end()) {
|
||||
int id = iter->first;
|
||||
Material * item = iter->second;
|
||||
MaterialItem *m = item->item;
|
||||
m->on_normal();
|
||||
iter++;
|
||||
}
|
||||
|
||||
m_current_filament_id = extruder;
|
||||
item->on_selected();
|
||||
|
||||
auto mouse_pos = ClientToScreen(e.GetPosition());
|
||||
wxPoint rect = item->ClientToScreen(wxPoint(0, 0));
|
||||
|
||||
// update ams data
|
||||
DeviceManager *dev_manager = Slic3r::GUI::wxGetApp().getDeviceManager();
|
||||
if (!dev_manager) return;
|
||||
MachineObject *obj_ = dev_manager->get_selected_machine();
|
||||
|
||||
if (obj_ && obj_->is_support_ams_mapping()) {
|
||||
if (m_mapping_popup.IsShown()) return;
|
||||
wxPoint pos = item->ClientToScreen(wxPoint(0, 0));
|
||||
pos.y += item->GetRect().height;
|
||||
m_mapping_popup.Move(pos);
|
||||
|
||||
if (obj_ && obj_->has_ams() && m_checkbox_list["use_ams"]->GetValue() && obj_->dev_id == m_printer_last_select) {
|
||||
m_mapping_popup.set_parent_item(item);
|
||||
m_mapping_popup.set_current_filament_id(extruder);
|
||||
m_mapping_popup.set_tag_texture(materials[extruder]);
|
||||
m_mapping_popup.update_ams_data(obj_->amsList);
|
||||
m_mapping_popup.Popup();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Material *material_item = new Material();
|
||||
material_item->id = extruder;
|
||||
material_item->item = item;
|
||||
m_materialList[i] = material_item;
|
||||
|
||||
// build for ams mapping
|
||||
if (extruder < materials.size() && extruder >= 0) {
|
||||
FilamentInfo info;
|
||||
info.id = extruder;
|
||||
info.type = materials[extruder];
|
||||
info.brand = brands[extruder];
|
||||
info.filament_id = m_filaments_id[extruder];
|
||||
info.color = wxString::Format("#%02X%02X%02X%02X", colour_rgb.Red(), colour_rgb.Green(), colour_rgb.Blue(), colour_rgb.Alpha()).ToStdString();
|
||||
m_filaments.push_back(info);
|
||||
}
|
||||
}
|
||||
|
||||
if (extruders.size() <= 4) {
|
||||
m_sizer_material->SetCols(extruders.size());
|
||||
} else {
|
||||
m_sizer_material->SetCols(4);
|
||||
}
|
||||
|
||||
// reset_ams_material();//show "-"
|
||||
}
|
||||
|
||||
void SelectMachineDialog::clone_thumbnail_data() {
|
||||
//record preview_colors
|
||||
MaterialHash::iterator iter = m_materialList.begin();
|
||||
if (m_preview_colors_in_thumbnail.size() != m_materialList.size()) {
|
||||
m_preview_colors_in_thumbnail.resize(m_materialList.size());
|
||||
}
|
||||
while (iter != m_materialList.end()) {
|
||||
int id = iter->first;
|
||||
Material * item = iter->second;
|
||||
MaterialItem *m = item->item;
|
||||
m_preview_colors_in_thumbnail[id] = m->m_material_coloul;
|
||||
if (item->id < m_cur_colors_in_thumbnail.size()) {
|
||||
m_cur_colors_in_thumbnail[item->id] = m->m_ams_coloul;
|
||||
}
|
||||
else {//exist empty or unrecognized type ams in machine
|
||||
m_cur_colors_in_thumbnail.resize(item->id + 1);
|
||||
m_cur_colors_in_thumbnail[item->id] = m->m_ams_coloul;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
//copy data
|
||||
auto &data = m_cur_input_thumbnail_data;
|
||||
m_preview_thumbnail_data.reset();
|
||||
m_preview_thumbnail_data.set(data.width, data.height);
|
||||
if (data.width > 0 && data.height > 0) {
|
||||
for (unsigned int r = 0; r < data.height; ++r) {
|
||||
unsigned int rr = (data.height - 1 - r) * data.width;
|
||||
for (unsigned int c = 0; c < data.width; ++c) {
|
||||
unsigned char *origin_px = (unsigned char *) data.pixels.data() + 4 * (rr + c);
|
||||
unsigned char *new_px = (unsigned char *) m_preview_thumbnail_data.pixels.data() + 4 * (rr + c);
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
new_px[i] = origin_px[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//record_edge_pixels_data
|
||||
record_edge_pixels_data();
|
||||
}
|
||||
|
||||
void SelectMachineDialog::record_edge_pixels_data()
|
||||
{
|
||||
auto is_not_in_preview_colors = [this](unsigned char r, unsigned char g , unsigned char b , unsigned char a) {
|
||||
for (size_t i = 0; i < m_preview_colors_in_thumbnail.size(); i++) {
|
||||
wxColour render_color = adjust_color_for_render(m_preview_colors_in_thumbnail[i]);
|
||||
if (render_color.Red() == r && render_color.Green() == g && render_color.Blue() == b /*&& render_color.Alpha() == a*/) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
ThumbnailData &data = m_cur_no_light_thumbnail_data;
|
||||
ThumbnailData &origin_data = m_cur_input_thumbnail_data;
|
||||
if (data.width > 0 && data.height > 0) {
|
||||
m_edge_pixels.resize(data.width * data.height);
|
||||
for (unsigned int r = 0; r < data.height; ++r) {
|
||||
unsigned int rr = (data.height - 1 - r) * data.width;
|
||||
for (unsigned int c = 0; c < data.width; ++c) {
|
||||
unsigned char *no_light_px = (unsigned char *) data.pixels.data() + 4 * (rr + c);
|
||||
unsigned char *origin_px = (unsigned char *) origin_data.pixels.data() + 4 * (rr + c);
|
||||
m_edge_pixels[r * data.width + c] = false;
|
||||
if (origin_px[3] > 0) {
|
||||
if (is_not_in_preview_colors(no_light_px[0], no_light_px[1], no_light_px[2], origin_px[3])) {
|
||||
m_edge_pixels[r * data.width + c] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxColour SelectMachineDialog::adjust_color_for_render(const wxColour &color)
|
||||
{
|
||||
ColorRGBA _temp_color_color(color.Red() / 255.0f, color.Green() / 255.0f, color.Blue() / 255.0f, color.Alpha() / 255.0f);
|
||||
auto _temp_color_color_ = adjust_color_for_rendering(_temp_color_color);
|
||||
wxColour render_color((int) (_temp_color_color_[0] * 255.0f), (int) (_temp_color_color_[1] * 255.0f), (int) (_temp_color_color_[2] * 255.0f),
|
||||
(int) (_temp_color_color_[3] * 255.0f));
|
||||
return render_color;
|
||||
}
|
||||
|
||||
void SelectMachineDialog::final_deal_edge_pixels_data(ThumbnailData &data)
|
||||
{
|
||||
if (data.width > 0 && data.height > 0 && m_edge_pixels.size() >0 ) {
|
||||
for (unsigned int r = 0; r < data.height; ++r) {
|
||||
unsigned int rr = (data.height - 1 - r) * data.width;
|
||||
bool exist_rr_up = r >= 1 ? true : false;
|
||||
bool exist_rr_down = r <= data.height - 2 ? true : false;
|
||||
unsigned int rr_up = exist_rr_up ? (data.height - 1 - (r - 1)) * data.width : 0;
|
||||
unsigned int rr_down = exist_rr_down ? (data.height - 1 - (r + 1)) * data.width : 0;
|
||||
for (unsigned int c = 0; c < data.width; ++c) {
|
||||
bool exist_c_left = c >= 1 ? true : false;
|
||||
bool exist_c_right = c <= data.width - 2 ? true : false;
|
||||
unsigned int c_left = exist_c_left ? c - 1 : 0;
|
||||
unsigned int c_right = exist_c_right ? c + 1 : 0;
|
||||
unsigned char *cur_px = (unsigned char *) data.pixels.data() + 4 * (rr + c);
|
||||
unsigned char *relational_pxs[8] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
|
||||
if (exist_rr_up && exist_c_left) { relational_pxs[0] = (unsigned char *) data.pixels.data() + 4 * (rr_up + c_left); }
|
||||
if (exist_rr_up) { relational_pxs[1] = (unsigned char *) data.pixels.data() + 4 * (rr_up + c); }
|
||||
if (exist_rr_up && exist_c_right) { relational_pxs[2] = (unsigned char *) data.pixels.data() + 4 * (rr_up + c_right); }
|
||||
if (exist_c_left) { relational_pxs[3] = (unsigned char *) data.pixels.data() + 4 * (rr + c_left); }
|
||||
if (exist_c_right) { relational_pxs[4] = (unsigned char *) data.pixels.data() + 4 * (rr + c_right); }
|
||||
if (exist_rr_down && exist_c_left) { relational_pxs[5] = (unsigned char *) data.pixels.data() + 4 * (rr_down + c_left); }
|
||||
if (exist_rr_down) { relational_pxs[6] = (unsigned char *) data.pixels.data() + 4 * (rr_down + c); }
|
||||
if (exist_rr_down && exist_c_right) { relational_pxs[7] = (unsigned char *) data.pixels.data() + 4 * (rr_down + c_right); }
|
||||
if (cur_px[3] > 0 && m_edge_pixels[r * data.width + c]) {
|
||||
int rgba_sum[4] = {0, 0, 0, 0};
|
||||
int valid_count = 0;
|
||||
for (size_t k = 0; k < 8; k++) {
|
||||
if (relational_pxs[k]) {
|
||||
if (k == 0 && m_edge_pixels[(r - 1) * data.width + c_left]) {
|
||||
continue;
|
||||
}
|
||||
if (k == 1 && m_edge_pixels[(r - 1) * data.width + c]) {
|
||||
continue;
|
||||
}
|
||||
if (k == 2 && m_edge_pixels[(r - 1) * data.width + c_right]) {
|
||||
continue;
|
||||
}
|
||||
if (k == 3 && m_edge_pixels[r * data.width + c_left]) {
|
||||
continue;
|
||||
}
|
||||
if (k == 4 && m_edge_pixels[r * data.width + c_right]) {
|
||||
continue;
|
||||
}
|
||||
if (k == 5 && m_edge_pixels[(r + 1) * data.width + c_left]) {
|
||||
continue;
|
||||
}
|
||||
if (k == 6 && m_edge_pixels[(r + 1) * data.width + c]) {
|
||||
continue;
|
||||
}
|
||||
if (k == 7 && m_edge_pixels[(r + 1) * data.width + c_right]) {
|
||||
continue;
|
||||
}
|
||||
for (size_t m = 0; m < 4; m++) {
|
||||
rgba_sum[m] += relational_pxs[k][m];
|
||||
}
|
||||
valid_count++;
|
||||
}
|
||||
}
|
||||
if (valid_count > 0) {
|
||||
for (size_t m = 0; m < 4; m++) {
|
||||
cur_px[m] = std::clamp(int(rgba_sum[m] / (float)valid_count), 0, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SelectMachineDialog::updata_thumbnail_data_after_connected_printer()
|
||||
{
|
||||
// change thumbnail_data
|
||||
ThumbnailData &input_data = m_plater->get_partplate_list().get_curr_plate()->thumbnail_data;
|
||||
ThumbnailData &no_light_data = m_plater->get_partplate_list().get_curr_plate()->no_light_thumbnail_data;
|
||||
if (input_data.width == 0 || input_data.height == 0 || no_light_data.width == 0 || no_light_data.height == 0) {
|
||||
wxGetApp().plater()->update_all_plate_thumbnails(false);
|
||||
}
|
||||
unify_deal_thumbnail_data(input_data, no_light_data);
|
||||
}
|
||||
|
||||
void SelectMachineDialog::unify_deal_thumbnail_data(ThumbnailData &input_data, ThumbnailData &no_light_data) {
|
||||
if (input_data.width == 0 || input_data.height == 0 || no_light_data.width == 0 || no_light_data.height == 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SelectMachineDialog::no_light_data is empty,error";
|
||||
return;
|
||||
}
|
||||
m_cur_input_thumbnail_data = input_data;
|
||||
m_cur_no_light_thumbnail_data = no_light_data;
|
||||
clone_thumbnail_data();
|
||||
MaterialHash::iterator iter = m_materialList.begin();
|
||||
bool is_connect_printer = true;
|
||||
while (iter != m_materialList.end()) {
|
||||
int id = iter->first;
|
||||
Material * item = iter->second;
|
||||
MaterialItem *m = item->item;
|
||||
if (m->m_ams_name == "-") {
|
||||
is_connect_printer = false;
|
||||
break;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
if (is_connect_printer) {
|
||||
change_default_normal(-1, wxColour());
|
||||
final_deal_edge_pixels_data(m_preview_thumbnail_data);
|
||||
set_default_normal(m_preview_thumbnail_data);
|
||||
}
|
||||
}
|
||||
|
||||
void SelectMachineDialog::change_default_normal(int old_filament_id, wxColour temp_ams_color)
|
||||
{
|
||||
if (m_cur_colors_in_thumbnail.size() == 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << "SelectMachineDialog::change_default_normal:error:m_cur_colors_in_thumbnail.size() == 0";
|
||||
return;
|
||||
}
|
||||
if (old_filament_id >= 0) {
|
||||
if (old_filament_id < m_cur_colors_in_thumbnail.size()) {
|
||||
m_cur_colors_in_thumbnail[old_filament_id] = temp_ams_color;
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(error) << "SelectMachineDialog::change_default_normal:error:old_filament_id > m_cur_colors_in_thumbnail.size()";
|
||||
return;
|
||||
}
|
||||
}
|
||||
ThumbnailData& data = m_cur_input_thumbnail_data;
|
||||
ThumbnailData& no_light_data = m_cur_no_light_thumbnail_data;
|
||||
if (data.width > 0 && data.height > 0 && data.width == no_light_data.width && data.height == no_light_data.height) {
|
||||
for (unsigned int r = 0; r < data.height; ++r) {
|
||||
unsigned int rr = (data.height - 1 - r) * data.width;
|
||||
for (unsigned int c = 0; c < data.width; ++c) {
|
||||
unsigned char *no_light_px = (unsigned char *) no_light_data.pixels.data() + 4 * (rr + c);
|
||||
unsigned char *origin_px = (unsigned char *) data.pixels.data() + 4 * (rr + c);
|
||||
unsigned char *new_px = (unsigned char *) m_preview_thumbnail_data.pixels.data() + 4 * (rr + c);
|
||||
if (origin_px[3] > 0 && m_edge_pixels[r * data.width + c] == false) {
|
||||
auto filament_id = 255 - no_light_px[3];
|
||||
if (filament_id >= m_cur_colors_in_thumbnail.size()) {
|
||||
continue;
|
||||
}
|
||||
wxColour temp_ams_color_in_loop = m_cur_colors_in_thumbnail[filament_id];
|
||||
wxColour ams_color = adjust_color_for_render(temp_ams_color_in_loop);
|
||||
//change color
|
||||
new_px[3] = origin_px[3]; // alpha
|
||||
int origin_rgb = origin_px[0] + origin_px[1] + origin_px[2];
|
||||
int no_light_px_rgb = no_light_px[0] + no_light_px[1] + no_light_px[2];
|
||||
unsigned char i = 0;
|
||||
if (origin_rgb >= no_light_px_rgb) {//Brighten up
|
||||
unsigned char cur_single_color = ams_color.Red();
|
||||
new_px[i] = std::clamp(cur_single_color + (origin_px[i] - no_light_px[i]), 0, 255);
|
||||
i++;
|
||||
cur_single_color = ams_color.Green();
|
||||
new_px[i] = std::clamp(cur_single_color + (origin_px[i] - no_light_px[i]), 0, 255);
|
||||
i++;
|
||||
cur_single_color = ams_color.Blue();
|
||||
new_px[i] = std::clamp(cur_single_color + (origin_px[i] - no_light_px[i]), 0, 255);
|
||||
} else {//Dimming
|
||||
float ratio = origin_rgb / (float) no_light_px_rgb;
|
||||
unsigned char cur_single_color = ams_color.Red();
|
||||
new_px[i] = std::clamp((int)(cur_single_color * ratio), 0, 255);
|
||||
i++;
|
||||
cur_single_color = ams_color.Green();
|
||||
new_px[i] = std::clamp((int) (cur_single_color * ratio), 0, 255);
|
||||
i++;
|
||||
cur_single_color = ams_color.Blue();
|
||||
new_px[i] = std::clamp((int) (cur_single_color * ratio), 0, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(error) << "SelectMachineDialog::change_defa:no_light_data is empty,error";
|
||||
}
|
||||
}
|
||||
|
||||
void SelectMachineDialog::set_default_normal(const ThumbnailData &data)
|
||||
{
|
||||
update_page_turn_state(false);
|
||||
ThumbnailData& data = m_plater->get_partplate_list().get_curr_plate()->thumbnail_data;
|
||||
if (data.is_valid()) {
|
||||
wxImage image(data.width, data.height);
|
||||
image.InitAlpha();
|
||||
|
@ -3955,135 +4346,6 @@ void SelectMachineDialog::set_default_normal()
|
|||
m_thumbnailPanel->set_thumbnail(image);
|
||||
}
|
||||
|
||||
//for black list
|
||||
std::vector<std::string> materials;
|
||||
std::vector<std::string> brands;
|
||||
std::vector<std::string> display_materials;
|
||||
std::vector<std::string> m_filaments_id;
|
||||
|
||||
|
||||
auto preset_bundle = wxGetApp().preset_bundle;
|
||||
|
||||
for (auto filament_name : preset_bundle->filament_presets) {
|
||||
for (int f_index = 0; f_index < preset_bundle->filaments.size(); f_index++) {
|
||||
PresetCollection* filament_presets = &wxGetApp().preset_bundle->filaments;
|
||||
Preset* preset = &filament_presets->preset(f_index);
|
||||
|
||||
if (preset && filament_name.compare(preset->name) == 0) {
|
||||
std::string display_filament_type;
|
||||
std::string filament_type = preset->config.get_filament_type(display_filament_type);
|
||||
std::string m_filament_id=preset->filament_id;
|
||||
display_materials.push_back(display_filament_type);
|
||||
materials.push_back(filament_type);
|
||||
m_filaments_id.push_back(m_filament_id);
|
||||
|
||||
std::string m_vendor_name = "";
|
||||
auto vendor = dynamic_cast<ConfigOptionStrings*> (preset->config.option("filament_vendor"));
|
||||
if (vendor && (vendor->values.size() > 0)) {
|
||||
std::string vendor_name = vendor->values[0];
|
||||
m_vendor_name = vendor_name;
|
||||
}
|
||||
brands.push_back(m_vendor_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//init MaterialItem
|
||||
auto extruders = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_used_extruders();
|
||||
|
||||
MaterialHash::iterator iter = m_materialList.begin();
|
||||
while (iter != m_materialList.end()) {
|
||||
int id = iter->first;
|
||||
Material* item = iter->second;
|
||||
item->item->Destroy();
|
||||
delete item;
|
||||
iter++;
|
||||
}
|
||||
|
||||
m_sizer_material->Clear();
|
||||
m_materialList.clear();
|
||||
m_filaments.clear();
|
||||
|
||||
for (auto i = 0; i < extruders.size(); i++) {
|
||||
auto extruder = extruders[i] - 1;
|
||||
auto colour = wxGetApp().preset_bundle->project_config.opt_string("filament_colour", (unsigned int) extruder);
|
||||
ColorRGBA rgb;
|
||||
decode_color(colour, rgb);
|
||||
|
||||
auto colour_rgb = wxColour((int) rgb.r_uchar(), (int) rgb.g_uchar(), (int) rgb.b_uchar(), (int) rgb.a_uchar());
|
||||
if (extruder >= materials.size() || extruder < 0 || extruder >= display_materials.size())
|
||||
continue;
|
||||
|
||||
MaterialItem* item = new MaterialItem(m_scrollable_region, colour_rgb, _L(display_materials[extruder]));
|
||||
m_sizer_material->Add(item, 0, wxALL, FromDIP(4));
|
||||
|
||||
item->Bind(wxEVT_LEFT_UP, [this, item, materials, extruder](wxMouseEvent& e) {});
|
||||
item->Bind(wxEVT_LEFT_DOWN, [this, item, materials, extruder](wxMouseEvent& e) {
|
||||
MaterialHash::iterator iter = m_materialList.begin();
|
||||
while (iter != m_materialList.end()) {
|
||||
int id = iter->first;
|
||||
Material* item = iter->second;
|
||||
MaterialItem* m = item->item;
|
||||
m->on_normal();
|
||||
iter++;
|
||||
}
|
||||
|
||||
m_current_filament_id = extruder;
|
||||
item->on_selected();
|
||||
|
||||
|
||||
auto mouse_pos = ClientToScreen(e.GetPosition());
|
||||
wxPoint rect = item->ClientToScreen(wxPoint(0, 0));
|
||||
|
||||
// update ams data
|
||||
DeviceManager* dev_manager = Slic3r::GUI::wxGetApp().getDeviceManager();
|
||||
if (!dev_manager) return;
|
||||
MachineObject* obj_ = dev_manager->get_selected_machine();
|
||||
|
||||
if (obj_ && obj_->is_support_ams_mapping()) {
|
||||
if (m_mapping_popup.IsShown()) return;
|
||||
wxPoint pos = item->ClientToScreen(wxPoint(0, 0));
|
||||
pos.y += item->GetRect().height;
|
||||
m_mapping_popup.Move(pos);
|
||||
|
||||
if (obj_ &&
|
||||
obj_->has_ams() &&
|
||||
m_checkbox_list["use_ams"]->GetValue() &&
|
||||
obj_->dev_id == m_printer_last_select)
|
||||
{
|
||||
m_mapping_popup.set_parent_item(item);
|
||||
m_mapping_popup.set_current_filament_id(extruder);
|
||||
m_mapping_popup.set_tag_texture(materials[extruder]);
|
||||
m_mapping_popup.update_ams_data(obj_->amsList);
|
||||
m_mapping_popup.Popup();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Material* material_item = new Material();
|
||||
material_item->id = extruder;
|
||||
material_item->item = item;
|
||||
m_materialList[i] = material_item;
|
||||
|
||||
// build for ams mapping
|
||||
if (extruder < materials.size() && extruder >= 0) {
|
||||
FilamentInfo info;
|
||||
info.id = extruder;
|
||||
info.type = materials[extruder];
|
||||
info.brand = brands[extruder];
|
||||
info.filament_id=m_filaments_id[extruder];
|
||||
info.color = wxString::Format("#%02X%02X%02X%02X", colour_rgb.Red(), colour_rgb.Green(), colour_rgb.Blue(), colour_rgb.Alpha()).ToStdString();
|
||||
m_filaments.push_back(info);
|
||||
}
|
||||
}
|
||||
|
||||
if (extruders.size() <= 4) {
|
||||
m_sizer_material->SetCols(extruders.size());
|
||||
}
|
||||
else {
|
||||
m_sizer_material->SetCols(4);
|
||||
}
|
||||
|
||||
m_scrollable_region->Layout();
|
||||
m_scrollable_region->Fit();
|
||||
|
||||
|
@ -4112,10 +4374,6 @@ void SelectMachineDialog::set_default_normal()
|
|||
m_scrollable_view->SetScrollRate(0, 0);
|
||||
}
|
||||
#endif // __WXOSX_MAC__
|
||||
|
||||
|
||||
reset_ams_material();
|
||||
|
||||
// basic info
|
||||
auto aprint_stats = m_plater->get_partplate_list().get_current_fff_print().print_statistics();
|
||||
wxString time;
|
||||
|
@ -4149,7 +4407,7 @@ void SelectMachineDialog::set_default_from_sdcard()
|
|||
image = image.Rescale(FromDIP(256), FromDIP(256));
|
||||
m_thumbnailPanel->set_thumbnail(image);
|
||||
}
|
||||
|
||||
|
||||
//for black list
|
||||
std::vector<std::string> materials;
|
||||
std::vector<std::string> brands;
|
||||
|
@ -4556,9 +4814,10 @@ void EditDevNameDialog::on_edit_name(wxCommandEvent &e)
|
|||
Fit();
|
||||
}
|
||||
|
||||
void ThumbnailPanel::set_thumbnail(wxImage img)
|
||||
void ThumbnailPanel::set_thumbnail(wxImage &img)
|
||||
{
|
||||
m_bitmap = img;
|
||||
m_brightness_value = get_brightness_value(img);
|
||||
m_bitmap = img;
|
||||
//Paint the background bitmap to the thumbnail bitmap with wxMemoryDC
|
||||
wxMemoryDC dc;
|
||||
bitmap_with_background.Create(wxSize(m_bitmap.GetWidth(), m_bitmap.GetHeight()));
|
||||
|
@ -4577,7 +4836,7 @@ void EditDevNameDialog::on_edit_name(wxCommandEvent &e)
|
|||
|
||||
void ThumbnailPanel::render(wxDC& dc) {
|
||||
|
||||
if (wxGetApp().dark_mode()) {
|
||||
if (wxGetApp().dark_mode() && m_brightness_value < SHOW_BACKGROUND_BITMAP_PIXEL_THRESHOLD) {
|
||||
#ifdef __WXMSW__
|
||||
wxMemoryDC memdc;
|
||||
wxBitmap bmp(GetSize());
|
||||
|
|
|
@ -445,6 +445,12 @@ protected:
|
|||
wxStaticBitmap * img_use_ams_tip{nullptr};
|
||||
wxStaticBitmap * img_ams_backup{nullptr};
|
||||
ScalableBitmap * enable_ams{nullptr};
|
||||
ThumbnailData m_cur_input_thumbnail_data;
|
||||
ThumbnailData m_cur_no_light_thumbnail_data;
|
||||
ThumbnailData m_preview_thumbnail_data;//when ams map change
|
||||
std::vector<wxColour> m_preview_colors_in_thumbnail;
|
||||
std::vector<wxColour> m_cur_colors_in_thumbnail;
|
||||
std::vector<bool> m_edge_pixels;
|
||||
|
||||
public:
|
||||
SelectMachineDialog(Plater *plater = nullptr);
|
||||
|
@ -483,7 +489,15 @@ public:
|
|||
void on_set_finish_mapping(wxCommandEvent& evt);
|
||||
void on_print_job_cancel(wxCommandEvent& evt);
|
||||
void set_default();
|
||||
void set_default_normal();
|
||||
void reset_and_sync_ams_list();
|
||||
void clone_thumbnail_data();
|
||||
void record_edge_pixels_data();
|
||||
wxColour adjust_color_for_render(const wxColour& color);
|
||||
void final_deal_edge_pixels_data(ThumbnailData& data);
|
||||
void updata_thumbnail_data_after_connected_printer();
|
||||
void unify_deal_thumbnail_data(ThumbnailData &input_data, ThumbnailData &no_light_data);
|
||||
void change_default_normal(int old_filament_id, wxColour temp_ams_color);
|
||||
void set_default_normal(const ThumbnailData&);
|
||||
void set_default_from_sdcard();
|
||||
void update_page_turn_state(bool show);
|
||||
void on_timer(wxTimerEvent& event);
|
||||
|
@ -567,12 +581,12 @@ public:
|
|||
void OnPaint(wxPaintEvent &event);
|
||||
void PaintBackground(wxDC &dc);
|
||||
void OnEraseBackground(wxEraseEvent &event);
|
||||
void set_thumbnail(wxImage img);
|
||||
void set_thumbnail(wxImage &img);
|
||||
void render(wxDC &dc);
|
||||
private:
|
||||
ScalableBitmap m_background_bitmap;
|
||||
wxBitmap bitmap_with_background;
|
||||
|
||||
int m_brightness_value{ -1 };
|
||||
};
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
|
|
@ -561,11 +561,19 @@ void PrintingTaskPanel::create_panel(wxWindow* parent)
|
|||
void PrintingTaskPanel::paint(wxPaintEvent&)
|
||||
{
|
||||
wxPaintDC dc(m_bitmap_thumbnail);
|
||||
if (wxGetApp().dark_mode())
|
||||
dc.DrawBitmap(m_bitmap_background.bmp(), 0, 0);
|
||||
if (wxGetApp().dark_mode()) {
|
||||
if (m_brightness_value > 0 && m_brightness_value < SHOW_BACKGROUND_BITMAP_PIXEL_THRESHOLD) {
|
||||
dc.DrawBitmap(m_bitmap_background.bmp(), 0, 0);
|
||||
dc.SetTextForeground(*wxBLACK);
|
||||
}
|
||||
else
|
||||
dc.SetTextForeground(*wxWHITE);
|
||||
}
|
||||
else
|
||||
dc.SetTextForeground(*wxBLACK);
|
||||
dc.DrawBitmap(m_thumbnail_bmp_display, wxPoint(0, 0));
|
||||
dc.SetTextForeground(*wxBLACK);
|
||||
dc.SetFont(Label::Body_12);
|
||||
|
||||
if (m_plate_index >= 0) {
|
||||
wxString plate_id_str = wxString::Format("%d", m_plate_index);
|
||||
dc.DrawText(plate_id_str, wxPoint(4, 4));
|
||||
|
@ -1990,6 +1998,7 @@ void StatusPanel::on_webrequest_state(wxWebRequestEvent &evt)
|
|||
img_list.insert(std::make_pair(m_request_url, img));
|
||||
wxImage resize_img = img.Scale(m_project_task_panel->get_bitmap_thumbnail()->GetSize().x, m_project_task_panel->get_bitmap_thumbnail()->GetSize().y, wxIMAGE_QUALITY_HIGH);
|
||||
m_project_task_panel->set_thumbnail_img(resize_img);
|
||||
m_project_task_panel->set_brightness_value(get_brightness_value(resize_img));
|
||||
}
|
||||
if (obj) {
|
||||
m_project_task_panel->set_plate_index(obj->m_plate_index);
|
||||
|
@ -3229,6 +3238,7 @@ void StatusPanel::update_cloud_subtask(MachineObject *obj)
|
|||
img = it->second;
|
||||
wxImage resize_img = img.Scale(m_project_task_panel->get_bitmap_thumbnail()->GetSize().x, m_project_task_panel->get_bitmap_thumbnail()->GetSize().y);
|
||||
m_project_task_panel->set_thumbnail_img(resize_img);
|
||||
m_project_task_panel->set_brightness_value(get_brightness_value(resize_img));
|
||||
}
|
||||
if (this->obj) {
|
||||
m_project_task_panel->set_plate_index(obj->m_plate_index);
|
||||
|
|
|
@ -206,6 +206,7 @@ private:
|
|||
ProgressBar* m_gauge_progress;
|
||||
Label* m_error_text;
|
||||
PrintingTaskType m_type;
|
||||
int m_brightness_value{ -1 };
|
||||
|
||||
public:
|
||||
void init_bitmaps();
|
||||
|
@ -227,6 +228,7 @@ public:
|
|||
void show_priting_use_info(bool show, wxString time = wxEmptyString, wxString weight = wxEmptyString);
|
||||
void show_profile_info(bool show, wxString profile = wxEmptyString);
|
||||
void set_thumbnail_img(const wxBitmap& bmp);
|
||||
void set_brightness_value(int value) { m_brightness_value = value; }
|
||||
void set_plate_index(int plate_idx = -1);
|
||||
void market_scoring_show();
|
||||
void market_scoring_hide();
|
||||
|
@ -246,7 +248,6 @@ public:
|
|||
void set_star_count_dirty(bool dirty) { m_star_count_dirty = dirty; }
|
||||
void set_has_reted_text(bool has_rated);
|
||||
void paint(wxPaintEvent&);
|
||||
|
||||
};
|
||||
|
||||
class StatusBasePanel : public wxScrolledWindow
|
||||
|
|
Loading…
Reference in a new issue