Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEnrico Turri <enricoturri@seznam.cz>2019-10-29 12:27:51 +0300
committerEnrico Turri <enricoturri@seznam.cz>2019-10-29 12:27:51 +0300
commit3ff3eed2b1e0751e823559542975e63d51f62010 (patch)
tree99688fedcae65515912f7efe91219ae26bab74f8 /src
parentf36dd833d2fecebe86d351fe0f2933e1c920673c (diff)
ENABLE_THUMBNAIL_GENERATOR -> Use off-screen framebuffer to render the thumbnail on graphic cards supporting it
Diffstat (limited to 'src')
-rw-r--r--src/slic3r/GUI/GLCanvas3D.cpp219
-rw-r--r--src/slic3r/GUI/GLCanvas3D.hpp6
-rw-r--r--src/slic3r/GUI/GLCanvas3DManager.cpp6
-rw-r--r--src/slic3r/GUI/GLCanvas3DManager.hpp2
4 files changed, 151 insertions, 82 deletions
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index 139ee5fa4..b40a83682 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -1649,88 +1649,10 @@ void GLCanvas3D::render()
#if ENABLE_THUMBNAIL_GENERATOR
void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only)
{
- auto is_visible = [](const GLVolume& v) -> bool {
- bool ret = v.printable;
- ret &= (!v.shader_outside_printer_detection_enabled || !v.is_outside);
- return ret;
- };
-
- static const float orange[] = { 0.99f, 0.49f, 0.26f };
- static const float gray[] = { 0.64f, 0.64f, 0.64f };
-
- const Size& cnv_size = get_canvas_size();
- unsigned int cnv_w = (unsigned int)cnv_size.get_width();
- unsigned int cnv_h = (unsigned int)cnv_size.get_height();
- if ((w > cnv_w) || (h > cnv_h))
- {
- float ratio = std::min((float)cnv_w / (float)w, (float)cnv_h / (float)h);
- w = (unsigned int)(ratio * (float)w);
- h = (unsigned int)(ratio * (float)h);
- }
-
- thumbnail_data.set(w, h);
-
- GLVolumePtrs visible_volumes;
-
- for (GLVolume* vol : m_volumes.volumes)
- {
- if (!vol->is_modifier && !vol->is_wipe_tower && (!parts_only || (vol->composite_id.volume_id >= 0)))
- {
- if (!printable_only || is_visible(*vol))
- visible_volumes.push_back(vol);
- }
- }
-
- if (visible_volumes.empty())
- return;
-
- BoundingBoxf3 box;
- for (const GLVolume* vol : visible_volumes)
- {
- box.merge(vol->transformed_bounding_box());
- }
-
- Camera camera;
- camera.zoom_to_box(box, thumbnail_data.width, thumbnail_data.height);
- camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height);
- camera.apply_view_matrix();
- camera.apply_projection(box);
-
- glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
- glsafe(::glEnable(GL_LIGHTING));
- glsafe(::glEnable(GL_DEPTH_TEST));
-
- for (const GLVolume* vol : visible_volumes)
- {
- glsafe(::glColor3fv((vol->printable && !vol->is_outside) ? orange : gray));
- vol->render();
- }
-
- glsafe(::glDisable(GL_DEPTH_TEST));
- glsafe(::glDisable(GL_LIGHTING));
- glsafe(::glReadPixels(0, 0, thumbnail_data.width, thumbnail_data.height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data()));
-
-#if 0
- // debug export of generated image
- wxImage image(thumbnail_data.width, thumbnail_data.height);
- image.InitAlpha();
-
- for (unsigned int r = 0; r < thumbnail_data.height; ++r)
- {
- unsigned int rr = (thumbnail_data.height - 1 - r) * thumbnail_data.width;
- for (unsigned int c = 0; c < thumbnail_data.width; ++c)
- {
- unsigned char* px = thumbnail_data.pixels.data() + 4 * (rr + c);
- image.SetRGB((int)c, (int)r, px[0], px[1], px[2]);
- image.SetAlpha((int)c, (int)r, px[3]);
- }
- }
-
- image.SaveFile("C:/test.png", wxBITMAP_TYPE_PNG);
-#endif
-
- // restore the framebuffer size to avoid flickering on the 3D scene
- m_camera.apply_viewport(0, 0, cnv_size.get_width(), cnv_size.get_height());
+ if (GLCanvas3DManager::are_framebuffers_supported())
+ _render_thumbnail_framebuffer(thumbnail_data, w, h, printable_only, parts_only);
+ else
+ _render_thumbnail_legacy(thumbnail_data, w, h, printable_only, parts_only);
}
#endif // ENABLE_THUMBNAIL_GENERATOR
@@ -3644,6 +3566,139 @@ void GLCanvas3D::_render_undo_redo_stack(const bool is_undo, float pos_x)
imgui->end();
}
+#if ENABLE_THUMBNAIL_GENERATOR
+static void render_volumes_in_thumbnail(const GLVolumePtrs& volumes, ThumbnailData& thumbnail_data, bool printable_only, bool parts_only)
+{
+ auto is_visible = [](const GLVolume& v) -> bool
+ {
+ bool ret = v.printable;
+ ret &= (!v.shader_outside_printer_detection_enabled || !v.is_outside);
+ return ret;
+ };
+
+ static const float orange[] = { 0.99f, 0.49f, 0.26f };
+ static const float gray[] = { 0.64f, 0.64f, 0.64f };
+
+ GLVolumePtrs visible_volumes;
+
+ for (GLVolume* vol : volumes)
+ {
+ if (!vol->is_modifier && !vol->is_wipe_tower && (!parts_only || (vol->composite_id.volume_id >= 0)))
+ {
+ if (!printable_only || is_visible(*vol))
+ visible_volumes.push_back(vol);
+ }
+ }
+
+ if (visible_volumes.empty())
+ return;
+
+ BoundingBoxf3 box;
+ for (const GLVolume* vol : visible_volumes)
+ {
+ box.merge(vol->transformed_bounding_box());
+ }
+
+ Camera camera;
+ camera.zoom_to_box(box, thumbnail_data.width, thumbnail_data.height);
+ camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height);
+ camera.apply_view_matrix();
+ camera.apply_projection(box);
+
+ glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
+ glsafe(::glEnable(GL_LIGHTING));
+ glsafe(::glEnable(GL_DEPTH_TEST));
+
+ for (const GLVolume* vol : visible_volumes)
+ {
+ glsafe(::glColor3fv((vol->printable && !vol->is_outside) ? orange : gray));
+ vol->render();
+ }
+
+ glsafe(::glDisable(GL_DEPTH_TEST));
+ glsafe(::glDisable(GL_LIGHTING));
+ glsafe(::glReadPixels(0, 0, thumbnail_data.width, thumbnail_data.height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data()));
+
+#if 0
+ // debug export of generated image
+ wxImage image(thumbnail_data.width, thumbnail_data.height);
+ image.InitAlpha();
+
+ for (unsigned int r = 0; r < thumbnail_data.height; ++r)
+ {
+ unsigned int rr = (thumbnail_data.height - 1 - r) * thumbnail_data.width;
+ for (unsigned int c = 0; c < thumbnail_data.width; ++c)
+ {
+ unsigned char* px = thumbnail_data.pixels.data() + 4 * (rr + c);
+ image.SetRGB((int)c, (int)r, px[0], px[1], px[2]);
+ image.SetAlpha((int)c, (int)r, px[3]);
+ }
+ }
+
+ image.SaveFile("C:/prusa/test/test.png", wxBITMAP_TYPE_PNG);
+#endif
+}
+
+void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only)
+{
+ thumbnail_data.set(w, h);
+ if (!thumbnail_data.is_valid())
+ return;
+
+ GLuint fbo;
+ glsafe(::glGenFramebuffers(1, &fbo));
+ glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, fbo));
+
+ GLuint tex;
+ glsafe(::glGenTextures(1, &tex));
+ glsafe(::glBindTexture(GL_TEXTURE_2D, tex));
+ glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
+ glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
+ glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+ glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0));
+
+ GLuint depth;
+ glsafe(::glGenRenderbuffers(1, &depth));
+ glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, depth));
+ glsafe(::glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h));
+ glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth));
+
+ GLenum drawBufs[] = { GL_COLOR_ATTACHMENT0 };
+ glsafe(::glDrawBuffers(1, drawBufs));
+
+ if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
+ render_volumes_in_thumbnail(m_volumes.volumes, thumbnail_data, printable_only, parts_only);
+
+ glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0));
+ glsafe(::glDeleteRenderbuffers(1, &depth));
+ glsafe(::glDeleteTextures(1, &tex));
+ glsafe(::glDeleteFramebuffers(1, &fbo));
+}
+
+void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only)
+{
+ // check that thumbnail size does not exceed the default framebuffer size
+ const Size& cnv_size = get_canvas_size();
+ unsigned int cnv_w = (unsigned int)cnv_size.get_width();
+ unsigned int cnv_h = (unsigned int)cnv_size.get_height();
+ if ((w > cnv_w) || (h > cnv_h))
+ {
+ float ratio = std::min((float)cnv_w / (float)w, (float)cnv_h / (float)h);
+ w = (unsigned int)(ratio * (float)w);
+ h = (unsigned int)(ratio * (float)h);
+ }
+
+ thumbnail_data.set(w, h);
+ if (!thumbnail_data.is_valid())
+ return;
+
+ render_volumes_in_thumbnail(m_volumes.volumes, thumbnail_data, printable_only, parts_only);
+
+ // restore the default framebuffer size to avoid flickering on the 3D scene
+ m_camera.apply_viewport(0, 0, cnv_size.get_width(), cnv_size.get_height());
+}
+#endif // ENABLE_THUMBNAIL_GENERATOR
+
bool GLCanvas3D::_init_toolbars()
{
if (!_init_main_toolbar())
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index 5b06b6311..fce4661a4 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -674,6 +674,12 @@ private:
void _render_sla_slices() const;
void _render_selection_sidebar_hints() const;
void _render_undo_redo_stack(const bool is_undo, float pos_x);
+#if ENABLE_THUMBNAIL_GENERATOR
+ // render thumbnail using an off-screen framebuffer
+ void _render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only);
+ // render thumbnail using the default framebuffer
+ void _render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only);
+#endif // ENABLE_THUMBNAIL_GENERATOR
void _update_volumes_hover_state() const;
diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp
index 9690e8a8d..03daa0b00 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.cpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.cpp
@@ -189,6 +189,7 @@ std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool exten
GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::MS_Unknown;
bool GLCanvas3DManager::s_compressed_textures_supported = false;
+bool GLCanvas3DManager::s_framebuffers_supported = false;
GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info;
GLCanvas3DManager::GLCanvas3DManager()
@@ -269,6 +270,11 @@ void GLCanvas3DManager::init_gl()
else
s_compressed_textures_supported = false;
+ if (s_gl_info.is_version_greater_or_equal_to(3, 0) && GLEW_ARB_framebuffer_object)
+ s_framebuffers_supported = true;
+ else
+ s_framebuffers_supported = false;
+
if (! s_gl_info.is_version_greater_or_equal_to(2, 0)) {
// Complain about the OpenGL version.
wxString message = wxString::Format(
diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp
index 760266a27..a2e35f811 100644
--- a/src/slic3r/GUI/GLCanvas3DManager.hpp
+++ b/src/slic3r/GUI/GLCanvas3DManager.hpp
@@ -77,6 +77,7 @@ private:
bool m_gl_initialized;
static EMultisampleState s_multisample;
static bool s_compressed_textures_supported;
+ static bool s_framebuffers_supported;
public:
GLCanvas3DManager();
@@ -97,6 +98,7 @@ public:
static bool can_multisample() { return s_multisample == MS_Enabled; }
static bool are_compressed_textures_supported() { return s_compressed_textures_supported; }
+ static bool are_framebuffers_supported() { return s_framebuffers_supported; }
static wxGLCanvas* create_wxglcanvas(wxWindow *parent);