Merge remote-tracking branch 'origin' into ys_printable_property

This commit is contained in:
YuSanka 2019-08-06 10:31:17 +02:00
commit 0520da3241
16 changed files with 2709 additions and 2039 deletions

File diff suppressed because it is too large Load diff

View file

@ -375,7 +375,7 @@ public:
this->values[i] = rhs_vec->values[i]; this->values[i] = rhs_vec->values[i];
modified = true; modified = true;
} }
return false; return modified;
} }
private: private:

View file

@ -579,11 +579,11 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
} }
if (print->config().remaining_times.value) { if (print->config().remaining_times.value) {
BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for normal mode"; BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for normal mode" << log_memory_info();
m_normal_time_estimator.post_process_remaining_times(path_tmp, 60.0f); m_normal_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
m_normal_time_estimator.reset(); m_normal_time_estimator.reset();
if (m_silent_time_estimator_enabled) { if (m_silent_time_estimator_enabled) {
BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for silent mode"; BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for silent mode" << log_memory_info();
m_silent_time_estimator.post_process_remaining_times(path_tmp, 60.0f); m_silent_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
m_silent_time_estimator.reset(); m_silent_time_estimator.reset();
} }
@ -591,7 +591,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
// starts analyzer calculations // starts analyzer calculations
if (m_enable_analyzer) { if (m_enable_analyzer) {
BOOST_LOG_TRIVIAL(debug) << "Preparing G-code preview data"; BOOST_LOG_TRIVIAL(debug) << "Preparing G-code preview data" << log_memory_info();
m_analyzer.calc_gcode_preview_data(*preview_data, [print]() { print->throw_if_canceled(); }); m_analyzer.calc_gcode_preview_data(*preview_data, [print]() { print->throw_if_canceled(); });
m_analyzer.reset(); m_analyzer.reset();
} }
@ -1838,7 +1838,8 @@ void GCode::process_layer(
", time estimator memory: " << ", time estimator memory: " <<
format_memsize_MB(m_normal_time_estimator.memory_used() + m_silent_time_estimator_enabled ? m_silent_time_estimator.memory_used() : 0) << format_memsize_MB(m_normal_time_estimator.memory_used() + m_silent_time_estimator_enabled ? m_silent_time_estimator.memory_used() : 0) <<
", analyzer memory: " << ", analyzer memory: " <<
format_memsize_MB(m_analyzer.memory_used()); format_memsize_MB(m_analyzer.memory_used()) <<
log_memory_info();
} }
void GCode::apply_print_config(const PrintConfig &print_config) void GCode::apply_print_config(const PrintConfig &print_config)

View file

@ -21,8 +21,6 @@
namespace Slic3r { namespace Slic3r {
unsigned int Model::s_auto_extruder_id = 1;
Model& Model::assign_copy(const Model &rhs) Model& Model::assign_copy(const Model &rhs)
{ {
this->copy_id(rhs); this->copy_id(rhs);
@ -485,9 +483,20 @@ bool Model::looks_like_multipart_object() const
return false; return false;
} }
// Generate next extruder ID string, in the range of (1, max_extruders).
static inline std::string auto_extruder_id(unsigned int max_extruders, unsigned int &cntr)
{
char str_extruder[64];
sprintf(str_extruder, "%ud", cntr + 1);
if (++ cntr == max_extruders)
cntr = 0;
return str_extruder;
}
void Model::convert_multipart_object(unsigned int max_extruders) void Model::convert_multipart_object(unsigned int max_extruders)
{ {
if (this->objects.empty()) assert(this->objects.size() >= 2);
if (this->objects.size() < 2)
return; return;
ModelObject* object = new ModelObject(this); ModelObject* object = new ModelObject(this);
@ -495,58 +504,32 @@ void Model::convert_multipart_object(unsigned int max_extruders)
object->name = this->objects.front()->name; object->name = this->objects.front()->name;
//FIXME copy the config etc? //FIXME copy the config etc?
reset_auto_extruder_id(); unsigned int extruder_counter = 0;
for (const ModelObject* o : this->objects)
bool is_single_object = (this->objects.size() == 1); for (const ModelVolume* v : o->volumes) {
// If there are more than one object, put all volumes together
for (const ModelObject* o : this->objects) // Each object may contain any number of volumes and instances
{ // The volumes transformations are relative to the object containing them...
for (const ModelVolume* v : o->volumes) Geometry::Transformation trafo_volume = v->get_transformation();
{ // Revert the centering operation.
if (is_single_object) trafo_volume.set_offset(trafo_volume.get_offset() - o->origin_translation);
{ int counter = 1;
// If there is only one object, just copy the volumes auto copy_volume = [o, max_extruders, &counter, &extruder_counter](ModelVolume *new_v) {
ModelVolume* new_v = object->add_volume(*v); assert(new_v != nullptr);
if (new_v != nullptr) new_v->name = o->name + "_" + std::to_string(counter++);
{ new_v->config.set_deserialize("extruder", auto_extruder_id(max_extruders, extruder_counter));
new_v->name = o->name; return new_v;
new_v->config.set_deserialize("extruder", get_auto_extruder_id_as_string(max_extruders)); };
new_v->translate(-o->origin_translation); if (o->instances.empty()) {
} copy_volume(object->add_volume(*v))->set_transformation(trafo_volume);
} } else {
else for (const ModelInstance* i : o->instances)
{ // ...so, transform everything to a common reference system (world)
// If there are more than one object, put all volumes together copy_volume(object->add_volume(*v))->set_transformation(i->get_transformation() * trafo_volume);
// Each object may contain any number of volumes and instances
// The volumes transformations are relative to the object containing them...
int counter = 1;
for (const ModelInstance* i : o->instances)
{
ModelVolume* new_v = object->add_volume(*v);
if (new_v != nullptr)
{
new_v->name = o->name + "_" + std::to_string(counter++);
new_v->config.set_deserialize("extruder", get_auto_extruder_id_as_string(max_extruders));
new_v->translate(-o->origin_translation);
// ...so, transform everything to a common reference system (world)
new_v->set_transformation(i->get_transformation() * v->get_transformation());
}
}
} }
} }
} // If there are more than one object, create a single instance
object->add_instance();
if (is_single_object)
{
// If there is only one object, keep its instances
for (const ModelInstance* i : this->objects.front()->instances)
{
object->add_instance(*i);
}
}
else
// If there are more than one object, create a single instance
object->add_instance();
this->clear_objects(); this->clear_objects();
this->objects.push_back(object); this->objects.push_back(object);
@ -571,32 +554,6 @@ void Model::adjust_min_z()
} }
} }
unsigned int Model::get_auto_extruder_id(unsigned int max_extruders)
{
unsigned int id = s_auto_extruder_id;
if (id > max_extruders) {
// The current counter is invalid, likely due to switching the printer profiles
// to a profile with a lower number of extruders.
reset_auto_extruder_id();
id = s_auto_extruder_id;
} else if (++ s_auto_extruder_id > max_extruders) {
reset_auto_extruder_id();
}
return id;
}
std::string Model::get_auto_extruder_id_as_string(unsigned int max_extruders)
{
char str_extruder[64];
sprintf(str_extruder, "%ud", get_auto_extruder_id(max_extruders));
return str_extruder;
}
void Model::reset_auto_extruder_id()
{
s_auto_extruder_id = 1;
}
// Propose a filename including path derived from the ModelObject's input path. // Propose a filename including path derived from the ModelObject's input path.
// If object's name is filled in, use the object name, otherwise use the input name. // If object's name is filled in, use the object name, otherwise use the input name.
std::string Model::propose_export_file_name_and_path() const std::string Model::propose_export_file_name_and_path() const
@ -1662,7 +1619,7 @@ size_t ModelVolume::split(unsigned int max_extruders)
size_t ivolume = std::find(this->object->volumes.begin(), this->object->volumes.end(), this) - this->object->volumes.begin(); size_t ivolume = std::find(this->object->volumes.begin(), this->object->volumes.end(), this) - this->object->volumes.begin();
std::string name = this->name; std::string name = this->name;
Model::reset_auto_extruder_id(); unsigned int extruder_counter = 0;
Vec3d offset = this->get_offset(); Vec3d offset = this->get_offset();
for (TriangleMesh *mesh : meshptrs) { for (TriangleMesh *mesh : meshptrs) {
@ -1681,7 +1638,7 @@ size_t ModelVolume::split(unsigned int max_extruders)
this->object->volumes[ivolume]->center_geometry_after_creation(); this->object->volumes[ivolume]->center_geometry_after_creation();
this->object->volumes[ivolume]->translate(offset); this->object->volumes[ivolume]->translate(offset);
this->object->volumes[ivolume]->name = name + "_" + std::to_string(idx + 1); this->object->volumes[ivolume]->name = name + "_" + std::to_string(idx + 1);
this->object->volumes[ivolume]->config.set_deserialize("extruder", Model::get_auto_extruder_id_as_string(max_extruders)); this->object->volumes[ivolume]->config.set_deserialize("extruder", auto_extruder_id(max_extruders, extruder_counter));
delete mesh; delete mesh;
++ idx; ++ idx;
} }

View file

@ -725,8 +725,6 @@ private:
// all objects may share mutliple materials. // all objects may share mutliple materials.
class Model final : public ObjectBase class Model final : public ObjectBase
{ {
static unsigned int s_auto_extruder_id;
public: public:
// Materials are owned by a model and referenced by objects through t_model_material_id. // Materials are owned by a model and referenced by objects through t_model_material_id.
// Single material may be shared by multiple models. // Single material may be shared by multiple models.
@ -795,14 +793,10 @@ public:
void print_info() const { for (const ModelObject *o : this->objects) o->print_info(); } void print_info() const { for (const ModelObject *o : this->objects) o->print_info(); }
static unsigned int get_auto_extruder_id(unsigned int max_extruders);
static std::string get_auto_extruder_id_as_string(unsigned int max_extruders);
static void reset_auto_extruder_id();
// Propose an output file name & path based on the first printable object's name and source input file's path. // Propose an output file name & path based on the first printable object's name and source input file's path.
std::string propose_export_file_name_and_path() const; std::string propose_export_file_name_and_path() const;
// Propose an output path, replace extension. The new_extension shall contain the initial dot. // Propose an output path, replace extension. The new_extension shall contain the initial dot.
std::string propose_export_file_name_and_path(const std::string &new_extension) const; std::string propose_export_file_name_and_path(const std::string &new_extension) const;
private: private:
explicit Model(int) : ObjectBase(-1) { assert(this->id().invalid()); }; explicit Model(int) : ObjectBase(-1) { assert(this->id().invalid()); };

View file

@ -18,8 +18,9 @@ extern void trace(unsigned int level, const char *message);
// Format memory allocated, separate thousands by comma. // Format memory allocated, separate thousands by comma.
extern std::string format_memsize_MB(size_t n); extern std::string format_memsize_MB(size_t n);
// Return string to be added to the boost::log output to inform about the current process memory allocation. // Return string to be added to the boost::log output to inform about the current process memory allocation.
// The string is non-empty only if the loglevel >= info (3). // The string is non-empty if the loglevel >= info (3) or ignore_loglevel==true.
extern std::string log_memory_info(); // Latter is used to get the memory info from SysInfoDialog.
extern std::string log_memory_info(bool ignore_loglevel = false);
extern void disable_multi_threading(); extern void disable_multi_threading();
// Returns the size of physical memory (RAM) in bytes. // Returns the size of physical memory (RAM) in bytes.
extern size_t total_physical_memory(); extern size_t total_physical_memory();

View file

@ -13,9 +13,13 @@
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/resource.h>
#ifdef BSD #ifdef BSD
#include <sys/sysctl.h> #include <sys/sysctl.h>
#endif #endif
#ifdef __APPLE__
#include <mach/mach.h>
#endif
#endif #endif
#include <boost/log/core.hpp> #include <boost/log/core.hpp>
@ -431,47 +435,82 @@ std::string format_memsize_MB(size_t n)
return out + "MB"; return out + "MB";
} }
#ifdef WIN32 // Returns platform-specific string to be used as log output or parsed in SysInfoDialog.
// The latter parses the string with (semi)colons as separators, it should look about as
#ifndef PROCESS_MEMORY_COUNTERS_EX // "desc1: value1; desc2: value2" or similar (spaces should not matter).
// MingW32 doesn't have this struct in psapi.h std::string log_memory_info(bool ignore_loglevel)
typedef struct _PROCESS_MEMORY_COUNTERS_EX {
DWORD cb;
DWORD PageFaultCount;
SIZE_T PeakWorkingSetSize;
SIZE_T WorkingSetSize;
SIZE_T QuotaPeakPagedPoolUsage;
SIZE_T QuotaPagedPoolUsage;
SIZE_T QuotaPeakNonPagedPoolUsage;
SIZE_T QuotaNonPagedPoolUsage;
SIZE_T PagefileUsage;
SIZE_T PeakPagefileUsage;
SIZE_T PrivateUsage;
} PROCESS_MEMORY_COUNTERS_EX, *PPROCESS_MEMORY_COUNTERS_EX;
#endif /* PROCESS_MEMORY_COUNTERS_EX */
std::string log_memory_info()
{ {
std::string out; std::string out;
if (logSeverity <= boost::log::trivial::info) { if (ignore_loglevel || logSeverity <= boost::log::trivial::info) {
#ifdef WIN32
#ifndef PROCESS_MEMORY_COUNTERS_EX
// MingW32 doesn't have this struct in psapi.h
typedef struct _PROCESS_MEMORY_COUNTERS_EX {
DWORD cb;
DWORD PageFaultCount;
SIZE_T PeakWorkingSetSize;
SIZE_T WorkingSetSize;
SIZE_T QuotaPeakPagedPoolUsage;
SIZE_T QuotaPagedPoolUsage;
SIZE_T QuotaPeakNonPagedPoolUsage;
SIZE_T QuotaNonPagedPoolUsage;
SIZE_T PagefileUsage;
SIZE_T PeakPagefileUsage;
SIZE_T PrivateUsage;
} PROCESS_MEMORY_COUNTERS_EX, *PPROCESS_MEMORY_COUNTERS_EX;
#endif /* PROCESS_MEMORY_COUNTERS_EX */
HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ::GetCurrentProcessId()); HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ::GetCurrentProcessId());
if (hProcess != nullptr) { if (hProcess != nullptr) {
PROCESS_MEMORY_COUNTERS_EX pmc; PROCESS_MEMORY_COUNTERS_EX pmc;
if (GetProcessMemoryInfo(hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc))) if (GetProcessMemoryInfo(hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc)))
out = " WorkingSet: " + format_memsize_MB(pmc.WorkingSetSize) + " PrivateBytes: " + format_memsize_MB(pmc.PrivateUsage) + " Pagefile(peak): " + format_memsize_MB(pmc.PagefileUsage) + "(" + format_memsize_MB(pmc.PeakPagefileUsage) + ")"; out = " WorkingSet: " + format_memsize_MB(pmc.WorkingSetSize) + "; PrivateBytes: " + format_memsize_MB(pmc.PrivateUsage) + "; Pagefile(peak): " + format_memsize_MB(pmc.PagefileUsage) + "(" + format_memsize_MB(pmc.PeakPagefileUsage) + ")";
else
out += " Used memory: N/A";
CloseHandle(hProcess); CloseHandle(hProcess);
} }
#elif defined(__linux__) or defined(__APPLE__)
// Get current memory usage.
#ifdef __APPLE__
struct mach_task_basic_info info;
mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
out += " Resident memory: ";
if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount ) == KERN_SUCCESS )
out += format_memsize_MB((size_t)info.resident_size);
else
out += "N/A";
#else // i.e. __linux__
size_t tSize = 0, resident = 0, share = 0;
std::ifstream buffer("/proc/self/statm");
if (buffer && (buffer >> tSize >> resident >> share)) {
size_t page_size = (size_t)sysconf(_SC_PAGE_SIZE); // in case x86-64 is configured to use 2MB pages
size_t rss = resident * page_size;
out += " Resident memory: " + format_memsize_MB(rss);
out += "; Shared memory: " + format_memsize_MB(share * page_size);
out += "; Private memory: " + format_memsize_MB(rss - share * page_size);
}
else
out += " Used memory: N/A";
#endif
// Now get peak memory usage.
out += "; Peak memory usage: ";
rusage memory_info;
if (getrusage(RUSAGE_SELF, &memory_info) == 0)
{
size_t peak_mem_usage = (size_t)memory_info.ru_maxrss;
#ifdef __linux__
peak_mem_usage *= 1024;// getrusage returns the value in kB on linux
#endif
out += format_memsize_MB(peak_mem_usage);
}
else
out += "N/A";
#endif
} }
return out; return out;
} }
#else
std::string log_memory_info()
{
return std::string();
}
#endif
// Returns the size of physical memory (RAM) in bytes. // Returns the size of physical memory (RAM) in bytes.
// http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system // http://nadeausoftware.com/articles/2012/09/c_c_tip_how_get_physical_memory_size_system
size_t total_physical_memory() size_t total_physical_memory()

View file

@ -12,6 +12,7 @@
#include "libslic3r/GCode/Analyzer.hpp" #include "libslic3r/GCode/Analyzer.hpp"
#include "slic3r/GUI/PresetBundle.hpp" #include "slic3r/GUI/PresetBundle.hpp"
#include "libslic3r/Format/STL.hpp" #include "libslic3r/Format/STL.hpp"
#include "libslic3r/Utils.hpp"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -74,15 +75,19 @@ void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh &mesh)
} }
} }
void GLIndexedVertexArray::finalize_geometry() const void GLIndexedVertexArray::finalize_geometry(bool opengl_initialized)
{ {
assert(this->vertices_and_normals_interleaved_VBO_id == 0); assert(this->vertices_and_normals_interleaved_VBO_id == 0);
assert(this->triangle_indices_VBO_id == 0); assert(this->triangle_indices_VBO_id == 0);
assert(this->quad_indices_VBO_id == 0); assert(this->quad_indices_VBO_id == 0);
this->shrink_to_fit(); if (! opengl_initialized) {
// Shrink the data vectors to conserve memory in case the data cannot be transfered to the OpenGL driver yet.
this->shrink_to_fit();
return;
}
if (! empty()) { if (! this->vertices_and_normals_interleaved.empty()) {
glsafe(::glGenBuffers(1, &this->vertices_and_normals_interleaved_VBO_id)); glsafe(::glGenBuffers(1, &this->vertices_and_normals_interleaved_VBO_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved.size() * 4, this->vertices_and_normals_interleaved.data(), GL_STATIC_DRAW)); glsafe(::glBufferData(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved.size() * 4, this->vertices_and_normals_interleaved.data(), GL_STATIC_DRAW));
@ -124,13 +129,8 @@ void GLIndexedVertexArray::release_geometry()
void GLIndexedVertexArray::render() const void GLIndexedVertexArray::render() const
{ {
if (this->vertices_and_normals_interleaved_VBO_id == 0) assert(this->vertices_and_normals_interleaved_VBO_id != 0);
{ assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0);
// sends data to gpu, if not done yet
finalize_geometry();
if (this->vertices_and_normals_interleaved_VBO_id == 0)
return;
}
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id));
glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)))); glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float))));
@ -161,13 +161,8 @@ void GLIndexedVertexArray::render(
const std::pair<size_t, size_t>& tverts_range, const std::pair<size_t, size_t>& tverts_range,
const std::pair<size_t, size_t>& qverts_range) const const std::pair<size_t, size_t>& qverts_range) const
{ {
if (this->vertices_and_normals_interleaved_VBO_id == 0) assert(this->vertices_and_normals_interleaved_VBO_id != 0);
{ assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0);
// sends data to gpu, if not done yet
finalize_geometry();
if (this->vertices_and_normals_interleaved_VBO_id == 0)
return;
}
// Render using the Vertex Buffer Objects. // Render using the Vertex Buffer Objects.
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id));
@ -423,30 +418,32 @@ bool GLVolume::is_sla_support() const { return this->composite_id.volume_id == -
bool GLVolume::is_sla_pad() const { return this->composite_id.volume_id == -int(slaposBasePool); } bool GLVolume::is_sla_pad() const { return this->composite_id.volume_id == -int(slaposBasePool); }
std::vector<int> GLVolumeCollection::load_object( std::vector<int> GLVolumeCollection::load_object(
const ModelObject* model_object, const ModelObject *model_object,
int obj_idx, int obj_idx,
const std::vector<int>& instance_idxs, const std::vector<int> &instance_idxs,
const std::string& color_by) const std::string &color_by,
bool opengl_initialized)
{ {
std::vector<int> volumes_idx; std::vector<int> volumes_idx;
for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx) for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx)
for (int instance_idx : instance_idxs) for (int instance_idx : instance_idxs)
volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by)); volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by, opengl_initialized));
return volumes_idx; return volumes_idx;
} }
int GLVolumeCollection::load_object_volume( int GLVolumeCollection::load_object_volume(
const ModelObject* model_object, const ModelObject *model_object,
int obj_idx, int obj_idx,
int volume_idx, int volume_idx,
int instance_idx, int instance_idx,
const std::string& color_by) const std::string &color_by,
bool opengl_initialized)
{ {
const ModelVolume* model_volume = model_object->volumes[volume_idx]; const ModelVolume *model_volume = model_object->volumes[volume_idx];
const int extruder_id = model_volume->extruder_id(); const int extruder_id = model_volume->extruder_id();
const ModelInstance* instance = model_object->instances[instance_idx]; const ModelInstance *instance = model_object->instances[instance_idx];
const TriangleMesh& mesh = model_volume->mesh(); const TriangleMesh &mesh = model_volume->mesh();
float color[4]; float color[4];
memcpy(color, GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3); memcpy(color, GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3);
/* if (model_volume->is_support_blocker()) { /* if (model_volume->is_support_blocker()) {
color[0] = 1.0f; color[0] = 1.0f;
@ -463,6 +460,7 @@ int GLVolumeCollection::load_object_volume(
GLVolume& v = *this->volumes.back(); GLVolume& v = *this->volumes.back();
v.set_color_from_model_volume(model_volume); v.set_color_from_model_volume(model_volume);
v.indexed_vertex_array.load_mesh(mesh); v.indexed_vertex_array.load_mesh(mesh);
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx); v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx);
if (model_volume->is_model_part()) if (model_volume->is_model_part())
{ {
@ -483,13 +481,14 @@ int GLVolumeCollection::load_object_volume(
// This function produces volumes for multiple instances in a single shot, // This function produces volumes for multiple instances in a single shot,
// as some object specific mesh conversions may be expensive. // as some object specific mesh conversions may be expensive.
void GLVolumeCollection::load_object_auxiliary( void GLVolumeCollection::load_object_auxiliary(
const SLAPrintObject* print_object, const SLAPrintObject *print_object,
int obj_idx, int obj_idx,
// pairs of <instance_idx, print_instance_idx> // pairs of <instance_idx, print_instance_idx>
const std::vector<std::pair<size_t, size_t>>& instances, const std::vector<std::pair<size_t, size_t>>& instances,
SLAPrintObjectStep milestone, SLAPrintObjectStep milestone,
// Timestamp of the last change of the milestone // Timestamp of the last change of the milestone
size_t timestamp) size_t timestamp,
bool opengl_initialized)
{ {
assert(print_object->is_step_done(milestone)); assert(print_object->is_step_done(milestone));
Transform3d mesh_trafo_inv = print_object->trafo().inverse(); Transform3d mesh_trafo_inv = print_object->trafo().inverse();
@ -503,6 +502,7 @@ void GLVolumeCollection::load_object_auxiliary(
this->volumes.emplace_back(new GLVolume((milestone == slaposBasePool) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR)); this->volumes.emplace_back(new GLVolume((milestone == slaposBasePool) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR));
GLVolume& v = *this->volumes.back(); GLVolume& v = *this->volumes.back();
v.indexed_vertex_array.load_mesh(mesh); v.indexed_vertex_array.load_mesh(mesh);
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first); v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first);
v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id); v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
// Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance. // Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance.
@ -519,7 +519,7 @@ void GLVolumeCollection::load_object_auxiliary(
} }
int GLVolumeCollection::load_wipe_tower_preview( int GLVolumeCollection::load_wipe_tower_preview(
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width) int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized)
{ {
if (depth < 0.01f) if (depth < 0.01f)
return int(this->volumes.size() - 1); return int(this->volumes.size() - 1);
@ -572,6 +572,7 @@ int GLVolumeCollection::load_wipe_tower_preview(
this->volumes.emplace_back(new GLVolume(color)); this->volumes.emplace_back(new GLVolume(color));
GLVolume& v = *this->volumes.back(); GLVolume& v = *this->volumes.back();
v.indexed_vertex_array.load_mesh(mesh); v.indexed_vertex_array.load_mesh(mesh);
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0)); v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle)); v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle));
v.composite_id = GLVolume::CompositeID(obj_idx, 0, 0); v.composite_id = GLVolume::CompositeID(obj_idx, 0, 0);
@ -831,6 +832,27 @@ std::vector<double> GLVolumeCollection::get_current_print_zs(bool active_only) c
return print_zs; return print_zs;
} }
size_t GLVolumeCollection::cpu_memory_used() const
{
size_t memsize = sizeof(*this) + this->volumes.capacity() * sizeof(GLVolume);
for (const GLVolume *volume : this->volumes)
memsize += volume->cpu_memory_used();
return memsize;
}
size_t GLVolumeCollection::gpu_memory_used() const
{
size_t memsize = 0;
for (const GLVolume *volume : this->volumes)
memsize += volume->gpu_memory_used();
return memsize;
}
std::string GLVolumeCollection::log_memory_info() const
{
return " (GLVolumeCollection RAM: " + format_memsize_MB(this->cpu_memory_used()) + " GPU: " + format_memsize_MB(this->gpu_memory_used()) + " Both: " + format_memsize_MB(this->gpu_memory_used()) + ")";
}
// caller is responsible for supplying NO lines with zero length // caller is responsible for supplying NO lines with zero length
static void thick_lines_to_indexed_vertex_array( static void thick_lines_to_indexed_vertex_array(
const Lines &lines, const Lines &lines,
@ -1606,6 +1628,7 @@ bool GLArrow::on_init()
triangles.emplace_back(7, 13, 6); triangles.emplace_back(7, 13, 6);
m_volume.indexed_vertex_array.load_mesh(TriangleMesh(vertices, triangles)); m_volume.indexed_vertex_array.load_mesh(TriangleMesh(vertices, triangles));
m_volume.indexed_vertex_array.finalize_geometry(true);
return true; return true;
} }
@ -1719,6 +1742,7 @@ bool GLCurvedArrow::on_init()
triangles.emplace_back(vertices_per_level, 2 * vertices_per_level + 1, vertices_per_level + 1); triangles.emplace_back(vertices_per_level, 2 * vertices_per_level + 1, vertices_per_level + 1);
m_volume.indexed_vertex_array.load_mesh(TriangleMesh(vertices, triangles)); m_volume.indexed_vertex_array.load_mesh(TriangleMesh(vertices, triangles));
m_volume.indexed_vertex_array.finalize_geometry(true);
return true; return true;
} }
@ -1745,6 +1769,7 @@ bool GLBed::on_init_from_file(const std::string& filename)
m_filename = filename; m_filename = filename;
m_volume.indexed_vertex_array.load_mesh(model.mesh()); m_volume.indexed_vertex_array.load_mesh(model.mesh());
m_volume.indexed_vertex_array.finalize_geometry(true);
float color[4] = { 0.235f, 0.235f, 0.235f, 1.0f }; float color[4] = { 0.235f, 0.235f, 0.235f, 1.0f };
set_color(color, 4); set_color(color, 4);

View file

@ -64,7 +64,7 @@ public:
vertices_and_normals_interleaved_VBO_id(0), vertices_and_normals_interleaved_VBO_id(0),
triangle_indices_VBO_id(0), triangle_indices_VBO_id(0),
quad_indices_VBO_id(0) quad_indices_VBO_id(0)
{} { assert(! rhs.has_VBOs()); }
GLIndexedVertexArray(GLIndexedVertexArray &&rhs) : GLIndexedVertexArray(GLIndexedVertexArray &&rhs) :
vertices_and_normals_interleaved(std::move(rhs.vertices_and_normals_interleaved)), vertices_and_normals_interleaved(std::move(rhs.vertices_and_normals_interleaved)),
triangle_indices(std::move(rhs.triangle_indices)), triangle_indices(std::move(rhs.triangle_indices)),
@ -72,7 +72,7 @@ public:
vertices_and_normals_interleaved_VBO_id(0), vertices_and_normals_interleaved_VBO_id(0),
triangle_indices_VBO_id(0), triangle_indices_VBO_id(0),
quad_indices_VBO_id(0) quad_indices_VBO_id(0)
{} { assert(! rhs.has_VBOs()); }
~GLIndexedVertexArray() { release_geometry(); } ~GLIndexedVertexArray() { release_geometry(); }
@ -80,14 +80,17 @@ public:
{ {
assert(vertices_and_normals_interleaved_VBO_id == 0); assert(vertices_and_normals_interleaved_VBO_id == 0);
assert(triangle_indices_VBO_id == 0); assert(triangle_indices_VBO_id == 0);
assert(triangle_indices_VBO_id == 0); assert(quad_indices_VBO_id == 0);
this->vertices_and_normals_interleaved = rhs.vertices_and_normals_interleaved; assert(rhs.vertices_and_normals_interleaved_VBO_id == 0);
this->triangle_indices = rhs.triangle_indices; assert(rhs.triangle_indices_VBO_id == 0);
this->quad_indices = rhs.quad_indices; assert(rhs.quad_indices_VBO_id == 0);
this->m_bounding_box = rhs.m_bounding_box; this->vertices_and_normals_interleaved = rhs.vertices_and_normals_interleaved;
vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size; this->triangle_indices = rhs.triangle_indices;
triangle_indices_size = rhs.triangle_indices_size; this->quad_indices = rhs.quad_indices;
quad_indices_size = rhs.quad_indices_size; this->m_bounding_box = rhs.m_bounding_box;
this->vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size;
this->triangle_indices_size = rhs.triangle_indices_size;
this->quad_indices_size = rhs.quad_indices_size;
return *this; return *this;
} }
@ -95,21 +98,24 @@ public:
{ {
assert(vertices_and_normals_interleaved_VBO_id == 0); assert(vertices_and_normals_interleaved_VBO_id == 0);
assert(triangle_indices_VBO_id == 0); assert(triangle_indices_VBO_id == 0);
assert(triangle_indices_VBO_id == 0); assert(quad_indices_VBO_id == 0);
this->vertices_and_normals_interleaved = std::move(rhs.vertices_and_normals_interleaved); assert(rhs.vertices_and_normals_interleaved_VBO_id == 0);
this->triangle_indices = std::move(rhs.triangle_indices); assert(rhs.triangle_indices_VBO_id == 0);
this->quad_indices = std::move(rhs.quad_indices); assert(rhs.quad_indices_VBO_id == 0);
this->m_bounding_box = std::move(rhs.m_bounding_box); this->vertices_and_normals_interleaved = std::move(rhs.vertices_and_normals_interleaved);
vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size; this->triangle_indices = std::move(rhs.triangle_indices);
triangle_indices_size = rhs.triangle_indices_size; this->quad_indices = std::move(rhs.quad_indices);
quad_indices_size = rhs.quad_indices_size; this->m_bounding_box = std::move(rhs.m_bounding_box);
this->vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size;
this->triangle_indices_size = rhs.triangle_indices_size;
this->quad_indices_size = rhs.quad_indices_size;
return *this; return *this;
} }
// Vertices and their normals, interleaved to be used by void glInterleavedArrays(GL_N3F_V3F, 0, x) // Vertices and their normals, interleaved to be used by void glInterleavedArrays(GL_N3F_V3F, 0, x)
mutable std::vector<float> vertices_and_normals_interleaved; std::vector<float> vertices_and_normals_interleaved;
mutable std::vector<int> triangle_indices; std::vector<int> triangle_indices;
mutable std::vector<int> quad_indices; std::vector<int> quad_indices;
// When the geometry data is loaded into the graphics card as Vertex Buffer Objects, // When the geometry data is loaded into the graphics card as Vertex Buffer Objects,
// the above mentioned std::vectors are cleared and the following variables keep their original length. // the above mentioned std::vectors are cleared and the following variables keep their original length.
@ -119,9 +125,9 @@ public:
// IDs of the Vertex Array Objects, into which the geometry has been loaded. // IDs of the Vertex Array Objects, into which the geometry has been loaded.
// Zero if the VBOs are not sent to GPU yet. // Zero if the VBOs are not sent to GPU yet.
mutable unsigned int vertices_and_normals_interleaved_VBO_id{ 0 }; unsigned int vertices_and_normals_interleaved_VBO_id{ 0 };
mutable unsigned int triangle_indices_VBO_id{ 0 }; unsigned int triangle_indices_VBO_id{ 0 };
mutable unsigned int quad_indices_VBO_id{ 0 }; unsigned int quad_indices_VBO_id{ 0 };
void load_mesh_full_shading(const TriangleMesh &mesh); void load_mesh_full_shading(const TriangleMesh &mesh);
void load_mesh(const TriangleMesh& mesh) { this->load_mesh_full_shading(mesh); } void load_mesh(const TriangleMesh& mesh) { this->load_mesh_full_shading(mesh); }
@ -141,12 +147,12 @@ public:
if (this->vertices_and_normals_interleaved.size() + 6 > this->vertices_and_normals_interleaved.capacity()) if (this->vertices_and_normals_interleaved.size() + 6 > this->vertices_and_normals_interleaved.capacity())
this->vertices_and_normals_interleaved.reserve(next_highest_power_of_2(this->vertices_and_normals_interleaved.size() + 6)); this->vertices_and_normals_interleaved.reserve(next_highest_power_of_2(this->vertices_and_normals_interleaved.size() + 6));
this->vertices_and_normals_interleaved.push_back(nx); this->vertices_and_normals_interleaved.emplace_back(nx);
this->vertices_and_normals_interleaved.push_back(ny); this->vertices_and_normals_interleaved.emplace_back(ny);
this->vertices_and_normals_interleaved.push_back(nz); this->vertices_and_normals_interleaved.emplace_back(nz);
this->vertices_and_normals_interleaved.push_back(x); this->vertices_and_normals_interleaved.emplace_back(x);
this->vertices_and_normals_interleaved.push_back(y); this->vertices_and_normals_interleaved.emplace_back(y);
this->vertices_and_normals_interleaved.push_back(z); this->vertices_and_normals_interleaved.emplace_back(z);
this->vertices_and_normals_interleaved_size = this->vertices_and_normals_interleaved.size(); this->vertices_and_normals_interleaved_size = this->vertices_and_normals_interleaved.size();
m_bounding_box.merge(Vec3f(x, y, z).cast<double>()); m_bounding_box.merge(Vec3f(x, y, z).cast<double>());
@ -167,9 +173,9 @@ public:
if (this->triangle_indices.size() + 3 > this->vertices_and_normals_interleaved.capacity()) if (this->triangle_indices.size() + 3 > this->vertices_and_normals_interleaved.capacity())
this->triangle_indices.reserve(next_highest_power_of_2(this->triangle_indices.size() + 3)); this->triangle_indices.reserve(next_highest_power_of_2(this->triangle_indices.size() + 3));
this->triangle_indices.push_back(idx1); this->triangle_indices.emplace_back(idx1);
this->triangle_indices.push_back(idx2); this->triangle_indices.emplace_back(idx2);
this->triangle_indices.push_back(idx3); this->triangle_indices.emplace_back(idx3);
this->triangle_indices_size = this->triangle_indices.size(); this->triangle_indices_size = this->triangle_indices.size();
}; };
@ -180,17 +186,17 @@ public:
if (this->quad_indices.size() + 4 > this->vertices_and_normals_interleaved.capacity()) if (this->quad_indices.size() + 4 > this->vertices_and_normals_interleaved.capacity())
this->quad_indices.reserve(next_highest_power_of_2(this->quad_indices.size() + 4)); this->quad_indices.reserve(next_highest_power_of_2(this->quad_indices.size() + 4));
this->quad_indices.push_back(idx1); this->quad_indices.emplace_back(idx1);
this->quad_indices.push_back(idx2); this->quad_indices.emplace_back(idx2);
this->quad_indices.push_back(idx3); this->quad_indices.emplace_back(idx3);
this->quad_indices.push_back(idx4); this->quad_indices.emplace_back(idx4);
this->quad_indices_size = this->quad_indices.size(); this->quad_indices_size = this->quad_indices.size();
}; };
// Finalize the initialization of the geometry & indices, // Finalize the initialization of the geometry & indices,
// upload the geometry and indices to OpenGL VBO objects // upload the geometry and indices to OpenGL VBO objects
// and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs. // and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs.
void finalize_geometry() const; void finalize_geometry(bool opengl_initialized);
// Release the geometry data, release OpenGL VBOs. // Release the geometry data, release OpenGL VBOs.
void release_geometry(); void release_geometry();
@ -211,7 +217,7 @@ public:
} }
// Shrink the internal storage to tighly fit the data stored. // Shrink the internal storage to tighly fit the data stored.
void shrink_to_fit() const { void shrink_to_fit() {
this->vertices_and_normals_interleaved.shrink_to_fit(); this->vertices_and_normals_interleaved.shrink_to_fit();
this->triangle_indices.shrink_to_fit(); this->triangle_indices.shrink_to_fit();
this->quad_indices.shrink_to_fit(); this->quad_indices.shrink_to_fit();
@ -219,6 +225,22 @@ public:
const BoundingBoxf3& bounding_box() const { return m_bounding_box; } const BoundingBoxf3& bounding_box() const { return m_bounding_box; }
// Return an estimate of the memory consumed by this class.
size_t cpu_memory_used() const { return sizeof(*this) + vertices_and_normals_interleaved.capacity() * sizeof(float) + triangle_indices.capacity() * sizeof(int) + quad_indices.capacity() * sizeof(int); }
// Return an estimate of the memory held by GPU vertex buffers.
size_t gpu_memory_used() const
{
size_t memsize = 0;
if (this->vertices_and_normals_interleaved_VBO_id != 0)
memsize += this->vertices_and_normals_interleaved_size * 4;
if (this->triangle_indices_VBO_id != 0)
memsize += this->triangle_indices_size * 4;
if (this->quad_indices_VBO_id != 0)
memsize += this->quad_indices_size * 4;
return memsize;
}
size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
private: private:
BoundingBoxf3 m_bounding_box; BoundingBoxf3 m_bounding_box;
}; };
@ -250,7 +272,7 @@ private:
Geometry::Transformation m_volume_transformation; Geometry::Transformation m_volume_transformation;
// Shift in z required by sla supports+pad // Shift in z required by sla supports+pad
double m_sla_shift_z; double m_sla_shift_z;
// Bounding box of this volume, in unscaled coordinates. // Bounding box of this volume, in unscaled coordinates.
mutable BoundingBoxf3 m_transformed_bounding_box; mutable BoundingBoxf3 m_transformed_bounding_box;
// Whether or not is needed to recalculate the transformed bounding box. // Whether or not is needed to recalculate the transformed bounding box.
@ -422,13 +444,22 @@ public:
void render() const; void render() const;
void render(int color_id, int detection_id, int worldmatrix_id) const; void render(int color_id, int detection_id, int worldmatrix_id) const;
void finalize_geometry() { this->indexed_vertex_array.finalize_geometry(); } void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); }
void release_geometry() { this->indexed_vertex_array.release_geometry(); } void release_geometry() { this->indexed_vertex_array.release_geometry(); }
void set_bounding_boxes_as_dirty() { m_transformed_bounding_box_dirty = true; m_transformed_convex_hull_bounding_box_dirty = true; } void set_bounding_boxes_as_dirty() { m_transformed_bounding_box_dirty = true; m_transformed_convex_hull_bounding_box_dirty = true; }
bool is_sla_support() const; bool is_sla_support() const;
bool is_sla_pad() const; bool is_sla_pad() const;
// Return an estimate of the memory consumed by this class.
size_t cpu_memory_used() const {
//FIXME what to do wih m_convex_hull?
return sizeof(*this) - sizeof(this->indexed_vertex_array) + this->indexed_vertex_array.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) + this->offsets.capacity() * sizeof(size_t);
}
// Return an estimate of the memory held by GPU vertex buffers.
size_t gpu_memory_used() const { return this->indexed_vertex_array.gpu_memory_used(); }
size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
}; };
typedef std::vector<GLVolume*> GLVolumePtrs; typedef std::vector<GLVolume*> GLVolumePtrs;
@ -463,30 +494,33 @@ public:
~GLVolumeCollection() { clear(); }; ~GLVolumeCollection() { clear(); };
std::vector<int> load_object( std::vector<int> load_object(
const ModelObject* model_object, const ModelObject *model_object,
int obj_idx, int obj_idx,
const std::vector<int>& instance_idxs, const std::vector<int> &instance_idxs,
const std::string& color_by); const std::string &color_by,
bool opengl_initialized);
int load_object_volume( int load_object_volume(
const ModelObject* model_object, const ModelObject *model_object,
int obj_idx, int obj_idx,
int volume_idx, int volume_idx,
int instance_idx, int instance_idx,
const std::string& color_by); const std::string &color_by,
bool opengl_initialized);
// Load SLA auxiliary GLVolumes (for support trees or pad). // Load SLA auxiliary GLVolumes (for support trees or pad).
void load_object_auxiliary( void load_object_auxiliary(
const SLAPrintObject* print_object, const SLAPrintObject *print_object,
int obj_idx, int obj_idx,
// pairs of <instance_idx, print_instance_idx> // pairs of <instance_idx, print_instance_idx>
const std::vector<std::pair<size_t, size_t>>& instances, const std::vector<std::pair<size_t, size_t>>& instances,
SLAPrintObjectStep milestone, SLAPrintObjectStep milestone,
// Timestamp of the last change of the milestone // Timestamp of the last change of the milestone
size_t timestamp); size_t timestamp,
bool opengl_initialized);
int load_wipe_tower_preview( int load_wipe_tower_preview(
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width); int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized);
// Render the volumes by OpenGL. // Render the volumes by OpenGL.
void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const; void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const;
@ -494,7 +528,7 @@ public:
// Finalize the initialization of the geometry & indices, // Finalize the initialization of the geometry & indices,
// upload the geometry and indices to OpenGL VBO objects // upload the geometry and indices to OpenGL VBO objects
// and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs. // and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs.
void finalize_geometry() { for (auto* v : volumes) v->finalize_geometry(); } void finalize_geometry(bool opengl_initialized) { for (auto* v : volumes) v->finalize_geometry(opengl_initialized); }
// Release the geometry data assigned to the volumes. // Release the geometry data assigned to the volumes.
// If OpenGL VBOs were allocated, an OpenGL context has to be active to release them. // If OpenGL VBOs were allocated, an OpenGL context has to be active to release them.
void release_geometry() { for (auto *v : volumes) v->release_geometry(); } void release_geometry() { for (auto *v : volumes) v->release_geometry(); }
@ -522,6 +556,14 @@ public:
// Returns a vector containing the sorted list of all the print_zs of the volumes contained in this collection // Returns a vector containing the sorted list of all the print_zs of the volumes contained in this collection
std::vector<double> get_current_print_zs(bool active_only) const; std::vector<double> get_current_print_zs(bool active_only) const;
// Return an estimate of the memory consumed by this class.
size_t cpu_memory_used() const;
// Return an estimate of the memory held by GPU vertex buffers.
size_t gpu_memory_used() const;
size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
// Return CPU, GPU and total memory log line.
std::string log_memory_info() const;
private: private:
GLVolumeCollection(const GLVolumeCollection &other); GLVolumeCollection(const GLVolumeCollection &other);
GLVolumeCollection& operator=(const GLVolumeCollection &); GLVolumeCollection& operator=(const GLVolumeCollection &);
@ -539,6 +581,7 @@ public:
GLModel(); GLModel();
virtual ~GLModel(); virtual ~GLModel();
// init() / init_from_file() shall be called with the OpenGL context active!
bool init() { return on_init(); } bool init() { return on_init(); }
bool init_from_file(const std::string& filename) { return on_init_from_file(filename); } bool init_from_file(const std::string& filename) { return on_init_from_file(filename); }
@ -568,7 +611,7 @@ protected:
class GLArrow : public GLModel class GLArrow : public GLModel
{ {
protected: protected:
virtual bool on_init(); bool on_init() override;
}; };
class GLCurvedArrow : public GLModel class GLCurvedArrow : public GLModel
@ -579,13 +622,13 @@ public:
explicit GLCurvedArrow(unsigned int resolution); explicit GLCurvedArrow(unsigned int resolution);
protected: protected:
virtual bool on_init(); bool on_init() override;
}; };
class GLBed : public GLModel class GLBed : public GLModel
{ {
protected: protected:
virtual bool on_init_from_file(const std::string& filename); bool on_init_from_file(const std::string& filename) override;
}; };
class _3DScene class _3DScene

View file

@ -212,7 +212,7 @@ wxPanel* BedShapePanel::init_texture_panel()
wxStaticText* lbl = dynamic_cast<wxStaticText*>(e.GetEventObject()); wxStaticText* lbl = dynamic_cast<wxStaticText*>(e.GetEventObject());
if (lbl != nullptr) if (lbl != nullptr)
{ {
wxString tooltip_text = (m_custom_texture == NONE) ? _(L("")) : _(m_custom_texture); wxString tooltip_text = (m_custom_texture == NONE) ? "" : _(m_custom_texture);
wxToolTip* tooltip = lbl->GetToolTip(); wxToolTip* tooltip = lbl->GetToolTip();
if ((tooltip == nullptr) || (tooltip->GetTip() != tooltip_text)) if ((tooltip == nullptr) || (tooltip->GetTip() != tooltip_text))
lbl->SetToolTip(tooltip_text); lbl->SetToolTip(tooltip_text);
@ -280,7 +280,7 @@ wxPanel* BedShapePanel::init_model_panel()
wxStaticText* lbl = dynamic_cast<wxStaticText*>(e.GetEventObject()); wxStaticText* lbl = dynamic_cast<wxStaticText*>(e.GetEventObject());
if (lbl != nullptr) if (lbl != nullptr)
{ {
wxString tooltip_text = (m_custom_model == NONE) ? _(L("")) : _(m_custom_model); wxString tooltip_text = (m_custom_model == NONE) ? "" : _(m_custom_model);
wxToolTip* tooltip = lbl->GetToolTip(); wxToolTip* tooltip = lbl->GetToolTip();
if ((tooltip == nullptr) || (tooltip->GetTip() != tooltip_text)) if ((tooltip == nullptr) || (tooltip->GetTip() != tooltip_text))
lbl->SetToolTip(tooltip_text); lbl->SetToolTip(tooltip_text);

View file

@ -1234,10 +1234,9 @@ bool GLCanvas3D::init()
return false; return false;
} }
// // on linux the gl context is not valid until the canvas is not shown on screen // on linux the gl context is not valid until the canvas is not shown on screen
// // we defer the geometry finalization of volumes until the first call to render() // we defer the geometry finalization of volumes until the first call to render()
// if (!m_volumes.empty()) m_volumes.finalize_geometry(true);
// m_volumes.finalize_geometry();
if (m_gizmos.is_enabled() && !m_gizmos.init()) if (m_gizmos.is_enabled() && !m_gizmos.init())
std::cout << "Unable to initialize gizmos: please, check that all the required textures are available" << std::endl; std::cout << "Unable to initialize gizmos: please, check that all the required textures are available" << std::endl;
@ -1708,7 +1707,7 @@ std::vector<int> GLCanvas3D::load_object(const ModelObject& model_object, int ob
instance_idxs.push_back(i); instance_idxs.push_back(i);
} }
} }
return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_color_by); return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_color_by, m_initialized);
} }
std::vector<int> GLCanvas3D::load_object(const Model& model, int obj_idx) std::vector<int> GLCanvas3D::load_object(const Model& model, int obj_idx)
@ -1896,7 +1895,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id);
if (it->new_geometry()) { if (it->new_geometry()) {
// New volume. // New volume.
m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by); m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_initialized);
m_volumes.volumes.back()->geometry_id = key.geometry_id; m_volumes.volumes.back()->geometry_id = key.geometry_id;
update_object_list = true; update_object_list = true;
} else { } else {
@ -1969,7 +1968,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
for (size_t istep = 0; istep < sla_steps.size(); ++istep) for (size_t istep = 0; istep < sla_steps.size(); ++istep)
if (!instances[istep].empty()) if (!instances[istep].empty())
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp); m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized);
} }
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed // Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
@ -2009,7 +2008,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
depth = (900.f/w) * (float)(extruders_count - 1); depth = (900.f/w) * (float)(extruders_count - 1);
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
1000, x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower), 1000, x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
brim_spacing * 4.5f); brim_spacing * 4.5f, m_initialized);
if (volume_idx_wipe_tower_old != -1) if (volume_idx_wipe_tower_old != -1)
map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new; map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new;
} }
@ -2946,7 +2945,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
else if (evt.Moving()) else if (evt.Moving())
{ {
m_mouse.position = pos.cast<double>(); m_mouse.position = pos.cast<double>();
std::string tooltip = L(""); std::string tooltip = "";
if (tooltip.empty()) if (tooltip.empty())
tooltip = m_gizmos.get_tooltip(); tooltip = m_gizmos.get_tooltip();
@ -3234,7 +3233,7 @@ void GLCanvas3D::do_flatten(const Vec3d& normal, const std::string& snapshot_typ
wxGetApp().plater()->take_snapshot(_(snapshot_type)); wxGetApp().plater()->take_snapshot(_(snapshot_type));
m_selection.flattening_rotate(normal); m_selection.flattening_rotate(normal);
do_rotate(L("")); // avoid taking another snapshot do_rotate(""); // avoid taking another snapshot
} }
void GLCanvas3D::do_mirror(const std::string& snapshot_type) void GLCanvas3D::do_mirror(const std::string& snapshot_type)
@ -3637,14 +3636,14 @@ bool GLCanvas3D::_init_undoredo_toolbar()
std::string curr_additional_tooltip; std::string curr_additional_tooltip;
m_undoredo_toolbar.get_additional_tooltip(id, curr_additional_tooltip); m_undoredo_toolbar.get_additional_tooltip(id, curr_additional_tooltip);
std::string new_additional_tooltip = L(""); std::string new_additional_tooltip = "";
if (can_undo) if (can_undo)
wxGetApp().plater()->undo_redo_topmost_string_getter(true, new_additional_tooltip); wxGetApp().plater()->undo_redo_topmost_string_getter(true, new_additional_tooltip);
if (new_additional_tooltip != curr_additional_tooltip) if (new_additional_tooltip != curr_additional_tooltip)
{ {
m_undoredo_toolbar.set_additional_tooltip(id, new_additional_tooltip); m_undoredo_toolbar.set_additional_tooltip(id, new_additional_tooltip);
set_tooltip(L("")); set_tooltip("");
} }
return can_undo; return can_undo;
}; };
@ -3666,14 +3665,14 @@ bool GLCanvas3D::_init_undoredo_toolbar()
std::string curr_additional_tooltip; std::string curr_additional_tooltip;
m_undoredo_toolbar.get_additional_tooltip(id, curr_additional_tooltip); m_undoredo_toolbar.get_additional_tooltip(id, curr_additional_tooltip);
std::string new_additional_tooltip = L(""); std::string new_additional_tooltip = "";
if (can_redo) if (can_redo)
wxGetApp().plater()->undo_redo_topmost_string_getter(false, new_additional_tooltip); wxGetApp().plater()->undo_redo_topmost_string_getter(false, new_additional_tooltip);
if (new_additional_tooltip != curr_additional_tooltip) if (new_additional_tooltip != curr_additional_tooltip)
{ {
m_undoredo_toolbar.set_additional_tooltip(id, new_additional_tooltip); m_undoredo_toolbar.set_additional_tooltip(id, new_additional_tooltip);
set_tooltip(L("")); set_tooltip("");
} }
return can_redo; return can_redo;
}; };
@ -4539,6 +4538,7 @@ void GLCanvas3D::_load_print_toolpaths()
_3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), volume); _3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), volume);
} }
volume.indexed_vertex_array.finalize_geometry(m_initialized);
} }
void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const std::vector<std::string>& str_tool_colors, const std::vector<double>& color_print_values) void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const std::vector<std::string>& str_tool_colors, const std::vector<double>& color_print_values)
@ -4604,7 +4604,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
std::sort(ctxt.layers.begin(), ctxt.layers.end(), [](const Layer *l1, const Layer *l2) { return l1->print_z < l2->print_z; }); std::sort(ctxt.layers.begin(), ctxt.layers.end(), [](const Layer *l1, const Layer *l2) { return l1->print_z < l2->print_z; });
// Maximum size of an allocation block: 32MB / sizeof(float) // Maximum size of an allocation block: 32MB / sizeof(float)
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - start"; BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - start" << m_volumes.log_memory_info() << log_memory_info();
//FIXME Improve the heuristics for a grain size. //FIXME Improve the heuristics for a grain size.
size_t grain_size = std::max(ctxt.layers.size() / 16, size_t(1)); size_t grain_size = std::max(ctxt.layers.size() / 16, size_t(1));
@ -4710,16 +4710,22 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
} }
} }
} }
for (GLVolume *vol : vols)
// Ideally one would call vol->indexed_vertex_array.finalize() here to move the buffers to the OpenGL driver,
// but this code runs in parallel and the OpenGL driver is not thread safe.
vol->indexed_vertex_array.shrink_to_fit();
}); });
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results"; BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info();
// Remove empty volumes from the newly added volumes. // Remove empty volumes from the newly added volumes.
m_volumes.volumes.erase( m_volumes.volumes.erase(
std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(), std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(),
[](const GLVolume *volume) { return volume->empty(); }), [](const GLVolume *volume) { return volume->empty(); }),
m_volumes.volumes.end()); m_volumes.volumes.end());
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i)
m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized);
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end"; BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
} }
void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_tool_colors) void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_tool_colors)
@ -4776,7 +4782,7 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_
ctxt.wipe_tower_angle = ctxt.print->config().wipe_tower_rotation_angle.value/180.f * PI; ctxt.wipe_tower_angle = ctxt.print->config().wipe_tower_rotation_angle.value/180.f * PI;
ctxt.wipe_tower_pos = Vec2f(ctxt.print->config().wipe_tower_x.value, ctxt.print->config().wipe_tower_y.value); ctxt.wipe_tower_pos = Vec2f(ctxt.print->config().wipe_tower_x.value, ctxt.print->config().wipe_tower_y.value);
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start"; BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start" << m_volumes.log_memory_info() << log_memory_info();
//FIXME Improve the heuristics for a grain size. //FIXME Improve the heuristics for a grain size.
size_t n_items = print->wipe_tower_data().tool_changes.size() + (ctxt.priming.empty() ? 0 : 1); size_t n_items = print->wipe_tower_data().tool_changes.size() + (ctxt.priming.empty() ? 0 : 1);
@ -4874,16 +4880,20 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_
vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve()); vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve());
} }
} }
for (GLVolume *vol : vols)
vol->indexed_vertex_array.shrink_to_fit();
}); });
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results"; BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info();
// Remove empty volumes from the newly added volumes. // Remove empty volumes from the newly added volumes.
m_volumes.volumes.erase( m_volumes.volumes.erase(
std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(), std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(),
[](const GLVolume *volume) { return volume->empty(); }), [](const GLVolume *volume) { return volume->empty(); }),
m_volumes.volumes.end()); m_volumes.volumes.end());
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i)
m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized);
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end"; BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
} }
static inline int hex_digit_to_int(const char c) static inline int hex_digit_to_int(const char c)
@ -4896,6 +4906,8 @@ static inline int hex_digit_to_int(const char c)
void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors) void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors)
{ {
BOOST_LOG_TRIVIAL(debug) << "Loading G-code extrusion paths - start" << m_volumes.log_memory_info() << log_memory_info();
// helper functions to select data in dependence of the extrusion view type // helper functions to select data in dependence of the extrusion view type
struct Helper struct Helper
{ {
@ -5011,6 +5023,8 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
if (filters.empty()) if (filters.empty())
return; return;
BOOST_LOG_TRIVIAL(debug) << "Loading G-code extrusion paths - create volumes" << m_volumes.log_memory_info() << log_memory_info();
// creates a new volume for each filter // creates a new volume for each filter
for (Filter& filter : filters) for (Filter& filter : filters)
{ {
@ -5041,6 +5055,8 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
} }
} }
BOOST_LOG_TRIVIAL(debug) << "Loading G-code extrusion paths - populate volumes" << m_volumes.log_memory_info() << log_memory_info();
// populates volumes // populates volumes
for (const GCodePreviewData::Extrusion::Layer& layer : preview_data.extrusion.layers) for (const GCodePreviewData::Extrusion::Layer& layer : preview_data.extrusion.layers)
{ {
@ -5058,6 +5074,12 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
} }
} }
} }
// finalize volumes and sends geometry to gpu
for (size_t i = initial_volumes_count; i < m_volumes.volumes.size(); ++i)
m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized);
BOOST_LOG_TRIVIAL(debug) << "Loading G-code extrusion paths - end" << m_volumes.log_memory_info() << log_memory_info();
} }
void GLCanvas3D::_load_gcode_travel_paths(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors) void GLCanvas3D::_load_gcode_travel_paths(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors)
@ -5102,6 +5124,10 @@ void GLCanvas3D::_load_gcode_travel_paths(const GCodePreviewData& preview_data,
return; return;
} }
// finalize volumes and sends geometry to gpu
for (size_t i = initial_volumes_count; i < m_volumes.volumes.size(); ++i)
m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized);
} }
bool GLCanvas3D::_travel_paths_by_type(const GCodePreviewData& preview_data) bool GLCanvas3D::_travel_paths_by_type(const GCodePreviewData& preview_data)
@ -5330,6 +5356,7 @@ void GLCanvas3D::_load_gcode_retractions(const GCodePreviewData& preview_data)
_3DScene::point3_to_verts(position.position, position.width, position.height, *volume); _3DScene::point3_to_verts(position.position, position.width, position.height, *volume);
} }
volume->indexed_vertex_array.finalize_geometry(m_initialized);
} }
} }
@ -5357,6 +5384,7 @@ void GLCanvas3D::_load_gcode_unretractions(const GCodePreviewData& preview_data)
_3DScene::point3_to_verts(position.position, position.width, position.height, *volume); _3DScene::point3_to_verts(position.position, position.width, position.height, *volume);
} }
volume->indexed_vertex_array.finalize_geometry(m_initialized);
} }
} }
@ -5382,7 +5410,7 @@ void GLCanvas3D::_load_fff_shells()
instance_ids[i] = i; instance_ids[i] = i;
} }
m_volumes.load_object(model_obj, object_id, instance_ids, "object"); m_volumes.load_object(model_obj, object_id, instance_ids, "object", m_initialized);
++object_id; ++object_id;
} }
@ -5404,7 +5432,7 @@ void GLCanvas3D::_load_fff_shells()
if (!print->is_step_done(psWipeTower)) if (!print->is_step_done(psWipeTower))
depth = (900.f/config.wipe_tower_width) * (float)(extruders_count - 1); depth = (900.f/config.wipe_tower_width) * (float)(extruders_count - 1);
m_volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle, m_volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
!print->is_step_done(psWipeTower), brim_spacing * 4.5f); !print->is_step_done(psWipeTower), brim_spacing * 4.5f, m_initialized);
} }
} }
} }

View file

@ -1778,7 +1778,7 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
m_objects_model->Delete(item); m_objects_model->Delete(item);
if (show_msg) if (show_msg)
Slic3r::GUI::show_error(nullptr, _(L("From Object List You can't delete the last intance from object."))); Slic3r::GUI::show_error(nullptr, _(L("Last instance of an object cannot be deleted.")));
} }
void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item) void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item)
@ -1880,7 +1880,7 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con
} }
else if (type == itInstance) { else if (type == itInstance) {
if (object->instances.size() == 1) { if (object->instances.size() == 1) {
Slic3r::GUI::show_error(nullptr, _(L("From Object List You can't delete the last intance from object."))); Slic3r::GUI::show_error(nullptr, _(L("Last instance of an object cannot be deleted.")));
return false; return false;
} }
@ -2870,6 +2870,9 @@ void ObjectList::update_selections_on_canvas()
wxDataViewItemArray sels; wxDataViewItemArray sels;
GetSelections(sels); GetSelections(sels);
// clear selection before adding new elements
selection.clear(); //OR remove_all()?
for (auto item : sels) for (auto item : sels)
{ {
add_to_selection(item, selection, instance_idx, mode); add_to_selection(item, selection, instance_idx, mode);

View file

@ -287,8 +287,8 @@ bool MainFrame::can_send_gcode() const
if (m_plater->model().objects.empty()) if (m_plater->model().objects.empty())
return false; return false;
const auto prin_host_opt =wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionString>("print_host"); const auto print_host_opt = wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionString>("print_host");
return prin_host_opt != nullptr && !prin_host_opt->value.empty(); return print_host_opt != nullptr && !print_host_opt->value.empty();
} }
bool MainFrame::can_slice() const bool MainFrame::can_slice() const

View file

@ -2302,7 +2302,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
} }
} }
if (new_model != nullptr) { if (new_model != nullptr && new_model->objects.size() > 1) {
wxMessageDialog dlg(q, _(L( wxMessageDialog dlg(q, _(L(
"Multiple objects were loaded for a multi-material printer.\n" "Multiple objects were loaded for a multi-material printer.\n"
"Instead of considering them as multiple objects, should I consider\n" "Instead of considering them as multiple objects, should I consider\n"
@ -4550,7 +4550,7 @@ void Plater::undo_redo_topmost_string_getter(const bool is_undo, std::string& ou
return; return;
} }
out_text = L(""); out_text = "";
} }
void Plater::on_extruders_change(int num_extruders) void Plater::on_extruders_change(int num_extruders)

View file

@ -100,6 +100,7 @@ void Selection::set_volumes(GLVolumePtrs* volumes)
update_valid(); update_valid();
} }
// Init shall be called from the OpenGL render function, so that the OpenGL context is initialized!
bool Selection::init() bool Selection::init()
{ {
if (!m_arrow.init()) if (!m_arrow.init())

View file

@ -58,21 +58,19 @@ std::string get_mem_info(bool format_as_html)
std::string b_end = format_as_html ? "</b>" : ""; std::string b_end = format_as_html ? "</b>" : "";
std::string line_end = format_as_html ? "<br>" : "\n"; std::string line_end = format_as_html ? "<br>" : "\n";
const Slic3r::UndoRedo::Stack &stack = wxGetApp().plater()->undo_redo_stack_main(); std::string mem_info_str = log_memory_info(true);
out << b_start << "RAM size reserved for the Undo / Redo stack [MB]: " << b_end << Slic3r::format_memsize_MB(stack.get_memory_limit()) << line_end; std::istringstream mem_info(mem_info_str);
out << b_start << "RAM size occupied by the Undo / Redo stack [MB]: " << b_end << Slic3r::format_memsize_MB(stack.memsize()) << line_end << line_end; std::string value;
while (std::getline(mem_info, value, ':')) {
#ifdef _WIN32 out << b_start << (value+": ") << b_end;
HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ::GetCurrentProcessId()); std::getline(mem_info, value, ';');
if (hProcess != nullptr) { out << value << line_end;
PROCESS_MEMORY_COUNTERS_EX pmc;
if (GetProcessMemoryInfo(hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc)))
out << b_start << "WorkingSet [MB]: " << b_end << format_memsize_MB(pmc.WorkingSetSize) << line_end
<< b_start << "PrivateBytes [MB]: " << b_end << format_memsize_MB(pmc.PrivateUsage) << line_end
<< b_start << "Pagefile(peak) [MB]: " << b_end << format_memsize_MB(pmc.PagefileUsage) << "(" << format_memsize_MB(pmc.PeakPagefileUsage) << ")" << line_end;
CloseHandle(hProcess);
} }
#endif
const Slic3r::UndoRedo::Stack &stack = wxGetApp().plater()->undo_redo_stack_main();
out << b_start << "RAM size reserved for the Undo / Redo stack: " << b_end << Slic3r::format_memsize_MB(stack.get_memory_limit()) << line_end;
out << b_start << "RAM size occupied by the Undo / Redo stack: " << b_end << Slic3r::format_memsize_MB(stack.memsize()) << line_end << line_end;
return out.str(); return out.str();
} }