mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-13 18:31:49 +08:00
Tech ENABLE_THUMBNAIL_GENERATOR partially (only export to .gcode) ported from master
This commit is contained in:
parent
02e107fa6a
commit
c1a316124f
@ -4031,7 +4031,6 @@ printer_model = SL1
|
|||||||
printer_variant = default
|
printer_variant = default
|
||||||
default_sla_material_profile = Prusa Orange Tough 0.05
|
default_sla_material_profile = Prusa Orange Tough 0.05
|
||||||
default_sla_print_profile = 0.05 Normal
|
default_sla_print_profile = 0.05 Normal
|
||||||
thumbnails = 400x400,800x480
|
|
||||||
bed_shape = 1.48x1.02,119.48x1.02,119.48x67.02,1.48x67.02
|
bed_shape = 1.48x1.02,119.48x1.02,119.48x67.02,1.48x67.02
|
||||||
display_height = 68.04
|
display_height = 68.04
|
||||||
display_orientation = portrait
|
display_orientation = portrait
|
||||||
|
@ -71,6 +71,8 @@ add_library(libslic3r STATIC
|
|||||||
Format/STL.hpp
|
Format/STL.hpp
|
||||||
GCode/Analyzer.cpp
|
GCode/Analyzer.cpp
|
||||||
GCode/Analyzer.hpp
|
GCode/Analyzer.hpp
|
||||||
|
GCode/ThumbnailData.cpp
|
||||||
|
GCode/ThumbnailData.hpp
|
||||||
GCode/CoolingBuffer.cpp
|
GCode/CoolingBuffer.cpp
|
||||||
GCode/CoolingBuffer.hpp
|
GCode/CoolingBuffer.hpp
|
||||||
GCode/PostProcessor.cpp
|
GCode/PostProcessor.cpp
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
#include <boost/beast/core/detail/base64.hpp>
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
#include <boost/nowide/iostream.hpp>
|
#include <boost/nowide/iostream.hpp>
|
||||||
#include <boost/nowide/cstdio.hpp>
|
#include <boost/nowide/cstdio.hpp>
|
||||||
@ -28,6 +31,8 @@
|
|||||||
|
|
||||||
#include <Shiny/Shiny.h>
|
#include <Shiny/Shiny.h>
|
||||||
|
|
||||||
|
#include "miniz_extension.hpp"
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// Enable debugging and asserts, even in the release build.
|
// Enable debugging and asserts, even in the release build.
|
||||||
#define DEBUG
|
#define DEBUG
|
||||||
@ -651,7 +656,11 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
|
|||||||
return layers_to_print;
|
return layers_to_print;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||||
|
#else
|
||||||
void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_data)
|
void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_data)
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
{
|
{
|
||||||
PROFILE_CLEAR();
|
PROFILE_CLEAR();
|
||||||
|
|
||||||
@ -677,7 +686,11 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
m_placeholder_parser_failed_templates.clear();
|
m_placeholder_parser_failed_templates.clear();
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
this->_do_export(*print, file, thumbnail_cb);
|
||||||
|
#else
|
||||||
this->_do_export(*print, file);
|
this->_do_export(*print, file);
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
fflush(file);
|
fflush(file);
|
||||||
if (ferror(file)) {
|
if (ferror(file)) {
|
||||||
fclose(file);
|
fclose(file);
|
||||||
@ -737,7 +750,11 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
|||||||
PROFILE_OUTPUT(debug_out_path("gcode-export-profile.txt").c_str());
|
PROFILE_OUTPUT(debug_out_path("gcode-export-profile.txt").c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||||
|
#else
|
||||||
void GCode::_do_export(Print &print, FILE *file)
|
void GCode::_do_export(Print &print, FILE *file)
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
{
|
{
|
||||||
PROFILE_FUNC();
|
PROFILE_FUNC();
|
||||||
|
|
||||||
@ -925,6 +942,49 @@ void GCode::_do_export(Print &print, FILE *file)
|
|||||||
|
|
||||||
// Write information on the generator.
|
// Write information on the generator.
|
||||||
_write_format(file, "; %s\n\n", Slic3r::header_slic3r_generated().c_str());
|
_write_format(file, "; %s\n\n", Slic3r::header_slic3r_generated().c_str());
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
// Write thumbnails using base64 encoding
|
||||||
|
if (thumbnail_cb != nullptr)
|
||||||
|
{
|
||||||
|
const size_t max_row_length = 78;
|
||||||
|
ThumbnailsList thumbnails;
|
||||||
|
thumbnail_cb(thumbnails, print.full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true, true);
|
||||||
|
for (const ThumbnailData& data : thumbnails)
|
||||||
|
{
|
||||||
|
if (data.is_valid())
|
||||||
|
{
|
||||||
|
size_t png_size = 0;
|
||||||
|
void* png_data = tdefl_write_image_to_png_file_in_memory_ex((const void*)data.pixels.data(), data.width, data.height, 4, &png_size, MZ_DEFAULT_LEVEL, 1);
|
||||||
|
if (png_data != nullptr)
|
||||||
|
{
|
||||||
|
std::string encoded;
|
||||||
|
encoded.resize(boost::beast::detail::base64::encoded_size(png_size));
|
||||||
|
encoded.resize(boost::beast::detail::base64::encode((void*)&encoded[0], (const void*)png_data, png_size));
|
||||||
|
|
||||||
|
_write_format(file, "\n;\n; thumbnail begin %dx%d %d\n", data.width, data.height, encoded.size());
|
||||||
|
|
||||||
|
unsigned int row_count = 0;
|
||||||
|
while (encoded.size() > max_row_length)
|
||||||
|
{
|
||||||
|
_write_format(file, "; %s\n", encoded.substr(0, max_row_length).c_str());
|
||||||
|
encoded = encoded.substr(max_row_length);
|
||||||
|
++row_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoded.size() > 0)
|
||||||
|
_write_format(file, "; %s\n", encoded.c_str());
|
||||||
|
|
||||||
|
_write(file, "; thumbnail end\n;\n");
|
||||||
|
|
||||||
|
mz_free(png_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print.throw_if_canceled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
// Write notes (content of the Print Settings tab -> Notes)
|
// Write notes (content of the Print Settings tab -> Notes)
|
||||||
{
|
{
|
||||||
std::list<std::string> lines;
|
std::list<std::string> lines;
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
#include "GCodeTimeEstimator.hpp"
|
#include "GCodeTimeEstimator.hpp"
|
||||||
#include "EdgeGrid.hpp"
|
#include "EdgeGrid.hpp"
|
||||||
#include "GCode/Analyzer.hpp"
|
#include "GCode/Analyzer.hpp"
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
#include "GCode/ThumbnailData.hpp"
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -162,7 +165,11 @@ public:
|
|||||||
|
|
||||||
// throws std::runtime_exception on error,
|
// throws std::runtime_exception on error,
|
||||||
// throws CanceledException through print->throw_if_canceled().
|
// throws CanceledException through print->throw_if_canceled().
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||||
|
#else
|
||||||
void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr);
|
void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr);
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
|
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
|
||||||
const Vec2d& origin() const { return m_origin; }
|
const Vec2d& origin() const { return m_origin; }
|
||||||
@ -190,7 +197,11 @@ public:
|
|||||||
static void append_full_config(const Print& print, std::string& str);
|
static void append_full_config(const Print& print, std::string& str);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
void _do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb);
|
||||||
|
#else
|
||||||
void _do_export(Print &print, FILE *file);
|
void _do_export(Print &print, FILE *file);
|
||||||
|
#endif //ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
// Object and support extrusions of the same PrintObject at the same print_z.
|
// Object and support extrusions of the same PrintObject at the same print_z.
|
||||||
struct LayerToPrint
|
struct LayerToPrint
|
||||||
|
36
src/libslic3r/GCode/ThumbnailData.cpp
Normal file
36
src/libslic3r/GCode/ThumbnailData.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include "libslic3r/libslic3r.h"
|
||||||
|
#include "ThumbnailData.hpp"
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
void ThumbnailData::set(unsigned int w, unsigned int h)
|
||||||
|
{
|
||||||
|
if ((w == 0) || (h == 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((width != w) || (height != h))
|
||||||
|
{
|
||||||
|
width = w;
|
||||||
|
height = h;
|
||||||
|
// defaults to white texture
|
||||||
|
pixels = std::vector<unsigned char>(width * height * 4, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThumbnailData::reset()
|
||||||
|
{
|
||||||
|
width = 0;
|
||||||
|
height = 0;
|
||||||
|
pixels.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ThumbnailData::is_valid() const
|
||||||
|
{
|
||||||
|
return (width != 0) && (height != 0) && ((unsigned int)pixels.size() == 4 * width * height);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
31
src/libslic3r/GCode/ThumbnailData.hpp
Normal file
31
src/libslic3r/GCode/ThumbnailData.hpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef slic3r_ThumbnailData_hpp_
|
||||||
|
#define slic3r_ThumbnailData_hpp_
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "libslic3r/Point.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
struct ThumbnailData
|
||||||
|
{
|
||||||
|
unsigned int width;
|
||||||
|
unsigned int height;
|
||||||
|
std::vector<unsigned char> pixels;
|
||||||
|
|
||||||
|
ThumbnailData() { reset(); }
|
||||||
|
void set(unsigned int w, unsigned int h);
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
bool is_valid() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<ThumbnailData> ThumbnailsList;
|
||||||
|
typedef std::function<void(ThumbnailsList & thumbnails, const Vec2ds & sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)> ThumbnailsGeneratorCallback;
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
|
#endif // slic3r_ThumbnailData_hpp_
|
@ -38,6 +38,7 @@ typedef std::vector<Point*> PointPtrs;
|
|||||||
typedef std::vector<const Point*> PointConstPtrs;
|
typedef std::vector<const Point*> PointConstPtrs;
|
||||||
typedef std::vector<Vec3crd> Points3;
|
typedef std::vector<Vec3crd> Points3;
|
||||||
typedef std::vector<Vec2d> Pointfs;
|
typedef std::vector<Vec2d> Pointfs;
|
||||||
|
typedef std::vector<Vec2d> Vec2ds;
|
||||||
typedef std::vector<Vec3d> Pointf3s;
|
typedef std::vector<Vec3d> Pointf3s;
|
||||||
|
|
||||||
typedef Eigen::Matrix<float, 2, 2, Eigen::DontAlign> Matrix2f;
|
typedef Eigen::Matrix<float, 2, 2, Eigen::DontAlign> Matrix2f;
|
||||||
@ -87,11 +88,12 @@ class Point : public Vec2crd
|
|||||||
public:
|
public:
|
||||||
typedef coord_t coord_type;
|
typedef coord_t coord_type;
|
||||||
|
|
||||||
Point() : Vec2crd() { (*this)(0) = 0; (*this)(1) = 0; }
|
Point() : Vec2crd(0, 0) {}
|
||||||
Point(coord_t x, coord_t y) { (*this)(0) = x; (*this)(1) = y; }
|
Point(coord_t x, coord_t y) : Vec2crd(x, y) {}
|
||||||
Point(int64_t x, int64_t y) { (*this)(0) = coord_t(x); (*this)(1) = coord_t(y); } // for Clipper
|
Point(int64_t x, int64_t y) : Vec2crd(coord_t(x), coord_t(y)) {} // for Clipper
|
||||||
Point(double x, double y) { (*this)(0) = coord_t(lrint(x)); (*this)(1) = coord_t(lrint(y)); }
|
Point(double x, double y) : Vec2crd(coord_t(lrint(x)), coord_t(lrint(y))) {}
|
||||||
Point(const Point& rhs) { *this = rhs; }
|
Point(const Point& rhs) { *this = rhs; }
|
||||||
|
explicit Point(const Vec2d& rhs) : Vec2crd(coord_t(lrint(rhs.x())), coord_t(lrint(rhs.y()))) {}
|
||||||
// This constructor allows you to construct Point from Eigen expressions
|
// This constructor allows you to construct Point from Eigen expressions
|
||||||
template<typename OtherDerived>
|
template<typename OtherDerived>
|
||||||
Point(const Eigen::MatrixBase<OtherDerived> &other) : Vec2crd(other) {}
|
Point(const Eigen::MatrixBase<OtherDerived> &other) : Vec2crd(other) {}
|
||||||
|
@ -1525,7 +1525,11 @@ void Print::process()
|
|||||||
// The export_gcode may die for various reasons (fails to process output_filename_format,
|
// The export_gcode may die for various reasons (fails to process output_filename_format,
|
||||||
// write error into the G-code, cannot execute post-processing scripts).
|
// write error into the G-code, cannot execute post-processing scripts).
|
||||||
// It is up to the caller to show an error message.
|
// It is up to the caller to show an error message.
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||||
|
#else
|
||||||
std::string Print::export_gcode(const std::string &path_template, GCodePreviewData *preview_data)
|
std::string Print::export_gcode(const std::string &path_template, GCodePreviewData *preview_data)
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
{
|
{
|
||||||
// output everything to a G-code file
|
// output everything to a G-code file
|
||||||
// The following call may die if the output_filename_format template substitution fails.
|
// The following call may die if the output_filename_format template substitution fails.
|
||||||
@ -1542,7 +1546,11 @@ std::string Print::export_gcode(const std::string &path_template, GCodePreviewDa
|
|||||||
|
|
||||||
// The following line may die for multiple reasons.
|
// The following line may die for multiple reasons.
|
||||||
GCode gcode;
|
GCode gcode;
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
gcode.do_export(this, path.c_str(), preview_data, thumbnail_cb);
|
||||||
|
#else
|
||||||
gcode.do_export(this, path.c_str(), preview_data);
|
gcode.do_export(this, path.c_str(), preview_data);
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
return path.c_str();
|
return path.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,9 @@
|
|||||||
#include "Slicing.hpp"
|
#include "Slicing.hpp"
|
||||||
#include "GCode/ToolOrdering.hpp"
|
#include "GCode/ToolOrdering.hpp"
|
||||||
#include "GCode/WipeTower.hpp"
|
#include "GCode/WipeTower.hpp"
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
#include "GCode/ThumbnailData.hpp"
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
@ -301,7 +304,11 @@ public:
|
|||||||
void process() override;
|
void process() override;
|
||||||
// Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file.
|
// Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file.
|
||||||
// If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r).
|
// If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r).
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||||
|
#else
|
||||||
std::string export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
|
std::string export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
// methods for handling state
|
// methods for handling state
|
||||||
bool is_step_done(PrintStep step) const { return Inherited::is_step_done(step); }
|
bool is_step_done(PrintStep step) const { return Inherited::is_step_done(step); }
|
||||||
|
@ -62,6 +62,11 @@ void PrintConfigDef::init_common_params()
|
|||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->set_default_value(new ConfigOptionString(""));
|
def->set_default_value(new ConfigOptionString(""));
|
||||||
|
|
||||||
|
def = this->add("thumbnails", coPoints);
|
||||||
|
def->label = L("Picture sizes to be stored into a .gcode and .sl1 files");
|
||||||
|
def->mode = comExpert;
|
||||||
|
def->set_default_value(new ConfigOptionPoints());
|
||||||
|
|
||||||
def = this->add("layer_height", coFloat);
|
def = this->add("layer_height", coFloat);
|
||||||
def->label = L("Layer height");
|
def->label = L("Layer height");
|
||||||
def->category = L("Layers and Perimeters");
|
def->category = L("Layers and Perimeters");
|
||||||
|
@ -32,4 +32,13 @@
|
|||||||
#define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1)
|
#define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1)
|
||||||
|
|
||||||
|
|
||||||
|
//============
|
||||||
|
// 2.1.1 techs
|
||||||
|
//============
|
||||||
|
#define ENABLE_2_1_1 1
|
||||||
|
|
||||||
|
// Enable thumbnail generator
|
||||||
|
#define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_1_1)
|
||||||
|
|
||||||
|
|
||||||
#endif // _technologies_h_
|
#endif // _technologies_h_
|
||||||
|
@ -171,6 +171,7 @@ void Bed3D::Axes::render() const
|
|||||||
glsafe(::glPopMatrix());
|
glsafe(::glPopMatrix());
|
||||||
|
|
||||||
glsafe(::glDisable(GL_LIGHTING));
|
glsafe(::glDisable(GL_LIGHTING));
|
||||||
|
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bed3D::Axes::render_axis(double length) const
|
void Bed3D::Axes::render_axis(double length) const
|
||||||
@ -262,12 +263,15 @@ Point Bed3D::point_projection(const Point& point) const
|
|||||||
return m_polygon.point_projection(point);
|
return m_polygon.point_projection(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bed3D::render(GLCanvas3D& canvas, float theta, float scale_factor) const
|
void Bed3D::render(GLCanvas3D& canvas, float theta, float scale_factor, bool show_axes) const
|
||||||
{
|
{
|
||||||
m_scale_factor = scale_factor;
|
m_scale_factor = scale_factor;
|
||||||
|
|
||||||
|
if (show_axes)
|
||||||
render_axes();
|
render_axes();
|
||||||
|
|
||||||
|
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||||
|
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
case MK2: { render_prusa(canvas, "mk2", theta > 90.0f); break; }
|
case MK2: { render_prusa(canvas, "mk2", theta > 90.0f); break; }
|
||||||
@ -277,6 +281,8 @@ void Bed3D::render(GLCanvas3D& canvas, float theta, float scale_factor) const
|
|||||||
default:
|
default:
|
||||||
case Custom: { render_custom(canvas, theta > 90.0f); break; }
|
case Custom: { render_custom(canvas, theta > 90.0f); break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bed3D::calc_bounding_boxes() const
|
void Bed3D::calc_bounding_boxes() const
|
||||||
|
@ -111,7 +111,7 @@ public:
|
|||||||
bool contains(const Point& point) const;
|
bool contains(const Point& point) const;
|
||||||
Point point_projection(const Point& point) const;
|
Point point_projection(const Point& point) const;
|
||||||
|
|
||||||
void render(GLCanvas3D& canvas, float theta, float scale_factor) const;
|
void render(GLCanvas3D& canvas, float theta, float scale_factor, bool show_axes) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void calc_bounding_boxes() const;
|
void calc_bounding_boxes() const;
|
||||||
|
@ -10,6 +10,10 @@
|
|||||||
#include <wx/wfstream.h>
|
#include <wx/wfstream.h>
|
||||||
#include <wx/zipstrm.h>
|
#include <wx/zipstrm.h>
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
#include <miniz.h>
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
// Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx.
|
// Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx.
|
||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
#include "libslic3r/SLAPrint.hpp"
|
#include "libslic3r/SLAPrint.hpp"
|
||||||
@ -82,7 +86,11 @@ void BackgroundSlicingProcess::process_fff()
|
|||||||
assert(m_print == m_fff_print);
|
assert(m_print == m_fff_print);
|
||||||
m_print->process();
|
m_print->process();
|
||||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_slicing_completed_id));
|
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_slicing_completed_id));
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data, m_thumbnail_cb);
|
||||||
|
#else
|
||||||
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data);
|
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data);
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
if (this->set_step_started(bspsGCodeFinalize)) {
|
if (this->set_step_started(bspsGCodeFinalize)) {
|
||||||
if (! m_export_path.empty()) {
|
if (! m_export_path.empty()) {
|
||||||
//FIXME localize the messages
|
//FIXME localize the messages
|
||||||
|
@ -49,6 +49,9 @@ public:
|
|||||||
void set_fff_print(Print *print) { m_fff_print = print; }
|
void set_fff_print(Print *print) { m_fff_print = print; }
|
||||||
void set_sla_print(SLAPrint *print) { m_sla_print = print; }
|
void set_sla_print(SLAPrint *print) { m_sla_print = print; }
|
||||||
void set_gcode_preview_data(GCodePreviewData *gpd) { m_gcode_preview_data = gpd; }
|
void set_gcode_preview_data(GCodePreviewData *gpd) { m_gcode_preview_data = gpd; }
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
void set_thumbnail_cb(ThumbnailsGeneratorCallback cb) { m_thumbnail_cb = cb; }
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
// The following wxCommandEvent will be sent to the UI thread / Platter window, when the slicing is finished
|
// The following wxCommandEvent will be sent to the UI thread / Platter window, when the slicing is finished
|
||||||
// and the background processing will transition into G-code export.
|
// and the background processing will transition into G-code export.
|
||||||
// The wxCommandEvent is sent to the UI thread asynchronously without waiting for the event to be processed.
|
// The wxCommandEvent is sent to the UI thread asynchronously without waiting for the event to be processed.
|
||||||
@ -151,6 +154,10 @@ private:
|
|||||||
SLAPrint *m_sla_print = nullptr;
|
SLAPrint *m_sla_print = nullptr;
|
||||||
// Data structure, to which the G-code export writes its annotations.
|
// Data structure, to which the G-code export writes its annotations.
|
||||||
GCodePreviewData *m_gcode_preview_data = nullptr;
|
GCodePreviewData *m_gcode_preview_data = nullptr;
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
// Callback function, used to write thumbnails into gcode.
|
||||||
|
ThumbnailsGeneratorCallback m_thumbnail_cb = nullptr;
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
// Temporary G-code, there is one defined for the BackgroundSlicingProcess, differentiated from the other processes by a process ID.
|
// Temporary G-code, there is one defined for the BackgroundSlicingProcess, differentiated from the other processes by a process ID.
|
||||||
std::string m_temp_output_path;
|
std::string m_temp_output_path;
|
||||||
// Output path provided by the user. The output path may be set even if the slicing is running,
|
// Output path provided by the user. The output path may be set even if the slicing is running,
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#include "libslic3r/libslic3r.h"
|
#include "libslic3r/libslic3r.h"
|
||||||
|
|
||||||
#include "Camera.hpp"
|
#include "Camera.hpp"
|
||||||
|
#if !ENABLE_THUMBNAIL_GENERATOR
|
||||||
#include "3DScene.hpp"
|
#include "3DScene.hpp"
|
||||||
|
#endif // !ENABLE_THUMBNAIL_GENERATOR
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
#include "AppConfig.hpp"
|
#include "AppConfig.hpp"
|
||||||
|
|
||||||
@ -22,6 +24,10 @@ namespace Slic3r {
|
|||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
const double Camera::DefaultDistance = 1000.0;
|
const double Camera::DefaultDistance = 1000.0;
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
const double Camera::DefaultZoomToBoxMarginFactor = 1.025;
|
||||||
|
const double Camera::DefaultZoomToVolumesMarginFactor = 1.025;
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
double Camera::FrustrumMinZRange = 50.0;
|
double Camera::FrustrumMinZRange = 50.0;
|
||||||
double Camera::FrustrumMinNearZ = 100.0;
|
double Camera::FrustrumMinNearZ = 100.0;
|
||||||
double Camera::FrustrumZMargin = 10.0;
|
double Camera::FrustrumZMargin = 10.0;
|
||||||
@ -184,7 +190,7 @@ void Camera::apply_view_matrix() const
|
|||||||
glsafe(::glGetDoublev(GL_MODELVIEW_MATRIX, m_view_matrix.data()));
|
glsafe(::glGetDoublev(GL_MODELVIEW_MATRIX, m_view_matrix.data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Camera::apply_projection(const BoundingBoxf3& box) const
|
void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double far_z) const
|
||||||
{
|
{
|
||||||
set_distance(DefaultDistance);
|
set_distance(DefaultDistance);
|
||||||
|
|
||||||
@ -195,6 +201,12 @@ void Camera::apply_projection(const BoundingBoxf3& box) const
|
|||||||
{
|
{
|
||||||
m_frustrum_zs = calc_tight_frustrum_zs_around(box);
|
m_frustrum_zs = calc_tight_frustrum_zs_around(box);
|
||||||
|
|
||||||
|
if (near_z > 0.0)
|
||||||
|
m_frustrum_zs.first = std::min(m_frustrum_zs.first, near_z);
|
||||||
|
|
||||||
|
if (far_z > 0.0)
|
||||||
|
m_frustrum_zs.second = std::max(m_frustrum_zs.second, far_z);
|
||||||
|
|
||||||
w = 0.5 * (double)m_viewport[2];
|
w = 0.5 * (double)m_viewport[2];
|
||||||
h = 0.5 * (double)m_viewport[3];
|
h = 0.5 * (double)m_viewport[3];
|
||||||
|
|
||||||
@ -266,10 +278,18 @@ void Camera::apply_projection(const BoundingBoxf3& box) const
|
|||||||
glsafe(::glMatrixMode(GL_MODELVIEW));
|
glsafe(::glMatrixMode(GL_MODELVIEW));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h, double margin_factor)
|
||||||
|
#else
|
||||||
void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h)
|
void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h)
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
{
|
{
|
||||||
// Calculate the zoom factor needed to adjust the view around the given box.
|
// Calculate the zoom factor needed to adjust the view around the given box.
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
double zoom = calc_zoom_to_bounding_box_factor(box, canvas_w, canvas_h, margin_factor);
|
||||||
|
#else
|
||||||
double zoom = calc_zoom_to_bounding_box_factor(box, canvas_w, canvas_h);
|
double zoom = calc_zoom_to_bounding_box_factor(box, canvas_w, canvas_h);
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
if (zoom > 0.0)
|
if (zoom > 0.0)
|
||||||
{
|
{
|
||||||
m_zoom = zoom;
|
m_zoom = zoom;
|
||||||
@ -278,6 +298,20 @@ void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
void Camera::zoom_to_volumes(const GLVolumePtrs& volumes, int canvas_w, int canvas_h, double margin_factor)
|
||||||
|
{
|
||||||
|
Vec3d center;
|
||||||
|
double zoom = calc_zoom_to_volumes_factor(volumes, canvas_w, canvas_h, center, margin_factor);
|
||||||
|
if (zoom > 0.0)
|
||||||
|
{
|
||||||
|
m_zoom = zoom;
|
||||||
|
// center view around the calculated center
|
||||||
|
m_target = center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
#if ENABLE_CAMERA_STATISTICS
|
#if ENABLE_CAMERA_STATISTICS
|
||||||
void Camera::debug_render() const
|
void Camera::debug_render() const
|
||||||
{
|
{
|
||||||
@ -372,7 +406,11 @@ std::pair<double, double> Camera::calc_tight_frustrum_zs_around(const BoundingBo
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h, double margin_factor) const
|
||||||
|
#else
|
||||||
double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const
|
double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
{
|
{
|
||||||
double max_bb_size = box.max_size();
|
double max_bb_size = box.max_size();
|
||||||
if (max_bb_size == 0.0)
|
if (max_bb_size == 0.0)
|
||||||
@ -402,35 +440,112 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int ca
|
|||||||
vertices.push_back(box.max);
|
vertices.push_back(box.max);
|
||||||
vertices.emplace_back(box.min(0), box.max(1), box.max(2));
|
vertices.emplace_back(box.min(0), box.max(1), box.max(2));
|
||||||
|
|
||||||
double max_x = 0.0;
|
double min_x = DBL_MAX;
|
||||||
double max_y = 0.0;
|
double min_y = DBL_MAX;
|
||||||
|
double max_x = -DBL_MAX;
|
||||||
|
double max_y = -DBL_MAX;
|
||||||
|
|
||||||
|
#if !ENABLE_THUMBNAIL_GENERATOR
|
||||||
// margin factor to give some empty space around the box
|
// margin factor to give some empty space around the box
|
||||||
double margin_factor = 1.25;
|
double margin_factor = 1.25;
|
||||||
|
#endif // !ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
for (const Vec3d& v : vertices)
|
for (const Vec3d& v : vertices)
|
||||||
{
|
{
|
||||||
// project vertex on the plane perpendicular to camera forward axis
|
// project vertex on the plane perpendicular to camera forward axis
|
||||||
Vec3d pos(v(0) - bb_center(0), v(1) - bb_center(1), v(2) - bb_center(2));
|
Vec3d pos = v - bb_center;
|
||||||
Vec3d proj_on_plane = pos - pos.dot(forward) * forward;
|
Vec3d proj_on_plane = pos - pos.dot(forward) * forward;
|
||||||
|
|
||||||
// calculates vertex coordinate along camera xy axes
|
// calculates vertex coordinate along camera xy axes
|
||||||
double x_on_plane = proj_on_plane.dot(right);
|
double x_on_plane = proj_on_plane.dot(right);
|
||||||
double y_on_plane = proj_on_plane.dot(up);
|
double y_on_plane = proj_on_plane.dot(up);
|
||||||
|
|
||||||
max_x = std::max(max_x, std::abs(x_on_plane));
|
min_x = std::min(min_x, x_on_plane);
|
||||||
max_y = std::max(max_y, std::abs(y_on_plane));
|
min_y = std::min(min_y, y_on_plane);
|
||||||
|
max_x = std::max(max_x, x_on_plane);
|
||||||
|
max_y = std::max(max_y, y_on_plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((max_x == 0.0) || (max_y == 0.0))
|
double dx = max_x - min_x;
|
||||||
|
double dy = max_y - min_y;
|
||||||
|
if ((dx <= 0.0) || (dy <= 0.0))
|
||||||
return -1.0f;
|
return -1.0f;
|
||||||
|
|
||||||
max_x *= margin_factor;
|
double med_x = 0.5 * (max_x + min_x);
|
||||||
max_y *= margin_factor;
|
double med_y = 0.5 * (max_y + min_y);
|
||||||
|
|
||||||
return std::min((double)canvas_w / (2.0 * max_x), (double)canvas_h / (2.0 * max_y));
|
dx *= margin_factor;
|
||||||
|
dy *= margin_factor;
|
||||||
|
|
||||||
|
return std::min((double)canvas_w / dx, (double)canvas_h / dy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, int canvas_w, int canvas_h, Vec3d& center, double margin_factor) const
|
||||||
|
{
|
||||||
|
if (volumes.empty())
|
||||||
|
return -1.0;
|
||||||
|
|
||||||
|
// project the volumes vertices on a plane perpendicular to the camera forward axis
|
||||||
|
// then calculates the vertices coordinate on this plane along the camera xy axes
|
||||||
|
|
||||||
|
// ensure that the view matrix is updated
|
||||||
|
apply_view_matrix();
|
||||||
|
|
||||||
|
Vec3d right = get_dir_right();
|
||||||
|
Vec3d up = get_dir_up();
|
||||||
|
Vec3d forward = get_dir_forward();
|
||||||
|
|
||||||
|
BoundingBoxf3 box;
|
||||||
|
for (const GLVolume* volume : volumes)
|
||||||
|
{
|
||||||
|
box.merge(volume->transformed_bounding_box());
|
||||||
|
}
|
||||||
|
center = box.center();
|
||||||
|
|
||||||
|
double min_x = DBL_MAX;
|
||||||
|
double min_y = DBL_MAX;
|
||||||
|
double max_x = -DBL_MAX;
|
||||||
|
double max_y = -DBL_MAX;
|
||||||
|
|
||||||
|
for (const GLVolume* volume : volumes)
|
||||||
|
{
|
||||||
|
const Transform3d& transform = volume->world_matrix();
|
||||||
|
const TriangleMesh* hull = volume->convex_hull();
|
||||||
|
if (hull == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (const Vec3f& vertex : hull->its.vertices)
|
||||||
|
{
|
||||||
|
Vec3d v = transform * vertex.cast<double>();
|
||||||
|
|
||||||
|
// project vertex on the plane perpendicular to camera forward axis
|
||||||
|
Vec3d pos = v - center;
|
||||||
|
Vec3d proj_on_plane = pos - pos.dot(forward) * forward;
|
||||||
|
|
||||||
|
// calculates vertex coordinate along camera xy axes
|
||||||
|
double x_on_plane = proj_on_plane.dot(right);
|
||||||
|
double y_on_plane = proj_on_plane.dot(up);
|
||||||
|
|
||||||
|
min_x = std::min(min_x, x_on_plane);
|
||||||
|
min_y = std::min(min_y, y_on_plane);
|
||||||
|
max_x = std::max(max_x, x_on_plane);
|
||||||
|
max_y = std::max(max_y, y_on_plane);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
center += 0.5 * (max_x + min_x) * right + 0.5 * (max_y + min_y) * up;
|
||||||
|
|
||||||
|
double dx = margin_factor * (max_x - min_x);
|
||||||
|
double dy = margin_factor * (max_y - min_y);
|
||||||
|
|
||||||
|
if ((dx <= 0.0) || (dy <= 0.0))
|
||||||
|
return -1.0f;
|
||||||
|
|
||||||
|
return std::min((double)canvas_w / dx, (double)canvas_h / dy);
|
||||||
|
}
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
void Camera::set_distance(double distance) const
|
void Camera::set_distance(double distance) const
|
||||||
{
|
{
|
||||||
m_distance = distance;
|
m_distance = distance;
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
#define slic3r_Camera_hpp_
|
#define slic3r_Camera_hpp_
|
||||||
|
|
||||||
#include "libslic3r/BoundingBox.hpp"
|
#include "libslic3r/BoundingBox.hpp"
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
#include "3DScene.hpp"
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
@ -10,6 +13,10 @@ namespace GUI {
|
|||||||
struct Camera
|
struct Camera
|
||||||
{
|
{
|
||||||
static const double DefaultDistance;
|
static const double DefaultDistance;
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
static const double DefaultZoomToBoxMarginFactor;
|
||||||
|
static const double DefaultZoomToVolumesMarginFactor;
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
static double FrustrumMinZRange;
|
static double FrustrumMinZRange;
|
||||||
static double FrustrumMinNearZ;
|
static double FrustrumMinNearZ;
|
||||||
static double FrustrumZMargin;
|
static double FrustrumZMargin;
|
||||||
@ -88,9 +95,16 @@ public:
|
|||||||
|
|
||||||
void apply_viewport(int x, int y, unsigned int w, unsigned int h) const;
|
void apply_viewport(int x, int y, unsigned int w, unsigned int h) const;
|
||||||
void apply_view_matrix() const;
|
void apply_view_matrix() const;
|
||||||
void apply_projection(const BoundingBoxf3& box) const;
|
// Calculates and applies the projection matrix tighting the frustrum z range around the given box.
|
||||||
|
// If larger z span is needed, pass the desired values of near and far z (negative values are ignored)
|
||||||
|
void apply_projection(const BoundingBoxf3& box, double near_z = -1.0, double far_z = -1.0) const;
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
void zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h, double margin_factor = DefaultZoomToBoxMarginFactor);
|
||||||
|
void zoom_to_volumes(const GLVolumePtrs& volumes, int canvas_w, int canvas_h, double margin_factor = DefaultZoomToVolumesMarginFactor);
|
||||||
|
#else
|
||||||
void zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h);
|
void zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h);
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
#if ENABLE_CAMERA_STATISTICS
|
#if ENABLE_CAMERA_STATISTICS
|
||||||
void debug_render() const;
|
void debug_render() const;
|
||||||
@ -100,7 +114,12 @@ private:
|
|||||||
// returns tight values for nearZ and farZ plane around the given bounding box
|
// returns tight values for nearZ and farZ plane around the given bounding box
|
||||||
// the camera MUST be outside of the bounding box in eye coordinate of the given box
|
// the camera MUST be outside of the bounding box in eye coordinate of the given box
|
||||||
std::pair<double, double> calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const;
|
std::pair<double, double> calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const;
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h, double margin_factor = DefaultZoomToBoxMarginFactor) const;
|
||||||
|
double calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, int canvas_w, int canvas_h, Vec3d& center, double margin_factor = DefaultZoomToVolumesMarginFactor) const;
|
||||||
|
#else
|
||||||
double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const;
|
double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const;
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
void set_distance(double distance) const;
|
void set_distance(double distance) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
#include "libslic3r/ClipperUtils.hpp"
|
#include "libslic3r/ClipperUtils.hpp"
|
||||||
#include "libslic3r/PrintConfig.hpp"
|
#include "libslic3r/PrintConfig.hpp"
|
||||||
#include "libslic3r/GCode/PreviewData.hpp"
|
#include "libslic3r/GCode/PreviewData.hpp"
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
#include "libslic3r/GCode/ThumbnailData.hpp"
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
#include "libslic3r/Geometry.hpp"
|
#include "libslic3r/Geometry.hpp"
|
||||||
#include "libslic3r/ExtrusionEntity.hpp"
|
#include "libslic3r/ExtrusionEntity.hpp"
|
||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
@ -1119,6 +1122,10 @@ wxDEFINE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
|
|||||||
wxDEFINE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
|
wxDEFINE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
|
||||||
wxDEFINE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
|
wxDEFINE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25;
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar)
|
GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar)
|
||||||
: m_canvas(canvas)
|
: m_canvas(canvas)
|
||||||
, m_context(nullptr)
|
, m_context(nullptr)
|
||||||
@ -1585,7 +1592,7 @@ void GLCanvas3D::render()
|
|||||||
_render_objects();
|
_render_objects();
|
||||||
_render_sla_slices();
|
_render_sla_slices();
|
||||||
_render_selection();
|
_render_selection();
|
||||||
_render_bed(theta);
|
_render_bed(theta, true);
|
||||||
|
|
||||||
#if ENABLE_RENDER_SELECTION_CENTER
|
#if ENABLE_RENDER_SELECTION_CENTER
|
||||||
_render_selection_center();
|
_render_selection_center();
|
||||||
@ -1645,6 +1652,18 @@ void GLCanvas3D::render()
|
|||||||
#endif // ENABLE_RENDER_STATISTICS
|
#endif // ENABLE_RENDER_STATISTICS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
|
||||||
|
{
|
||||||
|
switch (GLCanvas3DManager::get_framebuffers_type())
|
||||||
|
{
|
||||||
|
case GLCanvas3DManager::FB_Arb: { _render_thumbnail_framebuffer(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; }
|
||||||
|
case GLCanvas3DManager::FB_Ext: { _render_thumbnail_framebuffer_ext(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; }
|
||||||
|
default: { _render_thumbnail_legacy(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
void GLCanvas3D::select_all()
|
void GLCanvas3D::select_all()
|
||||||
{
|
{
|
||||||
m_selection.add_all();
|
m_selection.add_all();
|
||||||
@ -3526,6 +3545,323 @@ void GLCanvas3D::_render_undo_redo_stack(const bool is_undo, float pos_x)
|
|||||||
imgui->end();
|
imgui->end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
|
||||||
|
{
|
||||||
|
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 GLfloat orange[] = { 0.923f, 0.504f, 0.264f, 1.0f };
|
||||||
|
static const GLfloat gray[] = { 0.64f, 0.64f, 0.64f, 1.0f };
|
||||||
|
|
||||||
|
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.set_type(Camera::Ortho);
|
||||||
|
camera.zoom_to_volumes(visible_volumes, thumbnail_data.width, thumbnail_data.height);
|
||||||
|
camera.apply_viewport(0, 0, thumbnail_data.width, thumbnail_data.height);
|
||||||
|
camera.apply_view_matrix();
|
||||||
|
|
||||||
|
double near_z = -1.0;
|
||||||
|
double far_z = -1.0;
|
||||||
|
|
||||||
|
if (show_bed)
|
||||||
|
{
|
||||||
|
// extends the near and far z of the frustrum to avoid the bed being clipped
|
||||||
|
|
||||||
|
// box in eye space
|
||||||
|
BoundingBoxf3 t_bed_box = m_bed.get_bounding_box(true).transformed(camera.get_view_matrix());
|
||||||
|
near_z = -t_bed_box.max(2);
|
||||||
|
far_z = -t_bed_box.min(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
camera.apply_projection(box, near_z, far_z);
|
||||||
|
|
||||||
|
if (transparent_background)
|
||||||
|
glsafe(::glClearColor(0.0f, 0.0f, 0.0f, 0.0f));
|
||||||
|
|
||||||
|
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||||
|
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||||
|
|
||||||
|
m_shader.start_using();
|
||||||
|
|
||||||
|
GLint shader_id = m_shader.get_shader_program_id();
|
||||||
|
GLint color_id = ::glGetUniformLocation(shader_id, "uniform_color");
|
||||||
|
GLint print_box_detection_id = ::glGetUniformLocation(shader_id, "print_box.volume_detection");
|
||||||
|
glcheck();
|
||||||
|
|
||||||
|
if (print_box_detection_id != -1)
|
||||||
|
glsafe(::glUniform1i(print_box_detection_id, 0));
|
||||||
|
|
||||||
|
for (const GLVolume* vol : visible_volumes)
|
||||||
|
{
|
||||||
|
if (color_id >= 0)
|
||||||
|
glsafe(::glUniform4fv(color_id, 1, (vol->printable && !vol->is_outside) ? orange : gray));
|
||||||
|
else
|
||||||
|
glsafe(::glColor4fv((vol->printable && !vol->is_outside) ? orange : gray));
|
||||||
|
|
||||||
|
vol->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_shader.stop_using();
|
||||||
|
|
||||||
|
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||||
|
|
||||||
|
if (show_bed)
|
||||||
|
_render_bed(camera.get_theta(), false);
|
||||||
|
|
||||||
|
if (transparent_background)
|
||||||
|
glsafe(::glClearColor(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3D::_render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
|
||||||
|
{
|
||||||
|
thumbnail_data.set(w, h);
|
||||||
|
if (!thumbnail_data.is_valid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool multisample = m_multisample_allowed;
|
||||||
|
if (multisample)
|
||||||
|
glsafe(::glEnable(GL_MULTISAMPLE));
|
||||||
|
|
||||||
|
GLint max_samples;
|
||||||
|
glsafe(::glGetIntegerv(GL_MAX_SAMPLES, &max_samples));
|
||||||
|
GLsizei num_samples = max_samples / 2;
|
||||||
|
|
||||||
|
GLuint render_fbo;
|
||||||
|
glsafe(::glGenFramebuffers(1, &render_fbo));
|
||||||
|
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, render_fbo));
|
||||||
|
|
||||||
|
GLuint render_tex = 0;
|
||||||
|
GLuint render_tex_buffer = 0;
|
||||||
|
if (multisample)
|
||||||
|
{
|
||||||
|
// use renderbuffer instead of texture to avoid the need to use glTexImage2DMultisample which is available only since OpenGL 3.2
|
||||||
|
glsafe(::glGenRenderbuffers(1, &render_tex_buffer));
|
||||||
|
glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, render_tex_buffer));
|
||||||
|
glsafe(::glRenderbufferStorageMultisample(GL_RENDERBUFFER, num_samples, GL_RGBA8, w, h));
|
||||||
|
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, render_tex_buffer));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glsafe(::glGenTextures(1, &render_tex));
|
||||||
|
glsafe(::glBindTexture(GL_TEXTURE_2D, render_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, render_tex, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint render_depth;
|
||||||
|
glsafe(::glGenRenderbuffers(1, &render_depth));
|
||||||
|
glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, render_depth));
|
||||||
|
if (multisample)
|
||||||
|
glsafe(::glRenderbufferStorageMultisample(GL_RENDERBUFFER, num_samples, GL_DEPTH_COMPONENT24, w, h));
|
||||||
|
else
|
||||||
|
glsafe(::glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h));
|
||||||
|
|
||||||
|
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, render_depth));
|
||||||
|
|
||||||
|
GLenum drawBufs[] = { GL_COLOR_ATTACHMENT0 };
|
||||||
|
glsafe(::glDrawBuffers(1, drawBufs));
|
||||||
|
|
||||||
|
if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
|
||||||
|
{
|
||||||
|
_render_thumbnail_internal(thumbnail_data, printable_only, parts_only, show_bed, transparent_background);
|
||||||
|
|
||||||
|
if (multisample)
|
||||||
|
{
|
||||||
|
GLuint resolve_fbo;
|
||||||
|
glsafe(::glGenFramebuffers(1, &resolve_fbo));
|
||||||
|
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, resolve_fbo));
|
||||||
|
|
||||||
|
GLuint resolve_tex;
|
||||||
|
glsafe(::glGenTextures(1, &resolve_tex));
|
||||||
|
glsafe(::glBindTexture(GL_TEXTURE_2D, resolve_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, resolve_tex, 0));
|
||||||
|
|
||||||
|
glsafe(::glDrawBuffers(1, drawBufs));
|
||||||
|
|
||||||
|
if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
|
||||||
|
{
|
||||||
|
glsafe(::glBindFramebuffer(GL_READ_FRAMEBUFFER, render_fbo));
|
||||||
|
glsafe(::glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo));
|
||||||
|
glsafe(::glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR));
|
||||||
|
|
||||||
|
glsafe(::glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo));
|
||||||
|
glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
glsafe(::glDeleteTextures(1, &resolve_tex));
|
||||||
|
glsafe(::glDeleteFramebuffers(1, &resolve_fbo));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||||
|
glsafe(::glDeleteRenderbuffers(1, &render_depth));
|
||||||
|
if (render_tex_buffer != 0)
|
||||||
|
glsafe(::glDeleteRenderbuffers(1, &render_tex_buffer));
|
||||||
|
if (render_tex != 0)
|
||||||
|
glsafe(::glDeleteTextures(1, &render_tex));
|
||||||
|
glsafe(::glDeleteFramebuffers(1, &render_fbo));
|
||||||
|
|
||||||
|
if (multisample)
|
||||||
|
glsafe(::glDisable(GL_MULTISAMPLE));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3D::_render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
|
||||||
|
{
|
||||||
|
thumbnail_data.set(w, h);
|
||||||
|
if (!thumbnail_data.is_valid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool multisample = m_multisample_allowed;
|
||||||
|
if (multisample)
|
||||||
|
glsafe(::glEnable(GL_MULTISAMPLE));
|
||||||
|
|
||||||
|
GLint max_samples;
|
||||||
|
glsafe(::glGetIntegerv(GL_MAX_SAMPLES_EXT, &max_samples));
|
||||||
|
GLsizei num_samples = max_samples / 2;
|
||||||
|
|
||||||
|
GLuint render_fbo;
|
||||||
|
glsafe(::glGenFramebuffersEXT(1, &render_fbo));
|
||||||
|
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, render_fbo));
|
||||||
|
|
||||||
|
GLuint render_tex = 0;
|
||||||
|
GLuint render_tex_buffer = 0;
|
||||||
|
if (multisample)
|
||||||
|
{
|
||||||
|
// use renderbuffer instead of texture to avoid the need to use glTexImage2DMultisample which is available only since OpenGL 3.2
|
||||||
|
glsafe(::glGenRenderbuffersEXT(1, &render_tex_buffer));
|
||||||
|
glsafe(::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_tex_buffer));
|
||||||
|
glsafe(::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, num_samples, GL_RGBA8, w, h));
|
||||||
|
glsafe(::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, render_tex_buffer));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
glsafe(::glGenTextures(1, &render_tex));
|
||||||
|
glsafe(::glBindTexture(GL_TEXTURE_2D, render_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_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, render_tex, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint render_depth;
|
||||||
|
glsafe(::glGenRenderbuffersEXT(1, &render_depth));
|
||||||
|
glsafe(::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_depth));
|
||||||
|
if (multisample)
|
||||||
|
glsafe(::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, num_samples, GL_DEPTH_COMPONENT24, w, h));
|
||||||
|
else
|
||||||
|
glsafe(::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, w, h));
|
||||||
|
|
||||||
|
glsafe(::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, render_depth));
|
||||||
|
|
||||||
|
GLenum drawBufs[] = { GL_COLOR_ATTACHMENT0 };
|
||||||
|
glsafe(::glDrawBuffers(1, drawBufs));
|
||||||
|
|
||||||
|
if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||||
|
{
|
||||||
|
_render_thumbnail_internal(thumbnail_data, printable_only, parts_only, show_bed, transparent_background);
|
||||||
|
|
||||||
|
if (multisample)
|
||||||
|
{
|
||||||
|
GLuint resolve_fbo;
|
||||||
|
glsafe(::glGenFramebuffersEXT(1, &resolve_fbo));
|
||||||
|
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, resolve_fbo));
|
||||||
|
|
||||||
|
GLuint resolve_tex;
|
||||||
|
glsafe(::glGenTextures(1, &resolve_tex));
|
||||||
|
glsafe(::glBindTexture(GL_TEXTURE_2D, resolve_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(::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, resolve_tex, 0));
|
||||||
|
|
||||||
|
glsafe(::glDrawBuffers(1, drawBufs));
|
||||||
|
|
||||||
|
if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||||
|
{
|
||||||
|
glsafe(::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, render_fbo));
|
||||||
|
glsafe(::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, resolve_fbo));
|
||||||
|
glsafe(::glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR));
|
||||||
|
|
||||||
|
glsafe(::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, resolve_fbo));
|
||||||
|
glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
glsafe(::glDeleteTextures(1, &resolve_tex));
|
||||||
|
glsafe(::glDeleteFramebuffersEXT(1, &resolve_fbo));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
|
||||||
|
glsafe(::glDeleteRenderbuffersEXT(1, &render_depth));
|
||||||
|
if (render_tex_buffer != 0)
|
||||||
|
glsafe(::glDeleteRenderbuffersEXT(1, &render_tex_buffer));
|
||||||
|
if (render_tex != 0)
|
||||||
|
glsafe(::glDeleteTextures(1, &render_tex));
|
||||||
|
glsafe(::glDeleteFramebuffersEXT(1, &render_fbo));
|
||||||
|
|
||||||
|
if (multisample)
|
||||||
|
glsafe(::glDisable(GL_MULTISAMPLE));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
|
||||||
|
{
|
||||||
|
// 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_thumbnail_internal(thumbnail_data, printable_only, parts_only, show_bed, transparent_background);
|
||||||
|
|
||||||
|
glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data()));
|
||||||
|
|
||||||
|
// 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()
|
bool GLCanvas3D::_init_toolbars()
|
||||||
{
|
{
|
||||||
if (!_init_main_toolbar())
|
if (!_init_main_toolbar())
|
||||||
@ -3837,12 +4173,21 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_be
|
|||||||
return bb;
|
return bb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
void GLCanvas3D::_zoom_to_box(const BoundingBoxf3& box, double margin_factor)
|
||||||
|
{
|
||||||
|
const Size& cnv_size = get_canvas_size();
|
||||||
|
m_camera.zoom_to_box(box, cnv_size.get_width(), cnv_size.get_height(), margin_factor);
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
void GLCanvas3D::_zoom_to_box(const BoundingBoxf3& box)
|
void GLCanvas3D::_zoom_to_box(const BoundingBoxf3& box)
|
||||||
{
|
{
|
||||||
const Size& cnv_size = get_canvas_size();
|
const Size& cnv_size = get_canvas_size();
|
||||||
m_camera.zoom_to_box(box, cnv_size.get_width(), cnv_size.get_height());
|
m_camera.zoom_to_box(box, cnv_size.get_width(), cnv_size.get_height());
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
void GLCanvas3D::_refresh_if_shown_on_screen()
|
void GLCanvas3D::_refresh_if_shown_on_screen()
|
||||||
{
|
{
|
||||||
@ -4025,13 +4370,13 @@ void GLCanvas3D::_render_background() const
|
|||||||
glsafe(::glPopMatrix());
|
glsafe(::glPopMatrix());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::_render_bed(float theta) const
|
void GLCanvas3D::_render_bed(float theta, bool show_axes) const
|
||||||
{
|
{
|
||||||
float scale_factor = 1.0;
|
float scale_factor = 1.0;
|
||||||
#if ENABLE_RETINA_GL
|
#if ENABLE_RETINA_GL
|
||||||
scale_factor = m_retina_helper->get_scale_factor();
|
scale_factor = m_retina_helper->get_scale_factor();
|
||||||
#endif // ENABLE_RETINA_GL
|
#endif // ENABLE_RETINA_GL
|
||||||
m_bed.render(const_cast<GLCanvas3D&>(*this), theta, scale_factor);
|
m_bed.render(const_cast<GLCanvas3D&>(*this), theta, scale_factor, show_axes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::_render_objects() const
|
void GLCanvas3D::_render_objects() const
|
||||||
@ -4039,7 +4384,9 @@ void GLCanvas3D::_render_objects() const
|
|||||||
if (m_volumes.empty())
|
if (m_volumes.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if !ENABLE_THUMBNAIL_GENERATOR
|
||||||
glsafe(::glEnable(GL_LIGHTING));
|
glsafe(::glEnable(GL_LIGHTING));
|
||||||
|
#endif // !ENABLE_THUMBNAIL_GENERATOR
|
||||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||||
|
|
||||||
m_camera_clipping_plane = m_gizmos.get_sla_clipping_plane();
|
m_camera_clipping_plane = m_gizmos.get_sla_clipping_plane();
|
||||||
@ -4083,7 +4430,9 @@ void GLCanvas3D::_render_objects() const
|
|||||||
m_shader.stop_using();
|
m_shader.stop_using();
|
||||||
|
|
||||||
m_camera_clipping_plane = ClippingPlane::ClipsNothing();
|
m_camera_clipping_plane = ClippingPlane::ClipsNothing();
|
||||||
|
#if !ENABLE_THUMBNAIL_GENERATOR
|
||||||
glsafe(::glDisable(GL_LIGHTING));
|
glsafe(::glDisable(GL_LIGHTING));
|
||||||
|
#endif // !ENABLE_THUMBNAIL_GENERATOR
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::_render_selection() const
|
void GLCanvas3D::_render_selection() const
|
||||||
|
@ -35,6 +35,9 @@ class GLShader;
|
|||||||
class ExPolygon;
|
class ExPolygon;
|
||||||
class BackgroundSlicingProcess;
|
class BackgroundSlicingProcess;
|
||||||
class GCodePreviewData;
|
class GCodePreviewData;
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
struct ThumbnailData;
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
struct SlicingParameters;
|
struct SlicingParameters;
|
||||||
enum LayerHeightEditActionType : unsigned int;
|
enum LayerHeightEditActionType : unsigned int;
|
||||||
|
|
||||||
@ -131,6 +134,10 @@ wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
|
|||||||
|
|
||||||
class GLCanvas3D
|
class GLCanvas3D
|
||||||
{
|
{
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
static const double DefaultCameraZoomToBoxMarginFactor;
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct GCodePreviewVolumeIndex
|
struct GCodePreviewVolumeIndex
|
||||||
{
|
{
|
||||||
@ -543,6 +550,11 @@ public:
|
|||||||
bool is_dragging() const { return m_gizmos.is_dragging() || m_moving; }
|
bool is_dragging() const { return m_gizmos.is_dragging() || m_moving; }
|
||||||
|
|
||||||
void render();
|
void render();
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
// printable_only == false -> render also non printable volumes as grayed
|
||||||
|
// parts_only == false -> render also sla support and pad
|
||||||
|
void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
void select_all();
|
void select_all();
|
||||||
void deselect_all();
|
void deselect_all();
|
||||||
@ -662,14 +674,18 @@ private:
|
|||||||
|
|
||||||
BoundingBoxf3 _max_bounding_box(bool include_gizmos, bool include_bed_model) const;
|
BoundingBoxf3 _max_bounding_box(bool include_gizmos, bool include_bed_model) const;
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
void _zoom_to_box(const BoundingBoxf3& box, double margin_factor = DefaultCameraZoomToBoxMarginFactor);
|
||||||
|
#else
|
||||||
void _zoom_to_box(const BoundingBoxf3& box);
|
void _zoom_to_box(const BoundingBoxf3& box);
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
void _refresh_if_shown_on_screen();
|
void _refresh_if_shown_on_screen();
|
||||||
|
|
||||||
void _picking_pass() const;
|
void _picking_pass() const;
|
||||||
void _rectangular_selection_picking_pass() const;
|
void _rectangular_selection_picking_pass() const;
|
||||||
void _render_background() const;
|
void _render_background() const;
|
||||||
void _render_bed(float theta) const;
|
void _render_bed(float theta, bool show_axes) const;
|
||||||
void _render_objects() const;
|
void _render_objects() const;
|
||||||
void _render_selection() const;
|
void _render_selection() const;
|
||||||
#if ENABLE_RENDER_SELECTION_CENTER
|
#if ENABLE_RENDER_SELECTION_CENTER
|
||||||
@ -690,6 +706,15 @@ private:
|
|||||||
void _render_sla_slices() const;
|
void _render_sla_slices() const;
|
||||||
void _render_selection_sidebar_hints() const;
|
void _render_selection_sidebar_hints() const;
|
||||||
void _render_undo_redo_stack(const bool is_undo, float pos_x);
|
void _render_undo_redo_stack(const bool is_undo, float pos_x);
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
void _render_thumbnail_internal(ThumbnailData& thumbnail_data, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
|
||||||
|
// 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, bool show_bed, bool transparent_background);
|
||||||
|
// render thumbnail using an off-screen framebuffer when GLEW_EXT_framebuffer_object is supported
|
||||||
|
void _render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
|
||||||
|
// 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, bool show_bed, bool transparent_background);
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
void _update_volumes_hover_state() const;
|
void _update_volumes_hover_state() const;
|
||||||
|
|
||||||
|
@ -187,6 +187,7 @@ std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool exten
|
|||||||
|
|
||||||
GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::MS_Unknown;
|
GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::MS_Unknown;
|
||||||
bool GLCanvas3DManager::s_compressed_textures_supported = false;
|
bool GLCanvas3DManager::s_compressed_textures_supported = false;
|
||||||
|
GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::FB_None;
|
||||||
GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info;
|
GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info;
|
||||||
|
|
||||||
GLCanvas3DManager::GLCanvas3DManager()
|
GLCanvas3DManager::GLCanvas3DManager()
|
||||||
@ -267,6 +268,13 @@ void GLCanvas3DManager::init_gl()
|
|||||||
else
|
else
|
||||||
s_compressed_textures_supported = false;
|
s_compressed_textures_supported = false;
|
||||||
|
|
||||||
|
if (GLEW_ARB_framebuffer_object)
|
||||||
|
s_framebuffers_type = FB_Arb;
|
||||||
|
else if (GLEW_EXT_framebuffer_object)
|
||||||
|
s_framebuffers_type = FB_Ext;
|
||||||
|
else
|
||||||
|
s_framebuffers_type = FB_None;
|
||||||
|
|
||||||
if (! s_gl_info.is_version_greater_or_equal_to(2, 0)) {
|
if (! s_gl_info.is_version_greater_or_equal_to(2, 0)) {
|
||||||
// Complain about the OpenGL version.
|
// Complain about the OpenGL version.
|
||||||
wxString message = wxString::Format(
|
wxString message = wxString::Format(
|
||||||
|
@ -30,6 +30,13 @@ struct Camera;
|
|||||||
class GLCanvas3DManager
|
class GLCanvas3DManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum EFramebufferType : unsigned char
|
||||||
|
{
|
||||||
|
FB_None,
|
||||||
|
FB_Arb,
|
||||||
|
FB_Ext
|
||||||
|
};
|
||||||
|
|
||||||
class GLInfo
|
class GLInfo
|
||||||
{
|
{
|
||||||
mutable bool m_detected;
|
mutable bool m_detected;
|
||||||
@ -77,6 +84,7 @@ private:
|
|||||||
bool m_gl_initialized;
|
bool m_gl_initialized;
|
||||||
static EMultisampleState s_multisample;
|
static EMultisampleState s_multisample;
|
||||||
static bool s_compressed_textures_supported;
|
static bool s_compressed_textures_supported;
|
||||||
|
static EFramebufferType s_framebuffers_type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GLCanvas3DManager();
|
GLCanvas3DManager();
|
||||||
@ -97,6 +105,8 @@ public:
|
|||||||
|
|
||||||
static bool can_multisample() { return s_multisample == MS_Enabled; }
|
static bool can_multisample() { return s_multisample == MS_Enabled; }
|
||||||
static bool are_compressed_textures_supported() { return s_compressed_textures_supported; }
|
static bool are_compressed_textures_supported() { return s_compressed_textures_supported; }
|
||||||
|
static bool are_framebuffers_supported() { return (s_framebuffers_type != FB_None); }
|
||||||
|
static EFramebufferType get_framebuffers_type() { return s_framebuffers_type; }
|
||||||
|
|
||||||
static wxGLCanvas* create_wxglcanvas(wxWindow *parent);
|
static wxGLCanvas* create_wxglcanvas(wxWindow *parent);
|
||||||
|
|
||||||
|
@ -31,6 +31,9 @@
|
|||||||
#include "libslic3r/Format/AMF.hpp"
|
#include "libslic3r/Format/AMF.hpp"
|
||||||
#include "libslic3r/Format/3mf.hpp"
|
#include "libslic3r/Format/3mf.hpp"
|
||||||
#include "libslic3r/GCode/PreviewData.hpp"
|
#include "libslic3r/GCode/PreviewData.hpp"
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
#include "libslic3r/GCode/ThumbnailData.hpp"
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
#include "libslic3r/Polygon.hpp"
|
#include "libslic3r/Polygon.hpp"
|
||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
@ -1901,6 +1904,11 @@ struct Plater::priv
|
|||||||
bool can_set_instance_to_object() const;
|
bool can_set_instance_to_object() const;
|
||||||
bool can_mirror() const;
|
bool can_mirror() const;
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
|
||||||
|
void generate_thumbnails(ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
void msw_rescale_object_menu();
|
void msw_rescale_object_menu();
|
||||||
|
|
||||||
// returns the path to project file with the given extension (none if extension == wxEmptyString)
|
// returns the path to project file with the given extension (none if extension == wxEmptyString)
|
||||||
@ -1968,6 +1976,17 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||||||
background_process.set_fff_print(&fff_print);
|
background_process.set_fff_print(&fff_print);
|
||||||
background_process.set_sla_print(&sla_print);
|
background_process.set_sla_print(&sla_print);
|
||||||
background_process.set_gcode_preview_data(&gcode_preview_data);
|
background_process.set_gcode_preview_data(&gcode_preview_data);
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
background_process.set_thumbnail_cb([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
|
||||||
|
{
|
||||||
|
std::packaged_task<void(ThumbnailsList&, const Vec2ds&, bool, bool, bool, bool)> task([this](ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background) {
|
||||||
|
generate_thumbnails(thumbnails, sizes, printable_only, parts_only, show_bed, transparent_background);
|
||||||
|
});
|
||||||
|
std::future<void> result = task.get_future();
|
||||||
|
wxTheApp->CallAfter([&]() { task(thumbnails, sizes, printable_only, parts_only, show_bed, transparent_background); });
|
||||||
|
result.wait();
|
||||||
|
});
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
background_process.set_slicing_completed_event(EVT_SLICING_COMPLETED);
|
background_process.set_slicing_completed_event(EVT_SLICING_COMPLETED);
|
||||||
background_process.set_finished_event(EVT_PROCESS_COMPLETED);
|
background_process.set_finished_event(EVT_PROCESS_COMPLETED);
|
||||||
// Default printer technology for default config.
|
// Default printer technology for default config.
|
||||||
@ -3481,6 +3500,26 @@ bool Plater::priv::init_object_menu()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
void Plater::priv::generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
|
||||||
|
{
|
||||||
|
view3D->get_canvas3d()->render_thumbnail(data, w, h, printable_only, parts_only, show_bed, transparent_background);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plater::priv::generate_thumbnails(ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
|
||||||
|
{
|
||||||
|
thumbnails.clear();
|
||||||
|
for (const Vec2d& size : sizes)
|
||||||
|
{
|
||||||
|
thumbnails.push_back(ThumbnailData());
|
||||||
|
Point isize(size); // round to ints
|
||||||
|
generate_thumbnail(thumbnails.back(), isize.x(), isize.y(), printable_only, parts_only, show_bed, transparent_background);
|
||||||
|
if (!thumbnails.back().is_valid())
|
||||||
|
thumbnails.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||||
|
|
||||||
void Plater::priv::msw_rescale_object_menu()
|
void Plater::priv::msw_rescale_object_menu()
|
||||||
{
|
{
|
||||||
for (MenuWithSeparators* menu : { &object_menu, &sla_object_menu, &part_menu })
|
for (MenuWithSeparators* menu : { &object_menu, &sla_object_menu, &part_menu })
|
||||||
|
@ -426,7 +426,8 @@ const std::vector<std::string>& Preset::printer_options()
|
|||||||
"machine_max_acceleration_x", "machine_max_acceleration_y", "machine_max_acceleration_z", "machine_max_acceleration_e",
|
"machine_max_acceleration_x", "machine_max_acceleration_y", "machine_max_acceleration_z", "machine_max_acceleration_e",
|
||||||
"machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e",
|
"machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e",
|
||||||
"machine_min_extruding_rate", "machine_min_travel_rate",
|
"machine_min_extruding_rate", "machine_min_travel_rate",
|
||||||
"machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e"
|
"machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e",
|
||||||
|
"thumbnails"
|
||||||
};
|
};
|
||||||
s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end());
|
s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end());
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,7 @@ PresetBundle::PresetBundle() :
|
|||||||
preset.config.optptr("printer_vendor", true);
|
preset.config.optptr("printer_vendor", true);
|
||||||
preset.config.optptr("printer_model", true);
|
preset.config.optptr("printer_model", true);
|
||||||
preset.config.optptr("printer_variant", true);
|
preset.config.optptr("printer_variant", true);
|
||||||
|
preset.config.optptr("thumbnails", true);
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
preset.config.optptr("default_print_profile", true);
|
preset.config.optptr("default_print_profile", true);
|
||||||
preset.config.option<ConfigOptionStrings>("default_filament_profile", true)->values = { "" };
|
preset.config.option<ConfigOptionStrings>("default_filament_profile", true)->values = { "" };
|
||||||
|
Loading…
x
Reference in New Issue
Block a user