WIP Restoration of the layer editing.

This commit is contained in:
bubnikv 2019-01-21 10:06:51 +01:00
parent 3e28905621
commit d64b55d27d
17 changed files with 398 additions and 569 deletions

View file

@ -819,12 +819,16 @@ GLCanvas3D::LayersEditing::LayersEditing()
: m_use_legacy_opengl(false)
, m_enabled(false)
, m_z_texture_id(0)
, m_model_object(nullptr)
, m_object_max_z(0.f)
, m_slicing_parameters(new SlicingParameters)
, m_layer_height_profile_modified(false)
, state(Unknown)
, band_width(2.0f)
, strength(0.005f)
, last_object_id(-1)
, last_z(0.0f)
, last_action(0)
, last_action(LAYER_HEIGHT_EDIT_ACTION_INCREASE)
{
}
@ -835,6 +839,7 @@ GLCanvas3D::LayersEditing::~LayersEditing()
::glDeleteTextures(1, &m_z_texture_id);
m_z_texture_id = 0;
}
delete m_slicing_parameters;
}
bool GLCanvas3D::LayersEditing::init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename)
@ -854,9 +859,20 @@ bool GLCanvas3D::LayersEditing::init(const std::string& vertex_shader_filename,
return true;
}
void GLCanvas3D::LayersEditing::select_object(const Model &model, int object_id)
{
m_model_object = (object_id >= 0) ? model.objects[object_id] : nullptr;
m_object_max_z = (m_model_object == nullptr) ? 0.f : m_model_object->bounding_box().max.z();
if (m_model_object == nullptr || this->last_object_id != object_id) {
m_layer_height_profile.clear();
m_layer_height_profile_modified = false;
}
this->last_object_id = object_id;
}
bool GLCanvas3D::LayersEditing::is_allowed() const
{
return !m_use_legacy_opengl && m_shader.is_initialized();
return !m_use_legacy_opengl && m_shader.is_initialized() && m_shader.get_shader()->shader_program_id > 0 && m_z_texture_id > 0;
}
void GLCanvas3D::LayersEditing::set_use_legacy_opengl(bool use_legacy_opengl)
@ -874,12 +890,7 @@ void GLCanvas3D::LayersEditing::set_enabled(bool enabled)
m_enabled = is_allowed() && enabled;
}
unsigned int GLCanvas3D::LayersEditing::get_z_texture_id() const
{
return m_z_texture_id;
}
void GLCanvas3D::LayersEditing::render(const GLCanvas3D& canvas, const PrintObject& print_object, const GLVolume& volume) const
void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
{
if (!m_enabled)
return;
@ -896,8 +907,8 @@ void GLCanvas3D::LayersEditing::render(const GLCanvas3D& canvas, const PrintObje
_render_tooltip_texture(canvas, bar_rect, reset_rect);
_render_reset_texture(reset_rect);
_render_active_object_annotations(canvas, volume, print_object, bar_rect);
_render_profile(print_object, bar_rect);
_render_active_object_annotations(canvas, bar_rect);
_render_profile(bar_rect);
// Revert the matrices.
::glPopMatrix();
@ -905,12 +916,6 @@ void GLCanvas3D::LayersEditing::render(const GLCanvas3D& canvas, const PrintObje
::glEnable(GL_DEPTH_TEST);
}
int GLCanvas3D::LayersEditing::get_shader_program_id() const
{
const GLShader* shader = m_shader.get_shader();
return (shader != nullptr) ? shader->shader_program_id : -1;
}
float GLCanvas3D::LayersEditing::get_cursor_z_relative(const GLCanvas3D& canvas)
{
const Point& mouse_pos = canvas.get_local_mouse_position();
@ -1023,21 +1028,19 @@ void GLCanvas3D::LayersEditing::_render_reset_texture(const Rect& reset_rect) co
GLTexture::render_texture(m_reset_texture.get_id(), reset_rect.get_left(), reset_rect.get_right(), reset_rect.get_bottom(), reset_rect.get_top());
}
void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas3D& canvas, const GLVolume& volume, const PrintObject& print_object, const Rect& bar_rect) const
void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const
{
float max_z = print_object.model_object()->bounding_box().max(2);
m_shader.start_using();
m_shader.set_uniform("z_to_texture_row", (float)volume.layer_height_texture_z_to_row_id());
m_shader.set_uniform("z_texture_row_to_normalized", 1.0f / (float)volume.layer_height_texture_height());
m_shader.set_uniform("z_cursor", max_z * get_cursor_z_relative(canvas));
m_shader.set_uniform("z_to_texture_row", float(m_layers_texture.cells - 1) / (float(m_layers_texture.width) * m_object_max_z));
m_shader.set_uniform("z_texture_row_to_normalized", 1.0f / (float)m_layers_texture.height);
m_shader.set_uniform("z_cursor", m_object_max_z * this->get_cursor_z_relative(canvas));
m_shader.set_uniform("z_cursor_band_width", band_width);
// The shader requires the original model coordinates when rendering to the texture, so we pass it the unit matrix
m_shader.set_uniform("volume_world_matrix", UNIT_MATRIX);
GLsizei w = (GLsizei)volume.layer_height_texture_width();
GLsizei h = (GLsizei)volume.layer_height_texture_height();
GLsizei w = (GLsizei)m_layers_texture.width;
GLsizei h = (GLsizei)m_layers_texture.height;
GLsizei half_w = w / 2;
GLsizei half_h = h / 2;
@ -1045,8 +1048,8 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas
::glBindTexture(GL_TEXTURE_2D, m_z_texture_id);
::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
::glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, volume.layer_height_texture_data_ptr_level0());
::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, volume.layer_height_texture_data_ptr_level1());
::glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data());
::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data() + m_layers_texture.width * m_layers_texture.height * 4);
// Render the color bar
float l = bar_rect.get_left();
@ -1057,25 +1060,24 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas
::glBegin(GL_QUADS);
::glVertex3f(l, b, 0.0f);
::glVertex3f(r, b, 0.0f);
::glVertex3f(r, t, max_z);
::glVertex3f(l, t, max_z);
::glVertex3f(r, t, m_object_max_z);
::glVertex3f(l, t, m_object_max_z);
::glEnd();
::glBindTexture(GL_TEXTURE_2D, 0);
m_shader.stop_using();
}
void GLCanvas3D::LayersEditing::_render_profile(const PrintObject& print_object, const Rect& bar_rect) const
void GLCanvas3D::LayersEditing::_render_profile(const Rect& bar_rect) const
{
// FIXME show some kind of legend.
//FIXME show some kind of legend.
// Get a maximum layer height value.
// FIXME This is a duplicate code of Slicing.cpp.
//FIXME This is a duplicate code of Slicing.cpp.
double layer_height_max = DBL_MAX;
const PrintConfig& print_config = print_object.print()->config();
const std::vector<double>& nozzle_diameters = dynamic_cast<const ConfigOptionFloats*>(print_config.option("nozzle_diameter"))->values;
const std::vector<double>& layer_heights_min = dynamic_cast<const ConfigOptionFloats*>(print_config.option("min_layer_height"))->values;
const std::vector<double>& layer_heights_max = dynamic_cast<const ConfigOptionFloats*>(print_config.option("max_layer_height"))->values;
const std::vector<double>& nozzle_diameters = dynamic_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values;
const std::vector<double>& layer_heights_min = dynamic_cast<const ConfigOptionFloats*>(m_config->option("min_layer_height"))->values;
const std::vector<double>& layer_heights_max = dynamic_cast<const ConfigOptionFloats*>(m_config->option("max_layer_height"))->values;
for (unsigned int i = 0; i < (unsigned int)nozzle_diameters.size(); ++i)
{
double lh_min = (layer_heights_min[i] == 0.0) ? 0.07 : std::max(0.01, layer_heights_min[i]);
@ -1086,15 +1088,19 @@ void GLCanvas3D::LayersEditing::_render_profile(const PrintObject& print_object,
// Make the vertical bar a bit wider so the layer height curve does not touch the edge of the bar region.
layer_height_max *= 1.12;
double max_z = unscale<double>(print_object.size(2));
double layer_height = dynamic_cast<const ConfigOptionFloat*>(print_object.config().option("layer_height"))->value;
// Get global layer height.
double layer_height = dynamic_cast<const ConfigOptionFloat*>(m_config->option("layer_height"))->value;
// Override the global layer height with object's layer height if set.
const ConfigOption *opt_object_layer_height = m_model_object->config.option("layer_height");
if (opt_object_layer_height != nullptr)
layer_height = dynamic_cast<const ConfigOptionFloat*>(opt_object_layer_height)->value;
float l = bar_rect.get_left();
float w = bar_rect.get_right() - l;
float b = bar_rect.get_bottom();
float t = bar_rect.get_top();
float h = t - b;
float scale_x = w / (float)layer_height_max;
float scale_y = h / (float)max_z;
float scale_y = h / m_object_max_z;
float x = l + (float)layer_height * scale_x;
// Baseline
@ -1105,19 +1111,129 @@ void GLCanvas3D::LayersEditing::_render_profile(const PrintObject& print_object,
::glEnd();
// Curve
const ModelObject* model_object = print_object.model_object();
if (model_object->layer_height_profile_valid)
{
const std::vector<double>& profile = model_object->layer_height_profile;
::glColor3f(0.0f, 0.0f, 1.0f);
::glBegin(GL_LINE_STRIP);
for (unsigned int i = 0; i < m_layer_height_profile.size(); i += 2)
::glVertex2f(l + (float)m_layer_height_profile[i + 1] * scale_x, b + (float)m_layer_height_profile[i] * scale_y);
::glEnd();
}
::glColor3f(0.0f, 0.0f, 1.0f);
::glBegin(GL_LINE_STRIP);
for (unsigned int i = 0; i < profile.size(); i += 2)
{
::glVertex2f(l + (float)profile[i + 1] * scale_x, b + (float)profile[i] * scale_y);
void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const GLVolumeCollection &volumes) const
{
assert(this->is_allowed());
assert(this->last_object_id != -1);
GLint shader_id = m_shader.get_shader()->shader_program_id;
assert(shader_id > 0);
GLint current_program_id;
glGetIntegerv(GL_CURRENT_PROGRAM, &current_program_id);
if (shader_id > 0 && shader_id != current_program_id)
// The layer editing shader is not yet active. Activate it.
glUseProgram(shader_id);
else
// The layer editing shader was already active.
current_program_id = -1;
GLint z_to_texture_row_id = glGetUniformLocation(shader_id, "z_to_texture_row");
GLint z_texture_row_to_normalized_id = glGetUniformLocation(shader_id, "z_texture_row_to_normalized");
GLint z_cursor_id = glGetUniformLocation(shader_id, "z_cursor");
GLint z_cursor_band_width_id = glGetUniformLocation(shader_id, "z_cursor_band_width");
GLint world_matrix_id = glGetUniformLocation(shader_id, "volume_world_matrix");
if (z_to_texture_row_id != -1 && z_texture_row_to_normalized_id != -1 && z_cursor_id != -1 && z_cursor_band_width_id != -1 && world_matrix_id != -1)
{
const_cast<LayersEditing*>(this)->generate_layer_height_texture();
// Uniforms were resolved, go ahead using the layer editing shader.
glUniform1f(z_to_texture_row_id, GLfloat(m_layers_texture.cells - 1) / (GLfloat(m_layers_texture.width) * GLfloat(m_object_max_z)));
glUniform1f(z_texture_row_to_normalized_id, GLfloat(1.0f / m_layers_texture.height));
glUniform1f(z_cursor_id, GLfloat(m_object_max_z) * GLfloat(this->get_cursor_z_relative(canvas)));
glUniform1f(z_cursor_band_width_id, GLfloat(this->band_width));
// Initialize the layer height texture mapping.
GLsizei w = (GLsizei)m_layers_texture.width;
GLsizei h = (GLsizei)m_layers_texture.height;
GLsizei half_w = w / 2;
GLsizei half_h = h / 2;
::glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, m_z_texture_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data());
glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data() + m_layers_texture.width * m_layers_texture.height * 4);
for (const GLVolume *glvolume : volumes.volumes) {
// Render the object using the layer editing shader and texture.
if (! glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier)
continue;
::glUniformMatrix4fv(world_matrix_id, 1, GL_FALSE, (const GLfloat*)glvolume->world_matrix().cast<float>().data());
glvolume->render();
}
::glEnd();
// Revert back to the previous shader.
glBindTexture(GL_TEXTURE_2D, 0);
if (current_program_id > 0)
glUseProgram(current_program_id);
}
else
{
// Something went wrong. Just render the object.
assert(false);
for (const GLVolume *glvolume : volumes.volumes) {
// Render the object using the layer editing shader and texture.
if (!glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier)
continue;
::glUniformMatrix4fv(world_matrix_id, 1, GL_FALSE, (const GLfloat*)glvolume->world_matrix().cast<float>().data());
glvolume->render();
}
}
}
void GLCanvas3D::LayersEditing::adjust_layer_height_profile()
{
*m_slicing_parameters = PrintObject::slicing_parameters(*m_config, *m_model_object);
PrintObject::update_layer_height_profile(*m_model_object, *m_slicing_parameters, m_layer_height_profile);
Slic3r::adjust_layer_height_profile(*m_slicing_parameters, m_layer_height_profile, this->last_z, this->strength, this->band_width, this->last_action);
m_layer_height_profile_modified = true;
m_layers_texture.valid = false;
}
void GLCanvas3D::LayersEditing::generate_layer_height_texture()
{
// Always try to update the layer height profile.
bool update = ! m_layers_texture.valid;
*m_slicing_parameters = PrintObject::slicing_parameters(*m_config, *m_model_object);
if (PrintObject::update_layer_height_profile(*m_model_object, *m_slicing_parameters, m_layer_height_profile)) {
// Initialized to the default value.
m_layer_height_profile_modified = false;
update = true;
}
// Update if the layer height profile was changed, or when the texture is not valid.
if (! update && ! m_layers_texture.data.empty() && m_layers_texture.cells > 0)
// Texture is valid, don't update.
return;
if (m_layers_texture.data.empty()) {
m_layers_texture.width = 1024;
m_layers_texture.height = 1024;
m_layers_texture.levels = 2;
m_layers_texture.data.assign(m_layers_texture.width * m_layers_texture.height * 5, 0);
}
bool level_of_detail_2nd_level = true;
m_layers_texture.cells = Slic3r::generate_layer_height_texture(
*m_slicing_parameters,
Slic3r::generate_object_layers(*m_slicing_parameters, m_layer_height_profile),
m_layers_texture.data.data(), m_layers_texture.height, m_layers_texture.width, level_of_detail_2nd_level);
m_layers_texture.valid = true;
}
void GLCanvas3D::LayersEditing::accept_changes(GLCanvas3D& canvas)
{
if (last_object_id >= 0) {
if (m_layer_height_profile_modified) {
const_cast<ModelObject*>(m_model_object)->layer_height_profile = m_layer_height_profile;
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
}
}
m_layer_height_profile_modified = false;
}
const Point GLCanvas3D::Mouse::Drag::Invalid_2D_Point(INT_MAX, INT_MAX);
@ -3689,7 +3805,6 @@ wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_VIEWPORT_CHANGED, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_MODEL_UPDATE, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent);
@ -3916,9 +4031,10 @@ int GLCanvas3D::check_volumes_outside_state() const
return (int)state;
}
void GLCanvas3D::set_config(DynamicPrintConfig* config)
void GLCanvas3D::set_config(const DynamicPrintConfig* config)
{
m_config = config;
m_layers_editing.set_config(config);
}
void GLCanvas3D::set_process(BackgroundSlicingProcess *process)
@ -4262,7 +4378,8 @@ void GLCanvas3D::render()
_resize_toolbars();
_render_toolbar();
_render_view_toolbar();
_render_layer_editing_overlay();
if (m_layers_editing.last_object_id >= 0)
m_layers_editing.render_overlay(*this);
#if ENABLE_IMGUI
wxGetApp().imgui()->render();
@ -4502,8 +4619,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
m_volumes.volumes = std::move(glvolumes_new);
for (unsigned int obj_idx = 0; obj_idx < (unsigned int)m_model->objects.size(); ++ obj_idx) {
const ModelObject &model_object = *m_model->objects[obj_idx];
// Object will share a single common layer height texture between all printable volumes.
std::shared_ptr<LayersTexture> layer_height_texture;
for (int volume_idx = 0; volume_idx < (int)model_object.volumes.size(); ++ volume_idx) {
const ModelVolume &model_volume = *model_object.volumes[volume_idx];
for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) {
@ -4513,33 +4628,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id);
if (it->new_geometry()) {
// New volume.
if (model_volume.is_model_part() && ! layer_height_texture) {
// New object part needs to have the layer height texture assigned, which is shared with the other volumes of the same part.
// Search for the layer height texture in the other volumes.
for (int iv = volume_idx; iv < (int)model_object.volumes.size(); ++ iv) {
const ModelVolume &mv = *model_object.volumes[iv];
if (mv.is_model_part())
for (int ii = instance_idx; ii < (int)model_object.instances.size(); ++ ii) {
const ModelInstance &mi = *model_object.instances[ii];
ModelVolumeState key(mv.id(), mi.id());
auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower);
assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id);
if (! it->new_geometry()) {
// Found an old printable GLVolume (existing before this function was called).
assert(m_volumes.volumes[it->volume_idx]->geometry_id == key.geometry_id);
// Reuse the layer height texture.
const GLVolume *volume = m_volumes.volumes[it->volume_idx];
assert(volume->layer_height_texture);
layer_height_texture = volume->layer_height_texture;
goto iv_end;
}
}
}
iv_end:
if (! layer_height_texture)
layer_height_texture = std::make_shared<LayersTexture>();
}
m_volumes.load_object_volume(&model_object, layer_height_texture, obj_idx, volume_idx, instance_idx, m_color_by, m_use_VBOs && m_initialized);
m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_use_VBOs && m_initialized);
m_volumes.volumes.back()->geometry_id = key.geometry_id;
} else {
// Recycling an old GLVolume.
@ -4547,11 +4636,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
assert(existing_volume.geometry_id == key.geometry_id);
// Update the Object/Volume/Instance indices into the current Model.
existing_volume.composite_id = it->composite_id;
if (model_volume.is_model_part() && ! layer_height_texture) {
assert(existing_volume.layer_height_texture);
// cache its layer height texture
layer_height_texture = existing_volume.layer_height_texture;
}
}
}
}
@ -4945,10 +5029,8 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt)
void GLCanvas3D::on_timer(wxTimerEvent& evt)
{
if (m_layers_editing.state != LayersEditing::Editing)
return;
_perform_layer_editing_action();
if (m_layers_editing.state == LayersEditing::Editing)
_perform_layer_editing_action();
}
void GLCanvas3D::on_mouse(wxMouseEvent& evt)
@ -4967,7 +5049,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
int selected_object_idx = m_selection.get_object_idx();
int layer_editing_object_idx = is_layers_editing_enabled() ? selected_object_idx : -1;
m_layers_editing.last_object_id = layer_editing_object_idx;
m_layers_editing.select_object(*m_model, layer_editing_object_idx);
bool gizmos_overlay_contains_mouse = m_gizmos.overlay_contains_mouse(*this, m_mouse.position);
int toolbar_contains_mouse = m_toolbar.contains_mouse(m_mouse.position, *this);
int view_toolbar_contains_mouse = (m_view_toolbar != nullptr) ? m_view_toolbar->contains_mouse(m_mouse.position, *this) : -1;
@ -5032,10 +5114,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
{
if (evt.LeftDown())
{
// A volume is selected and the mouse is inside the reset button.
// The PrintObject::adjust_layer_height_profile() call adjusts the profile of its associated ModelObject, it does not modify the profile of the PrintObject itself,
// therefore it is safe to call it while the background processing is running.
const_cast<PrintObject*>(this->fff_print()->get_object(layer_editing_object_idx))->reset_layer_height_profile();
// A volume is selected and the mouse is inside the reset button. Reset the ModelObject's layer height profile.
m_model->objects[layer_editing_object_idx]->layer_height_profile.clear();
// Index 2 means no editing, just wait for mouse up event.
m_layers_editing.state = LayersEditing::Completed;
@ -5296,9 +5376,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
{
m_layers_editing.state = LayersEditing::Unknown;
_stop_timer();
if (layer_editing_object_idx != -1)
post_event(SimpleEvent(EVT_GLCANVAS_MODEL_UPDATE));
m_layers_editing.accept_changes(*this);
}
else if ((m_mouse.drag.move_volume_idx != -1) && m_mouse.dragging)
{
@ -6074,28 +6152,6 @@ float GLCanvas3D::_get_zoom_to_bounding_box_factor(const BoundingBoxf3& bbox) co
return (float)std::min((double)cnv_size.get_width() / max_x, (double)cnv_size.get_height() / max_y);
}
void GLCanvas3D::_mark_volumes_for_layer_height() const
{
const Print *print = (m_process == nullptr) ? nullptr : m_process->fff_print();
if (print == nullptr)
return;
for (GLVolume* vol : m_volumes.volumes)
{
int object_id = vol->object_idx();
int shader_id = m_layers_editing.get_shader_program_id();
if (is_layers_editing_enabled() && (shader_id != -1) && vol->selected &&
vol->has_layer_height_texture() && (object_id < (int)print->objects().size()))
{
vol->set_layer_height_texture_data(m_layers_editing.get_z_texture_id(), shader_id,
print->get_object(object_id), _get_layers_editing_cursor_z_relative(), m_layers_editing.band_width);
}
else
vol->reset_layer_height_texture_data();
}
}
void GLCanvas3D::_refresh_if_shown_on_screen()
{
if (_is_shown_on_screen())
@ -6241,7 +6297,8 @@ void GLCanvas3D::_render_objects() const
{
if (m_picking_enabled)
{
_mark_volumes_for_layer_height();
// Update the layer editing selection to the first object selected, update the current object maximum Z.
const_cast<LayersEditing&>(m_layers_editing).select_object(*m_model, this->is_layers_editing_enabled() ? m_selection.get_object_idx() : -1);
if (m_config != nullptr)
{
@ -6262,8 +6319,18 @@ void GLCanvas3D::_render_objects() const
m_shader.start_using();
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
// do not cull backfaces to show broken geometry, if any
m_volumes.render_VBOs(GLVolumeCollection::Opaque, m_picking_enabled);
if (m_picking_enabled && m_layers_editing.is_enabled() && m_layers_editing.last_object_id != -1) {
int object_id = m_layers_editing.last_object_id;
m_volumes.render_VBOs(GLVolumeCollection::Opaque, false, [object_id](const GLVolume &volume) {
// Which volume to paint without the layer height profile shader?
return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id);
});
// Let LayersEditing handle rendering of the active object using the layer height profile shader.
m_layers_editing.render_volumes(*this, this->m_volumes);
} else {
// do not cull backfaces to show broken geometry, if any
m_volumes.render_VBOs(GLVolumeCollection::Opaque, m_picking_enabled);
}
m_volumes.render_VBOs(GLVolumeCollection::Transparent, false);
#else
m_volumes.render_VBOs();
@ -6344,39 +6411,6 @@ void GLCanvas3D::_render_legend_texture() const
m_legend_texture.render(*this);
}
void GLCanvas3D::_render_layer_editing_overlay() const
{
const Print *print = this->fff_print();
if ((print == nullptr) || print->objects().empty())
return;
GLVolume* volume = nullptr;
for (GLVolume* vol : m_volumes.volumes)
{
if ((vol != nullptr) && vol->selected && vol->has_layer_height_texture())
{
volume = vol;
break;
}
}
if (volume == nullptr)
return;
// If the active object was not allocated at the Print, go away.This should only be a momentary case between an object addition / deletion
// and an update by Platter::async_apply_config.
int object_idx = volume->object_idx();
if ((int)print->objects().size() <= object_idx)
return;
const PrintObject* print_object = print->get_object(object_idx);
if (print_object == nullptr)
return;
m_layers_editing.render(*this, *print_object, *volume);
}
void GLCanvas3D::_render_volumes(bool fake_colors) const
{
static const GLfloat INV_255 = 1.0f / 255.0f;
@ -6776,55 +6810,24 @@ void GLCanvas3D::_update_gizmos_data()
}
}
float GLCanvas3D::_get_layers_editing_cursor_z_relative() const
{
return m_layers_editing.get_cursor_z_relative(*this);
}
void GLCanvas3D::_perform_layer_editing_action(wxMouseEvent* evt)
{
int object_idx_selected = m_layers_editing.last_object_id;
if (object_idx_selected == -1)
return;
const Print *print = this->fff_print();
if (print == nullptr)
return;
const PrintObject* selected_obj = print->get_object(object_idx_selected);
if (selected_obj == nullptr)
return;
// A volume is selected. Test, whether hovering over a layer thickness bar.
if (evt != nullptr)
{
const Rect& rect = LayersEditing::get_bar_rect_screen(*this);
float b = rect.get_bottom();
m_layers_editing.last_z = unscale<double>(selected_obj->size(2)) * (b - evt->GetY() - 1.0f) / (b - rect.get_top());
m_layers_editing.last_action = evt->ShiftDown() ? (evt->RightIsDown() ? 3 : 2) : (evt->RightIsDown() ? 0 : 1);
m_layers_editing.last_z = m_layers_editing.object_max_z() * (b - evt->GetY() - 1.0f) / (b - rect.get_top());
m_layers_editing.last_action =
evt->ShiftDown() ? (evt->RightIsDown() ? LAYER_HEIGHT_EDIT_ACTION_SMOOTH : LAYER_HEIGHT_EDIT_ACTION_REDUCE) :
(evt->RightIsDown() ? LAYER_HEIGHT_EDIT_ACTION_INCREASE : LAYER_HEIGHT_EDIT_ACTION_DECREASE);
}
// Mark the volume as modified, so Print will pick its layer height profile ? Where to mark it ?
// Start a timer to refresh the print ? schedule_background_process() ?
// The PrintObject::adjust_layer_height_profile() call adjusts the profile of its associated ModelObject, it does not modify the profile of the PrintObject itself,
// therefore it is safe to call it while the background processing is running.
const_cast<PrintObject*>(selected_obj)->adjust_layer_height_profile(m_layers_editing.last_z, m_layers_editing.strength, m_layers_editing.band_width, m_layers_editing.last_action);
// searches the id of the first volume of the selected object
int volume_idx = 0;
for (int i = 0; i < object_idx_selected; ++i)
{
const PrintObject* obj = print->get_object(i);
if (obj != nullptr)
{
for (int j = 0; j < (int)obj->region_volumes.size(); ++j)
{
volume_idx += (int)obj->region_volumes[j].size();
}
}
}
m_volumes.volumes[volume_idx]->generate_layer_height_texture(selected_obj, 1);
m_layers_editing.adjust_layer_height_profile();
_refresh_if_shown_on_screen();
// Automatic action on mouse down with the same coordinate.