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

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbubnikv <bubnikv@gmail.com>2018-09-12 12:59:02 +0300
committerbubnikv <bubnikv@gmail.com>2018-09-12 12:59:02 +0300
commit0235f1a8211cfecf75ac0a585295bc1378747972 (patch)
tree9c1d06a43a691d9691c7eff6f21646b0dcc8cc74 /xs/src/slic3r/GUI/3DScene.cpp
parent41ce69f327a2fe3324dc47756b64a6fdb001cfa3 (diff)
parenta97df55592f524eb73bd7d04ef8b7c1b3525d27d (diff)
Merged with dev
Diffstat (limited to 'xs/src/slic3r/GUI/3DScene.cpp')
-rw-r--r--xs/src/slic3r/GUI/3DScene.cpp2506
1 files changed, 1052 insertions, 1454 deletions
diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp
index 356d27b96..a488bfcde 100644
--- a/xs/src/slic3r/GUI/3DScene.cpp
+++ b/xs/src/slic3r/GUI/3DScene.cpp
@@ -2,13 +2,13 @@
#include "3DScene.hpp"
-#include "../../libslic3r/libslic3r.h"
#include "../../libslic3r/ExtrusionEntity.hpp"
#include "../../libslic3r/ExtrusionEntityCollection.hpp"
#include "../../libslic3r/Geometry.hpp"
#include "../../libslic3r/GCode/PreviewData.hpp"
#include "../../libslic3r/Print.hpp"
#include "../../libslic3r/Slicing.hpp"
+#include "../../slic3r/GUI/PresetBundle.hpp"
#include "GCode/Analyzer.hpp"
#include <stdio.h>
@@ -22,10 +22,7 @@
#include <tbb/parallel_for.h>
#include <tbb/spin_mutex.h>
-#include <wx/bitmap.h>
-#include <wx/dcmemory.h>
-#include <wx/image.h>
-#include <wx/settings.h>
+#include <Eigen/Dense>
#include "GUI.hpp"
@@ -42,7 +39,7 @@ void GLIndexedVertexArray::load_mesh_flat_shading(const TriangleMesh &mesh)
for (int i = 0; i < mesh.stl.stats.number_of_facets; ++ i) {
const stl_facet &facet = mesh.stl.facet_start[i];
for (int j = 0; j < 3; ++ j)
- this->push_geometry(facet.vertex[j].x, facet.vertex[j].y, facet.vertex[j].z, facet.normal.x, facet.normal.y, facet.normal.z);
+ this->push_geometry(facet.vertex[j](0), facet.vertex[j](1), facet.vertex[j](2), facet.normal(0), facet.normal(1), facet.normal(2));
}
}
@@ -58,7 +55,7 @@ void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh &mesh)
for (int i = 0; i < mesh.stl.stats.number_of_facets; ++i) {
const stl_facet &facet = mesh.stl.facet_start[i];
for (int j = 0; j < 3; ++j)
- this->push_geometry(facet.vertex[j].x, facet.vertex[j].y, facet.vertex[j].z, facet.normal.x, facet.normal.y, facet.normal.z);
+ this->push_geometry(facet.vertex[j](0), facet.vertex[j](1), facet.vertex[j](2), facet.normal(0), facet.normal(1), facet.normal(2));
this->push_triangle(vertices_count, vertices_count + 1, vertices_count + 2);
vertices_count += 3;
@@ -194,8 +191,40 @@ void GLIndexedVertexArray::render(
const float GLVolume::SELECTED_COLOR[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
const float GLVolume::HOVER_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f };
-const float GLVolume::OUTSIDE_COLOR[4] = { 0.75f, 0.0f, 0.75f, 1.0f };
-const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 1.0f, 0.0f, 1.0f, 1.0f };
+const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f };
+const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
+
+GLVolume::GLVolume(float r, float g, float b, float a)
+ : m_offset(Vec3d::Zero())
+ , m_rotation(0.0)
+ , m_scaling_factor(1.0)
+ , m_world_matrix(Transform3f::Identity())
+ , m_world_matrix_dirty(true)
+ , m_transformed_bounding_box_dirty(true)
+ , m_transformed_convex_hull_bounding_box_dirty(true)
+ , m_convex_hull(nullptr)
+ , composite_id(-1)
+ , select_group_id(-1)
+ , drag_group_id(-1)
+ , extruder_id(0)
+ , selected(false)
+ , is_active(true)
+ , zoom_to_volumes(true)
+ , shader_outside_printer_detection_enabled(false)
+ , is_outside(false)
+ , hover(false)
+ , is_modifier(false)
+ , is_wipe_tower(false)
+ , is_extrusion_path(false)
+ , tverts_range(0, size_t(-1))
+ , qverts_range(0, size_t(-1))
+{
+ color[0] = r;
+ color[1] = g;
+ color[2] = b;
+ color[3] = a;
+ set_render_color(r, g, b, a);
+}
void GLVolume::set_render_color(float r, float g, float b, float a)
{
@@ -217,20 +246,120 @@ void GLVolume::set_render_color(const float* rgba, unsigned int size)
void GLVolume::set_render_color()
{
if (selected)
- {
- if (is_outside)
- set_render_color(SELECTED_OUTSIDE_COLOR, 4);
- else
- set_render_color(SELECTED_COLOR, 4);
- }
+ set_render_color(is_outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR, 4);
else if (hover)
set_render_color(HOVER_COLOR, 4);
- else if (is_outside)
+ else if (is_outside && shader_outside_printer_detection_enabled)
set_render_color(OUTSIDE_COLOR, 4);
else
set_render_color(color, 4);
}
+double GLVolume::get_rotation()
+{
+ return m_rotation;
+}
+
+void GLVolume::set_rotation(double rotation)
+{
+ if (m_rotation != rotation)
+ {
+ m_rotation = rotation;
+ m_world_matrix_dirty = true;
+ m_transformed_bounding_box_dirty = true;
+ m_transformed_convex_hull_bounding_box_dirty = true;
+ }
+}
+
+const Vec3d& GLVolume::get_offset() const
+{
+ return m_offset;
+}
+
+void GLVolume::set_offset(const Vec3d& offset)
+{
+ if (m_offset != offset)
+ {
+ m_offset = offset;
+ m_world_matrix_dirty = true;
+ m_transformed_bounding_box_dirty = true;
+ m_transformed_convex_hull_bounding_box_dirty = true;
+ }
+}
+
+void GLVolume::set_scaling_factor(double factor)
+{
+ if (m_scaling_factor != factor)
+ {
+ m_scaling_factor = factor;
+ m_world_matrix_dirty = true;
+ m_transformed_bounding_box_dirty = true;
+ m_transformed_convex_hull_bounding_box_dirty = true;
+ }
+}
+
+void GLVolume::set_convex_hull(const TriangleMesh& convex_hull)
+{
+ m_convex_hull = &convex_hull;
+}
+
+void GLVolume::set_select_group_id(const std::string& select_by)
+{
+ if (select_by == "object")
+ select_group_id = object_idx() * 1000000;
+ else if (select_by == "volume")
+ select_group_id = object_idx() * 1000000 + volume_idx() * 1000;
+ else if (select_by == "instance")
+ select_group_id = composite_id;
+}
+
+void GLVolume::set_drag_group_id(const std::string& drag_by)
+{
+ if (drag_by == "object")
+ drag_group_id = object_idx() * 1000;
+ else if (drag_by == "instance")
+ drag_group_id = object_idx() * 1000 + instance_idx();
+}
+
+const Transform3f& GLVolume::world_matrix() const
+{
+ if (m_world_matrix_dirty)
+ {
+ m_world_matrix = Transform3f::Identity();
+ m_world_matrix.translate(m_offset.cast<float>());
+ m_world_matrix.rotate(Eigen::AngleAxisf((float)m_rotation, Vec3f::UnitZ()));
+ m_world_matrix.scale((float)m_scaling_factor);
+ m_world_matrix_dirty = false;
+ }
+ return m_world_matrix;
+}
+
+const BoundingBoxf3& GLVolume::transformed_bounding_box() const
+{
+ if (m_transformed_bounding_box_dirty)
+ {
+ m_transformed_bounding_box = bounding_box.transformed(world_matrix().cast<double>());
+ m_transformed_bounding_box_dirty = false;
+ }
+
+ return m_transformed_bounding_box;
+}
+
+const BoundingBoxf3& GLVolume::transformed_convex_hull_bounding_box() const
+{
+ if (m_transformed_convex_hull_bounding_box_dirty)
+ {
+ if ((m_convex_hull != nullptr) && (m_convex_hull->stl.stats.number_of_facets > 0))
+ m_transformed_convex_hull_bounding_box = m_convex_hull->transformed_bounding_box(world_matrix().cast<double>());
+ else
+ m_transformed_convex_hull_bounding_box = bounding_box.transformed(world_matrix().cast<double>());
+
+ m_transformed_convex_hull_bounding_box_dirty = false;
+ }
+
+ return m_transformed_convex_hull_bounding_box;
+}
+
void GLVolume::set_range(double min_z, double max_z)
{
this->qverts_range.first = 0;
@@ -271,14 +400,16 @@ void GLVolume::render() const
if (!is_active)
return;
- glCullFace(GL_BACK);
- glPushMatrix();
- glTranslated(this->origin.x, this->origin.y, this->origin.z);
+ ::glCullFace(GL_BACK);
+ ::glPushMatrix();
+ ::glTranslated(m_offset(0), m_offset(1), m_offset(2));
+ ::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0);
+ ::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor);
if (this->indexed_vertex_array.indexed())
this->indexed_vertex_array.render(this->tverts_range, this->qverts_range);
else
this->indexed_vertex_array.render();
- glPopMatrix();
+ ::glPopMatrix();
}
void GLVolume::render_using_layer_height() const
@@ -296,6 +427,7 @@ void GLVolume::render_using_layer_height() const
GLint z_texture_row_to_normalized_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_texture_row_to_normalized") : -1;
GLint z_cursor_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_cursor") : -1;
GLint z_cursor_band_width_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_cursor_band_width") : -1;
+ GLint world_matrix_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "volume_world_matrix") : -1;
if (z_to_texture_row_id >= 0)
glUniform1f(z_to_texture_row_id, (GLfloat)layer_height_texture_z_to_row_id());
@@ -304,19 +436,25 @@ void GLVolume::render_using_layer_height() const
glUniform1f(z_texture_row_to_normalized_id, (GLfloat)(1.0f / layer_height_texture_height()));
if (z_cursor_id >= 0)
- glUniform1f(z_cursor_id, (GLfloat)(bounding_box.max.z * layer_height_texture_data.z_cursor_relative));
+ glUniform1f(z_cursor_id, (GLfloat)(layer_height_texture_data.print_object->model_object()->bounding_box().max(2) * layer_height_texture_data.z_cursor_relative));
if (z_cursor_band_width_id >= 0)
glUniform1f(z_cursor_band_width_id, (GLfloat)layer_height_texture_data.edit_band_width);
- unsigned int w = layer_height_texture_width();
- unsigned int h = layer_height_texture_height();
+ if (world_matrix_id >= 0)
+ ::glUniformMatrix4fv(world_matrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().data());
+
+ GLsizei w = (GLsizei)layer_height_texture_width();
+ GLsizei h = (GLsizei)layer_height_texture_height();
+ GLsizei half_w = w / 2;
+ GLsizei half_h = h / 2;
+ ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, layer_height_texture_data.texture_id);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
- glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, w / 2, h / 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level0());
- glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, w / 2, h / 2, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level1());
+ glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level1());
render();
@@ -326,15 +464,142 @@ void GLVolume::render_using_layer_height() const
glUseProgram(current_program_id);
}
-void GLVolume::generate_layer_height_texture(PrintObject *print_object, bool force)
+void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) const
{
- GLTexture *tex = this->layer_height_texture.get();
- if (tex == nullptr)
+ if (!is_active)
+ return;
+
+ if (!indexed_vertex_array.vertices_and_normals_interleaved_VBO_id)
+ return;
+
+ if (layer_height_texture_data.can_use())
+ {
+ ::glDisableClientState(GL_VERTEX_ARRAY);
+ ::glDisableClientState(GL_NORMAL_ARRAY);
+ render_using_layer_height();
+ ::glEnableClientState(GL_VERTEX_ARRAY);
+ ::glEnableClientState(GL_NORMAL_ARRAY);
+ return;
+ }
+
+ GLsizei n_triangles = GLsizei(std::min(indexed_vertex_array.triangle_indices_size, tverts_range.second - tverts_range.first));
+ GLsizei n_quads = GLsizei(std::min(indexed_vertex_array.quad_indices_size, qverts_range.second - qverts_range.first));
+ if (n_triangles + n_quads == 0)
+ {
+ ::glDisableClientState(GL_VERTEX_ARRAY);
+ ::glDisableClientState(GL_NORMAL_ARRAY);
+
+ if (color_id >= 0)
+ {
+ float color[4];
+ ::memcpy((void*)color, (const void*)render_color, 4 * sizeof(float));
+ ::glUniform4fv(color_id, 1, (const GLfloat*)color);
+ }
+ else
+ ::glColor4f(render_color[0], render_color[1], render_color[2], render_color[3]);
+
+ if (detection_id != -1)
+ ::glUniform1i(detection_id, shader_outside_printer_detection_enabled ? 1 : 0);
+
+ if (worldmatrix_id != -1)
+ ::glUniformMatrix4fv(worldmatrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().data());
+
+ render();
+
+ ::glEnableClientState(GL_VERTEX_ARRAY);
+ ::glEnableClientState(GL_NORMAL_ARRAY);
+
+ return;
+ }
+
+ if (color_id >= 0)
+ ::glUniform4fv(color_id, 1, (const GLfloat*)render_color);
+ else
+ ::glColor4f(render_color[0], render_color[1], render_color[2], render_color[3]);
+
+ if (detection_id != -1)
+ ::glUniform1i(detection_id, shader_outside_printer_detection_enabled ? 1 : 0);
+
+ if (worldmatrix_id != -1)
+ ::glUniformMatrix4fv(worldmatrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().data());
+
+ ::glBindBuffer(GL_ARRAY_BUFFER, indexed_vertex_array.vertices_and_normals_interleaved_VBO_id);
+ ::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)));
+ ::glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr);
+
+ ::glPushMatrix();
+ ::glTranslated(m_offset(0), m_offset(1), m_offset(2));
+ ::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0);
+ ::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor);
+
+ if (n_triangles > 0)
+ {
+ ::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexed_vertex_array.triangle_indices_VBO_id);
+ ::glDrawElements(GL_TRIANGLES, n_triangles, GL_UNSIGNED_INT, (const void*)(tverts_range.first * 4));
+ }
+ if (n_quads > 0)
+ {
+ ::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexed_vertex_array.quad_indices_VBO_id);
+ ::glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, (const void*)(qverts_range.first * 4));
+ }
+
+ ::glPopMatrix();
+}
+
+void GLVolume::render_legacy() const
+{
+ assert(!indexed_vertex_array.vertices_and_normals_interleaved_VBO_id);
+ if (!is_active)
+ return;
+
+ GLsizei n_triangles = GLsizei(std::min(indexed_vertex_array.triangle_indices_size, tverts_range.second - tverts_range.first));
+ GLsizei n_quads = GLsizei(std::min(indexed_vertex_array.quad_indices_size, qverts_range.second - qverts_range.first));
+ if (n_triangles + n_quads == 0)
+ {
+ ::glDisableClientState(GL_VERTEX_ARRAY);
+ ::glDisableClientState(GL_NORMAL_ARRAY);
+
+ ::glColor4f(render_color[0], render_color[1], render_color[2], render_color[3]);
+ render();
+
+ ::glEnableClientState(GL_VERTEX_ARRAY);
+ ::glEnableClientState(GL_NORMAL_ARRAY);
+
+ return;
+ }
+
+ ::glColor4f(render_color[0], render_color[1], render_color[2], render_color[3]);
+ ::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), indexed_vertex_array.vertices_and_normals_interleaved.data() + 3);
+ ::glNormalPointer(GL_FLOAT, 6 * sizeof(float), indexed_vertex_array.vertices_and_normals_interleaved.data());
+
+ ::glPushMatrix();
+ ::glTranslated(m_offset(0), m_offset(1), m_offset(2));
+ ::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0);
+ ::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor);
+
+ if (n_triangles > 0)
+ ::glDrawElements(GL_TRIANGLES, n_triangles, GL_UNSIGNED_INT, indexed_vertex_array.triangle_indices.data() + tverts_range.first);
+
+ if (n_quads > 0)
+ ::glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, indexed_vertex_array.quad_indices.data() + qverts_range.first);
+
+ ::glPopMatrix();
+}
+
+double GLVolume::layer_height_texture_z_to_row_id() const
+{
+ return (this->layer_height_texture.get() == nullptr) ? 0.0 : double(this->layer_height_texture->cells - 1) / (double(this->layer_height_texture->width) * this->layer_height_texture_data.print_object->model_object()->bounding_box().max(2));
+}
+
+void GLVolume::generate_layer_height_texture(const PrintObject *print_object, bool force)
+{
+ LayersTexture *tex = this->layer_height_texture.get();
+ if (tex == nullptr)
// No layer_height_texture is assigned to this GLVolume, therefore the layer height texture cannot be filled.
return;
// Always try to update the layer height profile.
- bool update = print_object->update_layer_height_profile(print_object->model_object()->layer_height_profile) || force;
+ bool update = print_object->update_layer_height_profile(const_cast<ModelObject*>(print_object->model_object())->layer_height_profile) || force;
// Update if the layer height profile was changed, or when the texture is not valid.
if (! update && ! tex->data.empty() && tex->cells > 0)
// Texture is valid, don't update.
@@ -376,15 +641,23 @@ std::vector<int> GLVolumeCollection::load_object(
};
// Object will have a single common layer height texture for all volumes.
- std::shared_ptr<GLTexture> layer_height_texture = std::make_shared<GLTexture>();
-
+ std::shared_ptr<LayersTexture> layer_height_texture = std::make_shared<LayersTexture>();
+
std::vector<int> volumes_idx;
for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++ volume_idx) {
const ModelVolume *model_volume = model_object->volumes[volume_idx];
+
+ int extruder_id = -1;
+ if (!model_volume->modifier)
+ {
+ extruder_id = model_volume->config.has("extruder") ? model_volume->config.option("extruder")->getInt() : 0;
+ if (extruder_id == 0)
+ extruder_id = model_object->config.has("extruder") ? model_object->config.option("extruder")->getInt() : 0;
+ }
+
for (int instance_idx : instance_idxs) {
const ModelInstance *instance = model_object->instances[instance_idx];
TriangleMesh mesh = model_volume->mesh;
- instance->transform_mesh(&mesh);
volumes_idx.push_back(int(this->volumes.size()));
float color[4];
memcpy(color, colors[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3);
@@ -400,18 +673,20 @@ std::vector<int> GLVolumeCollection::load_object(
v.bounding_box = v.indexed_vertex_array.bounding_box();
v.indexed_vertex_array.finalize_geometry(use_VBOs);
v.composite_id = obj_idx * 1000000 + volume_idx * 1000 + instance_idx;
- if (select_by == "object")
- v.select_group_id = obj_idx * 1000000;
- else if (select_by == "volume")
- v.select_group_id = obj_idx * 1000000 + volume_idx * 1000;
- else if (select_by == "instance")
- v.select_group_id = v.composite_id;
- if (drag_by == "object")
- v.drag_group_id = obj_idx * 1000;
- else if (drag_by == "instance")
- v.drag_group_id = obj_idx * 1000 + instance_idx;
- if (! model_volume->modifier)
+ v.set_select_group_id(select_by);
+ v.set_drag_group_id(drag_by);
+ if (!model_volume->modifier)
+ {
+ v.set_convex_hull(model_volume->get_convex_hull());
v.layer_height_texture = layer_height_texture;
+ if (extruder_id != -1)
+ v.extruder_id = extruder_id;
+ }
+ v.is_modifier = model_volume->modifier;
+ v.shader_outside_printer_detection_enabled = !model_volume->modifier;
+ v.set_offset(Vec3d(instance->offset(0), instance->offset(1), 0.0));
+ v.set_rotation(instance->rotation);
+ v.set_scaling_factor(instance->scaling_factor);
}
}
@@ -420,24 +695,76 @@ std::vector<int> GLVolumeCollection::load_object(
int GLVolumeCollection::load_wipe_tower_preview(
- int obj_idx, float pos_x, float pos_y, float width, float depth, float height, bool use_VBOs)
+ int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width)
{
- float color[4] = { 1.0f, 1.0f, 0.0f, 0.5f };
+ if (depth < 0.01f)
+ return int(this->volumes.size() - 1);
+ if (height == 0.0f)
+ height = 0.1f;
+ Point origin_of_rotation(0.f, 0.f);
+ TriangleMesh mesh;
+ float color[4] = { 0.5f, 0.5f, 0.0f, 1.f };
+
+ // In case we don't know precise dimensions of the wipe tower yet, we'll draw the box with different color with one side jagged:
+ if (size_unknown) {
+ color[0] = 0.9f;
+ color[1] = 0.6f;
+
+ depth = std::max(depth, 10.f); // Too narrow tower would interfere with the teeth. The estimate is not precise anyway.
+ float min_width = 30.f;
+ // We'll now create the box with jagged edge. y-coordinates of the pre-generated model are shifted so that the front
+ // edge has y=0 and centerline of the back edge has y=depth:
+ Pointf3s points;
+ std::vector<Vec3crd> facets;
+ float out_points_idx[][3] = {{0, -depth, 0}, {0, 0, 0}, {38.453, 0, 0}, {61.547, 0, 0}, {100, 0, 0}, {100, -depth, 0}, {55.7735, -10, 0}, {44.2265, 10, 0},
+ {38.453, 0, 1}, {0, 0, 1}, {0, -depth, 1}, {100, -depth, 1}, {100, 0, 1}, {61.547, 0, 1}, {55.7735, -10, 1}, {44.2265, 10, 1}};
+ int out_facets_idx[][3] = {{0, 1, 2}, {3, 4, 5}, {6, 5, 0}, {3, 5, 6}, {6, 2, 7}, {6, 0, 2}, {8, 9, 10}, {11, 12, 13}, {10, 11, 14}, {14, 11, 13}, {15, 8, 14},
+ {8, 10, 14}, {3, 12, 4}, {3, 13, 12}, {6, 13, 3}, {6, 14, 13}, {7, 14, 6}, {7, 15, 14}, {2, 15, 7}, {2, 8, 15}, {1, 8, 2}, {1, 9, 8},
+ {0, 9, 1}, {0, 10, 9}, {5, 10, 0}, {5, 11, 10}, {4, 11, 5}, {4, 12, 11}};
+ for (int i=0;i<16;++i)
+ points.push_back(Vec3d(out_points_idx[i][0] / (100.f/min_width), out_points_idx[i][1] + depth, out_points_idx[i][2]));
+ for (int i=0;i<28;++i)
+ facets.push_back(Vec3crd(out_facets_idx[i][0], out_facets_idx[i][1], out_facets_idx[i][2]));
+ TriangleMesh tooth_mesh(points, facets);
+
+ // We have the mesh ready. It has one tooth and width of min_width. We will now append several of these together until we are close to
+ // the required width of the block. Than we can scale it precisely.
+ size_t n = std::max(1, int(width/min_width)); // How many shall be merged?
+ for (size_t i=0;i<n;++i) {
+ mesh.merge(tooth_mesh);
+ tooth_mesh.translate(min_width, 0.f, 0.f);
+ }
+
+ mesh.scale(Vec3d(width/(n*min_width), 1.f, height)); // Scaling to proper width
+ }
+ else
+ mesh = make_cube(width, depth, height);
+
+ // We'll make another mesh to show the brim (fixed layer height):
+ TriangleMesh brim_mesh = make_cube(width+2.f*brim_width, depth+2.f*brim_width, 0.2f);
+ brim_mesh.translate(-brim_width, -brim_width, 0.f);
+ mesh.merge(brim_mesh);
+
+ mesh.rotate(rotation_angle, &origin_of_rotation); // rotates the box according to the config rotation setting
+
this->volumes.emplace_back(new GLVolume(color));
GLVolume &v = *this->volumes.back();
- auto mesh = make_cube(width, depth, height);
+
if (use_VBOs)
v.indexed_vertex_array.load_mesh_full_shading(mesh);
else
v.indexed_vertex_array.load_mesh_flat_shading(mesh);
- v.origin = Pointf3(pos_x, pos_y, 0.);
+ v.set_offset(Vec3d(pos_x, pos_y, 0.0));
+
// finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
v.bounding_box = v.indexed_vertex_array.bounding_box();
v.indexed_vertex_array.finalize_geometry(use_VBOs);
v.composite_id = obj_idx * 1000000;
v.select_group_id = obj_idx * 1000000;
v.drag_group_id = obj_idx * 1000;
+ v.is_wipe_tower = true;
+ v.shader_outside_printer_detection_enabled = ! size_unknown;
return int(this->volumes.size() - 1);
}
@@ -455,102 +782,23 @@ void GLVolumeCollection::render_VBOs() const
GLint color_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "uniform_color") : -1;
GLint print_box_min_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.min") : -1;
GLint print_box_max_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.max") : -1;
- GLint print_box_origin_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.volume_origin") : -1;
+ GLint print_box_detection_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.volume_detection") : -1;
+ GLint print_box_worldmatrix_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.volume_world_matrix") : -1;
- for (GLVolume *volume : this->volumes) {
- if (!volume->is_active)
- continue;
+ if (print_box_min_id != -1)
+ ::glUniform3fv(print_box_min_id, 1, (const GLfloat*)print_box_min);
- if (!volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id)
- continue;
+ if (print_box_max_id != -1)
+ ::glUniform3fv(print_box_max_id, 1, (const GLfloat*)print_box_max);
+ for (GLVolume *volume : this->volumes)
+ {
if (volume->layer_height_texture_data.can_use())
- {
- ::glDisableClientState(GL_VERTEX_ARRAY);
- ::glDisableClientState(GL_NORMAL_ARRAY);
volume->generate_layer_height_texture(volume->layer_height_texture_data.print_object, false);
- volume->render_using_layer_height();
- ::glEnableClientState(GL_VERTEX_ARRAY);
- ::glEnableClientState(GL_NORMAL_ARRAY);
- continue;
- }
-
- volume->set_render_color();
-
- GLsizei n_triangles = GLsizei(std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first));
- GLsizei n_quads = GLsizei(std::min(volume->indexed_vertex_array.quad_indices_size, volume->qverts_range.second - volume->qverts_range.first));
- if (n_triangles + n_quads == 0)
- {
- ::glDisableClientState(GL_VERTEX_ARRAY);
- ::glDisableClientState(GL_NORMAL_ARRAY);
-
- if (color_id >= 0)
- {
- float color[4];
- ::memcpy((void*)color, (const void*)volume->render_color, 4 * sizeof(float));
- ::glUniform4fv(color_id, 1, (const GLfloat*)color);
- }
- else
- ::glColor4f(volume->render_color[0], volume->render_color[1], volume->render_color[2], volume->render_color[3]);
-
- if (print_box_min_id != -1)
- ::glUniform3fv(print_box_min_id, 1, (const GLfloat*)print_box_min);
-
- if (print_box_max_id != -1)
- ::glUniform3fv(print_box_max_id, 1, (const GLfloat*)print_box_max);
-
- if (print_box_origin_id != -1)
- {
- float origin[4] = { (float)volume->origin.x, (float)volume->origin.y, (float)volume->origin.z, volume->outside_printer_detection_enabled ? 1.0f : 0.0f };
- ::glUniform4fv(print_box_origin_id, 1, (const GLfloat*)origin);
- }
-
- volume->render();
-
- ::glEnableClientState(GL_VERTEX_ARRAY);
- ::glEnableClientState(GL_NORMAL_ARRAY);
-
- continue;
- }
-
- if (color_id >= 0)
- ::glUniform4fv(color_id, 1, (const GLfloat*)volume->render_color);
else
- ::glColor4f(volume->render_color[0], volume->render_color[1], volume->render_color[2], volume->render_color[3]);
-
- if (print_box_min_id != -1)
- ::glUniform3fv(print_box_min_id, 1, (const GLfloat*)print_box_min);
+ volume->set_render_color();
- if (print_box_max_id != -1)
- ::glUniform3fv(print_box_max_id, 1, (const GLfloat*)print_box_max);
-
- if (print_box_origin_id != -1)
- {
- float origin[4] = { (float)volume->origin.x, (float)volume->origin.y, (float)volume->origin.z, volume->outside_printer_detection_enabled ? 1.0f : 0.0f };
- ::glUniform4fv(print_box_origin_id, 1, (const GLfloat*)origin);
- }
-
- ::glBindBuffer(GL_ARRAY_BUFFER, volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id);
- ::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)));
- ::glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr);
-
- bool has_offset = (volume->origin.x != 0) || (volume->origin.y != 0) || (volume->origin.z != 0);
- if (has_offset) {
- ::glPushMatrix();
- ::glTranslated(volume->origin.x, volume->origin.y, volume->origin.z);
- }
-
- if (n_triangles > 0) {
- ::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, volume->indexed_vertex_array.triangle_indices_VBO_id);
- ::glDrawElements(GL_TRIANGLES, n_triangles, GL_UNSIGNED_INT, (const void*)(volume->tverts_range.first * 4));
- }
- if (n_quads > 0) {
- ::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, volume->indexed_vertex_array.quad_indices_VBO_id);
- ::glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, (const void*)(volume->qverts_range.first * 4));
- }
-
- if (has_offset)
- ::glPopMatrix();
+ volume->render_VBOs(color_id, print_box_detection_id, print_box_worldmatrix_id);
}
::glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -571,43 +819,10 @@ void GLVolumeCollection::render_legacy() const
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
- for (GLVolume *volume : this->volumes) {
- assert(! volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id);
- if (!volume->is_active)
- continue;
-
+ for (GLVolume *volume : this->volumes)
+ {
volume->set_render_color();
-
- GLsizei n_triangles = GLsizei(std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first));
- GLsizei n_quads = GLsizei(std::min(volume->indexed_vertex_array.quad_indices_size, volume->qverts_range.second - volume->qverts_range.first));
- if (n_triangles + n_quads == 0)
- {
- ::glDisableClientState(GL_VERTEX_ARRAY);
- ::glDisableClientState(GL_NORMAL_ARRAY);
-
- ::glColor4f(volume->render_color[0], volume->render_color[1], volume->render_color[2], volume->render_color[3]);
- volume->render();
-
- ::glEnableClientState(GL_VERTEX_ARRAY);
- ::glEnableClientState(GL_NORMAL_ARRAY);
-
- continue;
- }
-
- glColor4f(volume->render_color[0], volume->render_color[1], volume->render_color[2], volume->render_color[3]);
- glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), volume->indexed_vertex_array.vertices_and_normals_interleaved.data() + 3);
- glNormalPointer(GL_FLOAT, 6 * sizeof(float), volume->indexed_vertex_array.vertices_and_normals_interleaved.data());
- bool has_offset = volume->origin.x != 0 || volume->origin.y != 0 || volume->origin.z != 0;
- if (has_offset) {
- glPushMatrix();
- glTranslated(volume->origin.x, volume->origin.y, volume->origin.z);
- }
- if (n_triangles > 0)
- glDrawElements(GL_TRIANGLES, n_triangles, GL_UNSIGNED_INT, volume->indexed_vertex_array.triangle_indices.data() + volume->tverts_range.first);
- if (n_quads > 0)
- glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, volume->indexed_vertex_array.quad_indices.data() + volume->qverts_range.first);
- if (has_offset)
- glPopMatrix();
+ volume->render_legacy();
}
glDisableClientState(GL_VERTEX_ARRAY);
@@ -616,41 +831,174 @@ void GLVolumeCollection::render_legacy() const
glDisable(GL_BLEND);
}
-void GLVolumeCollection::update_outside_state(const DynamicPrintConfig* config, bool all_inside)
+bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstance::EPrintVolumeState* out_state)
{
if (config == nullptr)
- return;
+ return false;
const ConfigOptionPoints* opt = dynamic_cast<const ConfigOptionPoints*>(config->option("bed_shape"));
if (opt == nullptr)
- return;
+ return false;
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values));
- BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min.x), unscale(bed_box_2D.min.y), 0.0), Pointf3(unscale(bed_box_2D.max.x), unscale(bed_box_2D.max.y), config->opt_float("max_print_height")));
+ BoundingBoxf3 print_volume(Vec3d(unscale<double>(bed_box_2D.min(0)), unscale<double>(bed_box_2D.min(1)), 0.0), Vec3d(unscale<double>(bed_box_2D.max(0)), unscale<double>(bed_box_2D.max(1)), config->opt_float("max_print_height")));
+ // Allow the objects to protrude below the print bed
+ print_volume.min(2) = -1e10;
+
+ ModelInstance::EPrintVolumeState state = ModelInstance::PVS_Inside;
+ bool all_contained = true;
for (GLVolume* volume : this->volumes)
{
- if (all_inside)
+ if ((volume != nullptr) && !volume->is_modifier && (!volume->is_wipe_tower || (volume->is_wipe_tower && volume->shader_outside_printer_detection_enabled)))
{
+ const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box();
+ bool contained = print_volume.contains(bb);
+ all_contained &= contained;
+
+ volume->is_outside = !contained;
+
+ if ((state == ModelInstance::PVS_Inside) && volume->is_outside)
+ state = ModelInstance::PVS_Fully_Outside;
+
+ if ((state == ModelInstance::PVS_Fully_Outside) && volume->is_outside && print_volume.intersects(bb))
+ state = ModelInstance::PVS_Partly_Outside;
+ }
+ }
+
+ if (out_state != nullptr)
+ *out_state = state;
+
+ return all_contained;
+}
+
+void GLVolumeCollection::reset_outside_state()
+{
+ for (GLVolume* volume : this->volumes)
+ {
+ if (volume != nullptr)
volume->is_outside = false;
- continue;
+ }
+}
+
+void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* config)
+{
+ static const float inv_255 = 1.0f / 255.0f;
+
+ struct Color
+ {
+ std::string text;
+ unsigned char rgb[3];
+
+ Color()
+ : text("")
+ {
+ rgb[0] = 255;
+ rgb[1] = 255;
+ rgb[2] = 255;
+ }
+
+ void set(const std::string& text, unsigned char* rgb)
+ {
+ this->text = text;
+ ::memcpy((void*)this->rgb, (const void*)rgb, 3 * sizeof(unsigned char));
}
+ };
- volume->is_outside = !print_volume.contains(volume->transformed_bounding_box());
+ if (config == nullptr)
+ return;
+
+ const ConfigOptionStrings* extruders_opt = dynamic_cast<const ConfigOptionStrings*>(config->option("extruder_colour"));
+ if (extruders_opt == nullptr)
+ return;
+
+ const ConfigOptionStrings* filamemts_opt = dynamic_cast<const ConfigOptionStrings*>(config->option("filament_colour"));
+ if (filamemts_opt == nullptr)
+ return;
+
+ unsigned int colors_count = std::max((unsigned int)extruders_opt->values.size(), (unsigned int)filamemts_opt->values.size());
+ if (colors_count == 0)
+ return;
+
+ std::vector<Color> colors(colors_count);
+
+ unsigned char rgb[3];
+ for (unsigned int i = 0; i < colors_count; ++i)
+ {
+ const std::string& txt_color = config->opt_string("extruder_colour", i);
+ if (PresetBundle::parse_color(txt_color, rgb))
+ {
+ colors[i].set(txt_color, rgb);
+ }
+ else
+ {
+ const std::string& txt_color = config->opt_string("filament_colour", i);
+ if (PresetBundle::parse_color(txt_color, rgb))
+ colors[i].set(txt_color, rgb);
+ }
+ }
+
+ for (GLVolume* volume : volumes)
+ {
+ if ((volume == nullptr) || volume->is_modifier || volume->is_wipe_tower)
+ continue;
+
+ int extruder_id = volume->extruder_id - 1;
+ if ((extruder_id < 0) || ((unsigned int)colors.size() <= extruder_id))
+ extruder_id = 0;
+
+ const Color& color = colors[extruder_id];
+ if (!color.text.empty())
+ {
+ for (int i = 0; i < 3; ++i)
+ {
+ volume->color[i] = (float)color.rgb[i] * inv_255;
+ }
+ }
}
}
-std::vector<double> GLVolumeCollection::get_current_print_zs() const
+void GLVolumeCollection::set_select_by(const std::string& select_by)
{
- std::vector<double> print_zs;
+ for (GLVolume *vol : this->volumes)
+ {
+ if (vol != nullptr)
+ vol->set_select_group_id(select_by);
+ }
+}
+void GLVolumeCollection::set_drag_by(const std::string& drag_by)
+{
for (GLVolume *vol : this->volumes)
{
- for (coordf_t z : vol->print_zs)
- print_zs.emplace_back((double)round(z * 100000.0f) / 100000.0f);
+ if (vol != nullptr)
+ vol->set_drag_group_id(drag_by);
}
+}
- sort_remove_duplicates(print_zs);
+std::vector<double> GLVolumeCollection::get_current_print_zs(bool active_only) const
+{
+ // Collect layer top positions of all volumes.
+ std::vector<double> print_zs;
+ for (GLVolume *vol : this->volumes)
+ {
+ if (!active_only || vol->is_active)
+ append(print_zs, vol->print_zs);
+ }
+ std::sort(print_zs.begin(), print_zs.end());
+
+ // Replace intervals of layers with similar top positions with their average value.
+ int n = int(print_zs.size());
+ int k = 0;
+ for (int i = 0; i < n;) {
+ int j = i + 1;
+ coordf_t zmax = print_zs[i] + EPSILON;
+ for (; j < n && print_zs[j] <= zmax; ++ j) ;
+ print_zs[k ++] = (j > i + 1) ? (0.5 * (print_zs[i] + print_zs[j - 1])) : print_zs[i];
+ i = j;
+ }
+ if (k < n)
+ print_zs.erase(print_zs.begin() + k, print_zs.end());
return print_zs;
}
@@ -673,47 +1021,53 @@ static void thick_lines_to_indexed_vertex_array(
#define TOP 2
#define BOTTOM 3
- Line prev_line;
// right, left, top, bottom
int idx_prev[4] = { -1, -1, -1, -1 };
double bottom_z_prev = 0.;
- Pointf b1_prev;
- Pointf b2_prev;
- Vectorf v_prev;
+ Vec2d b1_prev(Vec2d::Zero());
+ Vec2d v_prev(Vec2d::Zero());
int idx_initial[4] = { -1, -1, -1, -1 };
double width_initial = 0.;
+ double bottom_z_initial = 0.0;
// loop once more in case of closed loops
size_t lines_end = closed ? (lines.size() + 1) : lines.size();
for (size_t ii = 0; ii < lines_end; ++ ii) {
size_t i = (ii == lines.size()) ? 0 : ii;
const Line &line = lines[i];
- double len = unscale(line.length());
+ double len = unscale<double>(line.length());
+ double inv_len = 1.0 / len;
double bottom_z = top_z - heights[i];
- double middle_z = (top_z + bottom_z) / 2.;
+ double middle_z = 0.5 * (top_z + bottom_z);
double width = widths[i];
-
- Vectorf v = Vectorf::new_unscale(line.vector());
- v.scale(1. / len);
-
- Pointf a = Pointf::new_unscale(line.a);
- Pointf b = Pointf::new_unscale(line.b);
- Pointf a1 = a;
- Pointf a2 = a;
- Pointf b1 = b;
- Pointf b2 = b;
+
+ bool is_first = (ii == 0);
+ bool is_last = (ii == lines_end - 1);
+ bool is_closing = closed && is_last;
+
+ Vec2d v = unscale(line.vector());
+ v *= inv_len;
+
+ Vec2d a = unscale(line.a);
+ Vec2d b = unscale(line.b);
+ Vec2d a1 = a;
+ Vec2d a2 = a;
+ Vec2d b1 = b;
+ Vec2d b2 = b;
{
- double dist = width / 2.; // scaled
- a1.translate(+dist*v.y, -dist*v.x);
- a2.translate(-dist*v.y, +dist*v.x);
- b1.translate(+dist*v.y, -dist*v.x);
- b2.translate(-dist*v.y, +dist*v.x);
+ double dist = 0.5 * width; // scaled
+ double dx = dist * v(0);
+ double dy = dist * v(1);
+ a1 += Vec2d(+dy, -dx);
+ a2 += Vec2d(-dy, +dx);
+ b1 += Vec2d(+dy, -dx);
+ b2 += Vec2d(-dy, +dx);
}
// calculate new XY normals
Vector n = line.normal();
- Vectorf3 xy_right_normal = Vectorf3::new_unscale(n.x, n.y, 0);
- xy_right_normal.scale(1.f / len);
+ Vec3d xy_right_normal = unscale(n(0), n(1), 0);
+ xy_right_normal *= inv_len;
int idx_a[4];
int idx_b[4];
@@ -722,72 +1076,92 @@ static void thick_lines_to_indexed_vertex_array(
bool bottom_z_different = bottom_z_prev != bottom_z;
bottom_z_prev = bottom_z;
+ if (!is_first && bottom_z_different)
+ {
+ // Found a change of the layer thickness -> Add a cap at the end of the previous segment.
+ volume.push_quad(idx_b[BOTTOM], idx_b[LEFT], idx_b[TOP], idx_b[RIGHT]);
+ }
+
// Share top / bottom vertices if possible.
- if (ii == 0) {
- idx_a[TOP] = idx_last ++;
- volume.push_geometry(a.x, a.y, top_z , 0., 0., 1.);
+ if (is_first) {
+ idx_a[TOP] = idx_last++;
+ volume.push_geometry(a(0), a(1), top_z , 0., 0., 1.);
} else {
idx_a[TOP] = idx_prev[TOP];
}
- if (ii == 0 || bottom_z_different) {
+
+ if (is_first || bottom_z_different) {
// Start of the 1st line segment or a change of the layer thickness while maintaining the print_z.
idx_a[BOTTOM] = idx_last ++;
- volume.push_geometry(a.x, a.y, bottom_z, 0., 0., -1.);
+ volume.push_geometry(a(0), a(1), bottom_z, 0., 0., -1.);
idx_a[LEFT ] = idx_last ++;
- volume.push_geometry(a2.x, a2.y, middle_z, -xy_right_normal.x, -xy_right_normal.y, -xy_right_normal.z);
+ volume.push_geometry(a2(0), a2(1), middle_z, -xy_right_normal(0), -xy_right_normal(1), -xy_right_normal(2));
idx_a[RIGHT] = idx_last ++;
- volume.push_geometry(a1.x, a1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z);
- } else {
+ volume.push_geometry(a1(0), a1(1), middle_z, xy_right_normal(0), xy_right_normal(1), xy_right_normal(2));
+ }
+ else {
idx_a[BOTTOM] = idx_prev[BOTTOM];
}
- if (ii == 0) {
+ if (is_first) {
// Start of the 1st line segment.
width_initial = width;
+ bottom_z_initial = bottom_z;
memcpy(idx_initial, idx_a, sizeof(int) * 4);
} else {
// Continuing a previous segment.
// Share left / right vertices if possible.
- double v_dot = dot(v_prev, v);
+ double v_dot = v_prev.dot(v);
bool sharp = v_dot < 0.707; // sin(45 degrees)
if (sharp) {
- // Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn.
- idx_a[RIGHT] = idx_last ++;
- volume.push_geometry(a1.x, a1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z);
- idx_a[LEFT ] = idx_last ++;
- volume.push_geometry(a2.x, a2.y, middle_z, -xy_right_normal.x, -xy_right_normal.y, -xy_right_normal.z);
+ if (!bottom_z_different)
+ {
+ // Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn.
+ idx_a[RIGHT] = idx_last++;
+ volume.push_geometry(a1(0), a1(1), middle_z, xy_right_normal(0), xy_right_normal(1), xy_right_normal(2));
+ idx_a[LEFT] = idx_last++;
+ volume.push_geometry(a2(0), a2(1), middle_z, -xy_right_normal(0), -xy_right_normal(1), -xy_right_normal(2));
+ }
}
if (v_dot > 0.9) {
- // The two successive segments are nearly collinear.
- idx_a[LEFT ] = idx_prev[LEFT];
- idx_a[RIGHT] = idx_prev[RIGHT];
- } else if (! sharp) {
- // Create a sharp corner with an overshot and average the left / right normals.
- // At the crease angle of 45 degrees, the overshot at the corner will be less than (1-1/cos(PI/8)) = 8.2% over an arc.
- Pointf intersection;
- Geometry::ray_ray_intersection(b1_prev, v_prev, a1, v, intersection);
- a1 = intersection;
- a2 = 2. * a - intersection;
- assert(length(a1.vector_to(a)) < width);
- assert(length(a2.vector_to(a)) < width);
- float *n_left_prev = volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT ] * 6;
- float *p_left_prev = n_left_prev + 3;
- float *n_right_prev = volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6;
- float *p_right_prev = n_right_prev + 3;
- p_left_prev [0] = float(a2.x);
- p_left_prev [1] = float(a2.y);
- p_right_prev[0] = float(a1.x);
- p_right_prev[1] = float(a1.y);
- xy_right_normal.x += n_right_prev[0];
- xy_right_normal.y += n_right_prev[1];
- xy_right_normal.scale(1. / length(xy_right_normal));
- n_left_prev [0] = float(-xy_right_normal.x);
- n_left_prev [1] = float(-xy_right_normal.y);
- n_right_prev[0] = float( xy_right_normal.x);
- n_right_prev[1] = float( xy_right_normal.y);
- idx_a[LEFT ] = idx_prev[LEFT ];
- idx_a[RIGHT] = idx_prev[RIGHT];
- } else if (cross(v_prev, v) > 0.) {
+ if (!bottom_z_different)
+ {
+ // The two successive segments are nearly collinear.
+ idx_a[LEFT ] = idx_prev[LEFT];
+ idx_a[RIGHT] = idx_prev[RIGHT];
+ }
+ }
+ else if (!sharp) {
+ if (!bottom_z_different)
+ {
+ // Create a sharp corner with an overshot and average the left / right normals.
+ // At the crease angle of 45 degrees, the overshot at the corner will be less than (1-1/cos(PI/8)) = 8.2% over an arc.
+ Vec2d intersection(Vec2d::Zero());
+ Geometry::ray_ray_intersection(b1_prev, v_prev, a1, v, intersection);
+ a1 = intersection;
+ a2 = 2. * a - intersection;
+ assert((a - a1).norm() < width);
+ assert((a - a2).norm() < width);
+ float *n_left_prev = volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT ] * 6;
+ float *p_left_prev = n_left_prev + 3;
+ float *n_right_prev = volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6;
+ float *p_right_prev = n_right_prev + 3;
+ p_left_prev [0] = float(a2(0));
+ p_left_prev [1] = float(a2(1));
+ p_right_prev[0] = float(a1(0));
+ p_right_prev[1] = float(a1(1));
+ xy_right_normal(0) += n_right_prev[0];
+ xy_right_normal(1) += n_right_prev[1];
+ xy_right_normal *= 1. / xy_right_normal.norm();
+ n_left_prev [0] = float(-xy_right_normal(0));
+ n_left_prev [1] = float(-xy_right_normal(1));
+ n_right_prev[0] = float( xy_right_normal(0));
+ n_right_prev[1] = float( xy_right_normal(1));
+ idx_a[LEFT ] = idx_prev[LEFT ];
+ idx_a[RIGHT] = idx_prev[RIGHT];
+ }
+ }
+ else if (cross2(v_prev, v) > 0.) {
// Right turn. Fill in the right turn wedge.
volume.push_triangle(idx_prev[RIGHT], idx_a [RIGHT], idx_prev[TOP] );
volume.push_triangle(idx_prev[RIGHT], idx_prev[BOTTOM], idx_a [RIGHT] );
@@ -796,18 +1170,21 @@ static void thick_lines_to_indexed_vertex_array(
volume.push_triangle(idx_prev[LEFT], idx_prev[TOP], idx_a [LEFT] );
volume.push_triangle(idx_prev[LEFT], idx_a [LEFT], idx_prev[BOTTOM]);
}
- if (ii == lines.size()) {
- if (! sharp) {
- // Closing a loop with smooth transition. Unify the closing left / right vertices.
- memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[LEFT ] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT ] * 6, sizeof(float) * 6);
- memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[RIGHT] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6, sizeof(float) * 6);
- volume.vertices_and_normals_interleaved.erase(volume.vertices_and_normals_interleaved.end() - 12, volume.vertices_and_normals_interleaved.end());
- // Replace the left / right vertex indices to point to the start of the loop.
- for (size_t u = volume.quad_indices.size() - 16; u < volume.quad_indices.size(); ++ u) {
- if (volume.quad_indices[u] == idx_prev[LEFT])
- volume.quad_indices[u] = idx_initial[LEFT];
- else if (volume.quad_indices[u] == idx_prev[RIGHT])
- volume.quad_indices[u] = idx_initial[RIGHT];
+ if (is_closing) {
+ if (!sharp) {
+ if (!bottom_z_different)
+ {
+ // Closing a loop with smooth transition. Unify the closing left / right vertices.
+ memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[LEFT ] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT ] * 6, sizeof(float) * 6);
+ memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[RIGHT] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6, sizeof(float) * 6);
+ volume.vertices_and_normals_interleaved.erase(volume.vertices_and_normals_interleaved.end() - 12, volume.vertices_and_normals_interleaved.end());
+ // Replace the left / right vertex indices to point to the start of the loop.
+ for (size_t u = volume.quad_indices.size() - 16; u < volume.quad_indices.size(); ++ u) {
+ if (volume.quad_indices[u] == idx_prev[LEFT])
+ volume.quad_indices[u] = idx_initial[LEFT];
+ else if (volume.quad_indices[u] == idx_prev[RIGHT])
+ volume.quad_indices[u] = idx_initial[RIGHT];
+ }
}
}
// This is the last iteration, only required to solve the transition.
@@ -816,40 +1193,45 @@ static void thick_lines_to_indexed_vertex_array(
}
// Only new allocate top / bottom vertices, if not closing a loop.
- if (closed && ii + 1 == lines.size()) {
+ if (is_closing) {
idx_b[TOP] = idx_initial[TOP];
} else {
idx_b[TOP] = idx_last ++;
- volume.push_geometry(b.x, b.y, top_z , 0., 0., 1.);
+ volume.push_geometry(b(0), b(1), top_z , 0., 0., 1.);
}
- if (closed && ii + 1 == lines.size() && width == width_initial) {
+
+ if (is_closing && (width == width_initial) && (bottom_z == bottom_z_initial)) {
idx_b[BOTTOM] = idx_initial[BOTTOM];
} else {
idx_b[BOTTOM] = idx_last ++;
- volume.push_geometry(b.x, b.y, bottom_z, 0., 0., -1.);
+ volume.push_geometry(b(0), b(1), bottom_z, 0., 0., -1.);
}
// Generate new vertices for the end of this line segment.
idx_b[LEFT ] = idx_last ++;
- volume.push_geometry(b2.x, b2.y, middle_z, -xy_right_normal.x, -xy_right_normal.y, -xy_right_normal.z);
+ volume.push_geometry(b2(0), b2(1), middle_z, -xy_right_normal(0), -xy_right_normal(1), -xy_right_normal(2));
idx_b[RIGHT ] = idx_last ++;
- volume.push_geometry(b1.x, b1.y, middle_z, xy_right_normal.x, xy_right_normal.y, xy_right_normal.z);
+ volume.push_geometry(b1(0), b1(1), middle_z, xy_right_normal(0), xy_right_normal(1), xy_right_normal(2));
- prev_line = line;
memcpy(idx_prev, idx_b, 4 * sizeof(int));
bottom_z_prev = bottom_z;
b1_prev = b1;
- b2_prev = b2;
- v_prev = v;
+ v_prev = v;
+
+ if (bottom_z_different && (closed || (!is_first && !is_last)))
+ {
+ // Found a change of the layer thickness -> Add a cap at the beginning of this segment.
+ volume.push_quad(idx_a[BOTTOM], idx_a[RIGHT], idx_a[TOP], idx_a[LEFT]);
+ }
if (! closed) {
// Terminate open paths with caps.
- if (i == 0)
+ if (is_first)
volume.push_quad(idx_a[BOTTOM], idx_a[RIGHT], idx_a[TOP], idx_a[LEFT]);
// We don't use 'else' because both cases are true if we have only one line.
- if (i + 1 == lines.size())
+ if (is_last)
volume.push_quad(idx_b[BOTTOM], idx_b[LEFT], idx_b[TOP], idx_b[RIGHT]);
}
-
+
// Add quads for a straight hollow tube-like segment.
// bottom-right face
volume.push_quad(idx_a[BOTTOM], idx_b[BOTTOM], idx_b[RIGHT], idx_a[RIGHT]);
@@ -887,15 +1269,15 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines,
int idx_initial[4] = { -1, -1, -1, -1 };
int idx_prev[4] = { -1, -1, -1, -1 };
double z_prev = 0.0;
- Vectorf3 n_right_prev;
- Vectorf3 n_top_prev;
- Vectorf3 unit_v_prev;
+ Vec3d n_right_prev = Vec3d::Zero();
+ Vec3d n_top_prev = Vec3d::Zero();
+ Vec3d unit_v_prev = Vec3d::Zero();
double width_initial = 0.0;
// new vertices around the line endpoints
// left, right, top, bottom
- Pointf3 a[4];
- Pointf3 b[4];
+ Vec3d a[4] = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() };
+ Vec3d b[4] = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() };
// loop once more in case of closed loops
size_t lines_end = closed ? (lines.size() + 1) : lines.size();
@@ -907,29 +1289,29 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines,
double height = heights[i];
double width = widths[i];
- Vectorf3 unit_v = normalize(Vectorf3::new_unscale(line.vector()));
+ Vec3d unit_v = unscale(line.vector()).normalized();
- Vectorf3 n_top;
- Vectorf3 n_right;
- Vectorf3 unit_positive_z(0.0, 0.0, 1.0);
+ Vec3d n_top = Vec3d::Zero();
+ Vec3d n_right = Vec3d::Zero();
+ Vec3d unit_positive_z(0.0, 0.0, 1.0);
- if ((line.a.x == line.b.x) && (line.a.y == line.b.y))
+ if ((line.a(0) == line.b(0)) && (line.a(1) == line.b(1)))
{
// vertical segment
- n_right = (line.a.z < line.b.z) ? Vectorf3(-1.0, 0.0, 0.0) : Vectorf3(1.0, 0.0, 0.0);
- n_top = Vectorf3(0.0, 1.0, 0.0);
+ n_right = (line.a(2) < line.b(2)) ? Vec3d(-1.0, 0.0, 0.0) : Vec3d(1.0, 0.0, 0.0);
+ n_top = Vec3d(0.0, 1.0, 0.0);
}
else
{
// generic segment
- n_right = normalize(cross(unit_v, unit_positive_z));
- n_top = normalize(cross(n_right, unit_v));
+ n_right = unit_v.cross(unit_positive_z).normalized();
+ n_top = n_right.cross(unit_v).normalized();
}
- Vectorf3 rl_displacement = 0.5 * width * n_right;
- Vectorf3 tb_displacement = 0.5 * height * n_top;
- Pointf3 l_a = Pointf3::new_unscale(line.a);
- Pointf3 l_b = Pointf3::new_unscale(line.b);
+ Vec3d rl_displacement = 0.5 * width * n_right;
+ Vec3d tb_displacement = 0.5 * height * n_top;
+ Vec3d l_a = unscale(line.a);
+ Vec3d l_b = unscale(line.b);
a[RIGHT] = l_a + rl_displacement;
a[LEFT] = l_a - rl_displacement;
@@ -940,15 +1322,15 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines,
b[TOP] = l_b + tb_displacement;
b[BOTTOM] = l_b - tb_displacement;
- Vectorf3 n_bottom = -n_top;
- Vectorf3 n_left = -n_right;
+ Vec3d n_bottom = -n_top;
+ Vec3d n_left = -n_right;
int idx_a[4];
int idx_b[4];
int idx_last = int(volume.vertices_and_normals_interleaved.size() / 6);
- bool z_different = (z_prev != l_a.z);
- z_prev = l_b.z;
+ bool z_different = (z_prev != l_a(2));
+ z_prev = l_b(2);
// Share top / bottom vertices if possible.
if (ii == 0)
@@ -982,9 +1364,9 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines,
{
// Continuing a previous segment.
// Share left / right vertices if possible.
- double v_dot = dot(unit_v_prev, unit_v);
+ double v_dot = unit_v_prev.dot(unit_v);
bool is_sharp = v_dot < 0.707; // sin(45 degrees)
- bool is_right_turn = dot(n_top_prev, cross(unit_v_prev, unit_v)) > 0.0;
+ bool is_right_turn = n_top_prev.dot(unit_v_prev.cross(unit_v)) > 0.0;
if (is_sharp)
{
@@ -1007,9 +1389,9 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines,
// At the crease angle of 45 degrees, the overshot at the corner will be less than (1-1/cos(PI/8)) = 8.2% over an arc.
// averages normals
- Vectorf3 average_n_right = normalize(0.5 * (n_right + n_right_prev));
- Vectorf3 average_n_left = -average_n_right;
- Vectorf3 average_rl_displacement = 0.5 * width * average_n_right;
+ Vec3d average_n_right = 0.5 * (n_right + n_right_prev).normalized();
+ Vec3d average_n_left = -average_n_right;
+ Vec3d average_rl_displacement = 0.5 * width * average_n_right;
// updates vertices around a
a[RIGHT] = l_a + average_rl_displacement;
@@ -1017,25 +1399,25 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines,
// updates previous line normals
float* normal_left_prev = volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT] * 6;
- normal_left_prev[0] = float(average_n_left.x);
- normal_left_prev[1] = float(average_n_left.y);
- normal_left_prev[2] = float(average_n_left.z);
+ normal_left_prev[0] = float(average_n_left(0));
+ normal_left_prev[1] = float(average_n_left(1));
+ normal_left_prev[2] = float(average_n_left(2));
float* normal_right_prev = volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6;
- normal_right_prev[0] = float(average_n_right.x);
- normal_right_prev[1] = float(average_n_right.y);
- normal_right_prev[2] = float(average_n_right.z);
+ normal_right_prev[0] = float(average_n_right(0));
+ normal_right_prev[1] = float(average_n_right(1));
+ normal_right_prev[2] = float(average_n_right(2));
// updates previous line's vertices around b
float* b_left_prev = normal_left_prev + 3;
- b_left_prev[0] = float(a[LEFT].x);
- b_left_prev[1] = float(a[LEFT].y);
- b_left_prev[2] = float(a[LEFT].z);
+ b_left_prev[0] = float(a[LEFT](0));
+ b_left_prev[1] = float(a[LEFT](1));
+ b_left_prev[2] = float(a[LEFT](2));
float* b_right_prev = normal_right_prev + 3;
- b_right_prev[0] = float(a[RIGHT].x);
- b_right_prev[1] = float(a[RIGHT].y);
- b_right_prev[2] = float(a[RIGHT].z);
+ b_right_prev[0] = float(a[RIGHT](0));
+ b_right_prev[1] = float(a[RIGHT](1));
+ b_right_prev[2] = float(a[RIGHT](2));
idx_a[LEFT] = idx_prev[LEFT];
idx_a[RIGHT] = idx_prev[RIGHT];
@@ -1132,14 +1514,14 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines,
#undef BOTTOM
}
-static void point_to_indexed_vertex_array(const Point3& point,
+static void point_to_indexed_vertex_array(const Vec3crd& point,
double width,
double height,
GLIndexedVertexArray& volume)
{
// builds a double piramid, with vertices on the local axes, around the point
- Pointf3 center = Pointf3::new_unscale(point);
+ Vec3d center = unscale(point);
double scale_factor = 1.0;
double w = scale_factor * width;
@@ -1153,13 +1535,13 @@ static void point_to_indexed_vertex_array(const Point3& point,
idxs[i] = idx_last + i;
}
- Vectorf3 displacement_x(w, 0.0, 0.0);
- Vectorf3 displacement_y(0.0, w, 0.0);
- Vectorf3 displacement_z(0.0, 0.0, h);
+ Vec3d displacement_x(w, 0.0, 0.0);
+ Vec3d displacement_y(0.0, w, 0.0);
+ Vec3d displacement_z(0.0, 0.0, h);
- Vectorf3 unit_x(1.0, 0.0, 0.0);
- Vectorf3 unit_y(0.0, 1.0, 0.0);
- Vectorf3 unit_z(0.0, 0.0, 1.0);
+ Vec3d unit_x(1.0, 0.0, 0.0);
+ Vec3d unit_y(0.0, 1.0, 0.0);
+ Vec3d unit_z(0.0, 0.0, 1.0);
// vertices
volume.push_geometry(center - displacement_x, -unit_x); // idxs[0]
@@ -1182,8 +1564,8 @@ static void point_to_indexed_vertex_array(const Point3& point,
volume.push_triangle(idxs[0], idxs[3], idxs[4]);
}
-static void thick_lines_to_verts(
- const Lines &lines,
+void _3DScene::thick_lines_to_verts(
+ const Lines &lines,
const std::vector<double> &widths,
const std::vector<double> &heights,
bool closed,
@@ -1193,7 +1575,7 @@ static void thick_lines_to_verts(
thick_lines_to_indexed_vertex_array(lines, widths, heights, closed, top_z, volume.indexed_vertex_array);
}
-static void thick_lines_to_verts(const Lines3& lines,
+void _3DScene::thick_lines_to_verts(const Lines3& lines,
const std::vector<double>& widths,
const std::vector<double>& heights,
bool closed,
@@ -1202,7 +1584,7 @@ static void thick_lines_to_verts(const Lines3& lines,
thick_lines_to_indexed_vertex_array(lines, widths, heights, closed, volume.indexed_vertex_array);
}
-static void thick_point_to_verts(const Point3& point,
+static void thick_point_to_verts(const Vec3crd& point,
double width,
double height,
GLVolume& volume)
@@ -1211,7 +1593,7 @@ static void thick_point_to_verts(const Point3& point,
}
// Fill in the qverts and tverts with quads and triangles for the extrusion_path.
-static inline void extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, GLVolume &volume)
+void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, GLVolume &volume)
{
Lines lines = extrusion_path.polyline.lines();
std::vector<double> widths(lines.size(), extrusion_path.width);
@@ -1220,7 +1602,7 @@ static inline void extrusionentity_to_verts(const ExtrusionPath &extrusion_path,
}
// Fill in the qverts and tverts with quads and triangles for the extrusion_path.
-static inline void extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, const Point &copy, GLVolume &volume)
+void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, const Point &copy, GLVolume &volume)
{
Polyline polyline = extrusion_path.polyline;
polyline.remove_duplicate_points();
@@ -1232,7 +1614,7 @@ static inline void extrusionentity_to_verts(const ExtrusionPath &extrusion_path,
}
// Fill in the qverts and tverts with quads and triangles for the extrusion_loop.
-static inline void extrusionentity_to_verts(const ExtrusionLoop &extrusion_loop, float print_z, const Point &copy, GLVolume &volume)
+void _3DScene::extrusionentity_to_verts(const ExtrusionLoop &extrusion_loop, float print_z, const Point &copy, GLVolume &volume)
{
Lines lines;
std::vector<double> widths;
@@ -1250,7 +1632,7 @@ static inline void extrusionentity_to_verts(const ExtrusionLoop &extrusion_loop,
}
// Fill in the qverts and tverts with quads and triangles for the extrusion_multi_path.
-static inline void extrusionentity_to_verts(const ExtrusionMultiPath &extrusion_multi_path, float print_z, const Point &copy, GLVolume &volume)
+void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath &extrusion_multi_path, float print_z, const Point &copy, GLVolume &volume)
{
Lines lines;
std::vector<double> widths;
@@ -1267,15 +1649,13 @@ static inline void extrusionentity_to_verts(const ExtrusionMultiPath &extrusion_
thick_lines_to_verts(lines, widths, heights, false, print_z, volume);
}
-static void extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity, float print_z, const Point &copy, GLVolume &volume);
-
-static inline void extrusionentity_to_verts(const ExtrusionEntityCollection &extrusion_entity_collection, float print_z, const Point &copy, GLVolume &volume)
+void _3DScene::extrusionentity_to_verts(const ExtrusionEntityCollection &extrusion_entity_collection, float print_z, const Point &copy, GLVolume &volume)
{
for (const ExtrusionEntity *extrusion_entity : extrusion_entity_collection.entities)
extrusionentity_to_verts(extrusion_entity, print_z, copy, volume);
}
-static void extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity, float print_z, const Point &copy, GLVolume &volume)
+void _3DScene::extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity, float print_z, const Point &copy, GLVolume &volume)
{
if (extrusion_entity != nullptr) {
auto *extrusion_path = dynamic_cast<const ExtrusionPath*>(extrusion_entity);
@@ -1302,7 +1682,7 @@ static void extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity, fl
}
}
-static void polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume)
+void _3DScene::polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume)
{
Lines3 lines = polyline.lines();
std::vector<double> widths(lines.size(), width);
@@ -1310,1280 +1690,498 @@ static void polyline3_to_verts(const Polyline3& polyline, double width, double h
thick_lines_to_verts(lines, widths, heights, false, volume);
}
-static void point3_to_verts(const Point3& point, double width, double height, GLVolume& volume)
+void _3DScene::point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume)
{
thick_point_to_verts(point, width, height, volume);
}
-_3DScene::GCodePreviewVolumeIndex _3DScene::s_gcode_preview_volume_index;
-_3DScene::LegendTexture _3DScene::s_legend_texture;
-_3DScene::WarningTexture _3DScene::s_warning_texture;
+GUI::GLCanvas3DManager _3DScene::s_canvas_mgr;
-unsigned int _3DScene::TextureBase::finalize()
+void _3DScene::init_gl()
{
- if (!m_data.empty()) {
- // sends buffer to gpu
- ::glGenTextures(1, &m_tex_id);
- ::glBindTexture(GL_TEXTURE_2D, m_tex_id);
- ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_tex_width, (GLsizei)m_tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)m_data.data());
- ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
- ::glBindTexture(GL_TEXTURE_2D, 0);
- m_data.clear();
- }
- return (m_tex_width > 0 && m_tex_height > 0) ? m_tex_id : 0;
+ s_canvas_mgr.init_gl();
}
-void _3DScene::TextureBase::_destroy_texture()
+std::string _3DScene::get_gl_info(bool format_as_html, bool extensions)
{
- if (m_tex_id > 0)
- {
- ::glDeleteTextures(1, &m_tex_id);
- m_tex_id = 0;
- m_tex_height = 0;
- m_tex_width = 0;
- }
- m_data.clear();
+ return s_canvas_mgr.get_gl_info(format_as_html, extensions);
}
-
-const unsigned char _3DScene::WarningTexture::Background_Color[3] = { 9, 91, 134 };
-const unsigned char _3DScene::WarningTexture::Opacity = 255;
-
-// Generate a texture data, but don't load it into the GPU yet, as the GPU context may not yet be valid.
-bool _3DScene::WarningTexture::generate(const std::string& msg)
+bool _3DScene::use_VBOs()
{
- // Mark the texture as released, but don't release the texture from the GPU yet.
- m_tex_width = m_tex_height = 0;
- m_data.clear();
-
- if (msg.empty())
- return false;
-
- wxMemoryDC memDC;
- // select default font
- memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
-
- // calculates texture size
- wxCoord w, h;
- memDC.GetTextExtent(msg, &w, &h);
- m_tex_width = (unsigned int)w;
- m_tex_height = (unsigned int)h;
-
- // generates bitmap
- wxBitmap bitmap(m_tex_width, m_tex_height);
-
-#if defined(__APPLE__) || defined(_MSC_VER)
- bitmap.UseAlpha();
-#endif
-
- memDC.SelectObject(bitmap);
- memDC.SetBackground(wxBrush(wxColour(Background_Color[0], Background_Color[1], Background_Color[2])));
- memDC.Clear();
-
- memDC.SetTextForeground(*wxWHITE);
-
- // draw message
- memDC.DrawText(msg, 0, 0);
-
- memDC.SelectObject(wxNullBitmap);
-
- // Convert the bitmap into a linear data ready to be loaded into the GPU.
- {
- wxImage image = bitmap.ConvertToImage();
- image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]);
-
- // prepare buffer
- m_data.assign(4 * m_tex_width * m_tex_height, 0);
- for (unsigned int h = 0; h < m_tex_height; ++h)
- {
- unsigned int hh = h * m_tex_width;
- unsigned char* px_ptr = m_data.data() + 4 * hh;
- for (unsigned int w = 0; w < m_tex_width; ++w)
- {
- *px_ptr++ = image.GetRed(w, h);
- *px_ptr++ = image.GetGreen(w, h);
- *px_ptr++ = image.GetBlue(w, h);
- *px_ptr++ = image.IsTransparent(w, h) ? 0 : Opacity;
- }
- }
- }
- return true;
+ return s_canvas_mgr.use_VBOs();
}
-const unsigned char _3DScene::LegendTexture::Squares_Border_Color[3] = { 64, 64, 64 };
-const unsigned char _3DScene::LegendTexture::Background_Color[3] = { 9, 91, 134 };
-const unsigned char _3DScene::LegendTexture::Opacity = 255;
-
-// Generate a texture data, but don't load it into the GPU yet, as the GPU context may not yet be valid.
-bool _3DScene::LegendTexture::generate(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors)
+bool _3DScene::add_canvas(wxGLCanvas* canvas)
{
- // Mark the texture as released, but don't release the texture from the GPU yet.
- m_tex_width = m_tex_height = 0;
- m_data.clear();
-
- // collects items to render
- auto title = GUI::L_str(preview_data.get_legend_title());
- const GCodePreviewData::LegendItemsList& items = preview_data.get_legend_items(tool_colors);
-
- unsigned int items_count = (unsigned int)items.size();
- if (items_count == 0)
- // nothing to render, return
- return false;
-
- wxMemoryDC memDC;
- // select default font
- memDC.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
-
- // calculates texture size
- wxCoord w, h;
- memDC.GetTextExtent(title, &w, &h);
- unsigned int title_width = (unsigned int)w;
- unsigned int title_height = (unsigned int)h;
-
- unsigned int max_text_width = 0;
- unsigned int max_text_height = 0;
- for (const GCodePreviewData::LegendItem& item : items)
- {
- memDC.GetTextExtent(GUI::from_u8(item.text), &w, &h);
- max_text_width = std::max(max_text_width, (unsigned int)w);
- max_text_height = std::max(max_text_height, (unsigned int)h);
- }
-
- m_tex_width = std::max(2 * Px_Border + title_width, 2 * (Px_Border + Px_Square_Contour) + Px_Square + Px_Text_Offset + max_text_width);
- m_tex_height = 2 * (Px_Border + Px_Square_Contour) + title_height + Px_Title_Offset + items_count * Px_Square;
- if (items_count > 1)
- m_tex_height += (items_count - 1) * Px_Square_Contour;
-
- // generates bitmap
- wxBitmap bitmap(m_tex_width, m_tex_height);
-
-#if defined(__APPLE__) || defined(_MSC_VER)
- bitmap.UseAlpha();
-#endif
-
- memDC.SelectObject(bitmap);
- memDC.SetBackground(wxBrush(wxColour(Background_Color[0], Background_Color[1], Background_Color[2])));
- memDC.Clear();
-
- memDC.SetTextForeground(*wxWHITE);
-
- // draw title
- unsigned int title_x = Px_Border;
- unsigned int title_y = Px_Border;
- memDC.DrawText(title, title_x, title_y);
-
- // draw icons contours as background
- unsigned int squares_contour_x = Px_Border;
- unsigned int squares_contour_y = Px_Border + title_height + Px_Title_Offset;
- unsigned int squares_contour_width = Px_Square + 2 * Px_Square_Contour;
- unsigned int squares_contour_height = items_count * Px_Square + 2 * Px_Square_Contour;
- if (items_count > 1)
- squares_contour_height += (items_count - 1) * Px_Square_Contour;
-
- wxColour color(Squares_Border_Color[0], Squares_Border_Color[1], Squares_Border_Color[2]);
- wxPen pen(color);
- wxBrush brush(color);
- memDC.SetPen(pen);
- memDC.SetBrush(brush);
- memDC.DrawRectangle(wxRect(squares_contour_x, squares_contour_y, squares_contour_width, squares_contour_height));
-
- // draw items (colored icon + text)
- unsigned int icon_x = squares_contour_x + Px_Square_Contour;
- unsigned int icon_x_inner = icon_x + 1;
- unsigned int icon_y = squares_contour_y + Px_Square_Contour;
- unsigned int icon_y_step = Px_Square + Px_Square_Contour;
-
- unsigned int text_x = icon_x + Px_Square + Px_Text_Offset;
- unsigned int text_y_offset = (Px_Square - max_text_height) / 2;
-
- unsigned int px_inner_square = Px_Square - 2;
-
- for (const GCodePreviewData::LegendItem& item : items)
- {
- // draw darker icon perimeter
- const std::vector<unsigned char>& item_color_bytes = item.color.as_bytes();
- wxImage::HSVValue dark_hsv = wxImage::RGBtoHSV(wxImage::RGBValue(item_color_bytes[0], item_color_bytes[1], item_color_bytes[2]));
- dark_hsv.value *= 0.75;
- wxImage::RGBValue dark_rgb = wxImage::HSVtoRGB(dark_hsv);
- color.Set(dark_rgb.red, dark_rgb.green, dark_rgb.blue, item_color_bytes[3]);
- pen.SetColour(color);
- brush.SetColour(color);
- memDC.SetPen(pen);
- memDC.SetBrush(brush);
- memDC.DrawRectangle(wxRect(icon_x, icon_y, Px_Square, Px_Square));
-
- // draw icon interior
- color.Set(item_color_bytes[0], item_color_bytes[1], item_color_bytes[2], item_color_bytes[3]);
- pen.SetColour(color);
- brush.SetColour(color);
- memDC.SetPen(pen);
- memDC.SetBrush(brush);
- memDC.DrawRectangle(wxRect(icon_x_inner, icon_y + 1, px_inner_square, px_inner_square));
-
- // draw text
- memDC.DrawText(GUI::from_u8(item.text), text_x, icon_y + text_y_offset);
-
- // update y
- icon_y += icon_y_step;
- }
-
- memDC.SelectObject(wxNullBitmap);
-
- // Convert the bitmap into a linear data ready to be loaded into the GPU.
- {
- wxImage image = bitmap.ConvertToImage();
- image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]);
-
- // prepare buffer
- m_data.assign(4 * m_tex_width * m_tex_height, 0);
- for (unsigned int h = 0; h < m_tex_height; ++h)
- {
- unsigned int hh = h * m_tex_width;
- unsigned char* px_ptr = m_data.data() + 4 * hh;
- for (unsigned int w = 0; w < m_tex_width; ++w)
- {
- *px_ptr++ = image.GetRed(w, h);
- *px_ptr++ = image.GetGreen(w, h);
- *px_ptr++ = image.GetBlue(w, h);
- *px_ptr++ = image.IsTransparent(w, h) ? 0 : Opacity;
- }
- }
- }
- return true;
+ return s_canvas_mgr.add(canvas);
}
-void _3DScene::_glew_init()
-{
- glewInit();
+bool _3DScene::remove_canvas(wxGLCanvas* canvas)
+{
+ return s_canvas_mgr.remove(canvas);
}
-static inline int hex_digit_to_int(const char c)
+void _3DScene::remove_all_canvases()
{
- return
- (c >= '0' && c <= '9') ? int(c - '0') :
- (c >= 'A' && c <= 'F') ? int(c - 'A') + 10 :
- (c >= 'a' && c <= 'f') ? int(c - 'a') + 10 : -1;
+ s_canvas_mgr.remove_all();
}
-static inline std::vector<float> parse_colors(const std::vector<std::string> &scolors)
+bool _3DScene::init(wxGLCanvas* canvas)
{
- std::vector<float> output(scolors.size() * 4, 1.f);
- for (size_t i = 0; i < scolors.size(); ++ i) {
- const std::string &scolor = scolors[i];
- const char *c = scolor.data() + 1;
- if (scolor.size() == 7 && scolor.front() == '#') {
- for (size_t j = 0; j < 3; ++j) {
- int digit1 = hex_digit_to_int(*c ++);
- int digit2 = hex_digit_to_int(*c ++);
- if (digit1 == -1 || digit2 == -1)
- break;
- output[i * 4 + j] = float(digit1 * 16 + digit2) / 255.f;
- }
- }
- }
- return output;
+ return s_canvas_mgr.init(canvas);
}
-void _3DScene::load_gcode_preview(const Print* print, const GCodePreviewData* preview_data, GLVolumeCollection* volumes, const std::vector<std::string>& str_tool_colors, bool use_VBOs)
+void _3DScene::set_as_dirty(wxGLCanvas* canvas)
{
- if ((preview_data == nullptr) || (volumes == nullptr))
- return;
-
- if (volumes->empty())
- {
- std::vector<float> tool_colors = parse_colors(str_tool_colors);
-
- s_gcode_preview_volume_index.reset();
-
- _load_gcode_extrusion_paths(*preview_data, *volumes, tool_colors, use_VBOs);
- _load_gcode_travel_paths(*preview_data, *volumes, tool_colors, use_VBOs);
- _load_gcode_retractions(*preview_data, *volumes, use_VBOs);
- _load_gcode_unretractions(*preview_data, *volumes, use_VBOs);
-
- if (volumes->empty())
- reset_legend_texture();
- else
- {
- _generate_legend_texture(*preview_data, tool_colors);
- _load_shells(*print, *volumes, use_VBOs);
- }
- }
-
- _update_gcode_volumes_visibility(*preview_data, *volumes);
+ s_canvas_mgr.set_as_dirty(canvas);
}
-unsigned int _3DScene::get_legend_texture_width()
+unsigned int _3DScene::get_volumes_count(wxGLCanvas* canvas)
{
- return s_legend_texture.get_texture_width();
+ return s_canvas_mgr.get_volumes_count(canvas);
}
-unsigned int _3DScene::get_legend_texture_height()
+void _3DScene::reset_volumes(wxGLCanvas* canvas)
{
- return s_legend_texture.get_texture_height();
+ s_canvas_mgr.reset_volumes(canvas);
}
-void _3DScene::reset_legend_texture()
+void _3DScene::deselect_volumes(wxGLCanvas* canvas)
{
- s_legend_texture.reset_texture();
+ s_canvas_mgr.deselect_volumes(canvas);
}
-unsigned int _3DScene::finalize_legend_texture()
+void _3DScene::select_volume(wxGLCanvas* canvas, unsigned int id)
{
- return s_legend_texture.finalize();
+ s_canvas_mgr.select_volume(canvas, id);
}
-unsigned int _3DScene::get_warning_texture_width()
+void _3DScene::update_volumes_selection(wxGLCanvas* canvas, const std::vector<int>& selections)
{
- return s_warning_texture.get_texture_width();
+ s_canvas_mgr.update_volumes_selection(canvas, selections);
}
-unsigned int _3DScene::get_warning_texture_height()
+int _3DScene::check_volumes_outside_state(wxGLCanvas* canvas, const DynamicPrintConfig* config)
{
- return s_warning_texture.get_texture_height();
+ return s_canvas_mgr.check_volumes_outside_state(canvas, config);
}
-void _3DScene::generate_warning_texture(const std::string& msg)
+bool _3DScene::move_volume_up(wxGLCanvas* canvas, unsigned int id)
{
- s_warning_texture.generate(msg);
+ return s_canvas_mgr.move_volume_up(canvas, id);
}
-void _3DScene::reset_warning_texture()
+bool _3DScene::move_volume_down(wxGLCanvas* canvas, unsigned int id)
{
- s_warning_texture.reset_texture();
+ return s_canvas_mgr.move_volume_down(canvas, id);
}
-unsigned int _3DScene::finalize_warning_texture()
+void _3DScene::set_objects_selections(wxGLCanvas* canvas, const std::vector<int>& selections)
{
- return s_warning_texture.finalize();
+ s_canvas_mgr.set_objects_selections(canvas, selections);
}
-// Create 3D thick extrusion lines for a skirt and brim.
-// Adds a new Slic3r::GUI::3DScene::Volume to volumes.
-void _3DScene::_load_print_toolpaths(
- const Print *print,
- GLVolumeCollection *volumes,
- const std::vector<std::string> &tool_colors,
- bool use_VBOs)
+void _3DScene::set_config(wxGLCanvas* canvas, DynamicPrintConfig* config)
{
- // The skirt and brim steps should be marked as done, so their paths are valid.
- assert(print->is_step_done(psSkirt) && print->is_step_done(psBrim));
-
- if (!print->has_skirt() && print->config().brim_width.value == 0)
- return;
-
- const float color[] = { 0.5f, 1.0f, 0.5f, 1.f }; // greenish
-
- // number of skirt layers
- size_t total_layer_count = 0;
- for (const PrintObject *print_object : print->objects())
- total_layer_count = std::max(total_layer_count, print_object->total_layer_count());
- size_t skirt_height = print->has_infinite_skirt() ?
- total_layer_count :
- std::min<size_t>(print->config().skirt_height.value, total_layer_count);
- if (skirt_height == 0 && print->config().brim_width.value > 0)
- skirt_height = 1;
-
- // get first skirt_height layers (maybe this should be moved to a PrintObject method?)
- const PrintObject *object0 = print->objects().front();
- std::vector<float> print_zs;
- print_zs.reserve(skirt_height * 2);
- for (size_t i = 0; i < std::min(skirt_height, object0->layers().size()); ++ i)
- print_zs.push_back(float(object0->layers()[i]->print_z));
- //FIXME why there are support layers?
- for (size_t i = 0; i < std::min(skirt_height, object0->support_layers().size()); ++ i)
- print_zs.push_back(float(object0->support_layers()[i]->print_z));
- sort_remove_duplicates(print_zs);
- if (print_zs.size() > skirt_height)
- print_zs.erase(print_zs.begin() + skirt_height, print_zs.end());
-
- volumes->volumes.emplace_back(new GLVolume(color));
- GLVolume &volume = *volumes->volumes.back();
- for (size_t i = 0; i < skirt_height; ++ i) {
- volume.print_zs.push_back(print_zs[i]);
- volume.offsets.push_back(volume.indexed_vertex_array.quad_indices.size());
- volume.offsets.push_back(volume.indexed_vertex_array.triangle_indices.size());
- if (i == 0)
- extrusionentity_to_verts(print->brim(), print_zs[i], Point(0, 0), volume);
- extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), volume);
- }
- volume.bounding_box = volume.indexed_vertex_array.bounding_box();
- volume.indexed_vertex_array.finalize_geometry(use_VBOs);
+ s_canvas_mgr.set_config(canvas, config);
}
-// Create 3D thick extrusion lines for object forming extrusions.
-// Adds a new Slic3r::GUI::3DScene::Volume to $self->volumes,
-// one for perimeters, one for infill and one for supports.
-void _3DScene::_load_print_object_toolpaths(
- const PrintObject *print_object,
- GLVolumeCollection *volumes,
- const std::vector<std::string> &tool_colors_str,
- bool use_VBOs)
+void _3DScene::set_print(wxGLCanvas* canvas, Print* print)
{
- std::vector<float> tool_colors = parse_colors(tool_colors_str);
-
- struct Ctxt
- {
- const Points *shifted_copies;
- std::vector<const Layer*> layers;
- bool has_perimeters;
- bool has_infill;
- bool has_support;
- const std::vector<float>* tool_colors;
-
- // Number of vertices (each vertex is 6x4=24 bytes long)
- static const size_t alloc_size_max () { return 131072; } // 3.15MB
-// static const size_t alloc_size_max () { return 65536; } // 1.57MB
-// static const size_t alloc_size_max () { return 32768; } // 786kB
- static const size_t alloc_size_reserve() { return alloc_size_max() * 2; }
-
- static const float* color_perimeters () { static float color[4] = { 1.0f, 1.0f, 0.0f, 1.f }; return color; } // yellow
- static const float* color_infill () { static float color[4] = { 1.0f, 0.5f, 0.5f, 1.f }; return color; } // redish
- static const float* color_support () { static float color[4] = { 0.5f, 1.0f, 0.5f, 1.f }; return color; } // greenish
-
- // For cloring by a tool, return a parsed color.
- bool color_by_tool() const { return tool_colors != nullptr; }
- size_t number_tools() const { return this->color_by_tool() ? tool_colors->size() / 4 : 0; }
- const float* color_tool(size_t tool) const { return tool_colors->data() + tool * 4; }
- int volume_idx(int extruder, int feature) const
- { return this->color_by_tool() ? std::min<int>(this->number_tools() - 1, std::max<int>(extruder - 1, 0)) : feature; }
- } ctxt;
-
- ctxt.shifted_copies = &print_object->_shifted_copies;
-
- // order layers by print_z
- ctxt.layers.reserve(print_object->layers().size() + print_object->support_layers().size());
- for (const Layer *layer : print_object->layers())
- ctxt.layers.push_back(layer);
- for (const Layer *layer : print_object->support_layers())
- ctxt.layers.push_back(layer);
- 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)
- ctxt.has_perimeters = print_object->is_step_done(posPerimeters);
- ctxt.has_infill = print_object->is_step_done(posInfill);
- ctxt.has_support = print_object->is_step_done(posSupportMaterial);
- ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors;
-
- BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - start";
-
- //FIXME Improve the heuristics for a grain size.
- size_t grain_size = std::max(ctxt.layers.size() / 16, size_t(1));
- tbb::spin_mutex new_volume_mutex;
- auto new_volume = [volumes, &new_volume_mutex](const float *color) -> GLVolume* {
- auto *volume = new GLVolume(color);
- new_volume_mutex.lock();
- volume->outside_printer_detection_enabled = false;
- volumes->volumes.emplace_back(volume);
- new_volume_mutex.unlock();
- return volume;
- };
- const size_t volumes_cnt_initial = volumes->volumes.size();
- std::vector<GLVolumeCollection> volumes_per_thread(ctxt.layers.size());
- tbb::parallel_for(
- tbb::blocked_range<size_t>(0, ctxt.layers.size(), grain_size),
- [&ctxt, &new_volume](const tbb::blocked_range<size_t>& range) {
- std::vector<GLVolume*> vols;
- if (ctxt.color_by_tool()) {
- for (size_t i = 0; i < ctxt.number_tools(); ++ i)
- vols.emplace_back(new_volume(ctxt.color_tool(i)));
- } else
- vols = { new_volume(ctxt.color_perimeters()), new_volume(ctxt.color_infill()), new_volume(ctxt.color_support()) };
- for (GLVolume *vol : vols)
- vol->indexed_vertex_array.reserve(ctxt.alloc_size_reserve());
- for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
- const Layer *layer = ctxt.layers[idx_layer];
- for (size_t i = 0; i < vols.size(); ++ i) {
- GLVolume &vol = *vols[i];
- if (vol.print_zs.empty() || vol.print_zs.back() != layer->print_z) {
- vol.print_zs.push_back(layer->print_z);
- vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size());
- vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size());
- }
- }
- for (const Point &copy: *ctxt.shifted_copies) {
- for (const LayerRegion *layerm : layer->regions()) {
- if (ctxt.has_perimeters)
- extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy,
- *vols[ctxt.volume_idx(layerm->region()->config().perimeter_extruder.value, 0)]);
- if (ctxt.has_infill) {
- for (const ExtrusionEntity *ee : layerm->fills.entities) {
- // fill represents infill extrusions of a single island.
- const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
- if (! fill->entities.empty())
- extrusionentity_to_verts(*fill, float(layer->print_z), copy,
- *vols[ctxt.volume_idx(
- is_solid_infill(fill->entities.front()->role()) ?
- layerm->region()->config().solid_infill_extruder :
- layerm->region()->config().infill_extruder,
- 1)]);
- }
- }
- }
- if (ctxt.has_support) {
- const SupportLayer *support_layer = dynamic_cast<const SupportLayer*>(layer);
- if (support_layer) {
- for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities)
- extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy,
- *vols[ctxt.volume_idx(
- (extrusion_entity->role() == erSupportMaterial) ?
- support_layer->object()->config().support_material_extruder :
- support_layer->object()->config().support_material_interface_extruder,
- 2)]);
- }
- }
- }
- for (size_t i = 0; i < vols.size(); ++ i) {
- GLVolume &vol = *vols[i];
- if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() / 6 > ctxt.alloc_size_max()) {
- // Store the vertex arrays and restart their containers,
- vols[i] = new_volume(vol.color);
- GLVolume &vol_new = *vols[i];
- // Assign the large pre-allocated buffers to the new GLVolume.
- vol_new.indexed_vertex_array = std::move(vol.indexed_vertex_array);
- // Copy the content back to the old GLVolume.
- vol.indexed_vertex_array = vol_new.indexed_vertex_array;
- // Finalize a bounding box of the old GLVolume.
- vol.bounding_box = vol.indexed_vertex_array.bounding_box();
- // Clear the buffers, but keep them pre-allocated.
- vol_new.indexed_vertex_array.clear();
- // Just make sure that clear did not clear the reserved memory.
- vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve());
- }
- }
- }
- for (GLVolume *vol : vols) {
- vol->bounding_box = vol->indexed_vertex_array.bounding_box();
- vol->indexed_vertex_array.shrink_to_fit();
- }
- });
-
- BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results";
- // Remove empty volumes from the newly added volumes.
- volumes->volumes.erase(
- std::remove_if(volumes->volumes.begin() + volumes_cnt_initial, volumes->volumes.end(),
- [](const GLVolume *volume) { return volume->empty(); }),
- volumes->volumes.end());
- for (size_t i = volumes_cnt_initial; i < volumes->volumes.size(); ++ i)
- volumes->volumes[i]->indexed_vertex_array.finalize_geometry(use_VBOs);
-
- BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end";
-}
-
-void _3DScene::_load_wipe_tower_toolpaths(
- const Print *print,
- GLVolumeCollection *volumes,
- const std::vector<std::string> &tool_colors_str,
- bool use_VBOs)
-{
- if (print->wipe_tower_data().tool_changes.empty())
- return;
-
- std::vector<float> tool_colors = parse_colors(tool_colors_str);
-
- struct Ctxt
- {
- const Print *print;
- const std::vector<float> *tool_colors;
-
- // Number of vertices (each vertex is 6x4=24 bytes long)
- static const size_t alloc_size_max () { return 131072; } // 3.15MB
- static const size_t alloc_size_reserve() { return alloc_size_max() * 2; }
-
- static const float* color_support () { static float color[4] = { 0.5f, 1.0f, 0.5f, 1.f }; return color; } // greenish
-
- // For cloring by a tool, return a parsed color.
- bool color_by_tool() const { return tool_colors != nullptr; }
- size_t number_tools() const { return this->color_by_tool() ? tool_colors->size() / 4 : 0; }
- const float* color_tool(size_t tool) const { return tool_colors->data() + tool * 4; }
- int volume_idx(int tool, int feature) const
- { return this->color_by_tool() ? std::min<int>(this->number_tools() - 1, std::max<int>(tool, 0)) : feature; }
-
- const std::vector<WipeTower::ToolChangeResult>& tool_change(size_t idx) {
- return priming.empty() ?
- ((idx == print->wipe_tower_data().tool_changes.size()) ? final : print->wipe_tower_data().tool_changes[idx]) :
- ((idx == 0) ? priming : (idx == print->wipe_tower_data().tool_changes.size() + 1) ? final : print->wipe_tower_data().tool_changes[idx - 1]);
- }
- std::vector<WipeTower::ToolChangeResult> priming;
- std::vector<WipeTower::ToolChangeResult> final;
- } ctxt;
-
- ctxt.print = print;
- ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors;
- if (print->wipe_tower_data().priming != nullptr)
- ctxt.priming.emplace_back(*print->wipe_tower_data().priming);
- if (print->wipe_tower_data().final_purge)
- ctxt.final.emplace_back(*print->wipe_tower_data().final_purge);
-
- BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start";
-
- //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 grain_size = std::max(n_items / 128, size_t(1));
- tbb::spin_mutex new_volume_mutex;
- auto new_volume = [volumes, &new_volume_mutex](const float *color) -> GLVolume* {
- auto *volume = new GLVolume(color);
- new_volume_mutex.lock();
- volume->outside_printer_detection_enabled = false;
- volumes->volumes.emplace_back(volume);
- new_volume_mutex.unlock();
- return volume;
- };
- const size_t volumes_cnt_initial = volumes->volumes.size();
- std::vector<GLVolumeCollection> volumes_per_thread(n_items);
- tbb::parallel_for(
- tbb::blocked_range<size_t>(0, n_items, grain_size),
- [&ctxt, &new_volume](const tbb::blocked_range<size_t>& range) {
- // Bounding box of this slab of a wipe tower.
- std::vector<GLVolume*> vols;
- if (ctxt.color_by_tool()) {
- for (size_t i = 0; i < ctxt.number_tools(); ++ i)
- vols.emplace_back(new_volume(ctxt.color_tool(i)));
- } else
- vols = { new_volume(ctxt.color_support()) };
- for (GLVolume *volume : vols)
- volume->indexed_vertex_array.reserve(ctxt.alloc_size_reserve());
- for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
- const std::vector<WipeTower::ToolChangeResult> &layer = ctxt.tool_change(idx_layer);
- for (size_t i = 0; i < vols.size(); ++ i) {
- GLVolume &vol = *vols[i];
- if (vol.print_zs.empty() || vol.print_zs.back() != layer.front().print_z) {
- vol.print_zs.push_back(layer.front().print_z);
- vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size());
- vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size());
- }
- }
- for (const WipeTower::ToolChangeResult &extrusions : layer) {
- for (size_t i = 1; i < extrusions.extrusions.size();) {
- const WipeTower::Extrusion &e = extrusions.extrusions[i];
- if (e.width == 0.) {
- ++ i;
- continue;
- }
- size_t j = i + 1;
- if (ctxt.color_by_tool())
- for (; j < extrusions.extrusions.size() && extrusions.extrusions[j].tool == e.tool && extrusions.extrusions[j].width > 0.f; ++ j) ;
- else
- for (; j < extrusions.extrusions.size() && extrusions.extrusions[j].width > 0.f; ++ j) ;
- size_t n_lines = j - i;
- Lines lines;
- std::vector<double> widths;
- std::vector<double> heights;
- lines.reserve(n_lines);
- widths.reserve(n_lines);
- heights.assign(n_lines, extrusions.layer_height);
- for (; i < j; ++ i) {
- const WipeTower::Extrusion &e = extrusions.extrusions[i];
- assert(e.width > 0.f);
- const WipeTower::Extrusion &e_prev = *(&e - 1);
- lines.emplace_back(Point::new_scale(e_prev.pos.x, e_prev.pos.y), Point::new_scale(e.pos.x, e.pos.y));
- widths.emplace_back(e.width);
- }
- thick_lines_to_verts(lines, widths, heights, lines.front().a == lines.back().b, extrusions.print_z,
- *vols[ctxt.volume_idx(e.tool, 0)]);
- }
- }
- }
- for (size_t i = 0; i < vols.size(); ++ i) {
- GLVolume &vol = *vols[i];
- if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() / 6 > ctxt.alloc_size_max()) {
- // Store the vertex arrays and restart their containers,
- vols[i] = new_volume(vol.color);
- GLVolume &vol_new = *vols[i];
- // Assign the large pre-allocated buffers to the new GLVolume.
- vol_new.indexed_vertex_array = std::move(vol.indexed_vertex_array);
- // Copy the content back to the old GLVolume.
- vol.indexed_vertex_array = vol_new.indexed_vertex_array;
- // Finalize a bounding box of the old GLVolume.
- vol.bounding_box = vol.indexed_vertex_array.bounding_box();
- // Clear the buffers, but keep them pre-allocated.
- vol_new.indexed_vertex_array.clear();
- // Just make sure that clear did not clear the reserved memory.
- vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve());
- }
- }
- for (GLVolume *vol : vols) {
- vol->bounding_box = vol->indexed_vertex_array.bounding_box();
- vol->indexed_vertex_array.shrink_to_fit();
- }
- });
-
- BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results";
- // Remove empty volumes from the newly added volumes.
- volumes->volumes.erase(
- std::remove_if(volumes->volumes.begin() + volumes_cnt_initial, volumes->volumes.end(),
- [](const GLVolume *volume) { return volume->empty(); }),
- volumes->volumes.end());
- for (size_t i = volumes_cnt_initial; i < volumes->volumes.size(); ++ i)
- volumes->volumes[i]->indexed_vertex_array.finalize_geometry(use_VBOs);
-
- BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end";
+ s_canvas_mgr.set_print(canvas, print);
}
-void _3DScene::_load_gcode_extrusion_paths(const GCodePreviewData& preview_data, GLVolumeCollection& volumes, const std::vector<float>& tool_colors, bool use_VBOs)
+void _3DScene::set_model(wxGLCanvas* canvas, Model* model)
{
- // helper functions to select data in dependence of the extrusion view type
- struct Helper
- {
- static float path_filter(GCodePreviewData::Extrusion::EViewType type, const ExtrusionPath& path)
- {
- switch (type)
- {
- case GCodePreviewData::Extrusion::FeatureType:
- return (float)path.role();
- case GCodePreviewData::Extrusion::Height:
- return path.height;
- case GCodePreviewData::Extrusion::Width:
- return path.width;
- case GCodePreviewData::Extrusion::Feedrate:
- return path.feedrate;
- case GCodePreviewData::Extrusion::Tool:
- return (float)path.extruder_id;
- }
-
- return 0.0f;
- }
-
- static const GCodePreviewData::Color& path_color(const GCodePreviewData& data, const std::vector<float>& tool_colors, float value)
- {
- switch (data.extrusion.view_type)
- {
- case GCodePreviewData::Extrusion::FeatureType:
- return data.get_extrusion_role_color((ExtrusionRole)(int)value);
- case GCodePreviewData::Extrusion::Height:
- return data.get_extrusion_height_color(value);
- case GCodePreviewData::Extrusion::Width:
- return data.get_extrusion_width_color(value);
- case GCodePreviewData::Extrusion::Feedrate:
- return data.get_extrusion_feedrate_color(value);
- case GCodePreviewData::Extrusion::Tool:
- {
- static GCodePreviewData::Color color;
- ::memcpy((void*)color.rgba, (const void*)(tool_colors.data() + (unsigned int)value * 4), 4 * sizeof(float));
- return color;
- }
- }
+ s_canvas_mgr.set_model(canvas, model);
+}
- return GCodePreviewData::Color::Dummy;
- }
- };
+void _3DScene::set_bed_shape(wxGLCanvas* canvas, const Pointfs& shape)
+{
+ s_canvas_mgr.set_bed_shape(canvas, shape);
+}
- // Helper structure for filters
- struct Filter
- {
- float value;
- ExtrusionRole role;
- GLVolume* volume;
-
- Filter(float value, ExtrusionRole role)
- : value(value)
- , role(role)
- , volume(nullptr)
- {
- }
+void _3DScene::set_auto_bed_shape(wxGLCanvas* canvas)
+{
+ s_canvas_mgr.set_auto_bed_shape(canvas);
+}
- bool operator == (const Filter& other) const
- {
- if (value != other.value)
- return false;
+BoundingBoxf3 _3DScene::get_volumes_bounding_box(wxGLCanvas* canvas)
+{
+ return s_canvas_mgr.get_volumes_bounding_box(canvas);
+}
- if (role != other.role)
- return false;
+void _3DScene::set_axes_length(wxGLCanvas* canvas, float length)
+{
+ s_canvas_mgr.set_axes_length(canvas, length);
+}
- return true;
- }
- };
+void _3DScene::set_cutting_plane(wxGLCanvas* canvas, float z, const ExPolygons& polygons)
+{
+ s_canvas_mgr.set_cutting_plane(canvas, z, polygons);
+}
- typedef std::vector<Filter> FiltersList;
+void _3DScene::set_color_by(wxGLCanvas* canvas, const std::string& value)
+{
+ s_canvas_mgr.set_color_by(canvas, value);
+}
- size_t initial_volumes_count = volumes.volumes.size();
+void _3DScene::set_select_by(wxGLCanvas* canvas, const std::string& value)
+{
+ s_canvas_mgr.set_select_by(canvas, value);
+}
- // detects filters
- FiltersList filters;
- for (const GCodePreviewData::Extrusion::Layer& layer : preview_data.extrusion.layers)
- {
- for (const ExtrusionPath& path : layer.paths)
- {
- ExtrusionRole role = path.role();
- float path_filter = Helper::path_filter(preview_data.extrusion.view_type, path);
- if (std::find(filters.begin(), filters.end(), Filter(path_filter, role)) == filters.end())
- filters.emplace_back(path_filter, role);
- }
- }
+void _3DScene::set_drag_by(wxGLCanvas* canvas, const std::string& value)
+{
+ s_canvas_mgr.set_drag_by(canvas, value);
+}
- // nothing to render, return
- if (filters.empty())
- return;
+std::string _3DScene::get_select_by(wxGLCanvas* canvas)
+{
+ return s_canvas_mgr.get_select_by(canvas);
+}
- // creates a new volume for each filter
- for (Filter& filter : filters)
- {
- s_gcode_preview_volume_index.first_volumes.emplace_back(GCodePreviewVolumeIndex::Extrusion, (unsigned int)filter.role, (unsigned int)volumes.volumes.size());
+bool _3DScene::is_layers_editing_enabled(wxGLCanvas* canvas)
+{
+ return s_canvas_mgr.is_layers_editing_enabled(canvas);
+}
- GLVolume* volume = new GLVolume(Helper::path_color(preview_data, tool_colors, filter.value).rgba);
- if (volume != nullptr)
- {
- filter.volume = volume;
- volumes.volumes.emplace_back(volume);
- }
- else
- {
- // an error occourred - restore to previous state and return
- s_gcode_preview_volume_index.first_volumes.pop_back();
- if (initial_volumes_count != volumes.volumes.size())
- {
- std::vector<GLVolume*>::iterator begin = volumes.volumes.begin() + initial_volumes_count;
- std::vector<GLVolume*>::iterator end = volumes.volumes.end();
- for (std::vector<GLVolume*>::iterator it = begin; it < end; ++it)
- {
- GLVolume* volume = *it;
- delete volume;
- }
- volumes.volumes.erase(begin, end);
- return;
- }
- }
- }
+bool _3DScene::is_layers_editing_allowed(wxGLCanvas* canvas)
+{
+ return s_canvas_mgr.is_layers_editing_allowed(canvas);
+}
- // populates volumes
- for (const GCodePreviewData::Extrusion::Layer& layer : preview_data.extrusion.layers)
- {
- for (const ExtrusionPath& path : layer.paths)
- {
- float path_filter = Helper::path_filter(preview_data.extrusion.view_type, path);
- FiltersList::iterator filter = std::find(filters.begin(), filters.end(), Filter(path_filter, path.role()));
- if (filter != filters.end())
- {
- filter->volume->print_zs.push_back(layer.z);
- filter->volume->offsets.push_back(filter->volume->indexed_vertex_array.quad_indices.size());
- filter->volume->offsets.push_back(filter->volume->indexed_vertex_array.triangle_indices.size());
+bool _3DScene::is_shader_enabled(wxGLCanvas* canvas)
+{
+ return s_canvas_mgr.is_shader_enabled(canvas);
+}
- extrusionentity_to_verts(path, layer.z, *filter->volume);
- }
- }
- }
+bool _3DScene::is_reload_delayed(wxGLCanvas* canvas)
+{
+ return s_canvas_mgr.is_reload_delayed(canvas);
+}
- // finalize volumes and sends geometry to gpu
- if (volumes.volumes.size() > initial_volumes_count)
- {
- for (size_t i = initial_volumes_count; i < volumes.volumes.size(); ++i)
- {
- GLVolume* volume = volumes.volumes[i];
- volume->bounding_box = volume->indexed_vertex_array.bounding_box();
- volume->indexed_vertex_array.finalize_geometry(use_VBOs);
- }
- }
+void _3DScene::enable_layers_editing(wxGLCanvas* canvas, bool enable)
+{
+ s_canvas_mgr.enable_layers_editing(canvas, enable);
}
-void _3DScene::_load_gcode_travel_paths(const GCodePreviewData& preview_data, GLVolumeCollection& volumes, const std::vector<float>& tool_colors, bool use_VBOs)
+void _3DScene::enable_warning_texture(wxGLCanvas* canvas, bool enable)
{
- size_t initial_volumes_count = volumes.volumes.size();
- s_gcode_preview_volume_index.first_volumes.emplace_back(GCodePreviewVolumeIndex::Travel, 0, (unsigned int)initial_volumes_count);
+ s_canvas_mgr.enable_warning_texture(canvas, enable);
+}
- bool res = true;
- switch (preview_data.extrusion.view_type)
- {
- case GCodePreviewData::Extrusion::Feedrate:
- {
- res = _travel_paths_by_feedrate(preview_data, volumes);
- break;
- }
- case GCodePreviewData::Extrusion::Tool:
- {
- res = _travel_paths_by_tool(preview_data, volumes, tool_colors);
- break;
- }
- default:
- {
- res = _travel_paths_by_type(preview_data, volumes);
- break;
- }
- }
+void _3DScene::enable_legend_texture(wxGLCanvas* canvas, bool enable)
+{
+ s_canvas_mgr.enable_legend_texture(canvas, enable);
+}
- if (!res)
- {
- // an error occourred - restore to previous state and return
- if (initial_volumes_count != volumes.volumes.size())
- {
- std::vector<GLVolume*>::iterator begin = volumes.volumes.begin() + initial_volumes_count;
- std::vector<GLVolume*>::iterator end = volumes.volumes.end();
- for (std::vector<GLVolume*>::iterator it = begin; it < end; ++it)
- {
- GLVolume* volume = *it;
- delete volume;
- }
- volumes.volumes.erase(begin, end);
- }
+void _3DScene::enable_picking(wxGLCanvas* canvas, bool enable)
+{
+ s_canvas_mgr.enable_picking(canvas, enable);
+}
- return;
- }
+void _3DScene::enable_moving(wxGLCanvas* canvas, bool enable)
+{
+ s_canvas_mgr.enable_moving(canvas, enable);
+}
- // finalize volumes and sends geometry to gpu
- if (volumes.volumes.size() > initial_volumes_count)
- {
- for (size_t i = initial_volumes_count; i < volumes.volumes.size(); ++i)
- {
- GLVolume* volume = volumes.volumes[i];
- volume->bounding_box = volume->indexed_vertex_array.bounding_box();
- volume->indexed_vertex_array.finalize_geometry(use_VBOs);
- }
- }
+void _3DScene::enable_gizmos(wxGLCanvas* canvas, bool enable)
+{
+ s_canvas_mgr.enable_gizmos(canvas, enable);
}
-bool _3DScene::_travel_paths_by_type(const GCodePreviewData& preview_data, GLVolumeCollection& volumes)
+void _3DScene::enable_toolbar(wxGLCanvas* canvas, bool enable)
{
- // Helper structure for types
- struct Type
- {
- GCodePreviewData::Travel::EType value;
- GLVolume* volume;
+ s_canvas_mgr.enable_toolbar(canvas, enable);
+}
- explicit Type(GCodePreviewData::Travel::EType value)
- : value(value)
- , volume(nullptr)
- {
- }
+void _3DScene::enable_shader(wxGLCanvas* canvas, bool enable)
+{
+ s_canvas_mgr.enable_shader(canvas, enable);
+}
- bool operator == (const Type& other) const
- {
- return value == other.value;
- }
- };
+void _3DScene::enable_force_zoom_to_bed(wxGLCanvas* canvas, bool enable)
+{
+ s_canvas_mgr.enable_force_zoom_to_bed(canvas, enable);
+}
- typedef std::vector<Type> TypesList;
+void _3DScene::enable_dynamic_background(wxGLCanvas* canvas, bool enable)
+{
+ s_canvas_mgr.enable_dynamic_background(canvas, enable);
+}
- // colors travels by travel type
+void _3DScene::allow_multisample(wxGLCanvas* canvas, bool allow)
+{
+ s_canvas_mgr.allow_multisample(canvas, allow);
+}
- // detects types
- TypesList types;
- for (const GCodePreviewData::Travel::Polyline& polyline : preview_data.travel.polylines)
- {
- if (std::find(types.begin(), types.end(), Type(polyline.type)) == types.end())
- types.emplace_back(polyline.type);
- }
+void _3DScene::enable_toolbar_item(wxGLCanvas* canvas, const std::string& name, bool enable)
+{
+ s_canvas_mgr.enable_toolbar_item(canvas, name, enable);
+}
- // nothing to render, return
- if (types.empty())
- return true;
+bool _3DScene::is_toolbar_item_pressed(wxGLCanvas* canvas, const std::string& name)
+{
+ return s_canvas_mgr.is_toolbar_item_pressed(canvas, name);
+}
- // creates a new volume for each type
- for (Type& type : types)
- {
- GLVolume* volume = new GLVolume(preview_data.travel.type_colors[type.value].rgba);
- if (volume == nullptr)
- return false;
- else
- {
- type.volume = volume;
- volumes.volumes.emplace_back(volume);
- }
- }
+void _3DScene::zoom_to_bed(wxGLCanvas* canvas)
+{
+ s_canvas_mgr.zoom_to_bed(canvas);
+}
- // populates volumes
- for (const GCodePreviewData::Travel::Polyline& polyline : preview_data.travel.polylines)
- {
- TypesList::iterator type = std::find(types.begin(), types.end(), Type(polyline.type));
- if (type != types.end())
- {
- type->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().max.z));
- type->volume->offsets.push_back(type->volume->indexed_vertex_array.quad_indices.size());
- type->volume->offsets.push_back(type->volume->indexed_vertex_array.triangle_indices.size());
+void _3DScene::zoom_to_volumes(wxGLCanvas* canvas)
+{
+ s_canvas_mgr.zoom_to_volumes(canvas);
+}
- polyline3_to_verts(polyline.polyline, preview_data.travel.width, preview_data.travel.height, *type->volume);
- }
- }
+void _3DScene::select_view(wxGLCanvas* canvas, const std::string& direction)
+{
+ s_canvas_mgr.select_view(canvas, direction);
+}
- return true;
+void _3DScene::set_viewport_from_scene(wxGLCanvas* canvas, wxGLCanvas* other)
+{
+ s_canvas_mgr.set_viewport_from_scene(canvas, other);
}
-bool _3DScene::_travel_paths_by_feedrate(const GCodePreviewData& preview_data, GLVolumeCollection& volumes)
+void _3DScene::update_volumes_colors_by_extruder(wxGLCanvas* canvas)
{
- // Helper structure for feedrate
- struct Feedrate
- {
- float value;
- GLVolume* volume;
+ s_canvas_mgr.update_volumes_colors_by_extruder(canvas);
+}
- explicit Feedrate(float value)
- : value(value)
- , volume(nullptr)
- {
- }
+void _3DScene::update_gizmos_data(wxGLCanvas* canvas)
+{
+ s_canvas_mgr.update_gizmos_data(canvas);
+}
- bool operator == (const Feedrate& other) const
- {
- return value == other.value;
- }
- };
+void _3DScene::render(wxGLCanvas* canvas)
+{
+ s_canvas_mgr.render(canvas);
+}
- typedef std::vector<Feedrate> FeedratesList;
+std::vector<double> _3DScene::get_current_print_zs(wxGLCanvas* canvas, bool active_only)
+{
+ return s_canvas_mgr.get_current_print_zs(canvas, active_only);
+}
- // colors travels by feedrate
+void _3DScene::set_toolpaths_range(wxGLCanvas* canvas, double low, double high)
+{
+ s_canvas_mgr.set_toolpaths_range(canvas, low, high);
+}
- // detects feedrates
- FeedratesList feedrates;
- for (const GCodePreviewData::Travel::Polyline& polyline : preview_data.travel.polylines)
- {
- if (std::find(feedrates.begin(), feedrates.end(), Feedrate(polyline.feedrate)) == feedrates.end())
- feedrates.emplace_back(polyline.feedrate);
- }
+void _3DScene::register_on_viewport_changed_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_viewport_changed_callback(canvas, callback);
+}
- // nothing to render, return
- if (feedrates.empty())
- return true;
+void _3DScene::register_on_double_click_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_double_click_callback(canvas, callback);
+}
- // creates a new volume for each feedrate
- for (Feedrate& feedrate : feedrates)
- {
- GLVolume* volume = new GLVolume(preview_data.get_extrusion_feedrate_color(feedrate.value).rgba);
- if (volume == nullptr)
- return false;
- else
- {
- feedrate.volume = volume;
- volumes.volumes.emplace_back(volume);
- }
- }
+void _3DScene::register_on_right_click_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_right_click_callback(canvas, callback);
+}
- // populates volumes
- for (const GCodePreviewData::Travel::Polyline& polyline : preview_data.travel.polylines)
- {
- FeedratesList::iterator feedrate = std::find(feedrates.begin(), feedrates.end(), Feedrate(polyline.feedrate));
- if (feedrate != feedrates.end())
- {
- feedrate->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().max.z));
- feedrate->volume->offsets.push_back(feedrate->volume->indexed_vertex_array.quad_indices.size());
- feedrate->volume->offsets.push_back(feedrate->volume->indexed_vertex_array.triangle_indices.size());
+void _3DScene::register_on_select_object_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_select_object_callback(canvas, callback);
+}
- polyline3_to_verts(polyline.polyline, preview_data.travel.width, preview_data.travel.height, *feedrate->volume);
- }
- }
+void _3DScene::register_on_model_update_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_model_update_callback(canvas, callback);
+}
- return true;
+void _3DScene::register_on_remove_object_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_remove_object_callback(canvas, callback);
}
-bool _3DScene::_travel_paths_by_tool(const GCodePreviewData& preview_data, GLVolumeCollection& volumes, const std::vector<float>& tool_colors)
+void _3DScene::register_on_arrange_callback(wxGLCanvas* canvas, void* callback)
{
- // Helper structure for tool
- struct Tool
- {
- unsigned int value;
- GLVolume* volume;
+ s_canvas_mgr.register_on_arrange_callback(canvas, callback);
+}
- explicit Tool(unsigned int value)
- : value(value)
- , volume(nullptr)
- {
- }
+void _3DScene::register_on_rotate_object_left_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_rotate_object_left_callback(canvas, callback);
+}
- bool operator == (const Tool& other) const
- {
- return value == other.value;
- }
- };
+void _3DScene::register_on_rotate_object_right_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_rotate_object_right_callback(canvas, callback);
+}
- typedef std::vector<Tool> ToolsList;
+void _3DScene::register_on_scale_object_uniformly_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_scale_object_uniformly_callback(canvas, callback);
+}
- // colors travels by tool
+void _3DScene::register_on_increase_objects_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_increase_objects_callback(canvas, callback);
+}
- // detects tools
- ToolsList tools;
- for (const GCodePreviewData::Travel::Polyline& polyline : preview_data.travel.polylines)
- {
- if (std::find(tools.begin(), tools.end(), Tool(polyline.extruder_id)) == tools.end())
- tools.emplace_back(polyline.extruder_id);
- }
+void _3DScene::register_on_decrease_objects_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_decrease_objects_callback(canvas, callback);
+}
- // nothing to render, return
- if (tools.empty())
- return true;
+void _3DScene::register_on_instance_moved_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_instance_moved_callback(canvas, callback);
+}
- // creates a new volume for each tool
- for (Tool& tool : tools)
- {
- GLVolume* volume = new GLVolume(tool_colors.data() + tool.value * 4);
- if (volume == nullptr)
- return false;
- else
- {
- tool.volume = volume;
- volumes.volumes.emplace_back(volume);
- }
- }
+void _3DScene::register_on_wipe_tower_moved_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_wipe_tower_moved_callback(canvas, callback);
+}
- // populates volumes
- for (const GCodePreviewData::Travel::Polyline& polyline : preview_data.travel.polylines)
- {
- ToolsList::iterator tool = std::find(tools.begin(), tools.end(), Tool(polyline.extruder_id));
- if (tool != tools.end())
- {
- tool->volume->print_zs.push_back(unscale(polyline.polyline.bounding_box().max.z));
- tool->volume->offsets.push_back(tool->volume->indexed_vertex_array.quad_indices.size());
- tool->volume->offsets.push_back(tool->volume->indexed_vertex_array.triangle_indices.size());
+void _3DScene::register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_enable_action_buttons_callback(canvas, callback);
+}
- polyline3_to_verts(polyline.polyline, preview_data.travel.width, preview_data.travel.height, *tool->volume);
- }
- }
+void _3DScene::register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_gizmo_scale_uniformly_callback(canvas, callback);
+}
- return true;
+void _3DScene::register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_gizmo_rotate_callback(canvas, callback);
}
-void _3DScene::_load_gcode_retractions(const GCodePreviewData& preview_data, GLVolumeCollection& volumes, bool use_VBOs)
+void _3DScene::register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback)
{
- s_gcode_preview_volume_index.first_volumes.emplace_back(GCodePreviewVolumeIndex::Retraction, 0, (unsigned int)volumes.volumes.size());
+ s_canvas_mgr.register_on_gizmo_flatten_callback(canvas, callback);
+}
- // nothing to render, return
- if (preview_data.retraction.positions.empty())
- return;
+void _3DScene::register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_on_update_geometry_info_callback(canvas, callback);
+}
- GLVolume* volume = new GLVolume(preview_data.retraction.color.rgba);
- if (volume != nullptr)
- {
- volumes.volumes.emplace_back(volume);
+void _3DScene::register_action_add_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_action_add_callback(canvas, callback);
+}
- for (const GCodePreviewData::Retraction::Position& position : preview_data.retraction.positions)
- {
- volume->print_zs.push_back(unscale(position.position.z));
- volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size());
- volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size());
+void _3DScene::register_action_delete_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_action_delete_callback(canvas, callback);
+}
- point3_to_verts(position.position, position.width, position.height, *volume);
- }
+void _3DScene::register_action_deleteall_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_action_deleteall_callback(canvas, callback);
+}
- // finalize volumes and sends geometry to gpu
- volume->bounding_box = volume->indexed_vertex_array.bounding_box();
- volume->indexed_vertex_array.finalize_geometry(use_VBOs);
- }
+void _3DScene::register_action_arrange_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_action_arrange_callback(canvas, callback);
}
-void _3DScene::_load_gcode_unretractions(const GCodePreviewData& preview_data, GLVolumeCollection& volumes, bool use_VBOs)
+void _3DScene::register_action_more_callback(wxGLCanvas* canvas, void* callback)
{
- s_gcode_preview_volume_index.first_volumes.emplace_back(GCodePreviewVolumeIndex::Unretraction, 0, (unsigned int)volumes.volumes.size());
+ s_canvas_mgr.register_action_more_callback(canvas, callback);
+}
- // nothing to render, return
- if (preview_data.unretraction.positions.empty())
- return;
+void _3DScene::register_action_fewer_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_action_fewer_callback(canvas, callback);
+}
- GLVolume* volume = new GLVolume(preview_data.unretraction.color.rgba);
- if (volume != nullptr)
- {
- volumes.volumes.emplace_back(volume);
+void _3DScene::register_action_split_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_action_split_callback(canvas, callback);
+}
- for (const GCodePreviewData::Retraction::Position& position : preview_data.unretraction.positions)
- {
- volume->print_zs.push_back(unscale(position.position.z));
- volume->offsets.push_back(volume->indexed_vertex_array.quad_indices.size());
- volume->offsets.push_back(volume->indexed_vertex_array.triangle_indices.size());
+void _3DScene::register_action_cut_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_action_cut_callback(canvas, callback);
+}
- point3_to_verts(position.position, position.width, position.height, *volume);
- }
+void _3DScene::register_action_settings_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_action_settings_callback(canvas, callback);
+}
- // finalize volumes and sends geometry to gpu
- volume->bounding_box = volume->indexed_vertex_array.bounding_box();
- volume->indexed_vertex_array.finalize_geometry(use_VBOs);
- }
+void _3DScene::register_action_layersediting_callback(wxGLCanvas* canvas, void* callback)
+{
+ s_canvas_mgr.register_action_layersediting_callback(canvas, callback);
}
-void _3DScene::_update_gcode_volumes_visibility(const GCodePreviewData& preview_data, GLVolumeCollection& volumes)
+void _3DScene::register_action_selectbyparts_callback(wxGLCanvas* canvas, void* callback)
{
- unsigned int size = (unsigned int)s_gcode_preview_volume_index.first_volumes.size();
- for (unsigned int i = 0; i < size; ++i)
- {
- std::vector<GLVolume*>::iterator begin = volumes.volumes.begin() + s_gcode_preview_volume_index.first_volumes[i].id;
- std::vector<GLVolume*>::iterator end = (i + 1 < size) ? volumes.volumes.begin() + s_gcode_preview_volume_index.first_volumes[i + 1].id : volumes.volumes.end();
+ s_canvas_mgr.register_action_selectbyparts_callback(canvas, callback);
+}
- for (std::vector<GLVolume*>::iterator it = begin; it != end; ++it)
- {
- GLVolume* volume = *it;
- volume->outside_printer_detection_enabled = false;
+static inline int hex_digit_to_int(const char c)
+{
+ return
+ (c >= '0' && c <= '9') ? int(c - '0') :
+ (c >= 'A' && c <= 'F') ? int(c - 'A') + 10 :
+ (c >= 'a' && c <= 'f') ? int(c - 'a') + 10 : -1;
+}
- switch (s_gcode_preview_volume_index.first_volumes[i].type)
- {
- case GCodePreviewVolumeIndex::Extrusion:
- {
- if ((ExtrusionRole)s_gcode_preview_volume_index.first_volumes[i].flag == erCustom)
- volume->zoom_to_volumes = false;
-
- volume->is_active = preview_data.extrusion.is_role_flag_set((ExtrusionRole)s_gcode_preview_volume_index.first_volumes[i].flag);
- break;
- }
- case GCodePreviewVolumeIndex::Travel:
- {
- volume->is_active = preview_data.travel.is_visible;
- volume->zoom_to_volumes = false;
- break;
- }
- case GCodePreviewVolumeIndex::Retraction:
- {
- volume->is_active = preview_data.retraction.is_visible;
- volume->zoom_to_volumes = false;
- break;
- }
- case GCodePreviewVolumeIndex::Unretraction:
- {
- volume->is_active = preview_data.unretraction.is_visible;
- volume->zoom_to_volumes = false;
- break;
- }
- case GCodePreviewVolumeIndex::Shell:
- {
- volume->is_active = preview_data.shell.is_visible;
- volume->color[3] = 0.25f;
- volume->zoom_to_volumes = false;
- break;
- }
- default:
- {
- volume->is_active = false;
- volume->zoom_to_volumes = false;
+static inline std::vector<float> parse_colors(const std::vector<std::string> &scolors)
+{
+ std::vector<float> output(scolors.size() * 4, 1.f);
+ for (size_t i = 0; i < scolors.size(); ++ i) {
+ const std::string &scolor = scolors[i];
+ const char *c = scolor.data() + 1;
+ if (scolor.size() == 7 && scolor.front() == '#') {
+ for (size_t j = 0; j < 3; ++j) {
+ int digit1 = hex_digit_to_int(*c ++);
+ int digit2 = hex_digit_to_int(*c ++);
+ if (digit1 == -1 || digit2 == -1)
break;
- }
+ output[i * 4 + j] = float(digit1 * 16 + digit2) / 255.f;
}
}
}
+ return output;
}
-void _3DScene::_generate_legend_texture(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors)
+std::vector<int> _3DScene::load_object(wxGLCanvas* canvas, const ModelObject* model_object, int obj_idx, std::vector<int> instance_idxs)
{
- s_legend_texture.generate(preview_data, tool_colors);
+ return s_canvas_mgr.load_object(canvas, model_object, obj_idx, instance_idxs);
}
-void _3DScene::_load_shells(const Print& print, GLVolumeCollection& volumes, bool use_VBOs)
+std::vector<int> _3DScene::load_object(wxGLCanvas* canvas, const Model* model, int obj_idx)
{
- size_t initial_volumes_count = volumes.volumes.size();
- s_gcode_preview_volume_index.first_volumes.emplace_back(GCodePreviewVolumeIndex::Shell, 0, (unsigned int)initial_volumes_count);
-
- if (print.objects().empty())
- // nothing to render, return
- return;
-
- // adds objects' volumes
- unsigned int object_id = 0;
- for (PrintObject* obj : print.objects())
- {
- ModelObject* model_obj = obj->model_object();
+ return s_canvas_mgr.load_object(canvas, model, obj_idx);
+}
- std::vector<int> instance_ids(model_obj->instances.size());
- for (int i = 0; i < model_obj->instances.size(); ++i)
- {
- instance_ids[i] = i;
- }
+int _3DScene::get_first_volume_id(wxGLCanvas* canvas, int obj_idx)
+{
+ return s_canvas_mgr.get_first_volume_id(canvas, obj_idx);
+}
- for (ModelInstance* instance : model_obj->instances)
- {
- volumes.load_object(model_obj, object_id, instance_ids, "object", "object", "object", use_VBOs);
- }
+void _3DScene::reload_scene(wxGLCanvas* canvas, bool force)
+{
+ s_canvas_mgr.reload_scene(canvas, force);
+}
- ++object_id;
- }
+void _3DScene::load_gcode_preview(wxGLCanvas* canvas, const GCodePreviewData* preview_data, const std::vector<std::string>& str_tool_colors)
+{
+ s_canvas_mgr.load_gcode_preview(canvas, preview_data, str_tool_colors);
+}
- // adds wipe tower's volume
- coordf_t max_z = print.objects().front()->model_object()->get_model()->bounding_box().max.z;
- const PrintConfig& config = print.config();
- unsigned int extruders_count = config.nozzle_diameter.size();
- if ((extruders_count > 1) && config.single_extruder_multi_material && config.wipe_tower && !config.complete_objects)
- volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, config.wipe_tower_per_color_wipe * (extruders_count - 1), max_z, use_VBOs);
+void _3DScene::load_preview(wxGLCanvas* canvas, const std::vector<std::string>& str_tool_colors)
+{
+ s_canvas_mgr.load_preview(canvas, str_tool_colors);
}
+void _3DScene::reset_legend_texture()
+{
+ s_canvas_mgr.reset_legend_texture();
}
+
+} // namespace Slic3r