mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-14 20:47:33 +00:00
Keep the Drawn Preview While Nothing in It Moves
Every preview frame redrew the whole scene, whether the camera had moved or a tooltip had faded. A cursor drifting over the canvas, a hovered legend row, a notification or the frame rate overlay each cost a full draw of every toolpath, so a large print stayed slow with nothing happening. Behind a preference, the window's colour and depth are now copied into a framebuffer of the same size, sample count and depth format right after the scene pass, and while nothing that pass draws has changed they are copied back instead of redrawn; only the panels, the marker and the overlays are drawn on top. What counts as a change is the camera's matrices, the canvas size, the hovered and current plate, the world axes, a colour mode change, and two counters from the viewer: one that libvgcode bumps whenever it applies an update or binds another set, one the G-code viewer bumps on load, reset, shell changes and its own toggles. A pending viewer update also forces a redraw. A driver that refuses the blit disables the cache for the session and the preview falls back to drawing every frame. The frames that follow a change cost what they did before; what changes is that a frame with no change costs a blit. On the tall fixture under llvmpipe, cursor motion over the canvas produced a frame every 600 ms and now every 110 ms, limited by the input rate. At rest, after a slider click and after a wheel burst the preview is pixel identical with the preference on and off, and with it off the preview is pixel identical to before.
This commit is contained in:
@@ -212,6 +212,10 @@ void AppConfig::set_defaults()
|
||||
set("preview_reduced_detail_mode", "no_infill");
|
||||
}
|
||||
|
||||
// ORCA: keep the drawn preview scene while nothing in it changes
|
||||
if (get("preview_cache_static_scene").empty())
|
||||
set_bool("preview_cache_static_scene", false);
|
||||
|
||||
{
|
||||
const std::string mode = get("preview_rest_detail_mode");
|
||||
if (mode != "full" && mode != "no_infill" && mode != "shell")
|
||||
|
||||
@@ -131,6 +131,13 @@ public:
|
||||
//
|
||||
bool is_rest_view_from_above() const;
|
||||
void set_rest_view_from_above(bool value);
|
||||
//
|
||||
// ORCA: a counter that changes whenever what render() draws changes, and whether an update is
|
||||
// still pending that the next render() will apply. Together they tell a caller whether a frame
|
||||
// it has kept from an earlier render() can be shown again.
|
||||
//
|
||||
uint64_t get_state_version() const;
|
||||
bool has_pending_updates() const;
|
||||
float get_dim_previous_layers_brightness() const;
|
||||
void set_dim_previous_layers_brightness(float value);
|
||||
//
|
||||
|
||||
@@ -137,6 +137,16 @@ void Viewer::set_rest_view_from_above(bool value)
|
||||
m_impl->set_rest_view_from_above(value);
|
||||
}
|
||||
|
||||
uint64_t Viewer::get_state_version() const
|
||||
{
|
||||
return m_impl->get_state_version();
|
||||
}
|
||||
|
||||
bool Viewer::has_pending_updates() const
|
||||
{
|
||||
return m_impl->has_pending_updates();
|
||||
}
|
||||
|
||||
void Viewer::set_dim_previous_layers(bool value)
|
||||
{
|
||||
m_impl->set_dim_previous_layers(value);
|
||||
|
||||
@@ -899,6 +899,7 @@ void ViewerImpl::reset()
|
||||
m_enabled_segments_reduced_count = 0;
|
||||
m_enabled_options_reduced_count = 0;
|
||||
m_enabled_segments_rest_count = 0;
|
||||
++m_state_version;
|
||||
m_shell_bitset = BitSet<>();
|
||||
m_near_shell_bitset = BitSet<>();
|
||||
m_top_visible_bitset = BitSet<>();
|
||||
@@ -1844,6 +1845,7 @@ void ViewerImpl::update_enabled_entities()
|
||||
#endif // ENABLE_OPENGL_ES
|
||||
|
||||
m_settings.update_enabled_entities = false;
|
||||
++m_state_version;
|
||||
}
|
||||
|
||||
static float encode_color(const Color& color) {
|
||||
@@ -1953,6 +1955,7 @@ void ViewerImpl::update_colors()
|
||||
|
||||
update_colors_texture();
|
||||
m_settings.update_colors = false;
|
||||
++m_state_version;
|
||||
}
|
||||
|
||||
void ViewerImpl::render(const Mat4x4& view_matrix, const Mat4x4& projection_matrix)
|
||||
@@ -2562,6 +2565,7 @@ void ViewerImpl::update_view_full_range()
|
||||
}
|
||||
|
||||
m_settings.update_view_full_range = false;
|
||||
++m_state_version;
|
||||
}
|
||||
|
||||
void ViewerImpl::update_color_ranges()
|
||||
|
||||
@@ -95,7 +95,12 @@ public:
|
||||
// Draw the preview from the reduced set of entities. Meant to be held only while the user is
|
||||
// dragging; the sets are already built, so this is just a buffer binding and never rebuilds.
|
||||
//
|
||||
void set_reduced_detail(bool value) { m_settings.reduced_detail = value; }
|
||||
void set_reduced_detail(bool value) {
|
||||
if (m_settings.reduced_detail != value) {
|
||||
m_settings.reduced_detail = value;
|
||||
++m_state_version;
|
||||
}
|
||||
}
|
||||
bool is_reduced_detail() const { return m_settings.reduced_detail; }
|
||||
EReducedDetailMode get_reduced_detail_mode() const { return m_settings.reduced_detail_mode; }
|
||||
void set_reduced_detail_mode(EReducedDetailMode mode);
|
||||
@@ -107,6 +112,10 @@ public:
|
||||
void set_rest_layer_stride(uint32_t value);
|
||||
bool is_rest_view_from_above() const { return m_settings.rest_view_from_above; }
|
||||
void set_rest_view_from_above(bool value);
|
||||
uint64_t get_state_version() const { return m_state_version; }
|
||||
bool has_pending_updates() const {
|
||||
return m_settings.update_view_full_range || m_settings.update_enabled_entities || m_settings.update_colors;
|
||||
}
|
||||
float get_dim_previous_layers_brightness() const { return m_settings.dim_previous_layers_brightness; }
|
||||
void set_dim_previous_layers_brightness(float value);
|
||||
|
||||
@@ -339,6 +348,11 @@ private:
|
||||
// fills the step of a sloped surface between one layer's outer wall and the next, too narrow
|
||||
// for the grid to see
|
||||
BitSet<> m_near_shell_bitset;
|
||||
//
|
||||
// ORCA: bumped whenever what render() draws changes: on every applied update, on a change of
|
||||
// the bound set, on load and reset
|
||||
//
|
||||
uint64_t m_state_version{ 0 };
|
||||
#endif // ENABLE_OPENGL_ES
|
||||
//
|
||||
// Variables used for toolpaths coloring
|
||||
|
||||
@@ -1178,6 +1178,7 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const
|
||||
m_reduced_detail_layer_stride = static_cast<unsigned int>(std::max(1, std::stoi(get_app_config()->get("preview_reduced_detail_layer_stride"))));
|
||||
m_rest_detail_mode = reduced_detail_mode_from_string(get_app_config()->get("preview_rest_detail_mode"));
|
||||
apply_reduced_detail_settings();
|
||||
++m_scene_version;
|
||||
// the median z step between layers, robust to the first layer and to variable layer height
|
||||
{
|
||||
std::vector<float> steps;
|
||||
@@ -1594,11 +1595,21 @@ void GCodeViewer::load_as_preview(libvgcode::GCodeInputData&& data)
|
||||
|
||||
void GCodeViewer::update_shells_color_by_extruder(const DynamicPrintConfig *config)
|
||||
{
|
||||
++m_scene_version;
|
||||
if (config != nullptr)
|
||||
m_shells.volumes.update_colors_by_extruder(config, false);
|
||||
}
|
||||
|
||||
void GCodeViewer::set_shell_transparency(float alpha) { m_shells.volumes.set_transparency(alpha); }
|
||||
void GCodeViewer::set_shell_transparency(float alpha)
|
||||
{
|
||||
m_shells.volumes.set_transparency(alpha);
|
||||
++m_scene_version;
|
||||
}
|
||||
|
||||
std::array<uint64_t, 2> GCodeViewer::scene_version() const
|
||||
{
|
||||
return { (m_scene_version << 2) | (m_shells.visible ? 1u : 0u) | (m_no_render_path ? 2u : 0u), m_viewer.get_state_version() };
|
||||
}
|
||||
|
||||
//BBS: always load shell at preview
|
||||
void GCodeViewer::reset_shell()
|
||||
@@ -1610,6 +1621,7 @@ void GCodeViewer::reset_shell()
|
||||
|
||||
void GCodeViewer::reset()
|
||||
{
|
||||
++m_scene_version;
|
||||
//BBS: should also reset the result id
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": current result id %1% ")%m_last_result_id;
|
||||
m_last_result_id = -1;
|
||||
@@ -1638,17 +1650,19 @@ void GCodeViewer::reset()
|
||||
}
|
||||
|
||||
//BBS: GUI refactor: add canvas width and height
|
||||
void GCodeViewer::render(int canvas_width, int canvas_height, int right_margin)
|
||||
void GCodeViewer::render(int canvas_width, int canvas_height, int right_margin, bool draw_scene)
|
||||
{
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
render_shells(canvas_width, canvas_height);
|
||||
if (draw_scene)
|
||||
render_shells(canvas_width, canvas_height);
|
||||
|
||||
if (m_viewer.get_extrusion_roles_count() == 0)
|
||||
return;
|
||||
|
||||
update_rest_layer_stride();
|
||||
|
||||
render_toolpaths();
|
||||
if (draw_scene)
|
||||
render_toolpaths();
|
||||
|
||||
float legend_height = 0.0f;
|
||||
render_legend(legend_height, canvas_width, canvas_height, right_margin);
|
||||
@@ -2336,6 +2350,7 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
|
||||
|
||||
void GCodeViewer::load_shells(const Print& print, bool initialized, bool force_previewing)
|
||||
{
|
||||
++m_scene_version;
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": initialized=%1%, force_previewing=%2%")%initialized %force_previewing;
|
||||
if ((print.id().id == m_shells.print_id)&&(print.get_modified_count() == m_shells.print_modify_count)) {
|
||||
//BBS: update force previewing logic
|
||||
|
||||
@@ -251,6 +251,8 @@ private:
|
||||
|
||||
bool m_contained_in_bed{ true };
|
||||
mutable bool m_no_render_path { false };
|
||||
// ORCA: bumped on every change to what the scene pass draws that libvgcode does not track
|
||||
uint64_t m_scene_version{ 0 };
|
||||
bool m_is_dark = false;
|
||||
|
||||
libvgcode::Viewer m_viewer;
|
||||
@@ -283,7 +285,12 @@ public:
|
||||
//BBS: add all plates filament statistics
|
||||
void render_all_plates_stats(const std::vector<const GCodeProcessorResult*>& gcode_result_list, bool show = true) const;
|
||||
//BBS: GUI refactor: add canvas width and height
|
||||
void render(int canvas_width, int canvas_height, int right_margin);
|
||||
// draw_scene = false records the legend, the sliders and the marker only, for a frame whose
|
||||
// toolpaths are shown again from a kept image
|
||||
void render(int canvas_width, int canvas_height, int right_margin, bool draw_scene = true);
|
||||
// ORCA: what the scene pass draws, as two counters that change whenever it would look different
|
||||
std::array<uint64_t, 2> scene_version() const;
|
||||
bool scene_update_pending() const { return m_viewer.has_pending_updates(); }
|
||||
//BBS
|
||||
// void _render_calibration_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
|
||||
// void _render_calibration_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
|
||||
|
||||
@@ -1224,6 +1224,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed)
|
||||
|
||||
GLCanvas3D::~GLCanvas3D()
|
||||
{
|
||||
_scene_cache_release();
|
||||
if (_set_current()) {
|
||||
if (m_fxaa_texture_id != 0) {
|
||||
glsafe(::glDeleteTextures(1, &m_fxaa_texture_id));
|
||||
@@ -1328,6 +1329,7 @@ bool GLCanvas3D::init()
|
||||
|
||||
void GLCanvas3D::on_change_color_mode(bool is_dark, bool reinit) {
|
||||
m_is_dark = is_dark;
|
||||
++m_scene_version;
|
||||
// Bed color
|
||||
m_bed.on_change_color_mode(is_dark);
|
||||
// GcodeViewer color
|
||||
@@ -2050,6 +2052,46 @@ void GLCanvas3D::render(bool only_init)
|
||||
}
|
||||
|
||||
// draw scene
|
||||
int hover_id = (m_hover_plate_idxs.size() > 0)?m_hover_plate_idxs.front():-1;
|
||||
|
||||
// ORCA: while the preference is on and nothing the scene pass draws has changed since the
|
||||
// last full frame, that frame is shown again and only the overlays are drawn on top of it
|
||||
const bool preview_scene = m_canvas_type == ECanvasType::CanvasPreview && m_render_preview && m_gcode_viewer.has_data();
|
||||
bool scene_from_cache = false;
|
||||
bool scene_to_cache = false;
|
||||
if (preview_scene && _scene_cache_enabled() && !m_scene_cache.broken) {
|
||||
const int current_plate = wxGetApp().plater()->get_partplate_list().get_curr_plate_index();
|
||||
const std::array<uint64_t, 2> viewer_version = m_gcode_viewer.scene_version();
|
||||
const bool unchanged = m_scene_cache.valid &&
|
||||
m_scene_cache.width == cnv_size.get_width() && m_scene_cache.height == cnv_size.get_height() &&
|
||||
m_scene_cache.view == camera.get_view_matrix().matrix() && m_scene_cache.projection == camera.get_projection_matrix().matrix() &&
|
||||
m_scene_cache.hover_plate == hover_id && m_scene_cache.current_plate == current_plate &&
|
||||
m_scene_cache.world_axes == m_show_world_axes && m_scene_cache.canvas_version == m_scene_version &&
|
||||
m_scene_cache.viewer_version == viewer_version && !m_gcode_viewer.scene_update_pending();
|
||||
if (unchanged) {
|
||||
_scene_cache_blit(false);
|
||||
scene_from_cache = !m_scene_cache.broken;
|
||||
}
|
||||
if (!scene_from_cache && _scene_cache_prepare(cnv_size.get_width(), cnv_size.get_height())) {
|
||||
m_scene_cache.valid = false;
|
||||
m_scene_cache.view = camera.get_view_matrix().matrix();
|
||||
m_scene_cache.projection = camera.get_projection_matrix().matrix();
|
||||
m_scene_cache.hover_plate = hover_id;
|
||||
m_scene_cache.current_plate = current_plate;
|
||||
m_scene_cache.world_axes = m_show_world_axes;
|
||||
m_scene_cache.canvas_version = m_scene_version;
|
||||
m_scene_cache.viewer_version = viewer_version;
|
||||
scene_to_cache = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_scene_cache.valid = false;
|
||||
|
||||
if (scene_from_cache) {
|
||||
// the preview's panels and its marker are drawn on top of the frame shown again
|
||||
_render_gcode(cnv_size.get_width(), cnv_size.get_height(), false);
|
||||
}
|
||||
else {
|
||||
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.
|
||||
@@ -2070,7 +2112,6 @@ void GLCanvas3D::render(bool only_init)
|
||||
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) {
|
||||
if (!no_partplate)
|
||||
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), m_show_world_axes);
|
||||
@@ -2147,6 +2188,13 @@ void GLCanvas3D::render(bool only_init)
|
||||
if (_is_fxaa_enabled())
|
||||
_render_fxaa_pass(static_cast<unsigned int>(cnv_size.get_width()), static_cast<unsigned int>(cnv_size.get_height()));
|
||||
|
||||
// ORCA: keep the finished scene, with its depth, for the frames that follow
|
||||
if (scene_to_cache) {
|
||||
_scene_cache_blit(true);
|
||||
m_scene_cache.valid = !m_scene_cache.broken;
|
||||
}
|
||||
}
|
||||
|
||||
// draw overlays
|
||||
_render_overlays();
|
||||
|
||||
@@ -8522,7 +8570,99 @@ void GLCanvas3D::_render_wireframe_overlay()
|
||||
}
|
||||
|
||||
//BBS: GUI refactor: add canvas size as parameters
|
||||
void GLCanvas3D::_render_gcode(int canvas_width, int canvas_height)
|
||||
bool GLCanvas3D::_scene_cache_enabled() const
|
||||
{
|
||||
return wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool("preview_cache_static_scene");
|
||||
}
|
||||
|
||||
// Makes the cache's framebuffer match the window: same size, same sample count, a depth buffer of
|
||||
// the same format, so that colour and depth can be blitted both ways. Returns false when it cannot.
|
||||
bool GLCanvas3D::_scene_cache_prepare(int width, int height)
|
||||
{
|
||||
SceneCache& cache = m_scene_cache;
|
||||
glsafe(::glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &cache.default_fbo));
|
||||
int samples = 0;
|
||||
glsafe(::glGetIntegerv(GL_SAMPLES, &samples));
|
||||
int depth_bits = 0;
|
||||
int stencil_bits = 0;
|
||||
const GLenum depth_query = (cache.default_fbo == 0) ? GL_DEPTH : GL_DEPTH_ATTACHMENT;
|
||||
const GLenum stencil_query = (cache.default_fbo == 0) ? GL_STENCIL : GL_DEPTH_ATTACHMENT;
|
||||
glsafe(::glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, depth_query, GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, &depth_bits));
|
||||
glsafe(::glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, stencil_query, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, &stencil_bits));
|
||||
const bool stencil = stencil_bits > 0;
|
||||
if (cache.fbo != 0 && cache.width == width && cache.height == height && cache.samples == samples && cache.stencil == stencil)
|
||||
return true;
|
||||
|
||||
_scene_cache_release();
|
||||
const GLenum depth_format = stencil ? GL_DEPTH24_STENCIL8 : (depth_bits <= 16) ? GL_DEPTH_COMPONENT16 : (depth_bits >= 32) ? GL_DEPTH_COMPONENT32 : GL_DEPTH_COMPONENT24;
|
||||
glsafe(::glGenRenderbuffers(1, &cache.color));
|
||||
glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, cache.color));
|
||||
if (samples > 0)
|
||||
glsafe(::glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_RGBA8, width, height));
|
||||
else
|
||||
glsafe(::glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height));
|
||||
glsafe(::glGenRenderbuffers(1, &cache.depth));
|
||||
glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, cache.depth));
|
||||
if (samples > 0)
|
||||
glsafe(::glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, depth_format, width, height));
|
||||
else
|
||||
glsafe(::glRenderbufferStorage(GL_RENDERBUFFER, depth_format, width, height));
|
||||
glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, 0));
|
||||
glsafe(::glGenFramebuffers(1, &cache.fbo));
|
||||
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, cache.fbo));
|
||||
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cache.color));
|
||||
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, stencil ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cache.depth));
|
||||
const GLenum status = ::glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, static_cast<GLuint>(cache.default_fbo)));
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Preview scene cache disabled: framebuffer incomplete, status " << status;
|
||||
_scene_cache_release();
|
||||
cache.broken = true;
|
||||
return false;
|
||||
}
|
||||
cache.width = width;
|
||||
cache.height = height;
|
||||
cache.samples = samples;
|
||||
cache.stencil = stencil;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copies colour and depth from the window into the cache (store) or back (restore). A driver that
|
||||
// refuses the blit marks the cache broken, and the preview falls back to drawing every frame.
|
||||
void GLCanvas3D::_scene_cache_blit(bool store)
|
||||
{
|
||||
SceneCache& cache = m_scene_cache;
|
||||
if (cache.fbo == 0)
|
||||
return;
|
||||
const GLuint window = static_cast<GLuint>(cache.default_fbo);
|
||||
glsafe(::glBindFramebuffer(GL_READ_FRAMEBUFFER, store ? window : cache.fbo));
|
||||
glsafe(::glBindFramebuffer(GL_DRAW_FRAMEBUFFER, store ? cache.fbo : window));
|
||||
while (::glGetError() != GL_NO_ERROR) {}
|
||||
::glBlitFramebuffer(0, 0, cache.width, cache.height, 0, 0, cache.width, cache.height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
||||
const GLenum error = ::glGetError();
|
||||
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, window));
|
||||
if (error != GL_NO_ERROR) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Preview scene cache disabled: framebuffer blit failed with GL error " << error;
|
||||
cache.broken = true;
|
||||
_scene_cache_release();
|
||||
}
|
||||
}
|
||||
|
||||
void GLCanvas3D::_scene_cache_release()
|
||||
{
|
||||
SceneCache& cache = m_scene_cache;
|
||||
if (cache.fbo != 0)
|
||||
glsafe(::glDeleteFramebuffers(1, &cache.fbo));
|
||||
if (cache.color != 0)
|
||||
glsafe(::glDeleteRenderbuffers(1, &cache.color));
|
||||
if (cache.depth != 0)
|
||||
glsafe(::glDeleteRenderbuffers(1, &cache.depth));
|
||||
cache.fbo = cache.color = cache.depth = 0;
|
||||
cache.width = cache.height = 0;
|
||||
cache.valid = false;
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_gcode(int canvas_width, int canvas_height, bool draw_scene)
|
||||
{
|
||||
IMSlider *layers_slider = m_gcode_viewer.get_layers_slider();
|
||||
IMSlider *moves_slider = m_gcode_viewer.get_moves_slider();
|
||||
@@ -8541,7 +8681,7 @@ void GLCanvas3D::_render_gcode(int canvas_width, int canvas_height)
|
||||
schedule_extra_frame(static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(m_preview_interaction_until - now).count()) + 1);
|
||||
}
|
||||
|
||||
m_gcode_viewer.render(canvas_width, canvas_height, SLIDER_RIGHT_MARGIN * GCODE_VIEWER_SLIDER_SCALE);
|
||||
m_gcode_viewer.render(canvas_width, canvas_height, SLIDER_RIGHT_MARGIN * GCODE_VIEWER_SLIDER_SCALE, draw_scene);
|
||||
|
||||
if (layers_slider->is_need_post_tick_event()) {
|
||||
auto evt = new wxCommandEvent(EVT_CUSTOMEVT_TICKSCHANGED, m_canvas->GetId());
|
||||
|
||||
@@ -736,6 +736,33 @@ public:
|
||||
std::array<unsigned int, 2> m_fxaa_texture_size{ 0, 0 };
|
||||
unsigned int m_ssao_color_texture_id{ 0 };
|
||||
unsigned int m_ssao_depth_texture_id{ 0 };
|
||||
|
||||
// ORCA: the last fully drawn preview scene, shown again while nothing it draws has changed
|
||||
struct SceneCache
|
||||
{
|
||||
unsigned int fbo{ 0 };
|
||||
unsigned int color{ 0 };
|
||||
unsigned int depth{ 0 };
|
||||
int default_fbo{ 0 };
|
||||
int width{ 0 };
|
||||
int height{ 0 };
|
||||
int samples{ 0 };
|
||||
bool stencil{ false };
|
||||
// the kept image matches the key below
|
||||
bool valid{ false };
|
||||
// a blit failed on this driver: never try again this session
|
||||
bool broken{ false };
|
||||
Matrix4d view{ Matrix4d::Zero() };
|
||||
Matrix4d projection{ Matrix4d::Zero() };
|
||||
int hover_plate{ -1 };
|
||||
int current_plate{ -1 };
|
||||
bool world_axes{ false };
|
||||
uint64_t canvas_version{ 0 };
|
||||
std::array<uint64_t, 2> viewer_version{ 0, 0 };
|
||||
};
|
||||
SceneCache m_scene_cache;
|
||||
// bumped on changes to what the scene pass draws that neither the camera nor the viewer track
|
||||
uint64_t m_scene_version{ 0 };
|
||||
std::array<unsigned int, 2> m_ssao_texture_size{ { 0, 0 } };
|
||||
GLModel m_plate_shadow_mask;
|
||||
std::string m_plate_shadow_mask_key;
|
||||
@@ -1280,7 +1307,12 @@ private:
|
||||
void _render_objects(GLVolumeCollection::ERenderType type, bool with_outline = true);
|
||||
void _render_wireframe_overlay();
|
||||
//BBS: GUI refactor: add canvas size as parameters
|
||||
void _render_gcode(int canvas_width, int canvas_height);
|
||||
void _render_gcode(int canvas_width, int canvas_height, bool draw_scene = true);
|
||||
// ORCA: scene cache, see SceneCache
|
||||
bool _scene_cache_enabled() const;
|
||||
bool _scene_cache_prepare(int width, int height);
|
||||
void _scene_cache_blit(bool store);
|
||||
void _scene_cache_release();
|
||||
//BBS: render a plane for assemble
|
||||
void _render_plane() const;
|
||||
void _render_selection();
|
||||
|
||||
@@ -2040,6 +2040,14 @@ void PreferencesDialog::create_items()
|
||||
);
|
||||
g_sizer->Add(item_rest_detail_mode);
|
||||
|
||||
auto item_cache_static_scene = create_item_checkbox(
|
||||
_L("Keep the drawn preview while nothing moves"),
|
||||
_L("Keep the last drawn preview and show it again for frames in which neither the camera nor the toolpaths changed, "
|
||||
"so that hovering, tooltips and notifications no longer redraw a large print. The scene is redrawn as soon as anything in it changes."),
|
||||
"preview_cache_static_scene"
|
||||
);
|
||||
g_sizer->Add(item_cache_static_scene);
|
||||
|
||||
auto item_dim_previous_layers = create_item_checkbox(
|
||||
_L("Dim lower layers"),
|
||||
_L("When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness."),
|
||||
|
||||
Reference in New Issue
Block a user