NEW:Use instance rendering by opengl for plate

jira: none
Change-Id: I3d5888480ad033953a597a6f74b0b9c8ac47795e
(cherry picked from commit 7fa3cb3d6224bab6ef6d8ad75446ed1b460afd4e)
This commit is contained in:
zhou.xu 2024-07-23 09:29:42 +08:00 committed by Lane.Wei
parent 66403ba19f
commit bb53c4b517
13 changed files with 794 additions and 383 deletions

View File

@ -0,0 +1,12 @@
#version 110
uniform mat4 view_matrix;
uniform mat4 projection_matrix;
attribute vec3 v_position;
attribute vec2 v_undefine;
attribute mat4 instanceMatrix;
void main()
{
gl_Position = projection_matrix * view_matrix * instanceMatrix * vec4(v_position, 1.0);
}

View File

@ -1,8 +0,0 @@
#version 110
uniform vec4 uniform_color;
void main()
{
gl_FragColor = uniform_color;
}

View File

@ -1,11 +0,0 @@
#version 110
uniform mat4 view_model_matrix;
uniform mat4 projection_matrix;
attribute vec3 v_position;
void main()
{
gl_Position = projection_matrix * view_model_matrix * vec4(v_position, 1.0);
}

View File

@ -2234,7 +2234,7 @@ std::map<std::string, std::vector<Preset const *>> PresetCollection::get_filamen
}
//BBS: add project embedded preset logic
void PresetCollection::save_current_preset(const std::string &new_name, bool detach, bool save_to_project, Preset* _curr_preset)
void PresetCollection::save_current_preset(const std::string &new_name, bool detach, bool save_to_project, Preset *_curr_preset, std::map<std::string, std::string> *extra_map)
{
Preset curr_preset = _curr_preset ? *_curr_preset : m_edited_preset;
//BBS: add lock logic for sync preset in background
@ -2273,8 +2273,12 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
preset.config.option<ConfigOptionString>("print_settings_id", true)->value = new_name;
else if (m_type == Preset::TYPE_FILAMENT)
preset.config.option<ConfigOptionStrings>("filament_settings_id", true)->values[0] = new_name;
else if (m_type == Preset::TYPE_PRINTER)
else if (m_type == Preset::TYPE_PRINTER) {
preset.config.option<ConfigOptionString>("printer_settings_id", true)->value = new_name;
for (auto iter : *extra_map) {
preset.config.option<ConfigOptionString>(iter.first, true)->value = iter.second;
}
}
final_inherits = preset.inherits();
unlock();
// TODO: apply change from custom root to devided presets.
@ -2318,8 +2322,12 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
preset.config.option<ConfigOptionString>("print_settings_id", true)->value = new_name;
else if (m_type == Preset::TYPE_FILAMENT)
preset.config.option<ConfigOptionStrings>("filament_settings_id", true)->values[0] = new_name;
else if (m_type == Preset::TYPE_PRINTER)
else if (m_type == Preset::TYPE_PRINTER) {
preset.config.option<ConfigOptionString>("printer_settings_id", true)->value = new_name;
for (auto iter : *extra_map) {
preset.config.option<ConfigOptionString>(iter.first, true)->value = iter.second;
}
}
//BBS: add lock logic for sync preset in background
final_inherits = inherits;
unlock();

View File

@ -506,7 +506,7 @@ public:
// a new preset is stored into the list of presets.
// All presets are marked as not modified and the new preset is activated.
//BBS: add project embedded preset logic
void save_current_preset(const std::string &new_name, bool detach = false, bool save_to_project = false, Preset* _curr_preset = nullptr);
void save_current_preset(const std::string &new_name, bool detach = false, bool save_to_project = false, Preset *_curr_preset = nullptr, std::map<std::string, std::string>* extra_map =nullptr);
// Delete the current preset, activate the first visible preset.
// returns true if the preset was deleted successfully.

View File

@ -897,6 +897,130 @@ void GLModel::render_geometry(int i,const std::pair<size_t, size_t> &range)
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
void GLModel::create_or_update_mats_vbo(unsigned int &vbo, const std::vector<Slic3r::Geometry::Transformation> &mats)
{ // first bind
if (vbo>0) {
glsafe(::glDeleteBuffers(1, &vbo));
}
std::vector<Matrix4f> out_mats;
out_mats.reserve(mats.size());
for (size_t i = 0; i < mats.size(); i++) {
out_mats.emplace_back(mats[i].get_matrix().matrix().cast<float>());
}
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
auto one_mat_all_size = sizeof(float) * 16;
glBufferData(GL_ARRAY_BUFFER, mats.size() * one_mat_all_size, out_mats.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void GLModel::bind_mats_vbo(unsigned int instance_mats_vbo, unsigned int instances_count, int location)
{
auto one_mat_all_size = sizeof(float) * 16;
auto one_mat_col_size = sizeof(float) * 4;
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, instance_mats_vbo));
for (unsigned int i = 0; i < instances_count; i++) { // set attribute pointers for matrix (4 times vec4)
glEnableVertexAttribArray(location);
glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, one_mat_all_size, (void *) 0);
glEnableVertexAttribArray(location + 1);
glVertexAttribPointer(location + 1, 4, GL_FLOAT, GL_FALSE, one_mat_all_size, (void *) (one_mat_col_size));
glEnableVertexAttribArray(location + 2);
glVertexAttribPointer(location + 2, 4, GL_FLOAT, GL_FALSE, one_mat_all_size, (void *) (2 * one_mat_col_size));
glEnableVertexAttribArray(location + 3);
glVertexAttribPointer(location + 3, 4, GL_FLOAT, GL_FALSE, one_mat_all_size, (void *) (3 * one_mat_col_size));
// Update the matrix every time after an object is drawn//useful
glVertexAttribDivisor(location, 1);
glVertexAttribDivisor(location + 1, 1);
glVertexAttribDivisor(location + 2, 1);
glVertexAttribDivisor(location + 3, 1);
}
}
void GLModel::render_geometry_instance(unsigned int instance_mats_vbo, unsigned int instances_count)
{
render_geometry_instance(instance_mats_vbo, instances_count,std::make_pair<size_t, size_t>(0, indices_count()));
}
void GLModel::render_geometry_instance(unsigned int instance_mats_vbo, unsigned int instances_count, const std::pair<size_t, size_t> &range)
{
if (m_render_data.size() != 1) { return; }
GLShaderProgram *shader = wxGetApp().get_current_shader();
if (shader == nullptr) return;
auto &render_data = m_render_data[0];
// sends data to gpu if not done yet
if (render_data.vbo_id == 0 || render_data.ibo_id == 0) {
if (render_data.geometry.vertices_count() > 0 && render_data.geometry.indices_count() > 0 && !send_to_gpu(render_data.geometry))
return;
}
if (instance_mats_vbo == 0) {
return;
}
const Geometry &data = render_data.geometry;
const GLenum mode = get_primitive_mode(data.format);
const GLenum index_type = get_index_type(data);
const size_t vertex_stride_bytes = Geometry::vertex_stride_bytes(data.format);
const bool position = Geometry::has_position(data.format);
const bool normal = Geometry::has_normal(data.format);
const bool tex_coord = Geometry::has_tex_coord(data.format);
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, render_data.vbo_id));
int position_id = -1;
int normal_id = -1;
int tex_coord_id = -1;
int instace_mats_id = -1;
if (position) {
position_id = shader->get_attrib_location("v_position");
if (position_id != -1) {
glsafe(::glVertexAttribPointer(position_id, Geometry::position_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes,
(const void *) Geometry::position_offset_bytes(data.format)));
glsafe(::glEnableVertexAttribArray(position_id));
}
}
if (normal) {
normal_id = shader->get_attrib_location("v_normal");
if (normal_id != -1) {
glsafe(::glVertexAttribPointer(normal_id, Geometry::normal_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes,
(const void *) Geometry::normal_offset_bytes(data.format)));
glsafe(::glEnableVertexAttribArray(normal_id));
}
}
if (tex_coord) {
tex_coord_id = shader->get_attrib_location("v_tex_coord");
if (tex_coord_id != -1) {
glsafe(::glVertexAttribPointer(tex_coord_id, Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, GL_FALSE, vertex_stride_bytes,
(const void *) Geometry::tex_coord_offset_bytes(data.format)));
glsafe(::glEnableVertexAttribArray(tex_coord_id));
}
}
//glBindAttribLocation(shader->get_id(), 2, "instanceMatrix");
//glBindAttribLocation(2, "instanceMatrix");
//shader->bind(shaderProgram, 0, 'position');
instace_mats_id = shader->get_attrib_location("instanceMatrix");
if (instace_mats_id != -1) {
bind_mats_vbo(instance_mats_vbo, instances_count, instace_mats_id);
}
else {
return;
}
auto res = shader->set_uniform("uniform_color", render_data.color);
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, render_data.ibo_id));
glsafe(::glDrawElementsInstanced(mode, range.second - range.first, index_type, (const void *) (range.first * Geometry::index_stride_bytes(data)), instances_count));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
if (instace_mats_id != -1) glsafe(::glDisableVertexAttribArray(instace_mats_id));
if (tex_coord_id != -1) glsafe(::glDisableVertexAttribArray(tex_coord_id));
if (normal_id != -1) glsafe(::glDisableVertexAttribArray(normal_id));
if (position_id != -1) glsafe(::glDisableVertexAttribArray(position_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instances_count) const
{
if (instances_vbo == 0)
@ -974,7 +1098,59 @@ void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instance
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
bool GLModel::send_to_gpu(RenderData& data, const std::vector<float>& vertices, const std::vector<unsigned int>& indices) const
bool GLModel::send_to_gpu(Geometry &geometry)
{
if (m_render_data.size() != 1) { return false; }
auto& render_data = m_render_data[0];
if (render_data.vbo_id > 0 || render_data.ibo_id > 0) {
assert(false);
return false;
}
Geometry &data = render_data.geometry;
if (data.vertices.empty() || data.indices.empty()) {
assert(false);
return false;
}
// vertices
glsafe(::glGenBuffers(1, &render_data.vbo_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, render_data.vbo_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, data.vertices_size_bytes(), data.vertices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
render_data.vertices_count = vertices_count();
data.vertices = std::vector<float>();
// indices
glsafe(::glGenBuffers(1, &render_data.ibo_id));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, render_data.ibo_id));
const size_t indices_count = data.indices.size();
if (render_data.vertices_count <= 256) {
// convert indices to unsigned char to save gpu memory
std::vector<unsigned char> reduced_indices(indices_count);
for (size_t i = 0; i < indices_count; ++i) { reduced_indices[i] = (unsigned char) data.indices[i]; }
data.index_type = Geometry::EIndexType::UBYTE;
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_count * sizeof(unsigned char), reduced_indices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
} else if (render_data.vertices_count <= 65536) {
// convert indices to unsigned short to save gpu memory
std::vector<unsigned short> reduced_indices(indices_count);
for (size_t i = 0; i < data.indices.size(); ++i) { reduced_indices[i] = (unsigned short) data.indices[i]; }
data.index_type = Geometry::EIndexType::USHORT;
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_count * sizeof(unsigned short), reduced_indices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
} else {
data.index_type = Geometry::EIndexType::UINT;
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.indices_size_bytes(), data.indices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
render_data.indices_count = indices_count;
data.indices = std::vector<unsigned int>();
return true;
}
bool GLModel::send_to_gpu(RenderData &data, const std::vector<float> &vertices, const std::vector<unsigned int> &indices) const
{
if (data.vbo_id > 0 || data.ibo_id > 0) {
assert(false);

View File

@ -4,6 +4,7 @@
#include "libslic3r/Point.hpp"
#include "libslic3r/Color.hpp"
#include "libslic3r/BoundingBox.hpp"
#include "libslic3r/Geometry.hpp"
#include <vector>
#include <string>
@ -194,6 +195,10 @@ namespace GUI {
void render() const;
void render_geometry();
void render_geometry(int i,const std::pair<size_t, size_t> &range);
static void create_or_update_mats_vbo(unsigned int &vbo, const std::vector<Slic3r::Geometry::Transformation> &mats);
void bind_mats_vbo(unsigned int instance_mats_vbo, unsigned int instances_count, int location);
void render_geometry_instance(unsigned int instance_mats_vbo, unsigned int instances_count);
void render_geometry_instance(unsigned int instance_mats_vbo, unsigned int instances_count, const std::pair<size_t, size_t> &range);
void render_instanced(unsigned int instances_vbo, unsigned int instances_count) const;
bool is_initialized() const { return !m_render_data.empty(); }
@ -202,6 +207,7 @@ namespace GUI {
const std::string& get_filename() const { return m_filename; }
private:
bool send_to_gpu(Geometry& geometry);
bool send_to_gpu(RenderData &data, const std::vector<float> &vertices, const std::vector<unsigned int> &indices) const;
};

View File

@ -168,6 +168,9 @@ bool GLShaderProgram::init_from_texts(const std::string& name, const ShaderSourc
if (shader_ids[i] > 0)
glsafe(::glAttachShader(m_id, shader_ids[i]));
}
if (boost::ends_with(name,"_instance")) {
glBindAttribLocation(m_id, 3, "instanceMatrix");
}
glsafe(::glLinkProgram(m_id));
GLint params;
@ -364,13 +367,13 @@ int GLShaderProgram::get_attrib_location(const char* name) const
// Shader program not loaded. This should not happen.
return -1;
auto it = std::find_if(m_attrib_location_cache.begin(), m_attrib_location_cache.end(), [name](const auto& p) { return p.first == name; });
if (it != m_attrib_location_cache.end())
// Attrib ID cached.
return it->second;
//auto it = std::find_if(m_attrib_location_cache.begin(), m_attrib_location_cache.end(), [name](const auto& p) { return p.first == name; });
//if (it != m_attrib_location_cache.end())
// // Attrib ID cached.
// return it->second;
int id = ::glGetAttribLocation(m_id, name);
const_cast<GLShaderProgram*>(this)->m_attrib_location_cache.push_back({ name, id });
//const_cast<GLShaderProgram*>(this)->m_attrib_location_cache.push_back({ name, id });
return id;
}

View File

@ -39,7 +39,8 @@ std::pair<bool, std::string> GLShadersManager::init()
valid &= append_shader("thumbnail", { "thumbnail.vs", "thumbnail.fs" });
// used to render first layer for calibration
valid &= append_shader("cali", { "cali.vs", "cali.fs"});
valid &= append_shader("flat", {"flat.vs", "flat.fs"});
valid &= append_shader("flat", {"110/flat.vs", "110/flat.fs"});
valid &= append_shader("flat_instance", {"110/flat_instance.vs", "110/flat.fs"});
// used to render printbed
valid &= append_shader("printbed", {"110/printbed.vs", "110/printbed.fs"});
// used to render options in gcode preview

File diff suppressed because it is too large Load Diff

View File

@ -125,36 +125,12 @@ private:
mutable std::vector<BoundingBoxf3> m_exclude_bounding_box;
mutable BoundingBoxf3 m_grabber_box;
Transform3d m_grabber_trans_matrix;
Slic3r::Geometry::Transformation position;
std::vector<Vec3f> positions;
unsigned int m_vbo_id{ 0 };
GLModel m_triangles;
GLModel m_exclude_triangles;
GLModel m_logo_triangles;
GLModel m_gridlines;
GLModel m_gridlines_bolder;
GLModel m_height_limit_common;
GLModel m_height_limit_bottom;
GLModel m_height_limit_top;
GLModel m_del_icon;
GLModel m_plate_name_edit_icon;
//GeometryBuffer m_del_and_background_icon;
mutable unsigned int m_del_vbo_id{ 0 };
GLModel m_arrange_icon;
mutable unsigned int m_arrange_vbo_id{ 0 };
GLModel m_orient_icon;
mutable unsigned int m_orient_vbo_id{ 0 };
GLModel m_lock_icon;
mutable unsigned int m_lock_vbo_id{ 0 };
GLModel m_plate_settings_icon;
mutable unsigned int m_plate_settings_vbo_id{ 0 };
GLModel m_plate_filament_map_icon;
mutable unsigned int m_plate_filament_map_vbo_id{0};
GLModel m_plate_idx_icon;
mutable unsigned int m_plate_idx_vbo_id{ 0 };
mutable unsigned int m_plate_name_edit_vbo_id{0};
GLTexture m_texture;
float m_scale_factor{ 1.0f };
GLUquadricObject* m_quadric;
@ -179,24 +155,15 @@ private:
void generate_logo_polygon(ExPolygon &logo_polygon);
void generate_logo_polygon(ExPolygon &logo_polygon,const BoundingBoxf3& box);
void calc_bounding_boxes() const;
void calc_triangles(const ExPolygon& poly);
void calc_exclude_triangles(const ExPolygon& poly);
void calc_gridlines(const ExPolygon& poly, const BoundingBox& pp_bbox);
void calc_height_limit();
void calc_vertex_for_number(int index, bool one_number, GLModel &gl_model);
void calc_vertex_for_plate_name(GLTexture &texture, GLModel &buffer);
void calc_vertex_for_plate_name_edit_icon(GLTexture *texture, int index, GLModel &buffer);
void calc_vertex_for_icons(int index, GLModel &gl_model);
void calc_vertex_for_icons_background(int icon_count, GeometryBuffer &buffer);
void render_background(bool force_default_color = false);
bool calc_bed_3d_boundingbox(BoundingBoxf3 & box_in_plate_origin);
void render_logo(bool bottom, bool render_cali = true);
void render_logo_texture(GLTexture &logo_texture, GLModel &logo_buffer, bool bottom);
void render_exclude_area(bool force_default_color);
//void render_background_for_picking(const float* render_color) const;
void render_grid(bool bottom);
void render_height_limit(PartPlate::HeightLimitMode mode = HEIGHT_LIMIT_BOTH);
void render_label(GLCanvas3D& canvas) const;
void render_grabber(const float* render_color, bool use_lighting) const;
@ -209,7 +176,7 @@ private:
void render_plate_name_texture();
void render_icons(bool bottom, bool only_body = false, int hover_id = -1);
void render_only_numbers(bool bottom);
void render_numbers(bool bottom);
void on_render_for_picking();
std::array<float, 4> picking_color_component(int idx) const;
void release_opengl_resource();
@ -382,7 +349,6 @@ public:
bool intersects(const BoundingBoxf3& bb) const;
void render(bool bottom, bool only_body = false, bool force_background_color = false, HeightLimitMode mode = HEIGHT_LIMIT_NONE, int hover_id = -1, bool render_cali = false);
void render_for_picking() { on_render_for_picking(); }
void set_selected();
void set_unselected();
void set_hover_id(int id) { m_hover_id = id; }
@ -611,6 +577,39 @@ class PartPlateList : public ObjectBase
friend class cereal::access;
friend class UndoRedo::StackImpl;
friend class PartPlate;
//render plate repetitive object and so on
private:
void generate_print_polygon(ExPolygon &print_polygon);
void generate_exclude_polygon(ExPolygon &exclude_polygon);
void calc_triangles(const ExPolygon &poly);
void calc_vertex_for_icons(int index, GLModel &gl_model);
void calc_exclude_triangles(const ExPolygon &poly);
void calc_gridlines(const ExPolygon &poly, const BoundingBox &pp_bbox);
void calc_vertex_for_number(int index, bool one_number, GLModel &gl_model);
private:
int m_plate_hover_index{-1};
int m_plate_hover_action{-1};
std::vector<Geometry::Transformation> m_plate_trans; // MAX_PLATE_COUNT
unsigned int m_plate_mats_vbo{0};
bool m_update_plate_mats_vbo{true};
std::vector<Geometry::Transformation> m_unselected_plate_trans;
unsigned int m_unselected_plate_mats_vbo{0};
bool m_update_unselected_plate_mats_vbo{true};
GLModel m_triangles;
GLModel m_exclude_triangles;
GLModel m_gridlines;
GLModel m_gridlines_bolder;
GLModel m_del_icon;
GLModel m_arrange_icon;
GLModel m_orient_icon;
GLModel m_lock_icon;
GLModel m_plate_settings_icon;
GLModel m_plate_filament_map_icon;
GLModel m_plate_idx_icon;
float m_scale_factor{1.0f};
public:
class BedTextureInfo {
@ -676,9 +675,12 @@ public:
//compute the origin for printable plate with index i using new width
Vec3d compute_origin_using_new_size(int i, int new_width, int new_depth);
void update_plate_trans(int count);
void update_unselected_plate_trans(int count);
//reset partplate to init states
void reinit();
void set_bed3d(Bed3D* _bed3d);
Bed3D *get_bed3d() { return m_bed3d; }
//get the plate stride
double plate_stride_x();
double plate_stride_y();
@ -695,6 +697,7 @@ public:
//destroy print which has the index of print_index
int destroy_print(int print_index);
void add_plate();
//delete a plate by index
int delete_plate(int index);
@ -804,6 +807,18 @@ public:
void postprocess_arrange_polygon(arrangement::ArrangePolygon& arrange_polygon, bool selected);
/*rendering related functions*/
void render_instance(bool bottom,
bool only_current = false,
bool only_body = false,
bool force_background_color = false,
int hover_id = -1);
void render_instance_grid(bool bottom);
void render_instance_background(bool force_default_color = false);
void render_grid(bool bottom);
void render_background(bool force_default_color = false);
void render_exclude_area(bool force_default_color);
void render_instance_exclude_area(bool force_default_color);
void on_change_color_mode(bool is_dark) { m_is_dark = is_dark; }
void render(bool bottom, bool only_current = false, bool only_body = false, int hover_id = -1, bool render_cali = false);
void render_for_picking_pass();

View File

@ -6939,10 +6939,7 @@ void Plater::priv::on_action_add(SimpleEvent&)
void Plater::priv::on_action_add_plate(SimpleEvent&)
{
if (q != nullptr) {
take_snapshot("add partplate");
this->partplate_list.create_plate();
int new_plate = this->partplate_list.get_plate_count() - 1;
this->partplate_list.select_plate(new_plate);
partplate_list.add_plate();
update();
// BBS set default view

View File

@ -5070,7 +5070,21 @@ void Tab::save_preset(std::string name /*= ""*/, bool detach, bool save_to_proje
//BBS record current preset name
std::string curr_preset_name = m_presets->get_edited_preset().name;
auto curr_preset = m_presets->get_edited_preset();
std::map<std::string, std::string> extra_map;
{
bool is_configed_by_BBL = PresetUtils::system_printer_bed_model(curr_preset).size() > 0;
if (is_configed_by_BBL && wxGetApp().app_config->has_section("user_bbl_svg_list")) {
auto user_bbl_svg_list = wxGetApp().app_config->get_section("user_bbl_svg_list");
if (user_bbl_svg_list.size() > 0 && user_bbl_svg_list[curr_preset_name].size() > 0) {
extra_map["bed_custom_texture"] = ConfigOptionString(user_bbl_svg_list[curr_preset_name]);
}
}
auto bed_model_path = wxGetApp().plater()->get_partplate_list().get_bed3d()->get_model_filename();
if (!bed_model_path.empty()) {
extra_map["bed_custom_model"] = bed_model_path;
}
}
bool exist_preset = false;
Preset* new_preset = m_presets->find_preset(name, false);
if (new_preset) {
@ -5078,7 +5092,7 @@ void Tab::save_preset(std::string name /*= ""*/, bool detach, bool save_to_proje
}
// Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini
m_presets->save_current_preset(name, detach, save_to_project);
m_presets->save_current_preset(name, detach, save_to_project, nullptr, &extra_map);
//BBS create new settings
new_preset = m_presets->find_preset(name, false, true);