mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-26 18:31:11 +00:00
cut the GPU load of moving the mouse over the 3D viewport (#15674)
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
This commit is contained in:
co-authored by
Rodrigo Faselli
parent
e0410db22e
commit
213c6569ab
+339
-160
@@ -69,6 +69,7 @@
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/spin_mutex.h>
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
@@ -370,7 +371,6 @@ void GLCanvas3D::LayersEditing::render_variable_layer_height_dialog(GLCanvas3D&
|
||||
|
||||
void GLCanvas3D::LayersEditing::render_overlay(GLCanvas3D& canvas)
|
||||
{
|
||||
render_variable_layer_height_dialog(canvas);
|
||||
render_active_object_annotations(canvas);
|
||||
render_profile(canvas);
|
||||
}
|
||||
@@ -1191,6 +1191,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed)
|
||||
#endif // ENABLE_RETINA_GL
|
||||
}
|
||||
m_timer_set_color.Bind(wxEVT_TIMER, &GLCanvas3D::on_set_color_timer, this);
|
||||
m_fps_overlay_timer.Bind(wxEVT_TIMER, &GLCanvas3D::on_fps_overlay_timer, this);
|
||||
load_arrange_settings();
|
||||
|
||||
m_selection.set_volumes(&m_volumes.volumes);
|
||||
@@ -1207,6 +1208,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed)
|
||||
GLCanvas3D::~GLCanvas3D()
|
||||
{
|
||||
if (_set_current()) {
|
||||
m_scene_cache.reset();
|
||||
if (m_fxaa_texture_id != 0) {
|
||||
glsafe(::glDeleteTextures(1, &m_fxaa_texture_id));
|
||||
m_fxaa_texture_id = 0;
|
||||
@@ -1354,6 +1356,7 @@ void GLCanvas3D::on_change_color_mode(bool is_dark, bool reinit) {
|
||||
m_gizmos.set_icon_dirty();
|
||||
}
|
||||
}
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
const float GLCanvas3D::get_scale() const
|
||||
@@ -1938,7 +1941,14 @@ bool GLCanvas3D::make_current_for_postinit() {
|
||||
return _set_current();
|
||||
}
|
||||
|
||||
// Redraws the scene and presents it.
|
||||
void GLCanvas3D::render(bool only_init)
|
||||
{
|
||||
m_presented_signature.reset();
|
||||
_render_frame(true, only_init);
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_frame(bool scene_dirty, bool only_init)
|
||||
{
|
||||
if (m_in_render) {
|
||||
// if called recursively, return
|
||||
@@ -2041,121 +2051,33 @@ void GLCanvas3D::render(bool only_init)
|
||||
}
|
||||
}
|
||||
|
||||
// draw scene
|
||||
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||
// Invalidate the shadow map each frame; only the View3D path below rebuilds it. This keeps
|
||||
// the Preview / Assemble canvases from sampling a stale map with an outdated light matrix.
|
||||
m_shadow_map_valid = false;
|
||||
_render_background();
|
||||
const bool overlay_tick = m_fps_overlay_tick;
|
||||
m_fps_overlay_tick = false;
|
||||
|
||||
//BBS add partplater rendering logic
|
||||
bool only_current = false, only_body = false, no_partplate = false;
|
||||
bool show_grid = true;
|
||||
GLGizmosManager::EType gizmo_type = m_gizmos.get_current_type();
|
||||
if (!m_main_toolbar.is_enabled()) {
|
||||
//only_body = true;
|
||||
only_current = true;
|
||||
// An overlay-only frame reuses the last scene pass. The overlay is rebuilt either way, and drawn
|
||||
// below once it is known whether the frame differs from the one on screen.
|
||||
const bool reuse_scene = !scene_dirty && _can_reuse_cached_scene(camera);
|
||||
if (!reuse_scene) {
|
||||
_render_scene(camera, cnv_size);
|
||||
if (!overlay_tick)
|
||||
m_render_stats.increment_scene_fps_counter();
|
||||
}
|
||||
else if ((gizmo_type == GLGizmosManager::FdmSupports) || (gizmo_type == GLGizmosManager::Seam) || (gizmo_type == GLGizmosManager::MmSegmentation) || (gizmo_type == GLGizmosManager::FuzzySkin))
|
||||
no_partplate = true;
|
||||
else if (gizmo_type == GLGizmosManager::BrimEars && !camera.is_looking_downward())
|
||||
show_grid = false;
|
||||
if (m_axes_at_bed_center)
|
||||
// Design tab: the plate grid is generated from the plate's front-left corner, so it
|
||||
// floats mid-cell under the modeling-origin triad. Suppress it here; a CAD grid centred
|
||||
// on the origin is rendered in its place (see _render_cad_grid).
|
||||
show_grid = false;
|
||||
|
||||
/* view3D render*/
|
||||
int hover_id = (m_hover_plate_idxs.size() > 0)?m_hover_plate_idxs.front():-1;
|
||||
if (m_canvas_type == ECanvasType::CanvasView3D) {
|
||||
// m_show_bed gates the plate list too: hiding the bed but leaving its grid and outline
|
||||
// floating would read as a rendering fault rather than a deliberate view option.
|
||||
if (!no_partplate && m_show_bed)
|
||||
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), m_show_world_axes);
|
||||
if (!no_partplate && m_show_bed) //BBS: add outline logic
|
||||
_render_platelist(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), only_current, only_body, hover_id, true, show_grid);
|
||||
if (m_axes_at_bed_center && m_show_bed && !no_partplate)
|
||||
// Design tab: replace the plate's corner-origin grid with the origin-centred CAD grid.
|
||||
_render_cad_grid(camera.get_view_matrix(), camera.get_projection_matrix());
|
||||
|
||||
//BBS: add outline logic
|
||||
// Depth pass for object-on-object and self shadows; consumed by the gouraud shader below.
|
||||
_render_shadows(camera.get_view_matrix(), camera.get_projection_matrix());
|
||||
_render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running());
|
||||
_render_sla_slices();
|
||||
_render_selection();
|
||||
_render_objects(GLVolumeCollection::ERenderType::Transparent, !m_gizmos.is_running());
|
||||
_render_wireframe_overlay();
|
||||
}
|
||||
/* preview render */
|
||||
else if (m_canvas_type == ECanvasType::CanvasPreview && m_render_preview) {
|
||||
_render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running());
|
||||
_render_sla_slices();
|
||||
_render_selection();
|
||||
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), m_show_world_axes);
|
||||
_render_platelist(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), only_current, true, hover_id);
|
||||
if (m_canvas_type == ECanvasType::CanvasPreview && m_render_preview)
|
||||
// BBS: GUI refactor: add canvas size as parameters
|
||||
_render_gcode(cnv_size.get_width(), cnv_size.get_height());
|
||||
}
|
||||
/* assemble render*/
|
||||
else if (m_canvas_type == ECanvasType::CanvasAssembleView) {
|
||||
//BBS: add outline logic
|
||||
//if (m_show_world_axes) {
|
||||
// m_axes.render();
|
||||
//}
|
||||
_render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running());
|
||||
_render_selection();
|
||||
//_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), show_axes);
|
||||
_render_plane();
|
||||
//BBS: add outline logic insteadof selection under assemble view
|
||||
//_render_selection();
|
||||
// BBS: add outline logic
|
||||
_render_objects(GLVolumeCollection::ERenderType::Transparent, !m_gizmos.is_running());
|
||||
_render_wireframe_overlay();
|
||||
}
|
||||
|
||||
_render_sequential_clearance();
|
||||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
_render_selection_center();
|
||||
#endif // ENABLE_RENDER_SELECTION_CENTER
|
||||
|
||||
// sidebar hints need to be rendered before the gizmos because the depth buffer
|
||||
// could be invalidated by the following gizmo render methods
|
||||
_render_selection_sidebar_hints();
|
||||
_render_current_gizmo();
|
||||
|
||||
#if ENABLE_RAYCAST_PICKING_DEBUG
|
||||
if (m_picking_enabled && !m_mouse.dragging && !m_gizmos.is_dragging() && !m_rectangle_selection.is_dragging())
|
||||
m_scene_raycaster.render_hit(camera);
|
||||
#endif // ENABLE_RAYCAST_PICKING_DEBUG
|
||||
|
||||
#if ENABLE_SHOW_CAMERA_TARGET
|
||||
_render_camera_target();
|
||||
#endif // ENABLE_SHOW_CAMERA_TARGET
|
||||
|
||||
if (m_picking_enabled && m_rectangle_selection.is_dragging())
|
||||
m_rectangle_selection.render(*this);
|
||||
|
||||
if (_is_ssao_enabled())
|
||||
_render_ssao_pass(static_cast<unsigned int>(cnv_size.get_width()), static_cast<unsigned int>(cnv_size.get_height()));
|
||||
|
||||
if (_is_fxaa_enabled())
|
||||
_render_fxaa_pass(static_cast<unsigned int>(cnv_size.get_width()), static_cast<unsigned int>(cnv_size.get_height()));
|
||||
|
||||
// Design tab: interactive 2D sketch overlay, drawn over the scene but
|
||||
// beneath the UI overlays (toolbars, labels).
|
||||
#ifdef SLIC3R_CAD
|
||||
if (m_design_sketch_tool != nullptr && m_design_sketch_tool->has_display())
|
||||
m_design_sketch_tool->render(*this);
|
||||
#endif
|
||||
_render_gcode_overlay(cnv_size.get_width(), cnv_size.get_height());
|
||||
|
||||
// draw overlays
|
||||
_render_overlays();
|
||||
|
||||
const int current_fps = m_render_stats.get_fps_and_reset_if_needed();
|
||||
if (_is_fps_overlay_enabled())
|
||||
if (_is_fps_overlay_enabled()) {
|
||||
_render_fps_overlay(current_fps);
|
||||
// The timer requests an overlay-only frame a second from now. A frame it requested
|
||||
// re-arms it only while a count is above zero.
|
||||
if (!overlay_tick || current_fps > 0 || m_render_stats.get_scene_fps() > 0)
|
||||
m_fps_overlay_timer.StartOnce(1000);
|
||||
}
|
||||
|
||||
if (wxGetApp().plater()->is_render_statistic_dialog_visible()) {
|
||||
ImGui::ShowMetricsWindow();
|
||||
@@ -2241,14 +2163,149 @@ void GLCanvas3D::render(bool only_init)
|
||||
wxGetApp().plater()->get_dailytips()->render();
|
||||
}
|
||||
|
||||
wxGetApp().imgui()->render();
|
||||
ImDrawData* draw_data = wxGetApp().imgui()->end_frame();
|
||||
|
||||
std::optional<size_t> signature;
|
||||
if (_is_frame_skipping_enabled())
|
||||
signature = _overlay_signature(draw_data);
|
||||
|
||||
if (reuse_scene) {
|
||||
// A reused scene under an unchanged overlay is the frame already on screen.
|
||||
if (signature.has_value() && signature == m_presented_signature)
|
||||
return;
|
||||
m_scene_cache.render(m_background);
|
||||
}
|
||||
|
||||
_render_overlay_toolbars();
|
||||
|
||||
wxGetApp().imgui()->render(draw_data);
|
||||
|
||||
// On Wayland, eglSwapBuffers blocks when the canvas is hidden or
|
||||
// occluded. Skip the swap to avoid stalling the render loop.
|
||||
if (m_canvas->IsShownOnScreen()) {
|
||||
m_canvas->SwapBuffers();
|
||||
m_render_stats.increment_fps_counter();
|
||||
if (!overlay_tick)
|
||||
m_render_stats.increment_fps_counter();
|
||||
m_presented_signature = signature;
|
||||
}
|
||||
else
|
||||
m_presented_signature.reset();
|
||||
}
|
||||
|
||||
// Everything drawn into the 3D scene, from the clear to the post processing passes, ending in the
|
||||
// capture an overlay-only frame reuses.
|
||||
void GLCanvas3D::_render_scene(const Camera& camera, const Size& cnv_size)
|
||||
{
|
||||
// Recorded by PartPlate::render_icons() below, when it runs.
|
||||
wxGetApp().plater()->get_partplate_list().clear_hover_tooltip();
|
||||
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||
// Invalidate the shadow map each frame; only the View3D path below rebuilds it. This keeps
|
||||
// the Preview / Assemble canvases from sampling a stale map with an outdated light matrix.
|
||||
m_shadow_map_valid = false;
|
||||
_render_background();
|
||||
|
||||
//BBS add partplater rendering logic
|
||||
bool only_current = false, only_body = false, no_partplate = false;
|
||||
bool show_grid = true;
|
||||
GLGizmosManager::EType gizmo_type = m_gizmos.get_current_type();
|
||||
if (!m_main_toolbar.is_enabled()) {
|
||||
//only_body = true;
|
||||
only_current = true;
|
||||
}
|
||||
else if ((gizmo_type == GLGizmosManager::FdmSupports) || (gizmo_type == GLGizmosManager::Seam) || (gizmo_type == GLGizmosManager::MmSegmentation) || (gizmo_type == GLGizmosManager::FuzzySkin))
|
||||
no_partplate = true;
|
||||
else if (gizmo_type == GLGizmosManager::BrimEars && !camera.is_looking_downward())
|
||||
show_grid = false;
|
||||
if (m_axes_at_bed_center)
|
||||
// Design tab: the plate grid is generated from the plate's front-left corner, so it
|
||||
// floats mid-cell under the modeling-origin triad. Suppress it here; a CAD grid centred
|
||||
// on the origin is rendered in its place (see _render_cad_grid).
|
||||
show_grid = false;
|
||||
|
||||
/* view3D render*/
|
||||
int hover_id = (m_hover_plate_idxs.size() > 0)?m_hover_plate_idxs.front():-1;
|
||||
if (m_canvas_type == ECanvasType::CanvasView3D) {
|
||||
// m_show_bed gates the plate list too: hiding the bed but leaving its grid and outline
|
||||
// floating would read as a rendering fault rather than a deliberate view option.
|
||||
if (!no_partplate && m_show_bed)
|
||||
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), m_show_world_axes);
|
||||
if (!no_partplate && m_show_bed) //BBS: add outline logic
|
||||
_render_platelist(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), only_current, only_body, hover_id, true, show_grid);
|
||||
if (m_axes_at_bed_center && m_show_bed && !no_partplate)
|
||||
// Design tab: replace the plate's corner-origin grid with the origin-centred CAD grid.
|
||||
_render_cad_grid(camera.get_view_matrix(), camera.get_projection_matrix());
|
||||
|
||||
//BBS: add outline logic
|
||||
// Depth pass for object-on-object and self shadows; consumed by the gouraud shader below.
|
||||
_render_shadows(camera.get_view_matrix(), camera.get_projection_matrix());
|
||||
_render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running());
|
||||
_render_sla_slices();
|
||||
_render_selection();
|
||||
_render_objects(GLVolumeCollection::ERenderType::Transparent, !m_gizmos.is_running());
|
||||
_render_wireframe_overlay();
|
||||
}
|
||||
/* preview render */
|
||||
else if (m_canvas_type == ECanvasType::CanvasPreview && m_render_preview) {
|
||||
_render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running());
|
||||
_render_sla_slices();
|
||||
_render_selection();
|
||||
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), m_show_world_axes);
|
||||
_render_platelist(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), only_current, true, hover_id);
|
||||
// BBS: GUI refactor: add canvas size as parameters
|
||||
_render_gcode(cnv_size.get_width(), cnv_size.get_height());
|
||||
}
|
||||
/* assemble render*/
|
||||
else if (m_canvas_type == ECanvasType::CanvasAssembleView) {
|
||||
//BBS: add outline logic
|
||||
//if (m_show_world_axes) {
|
||||
// m_axes.render();
|
||||
//}
|
||||
_render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running());
|
||||
_render_selection();
|
||||
//_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), show_axes);
|
||||
_render_plane();
|
||||
//BBS: add outline logic insteadof selection under assemble view
|
||||
//_render_selection();
|
||||
// BBS: add outline logic
|
||||
_render_objects(GLVolumeCollection::ERenderType::Transparent, !m_gizmos.is_running());
|
||||
_render_wireframe_overlay();
|
||||
}
|
||||
|
||||
_render_sequential_clearance();
|
||||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
_render_selection_center();
|
||||
#endif // ENABLE_RENDER_SELECTION_CENTER
|
||||
// sidebar hints need to be rendered before the gizmos because the depth buffer
|
||||
// could be invalidated by the following gizmo render methods
|
||||
_render_selection_sidebar_hints();
|
||||
_render_current_gizmo();
|
||||
|
||||
#if ENABLE_RAYCAST_PICKING_DEBUG
|
||||
if (m_picking_enabled && !m_mouse.dragging && !m_gizmos.is_dragging() && !m_rectangle_selection.is_dragging())
|
||||
m_scene_raycaster.render_hit(camera);
|
||||
#endif // ENABLE_RAYCAST_PICKING_DEBUG
|
||||
|
||||
#if ENABLE_SHOW_CAMERA_TARGET
|
||||
_render_camera_target();
|
||||
#endif // ENABLE_SHOW_CAMERA_TARGET
|
||||
|
||||
if (m_picking_enabled && m_rectangle_selection.is_dragging())
|
||||
m_rectangle_selection.render(*this);
|
||||
|
||||
if (_is_ssao_enabled())
|
||||
_render_ssao_pass(static_cast<unsigned int>(cnv_size.get_width()), static_cast<unsigned int>(cnv_size.get_height()));
|
||||
|
||||
if (_is_fxaa_enabled())
|
||||
_render_fxaa_pass(static_cast<unsigned int>(cnv_size.get_width()), static_cast<unsigned int>(cnv_size.get_height()));
|
||||
|
||||
// Design tab: interactive 2D sketch overlay, drawn over the scene but
|
||||
// beneath the UI overlays (toolbars, labels).
|
||||
#ifdef SLIC3R_CAD
|
||||
if (m_design_sketch_tool != nullptr && m_design_sketch_tool->has_display())
|
||||
m_design_sketch_tool->render(*this);
|
||||
#endif
|
||||
|
||||
_capture_scene_cache(camera);
|
||||
}
|
||||
|
||||
void GLCanvas3D::render_thumbnail(ThumbnailData & thumbnail_data,
|
||||
@@ -3226,29 +3283,30 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
|
||||
if (!m_initialized)
|
||||
return;
|
||||
|
||||
m_dirty |= m_main_toolbar.update_items_state();
|
||||
// Toolbar states, notifications and ImGui's own layout settling only touch the overlay.
|
||||
m_overlay_dirty |= m_main_toolbar.update_items_state();
|
||||
//BBS: GUI refactor: GLToolbar
|
||||
m_dirty |= m_assemble_view_toolbar.update_items_state();
|
||||
m_overlay_dirty |= m_assemble_view_toolbar.update_items_state();
|
||||
// BBS
|
||||
//m_dirty |= wxGetApp().plater()->get_view_toolbar().update_items_state();
|
||||
m_dirty |= wxGetApp().plater()->get_collapse_toolbar().update_items_state();
|
||||
m_overlay_dirty |= wxGetApp().plater()->get_collapse_toolbar().update_items_state();
|
||||
// apply() DRAINS the 3D-mouse queue, so only the canvas actually on screen may call it: a
|
||||
// hidden canvas renders nothing, so the motion it swallowed moves the shared camera without
|
||||
// ever being drawn and the next visible frame jumps several states at once.
|
||||
bool mouse3d_controller_applied = _is_shown_on_screen()
|
||||
&& wxGetApp().plater()->get_mouse3d_controller().apply(wxGetApp().plater()->get_camera());
|
||||
m_dirty |= mouse3d_controller_applied;
|
||||
m_dirty |= wxGetApp().plater()->get_notification_manager()->update_notifications(*this);
|
||||
m_overlay_dirty |= wxGetApp().plater()->get_notification_manager()->update_notifications(*this);
|
||||
auto gizmo = wxGetApp().plater()->get_view3D_canvas3D()->get_gizmos_manager().get_current();
|
||||
if (gizmo != nullptr) m_dirty |= gizmo->update_items_state();
|
||||
#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
|
||||
// ImGuiWrapper::m_requires_extra_frame may have been set by a render made outside of the OnIdle mechanism
|
||||
bool imgui_requires_extra_frame = wxGetApp().imgui()->requires_extra_frame();
|
||||
m_dirty |= imgui_requires_extra_frame;
|
||||
m_overlay_dirty |= imgui_requires_extra_frame;
|
||||
#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
|
||||
m_dirty |= GLTexture::Compressor::has_compressed_texture_to_refresh();
|
||||
|
||||
if (!m_dirty)
|
||||
if (!m_dirty && !m_overlay_dirty)
|
||||
return;
|
||||
|
||||
#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
|
||||
@@ -3273,19 +3331,24 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
|
||||
m_last_frame_start_time = now;
|
||||
}
|
||||
|
||||
_refresh_if_shown_on_screen();
|
||||
// Read and cleared before the render; a request made during it is left for the next frame.
|
||||
const bool scene_dirty = m_dirty;
|
||||
m_dirty = false;
|
||||
m_overlay_dirty = false;
|
||||
_refresh_if_shown_on_screen(scene_dirty);
|
||||
|
||||
#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
|
||||
if (m_extra_frame_requested || mouse3d_controller_applied || imgui_requires_extra_frame || wxGetApp().imgui()->requires_extra_frame()) {
|
||||
#else
|
||||
if (m_extra_frame_requested || mouse3d_controller_applied) {
|
||||
m_dirty = true;
|
||||
#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
|
||||
m_extra_frame_requested = false;
|
||||
evt.RequestMore();
|
||||
}
|
||||
else
|
||||
m_dirty = false;
|
||||
#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
|
||||
else if (imgui_requires_extra_frame || wxGetApp().imgui()->requires_extra_frame()) {
|
||||
// ImGui settling a window or fading a tooltip.
|
||||
m_overlay_dirty = true;
|
||||
evt.RequestMore();
|
||||
}
|
||||
#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
|
||||
}
|
||||
|
||||
void GLCanvas3D::on_char(wxKeyEvent& evt)
|
||||
@@ -4124,6 +4187,12 @@ void GLCanvas3D::on_set_color_timer(wxTimerEvent& evt)
|
||||
m_timer_set_color.Stop();
|
||||
}
|
||||
|
||||
void GLCanvas3D::on_fps_overlay_timer(wxTimerEvent& evt)
|
||||
{
|
||||
m_fps_overlay_tick = true;
|
||||
_set_overlay_as_dirty();
|
||||
wxWakeUpIdle();
|
||||
}
|
||||
|
||||
void GLCanvas3D::schedule_extra_frame(int milliseconds)
|
||||
{
|
||||
@@ -4301,11 +4370,18 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())
|
||||
mouse_up_cleanup();
|
||||
|
||||
render();
|
||||
// Hovering an ImGui window only changes the overlay.
|
||||
const bool overlay_only = evt.Moving() && !m_mouse.dragging;
|
||||
// ImGui takes a press or a release only inside a frame. Motion is rendered from on_idle().
|
||||
if (evt.ButtonDown() || evt.ButtonUp() || evt.ButtonDClick())
|
||||
_render_frame(true);
|
||||
#ifdef SLIC3R_DEBUG_MOUSE_EVENTS
|
||||
printf((format_mouse_event_debug_message(evt) + " - Consumed by ImGUI\n").c_str());
|
||||
#endif /* SLIC3R_DEBUG_MOUSE_EVENTS */
|
||||
m_dirty = true;
|
||||
if (overlay_only)
|
||||
_set_overlay_as_dirty();
|
||||
else
|
||||
m_dirty = true;
|
||||
// do not return if dragging or tooltip not empty to allow for tooltip update
|
||||
// also, do not return if the mouse is moving and also is inside MM gizmo to allow update seed fill selection
|
||||
if (!m_mouse.dragging && m_tooltip.is_empty() && (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation || !evt.Moving()))
|
||||
@@ -4448,6 +4524,9 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
wxGetApp().obj_list()->selection_changed();
|
||||
}
|
||||
|
||||
// A gizmo that acts on a click or a drag may not request a frame itself.
|
||||
if (!evt.Moving())
|
||||
m_dirty = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4939,7 +5018,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
if (m_selection.is_empty())
|
||||
m_gizmos.reset_all_states();
|
||||
|
||||
m_dirty = true;
|
||||
_set_overlay_as_dirty();
|
||||
}
|
||||
else
|
||||
evt.Skip();
|
||||
@@ -4989,6 +5068,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||
|
||||
void GLCanvas3D::on_paint(wxPaintEvent& evt)
|
||||
{
|
||||
m_presented_signature.reset();
|
||||
if (m_initialized) {
|
||||
#ifdef __WXMSW__
|
||||
// Idle events are not dispatched during the Windows resize modal loop,
|
||||
@@ -5542,7 +5622,11 @@ void GLCanvas3D::update_gizmos_on_off_state()
|
||||
|
||||
void GLCanvas3D::handle_sidebar_focus_event(const std::string& opt_key, bool focus_on)
|
||||
{
|
||||
m_sidebar_field = focus_on ? opt_key : "";
|
||||
const std::string field = focus_on ? opt_key : "";
|
||||
// The gizmo panels report this on every build.
|
||||
if (m_sidebar_field == field)
|
||||
return;
|
||||
m_sidebar_field = field;
|
||||
|
||||
//BBS: this event was sent from gizmo now, no need to clear gizmo
|
||||
//if (!m_sidebar_field.empty())
|
||||
@@ -6640,6 +6724,9 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const
|
||||
//if (thumbnail_params.transparent_background)
|
||||
// glsafe(::glClearColor(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("render_thumbnail: finished");
|
||||
|
||||
// Puts the canvas viewport back in place of the thumbnail one set above.
|
||||
wxGetApp().plater()->get_camera().apply_viewport();
|
||||
}
|
||||
|
||||
void GLCanvas3D::render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
||||
@@ -6890,9 +6977,6 @@ void GLCanvas3D::render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned
|
||||
#if ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
|
||||
debug_output_thumbnail(thumbnail_data);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
|
||||
|
||||
// restore the default framebuffer size to avoid flickering on the 3D scene
|
||||
//wxGetApp().plater()->get_camera().apply_viewport();
|
||||
}
|
||||
|
||||
//BBS: GUI refractor
|
||||
@@ -7441,15 +7525,15 @@ void GLCanvas3D::_update_camera_zoom(double zoom)
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
void GLCanvas3D::_refresh_if_shown_on_screen()
|
||||
void GLCanvas3D::_refresh_if_shown_on_screen(bool scene_dirty)
|
||||
{
|
||||
if (_is_shown_on_screen()) {
|
||||
const Size& cnv_size = get_canvas_size();
|
||||
_resize((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height());
|
||||
|
||||
// Because of performance problems on macOS, where PaintEvents are not delivered
|
||||
// frequently enough, we call render() here directly when we can.
|
||||
render();
|
||||
// frequently enough, we render here directly when we can.
|
||||
_render_frame(scene_dirty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7841,6 +7925,36 @@ bool GLCanvas3D::_is_fps_overlay_enabled() const
|
||||
return wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_SHOW_FPS_OVERLAY);
|
||||
}
|
||||
|
||||
bool GLCanvas3D::_is_scene_cache_enabled() const
|
||||
{
|
||||
return wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_SCENE_CACHE);
|
||||
}
|
||||
|
||||
bool GLCanvas3D::_is_scene_cacheable() const
|
||||
{
|
||||
if (!_is_scene_cache_enabled())
|
||||
return false;
|
||||
|
||||
#ifdef SLIC3R_CAD
|
||||
// The Design tab draws its sketch overlay, ImGui included, inside the scene.
|
||||
if (m_design_sketch_tool != nullptr && m_design_sketch_tool->has_display())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// The scene follows the cursor during a drag, under a gizmo that draws at the cursor, and while
|
||||
// the cursor is on the layer height bar, where the object shader draws a band at its height.
|
||||
const GLGizmoBase* gizmo = m_gizmos.get_current();
|
||||
const bool cursor_on_layers_bar = is_layers_editing_enabled() &&
|
||||
m_layers_editing.bar_rect_contains(*this, (float)m_mouse.position.x(), (float)m_mouse.position.y());
|
||||
return !m_mouse.dragging && !m_gizmos.is_dragging() && !m_rectangle_selection.is_dragging() &&
|
||||
(gizmo == nullptr || !gizmo->render_follows_cursor()) && !cursor_on_layers_bar;
|
||||
}
|
||||
|
||||
bool GLCanvas3D::_is_frame_skipping_enabled() const
|
||||
{
|
||||
return wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_SKIP_IDENTICAL_FRAMES);
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_fps_overlay(int fps) const
|
||||
{
|
||||
if (fps < 0)
|
||||
@@ -7861,6 +7975,8 @@ void GLCanvas3D::_render_fps_overlay(int fps) const
|
||||
ImGuiWindowFlags_NoSavedSettings |
|
||||
ImGuiWindowFlags_NoInputs);
|
||||
imgui.text(std::string("FPS: ") + std::to_string(fps));
|
||||
// The subset of those frames that redrew the scene rather than reusing the cached one.
|
||||
imgui.text(std::string("3D: ") + std::to_string(m_render_stats.get_scene_fps()));
|
||||
imgui.end();
|
||||
}
|
||||
|
||||
@@ -7873,23 +7989,7 @@ void GLCanvas3D::_render_fxaa_pass(unsigned int width, unsigned int height)
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
if (m_fxaa_texture_id == 0) {
|
||||
glsafe(::glGenTextures(1, &m_fxaa_texture_id));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_fxaa_texture_id));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||
}
|
||||
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_fxaa_texture_id));
|
||||
if (m_fxaa_texture_size[0] != width || m_fxaa_texture_size[1] != height) {
|
||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
|
||||
m_fxaa_texture_size = { width, height };
|
||||
}
|
||||
|
||||
glsafe(::glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height));
|
||||
GLTexture::copy_from_framebuffer(m_fxaa_texture_id, m_fxaa_texture_size, width, height, GL_LINEAR);
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
@@ -8065,6 +8165,51 @@ void GLCanvas3D::_render_ssao_pass(unsigned int width, unsigned int height)
|
||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
}
|
||||
|
||||
SceneCache::Key GLCanvas3D::_scene_cache_key(const Camera& camera) const
|
||||
{
|
||||
SceneCache::Key key;
|
||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||
key.size = { { (unsigned int)viewport[2], (unsigned int)viewport[3] } };
|
||||
key.view_matrix = camera.get_view_matrix();
|
||||
key.projection_matrix = camera.get_projection_matrix();
|
||||
// Hover reaches the scene only through the sinking contour a hovered volume draws over
|
||||
// itself (GLVolumeCollection::render()), the plate icons (PartPlate::render_icons()) and the
|
||||
// open gizmo's grabbers.
|
||||
for (size_t i = 0; i < m_volumes.volumes.size(); ++i) {
|
||||
const GLVolume& volume = *m_volumes.volumes[i];
|
||||
if (volume.hover != GLVolume::HS_None && volume.is_sinking() && !volume.is_below_printbed())
|
||||
key.sinking_hover_volume_idxs.emplace_back((int)i);
|
||||
}
|
||||
for (int id : m_hover_plate_idxs) {
|
||||
if (id % PartPlate::GRABBER_COUNT != 0)
|
||||
key.hover_plate_icon_idxs.emplace_back(id);
|
||||
}
|
||||
const GLGizmoBase* gizmo = m_gizmos.get_current();
|
||||
key.gizmo_hover_id = gizmo != nullptr ? gizmo->get_hover_id() : -1;
|
||||
key.render_preview = m_render_preview;
|
||||
return key;
|
||||
}
|
||||
|
||||
bool GLCanvas3D::_can_reuse_cached_scene(const Camera& camera) const
|
||||
{
|
||||
return _is_scene_cacheable() && m_scene_cache.matches(_scene_cache_key(camera));
|
||||
}
|
||||
|
||||
void GLCanvas3D::_capture_scene_cache(const Camera& camera)
|
||||
{
|
||||
if (!_is_scene_cache_enabled()) {
|
||||
m_scene_cache.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_is_scene_cacheable()) {
|
||||
m_scene_cache.invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
m_scene_cache.capture(_scene_cache_key(camera));
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_background()
|
||||
{
|
||||
bool use_error_color = false;
|
||||
@@ -8792,7 +8937,12 @@ void GLCanvas3D::_render_wireframe_overlay()
|
||||
//BBS: GUI refactor: add canvas size as parameters
|
||||
void GLCanvas3D::_render_gcode(int canvas_width, int canvas_height)
|
||||
{
|
||||
m_gcode_viewer.render(canvas_width, canvas_height, SLIDER_RIGHT_MARGIN * GCODE_VIEWER_SLIDER_SCALE);
|
||||
m_gcode_viewer.render_scene(canvas_width, canvas_height);
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_gcode_overlay(int canvas_width, int canvas_height)
|
||||
{
|
||||
m_gcode_viewer.render_overlay(canvas_width, canvas_height, SLIDER_RIGHT_MARGIN * GCODE_VIEWER_SLIDER_SCALE);
|
||||
IMSlider *layers_slider = m_gcode_viewer.get_layers_slider();
|
||||
IMSlider *moves_slider = m_gcode_viewer.get_moves_slider();
|
||||
|
||||
@@ -8924,20 +9074,14 @@ void GLCanvas3D::_check_and_update_toolbar_icon_scale()
|
||||
wxGetApp().set_auto_toolbar_icon_scale(new_scale);
|
||||
}
|
||||
|
||||
// The ImGui half of the overlay, drawn by ImGui at the end of the frame.
|
||||
void GLCanvas3D::_render_overlays()
|
||||
{
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
|
||||
_check_and_update_toolbar_icon_scale();
|
||||
|
||||
_render_assemble_control();
|
||||
_render_assemble_info();
|
||||
|
||||
_render_separator_toolbar_right();
|
||||
_render_separator_toolbar_left();
|
||||
_render_main_toolbar();
|
||||
_render_collapse_toolbar();
|
||||
_render_assemble_view_toolbar();
|
||||
//BBS: GUI refactor: GLToolbar
|
||||
_render_imgui_select_plate_toolbar();
|
||||
_render_return_toolbar();
|
||||
@@ -8945,12 +9089,13 @@ void GLCanvas3D::_render_overlays()
|
||||
//_render_view_toolbar();
|
||||
_render_paint_toolbar();
|
||||
|
||||
//BBS: GUI refactor: GLToolbar
|
||||
//move gizmos behind of main
|
||||
_render_gizmos_overlay();
|
||||
// The options window of a pressed toolbar item (arrange).
|
||||
m_main_toolbar.render_item_windows(*this);
|
||||
|
||||
m_gizmos.render_overlay_input_window();
|
||||
|
||||
if (m_layers_editing.last_object_id >= 0 && m_layers_editing.object_max_z() > 0.0f)
|
||||
m_layers_editing.render_overlay(*this);
|
||||
m_layers_editing.render_variable_layer_height_dialog(*this);
|
||||
|
||||
auto curr_plate = wxGetApp().plater()->get_partplate_list().get_curr_plate();
|
||||
auto curr_print_seq = curr_plate->get_real_print_seq();
|
||||
@@ -8977,6 +9122,40 @@ void GLCanvas3D::_render_overlays()
|
||||
_render_3d_navigator();
|
||||
|
||||
_render_canvas_toolbar();
|
||||
|
||||
// Recorded by the scene pass, which a reused frame skips.
|
||||
wxGetApp().plater()->get_partplate_list().render_hover_tooltip();
|
||||
}
|
||||
|
||||
// The GL half of the overlay.
|
||||
void GLCanvas3D::_render_overlay_toolbars()
|
||||
{
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
|
||||
_render_separator_toolbar_right();
|
||||
_render_separator_toolbar_left();
|
||||
_render_main_toolbar();
|
||||
_render_collapse_toolbar();
|
||||
_render_assemble_view_toolbar();
|
||||
//BBS: GUI refactor: GLToolbar
|
||||
//move gizmos behind of main
|
||||
_render_gizmos_overlay();
|
||||
|
||||
if (m_layers_editing.last_object_id >= 0 && m_layers_editing.object_max_z() > 0.0f)
|
||||
m_layers_editing.render_overlay(*this);
|
||||
}
|
||||
|
||||
size_t GLCanvas3D::_overlay_signature(const ImDrawData* draw_data) const
|
||||
{
|
||||
// The recorded ImGui geometry plus the state of the toolbars and the gizmo bar, which draw
|
||||
// outside ImGui.
|
||||
size_t hash = ImGuiWrapper::draw_data_signature(draw_data);
|
||||
for (size_t state_hash : { m_main_toolbar.get_state_hash(), m_separator_toolbar.get_state_hash(),
|
||||
m_assemble_view_toolbar.get_state_hash(),
|
||||
wxGetApp().plater()->get_collapse_toolbar().get_state_hash(),
|
||||
m_gizmos.get_overlay_state_hash() })
|
||||
boost::hash_combine(hash, state_hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_style_editor()
|
||||
|
||||
Reference in New Issue
Block a user